nstantpage-agent 0.2.0
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/README.md +207 -0
- package/dist/checker.d.ts +35 -0
- package/dist/checker.js +151 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +67 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.js +62 -0
- package/dist/commands/start.d.ts +23 -0
- package/dist/commands/start.js +140 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +53 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +23 -0
- package/dist/devServer.d.ts +65 -0
- package/dist/devServer.js +308 -0
- package/dist/errorStore.d.ts +51 -0
- package/dist/errorStore.js +167 -0
- package/dist/fileManager.d.ts +44 -0
- package/dist/fileManager.js +129 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/localServer.d.ts +70 -0
- package/dist/localServer.js +555 -0
- package/dist/packageInstaller.d.ts +29 -0
- package/dist/packageInstaller.js +111 -0
- package/dist/tunnel.d.ts +71 -0
- package/dist/tunnel.js +247 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# nstantpage-agent
|
|
2
|
+
|
|
3
|
+
Local development agent for [nstantpage.com](https://nstantpage.com) ā run your projects on your own machine with full native performance while editing in the cloud.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
The agent **replaces cloud Docker containers** for your project. Instead of running your dev server in a remote container (which can be slow for heavy projects), the agent:
|
|
8
|
+
|
|
9
|
+
- š„ļø Runs the dev server (Vite/Next.js) **natively on your machine**
|
|
10
|
+
- š Receives file changes from the cloud editor through a secure tunnel
|
|
11
|
+
- š Runs TypeScript type checking locally (full speed, no container limits)
|
|
12
|
+
- š¦ Installs packages using your local npm/pnpm
|
|
13
|
+
- š Connects to the cloud editor through a WebSocket tunnel
|
|
14
|
+
|
|
15
|
+
Your browser still uses the nstantpage.com editor ā but all the heavy lifting happens on your computer.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- **Node.js 18+** (20+ recommended)
|
|
20
|
+
- **npm**, **pnpm**, or **yarn**
|
|
21
|
+
- Works on **macOS**, **Windows**, and **Linux**
|
|
22
|
+
|
|
23
|
+
## Installation & Usage
|
|
24
|
+
|
|
25
|
+
### Quick Start (no install needed)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx nstantpage-agent start --project-id YOUR_PROJECT_ID
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Global Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g nstantpage-agent
|
|
35
|
+
|
|
36
|
+
# Then:
|
|
37
|
+
nstantpage login
|
|
38
|
+
nstantpage start --project-id YOUR_PROJECT_ID
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Step by Step
|
|
42
|
+
|
|
43
|
+
1. **Authenticate** (one-time):
|
|
44
|
+
```bash
|
|
45
|
+
npx nstantpage-agent login
|
|
46
|
+
```
|
|
47
|
+
This opens your browser to authenticate with nstantpage.com.
|
|
48
|
+
|
|
49
|
+
2. **Start the agent** in your project directory:
|
|
50
|
+
```bash
|
|
51
|
+
cd /path/to/your/project
|
|
52
|
+
npx nstantpage-agent start --project-id 1234
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or from anywhere:
|
|
56
|
+
```bash
|
|
57
|
+
npx nstantpage-agent start /path/to/your/project --project-id 1234
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
3. **Open nstantpage.com** ā you'll see the purple "Local" indicator in the header, confirming the agent is connected.
|
|
61
|
+
|
|
62
|
+
### Project Configuration
|
|
63
|
+
|
|
64
|
+
Create a `.nstantpage.json` file in your project root to skip the `--project-id` flag:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"projectId": "1234"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then just run:
|
|
73
|
+
```bash
|
|
74
|
+
npx nstantpage-agent start
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## CLI Commands
|
|
78
|
+
|
|
79
|
+
| Command | Description |
|
|
80
|
+
|---------|-------------|
|
|
81
|
+
| `nstantpage login` | Authenticate with nstantpage.com |
|
|
82
|
+
| `nstantpage start [dir]` | Start the agent for a project |
|
|
83
|
+
| `nstantpage stop` | Stop the running agent |
|
|
84
|
+
| `nstantpage status` | Show agent connection status |
|
|
85
|
+
|
|
86
|
+
### Start Options
|
|
87
|
+
|
|
88
|
+
| Flag | Default | Description |
|
|
89
|
+
|------|---------|-------------|
|
|
90
|
+
| `-p, --port <port>` | `3000` | Local dev server port |
|
|
91
|
+
| `-a, --api-port <port>` | `18924` | Internal API port |
|
|
92
|
+
| `--project-id <id>` | ā | Link to a specific project |
|
|
93
|
+
| `--gateway <url>` | `wss://webprev.live` | Gateway URL |
|
|
94
|
+
| `--no-dev` | ā | Don't start dev server automatically |
|
|
95
|
+
|
|
96
|
+
## How It Works
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
āāāāāāāāāāāāāāāāāāāāāāā WebSocket Tunnel āāāāāāāāāāāāāāāāāāāā
|
|
100
|
+
ā nstantpage.com ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŗ ā Your Computer ā
|
|
101
|
+
ā (Cloud Editor) ā /live/* API + Dev traffic ā ā
|
|
102
|
+
ā ā ā āāāāāāāāāāāāāā ā
|
|
103
|
+
ā - Chat with AI ā ā ā API Server ā ā
|
|
104
|
+
ā - Edit code ā All /live/* requests ā ā (port 18924)ā ā
|
|
105
|
+
ā - See preview ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŗ ā āāāāāāāāāāāāāā ā
|
|
106
|
+
ā ā ā ā
|
|
107
|
+
ā āāāāāāāāāāāāāāāāā ā ā āāāāāāāāāāāāāā ā
|
|
108
|
+
ā ā Preview iFrameā ā Dev server traffic ā ā Vite/Next ā ā
|
|
109
|
+
ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā (port 3000) ā ā
|
|
110
|
+
ā āāāāāāāāāāāāāāāāā ā ā āāāāāāāāāāāāāā ā
|
|
111
|
+
āāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
1. **API Server** (port 18924): Handles file sync, type checking, error tracking, package installation ā everything the cloud containers used to do.
|
|
115
|
+
|
|
116
|
+
2. **Dev Server** (port 3000): Runs Vite/Next.js natively with full access to your machine's CPU and RAM. No container memory limits.
|
|
117
|
+
|
|
118
|
+
3. **Tunnel**: Secure WebSocket connection to the gateway. Routes cloud editor requests to your local servers.
|
|
119
|
+
|
|
120
|
+
## Testing Locally
|
|
121
|
+
|
|
122
|
+
### Test the agent against a local gateway
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Terminal 1: Start the gateway
|
|
126
|
+
cd PreviewGateway && node dist/index-v2.js
|
|
127
|
+
|
|
128
|
+
# Terminal 2: Start the agent
|
|
129
|
+
cd nstantpage-agent
|
|
130
|
+
npx tsx src/cli.ts start /path/to/project \
|
|
131
|
+
--project-id 1234 \
|
|
132
|
+
--gateway ws://localhost:4000
|
|
133
|
+
|
|
134
|
+
# Terminal 3: Verify connection
|
|
135
|
+
curl http://localhost:4000/live/agent-status?projectId=1234
|
|
136
|
+
# ā {"connected":true,"projectId":"1234","agent":{"version":"0.2.0",...}}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Test individual components
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
cd nstantpage-agent
|
|
143
|
+
|
|
144
|
+
# Type check
|
|
145
|
+
npx tsc --noEmit
|
|
146
|
+
|
|
147
|
+
# Run in dev mode (auto-reloads)
|
|
148
|
+
npx tsx src/cli.ts start . --project-id test --gateway ws://localhost:4000
|
|
149
|
+
|
|
150
|
+
# Build
|
|
151
|
+
npm run build
|
|
152
|
+
|
|
153
|
+
# Run built version
|
|
154
|
+
node dist/cli.js start . --project-id test --gateway ws://localhost:4000
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Troubleshooting
|
|
158
|
+
|
|
159
|
+
### "Not authenticated" error
|
|
160
|
+
Run `npx nstantpage-agent login` to authenticate.
|
|
161
|
+
|
|
162
|
+
### Port already in use
|
|
163
|
+
Use `--port` and `--api-port` flags to change ports:
|
|
164
|
+
```bash
|
|
165
|
+
npx nstantpage-agent start --port 3001 --api-port 18925
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Agent connects but preview doesn't load
|
|
169
|
+
- Make sure your project has a valid `package.json`
|
|
170
|
+
- Check that `npx vite` or `npx next dev` works in your project directory
|
|
171
|
+
- Try `--no-dev` to skip auto-starting the dev server, then start it manually
|
|
172
|
+
|
|
173
|
+
### Windows: `npx` not found
|
|
174
|
+
Make sure Node.js is in your PATH. Try running from PowerShell or Git Bash.
|
|
175
|
+
|
|
176
|
+
### macOS: Permission denied
|
|
177
|
+
If you get EACCES errors, the agent may need access to the project directory. Check file permissions.
|
|
178
|
+
|
|
179
|
+
## Platform Notes
|
|
180
|
+
|
|
181
|
+
| Platform | Status | Notes |
|
|
182
|
+
|----------|--------|-------|
|
|
183
|
+
| macOS (Intel/Apple Silicon) | ā
Full support | Recommended |
|
|
184
|
+
| Windows 10/11 | ā
Full support | Use PowerShell or Git Bash |
|
|
185
|
+
| Linux (Ubuntu/Debian/Fedora) | ā
Full support | Tested on Ubuntu 22.04+ |
|
|
186
|
+
| WSL2 | ā
Works | Run inside WSL2 terminal |
|
|
187
|
+
|
|
188
|
+
## Architecture
|
|
189
|
+
|
|
190
|
+
The agent consists of these modules:
|
|
191
|
+
|
|
192
|
+
- **`localServer.ts`** ā HTTP server handling all `/live/*` API endpoints locally
|
|
193
|
+
- **`tunnel.ts`** ā WebSocket client that connects to the gateway and routes requests
|
|
194
|
+
- **`devServer.ts`** ā Manages local Vite/Next.js/Express dev server processes
|
|
195
|
+
- **`fileManager.ts`** ā File I/O (replaces `docker cp`)
|
|
196
|
+
- **`checker.ts`** ā TypeScript type checking (replaces container-based `tsc`)
|
|
197
|
+
- **`packageInstaller.ts`** ā npm/pnpm/yarn package installation
|
|
198
|
+
- **`errorStore.ts`** ā Error tracking and deduplication
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd nstantpage-agent
|
|
204
|
+
npm install
|
|
205
|
+
npm run build # Compile TypeScript
|
|
206
|
+
npm run dev # Run in watch mode with tsx
|
|
207
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Checker ā runs tsc to detect type errors.
|
|
3
|
+
* Replaces the container-based type checking from the gateway.
|
|
4
|
+
*
|
|
5
|
+
* Uses the TypeScript compiler API or `npx tsc --noEmit` for checking.
|
|
6
|
+
*/
|
|
7
|
+
import { type StructuredError } from './errorStore.js';
|
|
8
|
+
export interface CheckerOptions {
|
|
9
|
+
projectDir: string;
|
|
10
|
+
projectId: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class Checker {
|
|
13
|
+
private projectDir;
|
|
14
|
+
private projectId;
|
|
15
|
+
constructor(options: CheckerOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Run TypeScript type checking on the project.
|
|
18
|
+
* Returns structured errors.
|
|
19
|
+
*/
|
|
20
|
+
checkTypes(filterFiles?: string[]): Promise<StructuredError[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Run a full check: type check + collect build errors from Vite stderr.
|
|
23
|
+
*/
|
|
24
|
+
fullCheck(filterFiles?: string[]): Promise<{
|
|
25
|
+
typeErrors: StructuredError[];
|
|
26
|
+
allErrors: StructuredError[];
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Validate hard patterns in source code (fast, stateless).
|
|
30
|
+
* Checks for common anti-patterns that break builds.
|
|
31
|
+
*/
|
|
32
|
+
validateHardPatterns(filePath: string, code: string): Promise<StructuredError[]>;
|
|
33
|
+
private runTsc;
|
|
34
|
+
private parseTscOutput;
|
|
35
|
+
}
|
package/dist/checker.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Checker ā runs tsc to detect type errors.
|
|
3
|
+
* Replaces the container-based type checking from the gateway.
|
|
4
|
+
*
|
|
5
|
+
* Uses the TypeScript compiler API or `npx tsc --noEmit` for checking.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { parseErrorString } from './errorStore.js';
|
|
11
|
+
export class Checker {
|
|
12
|
+
projectDir;
|
|
13
|
+
projectId;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.projectDir = options.projectDir;
|
|
16
|
+
this.projectId = options.projectId;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run TypeScript type checking on the project.
|
|
20
|
+
* Returns structured errors.
|
|
21
|
+
*/
|
|
22
|
+
async checkTypes(filterFiles) {
|
|
23
|
+
const tsconfigPath = path.join(this.projectDir, 'tsconfig.json');
|
|
24
|
+
if (!existsSync(tsconfigPath)) {
|
|
25
|
+
// No tsconfig ā skip type checking
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const output = await this.runTsc(filterFiles);
|
|
30
|
+
return this.parseTscOutput(output, filterFiles);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
console.error(` [Checker] Type check failed: ${err.message}`);
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run a full check: type check + collect build errors from Vite stderr.
|
|
39
|
+
*/
|
|
40
|
+
async fullCheck(filterFiles) {
|
|
41
|
+
const typeErrors = await this.checkTypes(filterFiles);
|
|
42
|
+
const allErrors = [...typeErrors];
|
|
43
|
+
// Deduplicate
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
const deduped = allErrors.filter(e => {
|
|
46
|
+
if (seen.has(e.signature))
|
|
47
|
+
return false;
|
|
48
|
+
seen.add(e.signature);
|
|
49
|
+
return true;
|
|
50
|
+
});
|
|
51
|
+
return { typeErrors, allErrors: deduped };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate hard patterns in source code (fast, stateless).
|
|
55
|
+
* Checks for common anti-patterns that break builds.
|
|
56
|
+
*/
|
|
57
|
+
async validateHardPatterns(filePath, code) {
|
|
58
|
+
const errors = [];
|
|
59
|
+
// Check for common issues
|
|
60
|
+
const lines = code.split('\n');
|
|
61
|
+
for (let i = 0; i < lines.length; i++) {
|
|
62
|
+
const line = lines[i];
|
|
63
|
+
const lineNum = i + 1;
|
|
64
|
+
// Detect require() in ES module context
|
|
65
|
+
if (/\brequire\s*\(/.test(line) && !line.includes('// eslint-disable')) {
|
|
66
|
+
// Only flag if it's not in a comment
|
|
67
|
+
const trimmed = line.trim();
|
|
68
|
+
if (!trimmed.startsWith('//') && !trimmed.startsWith('*')) {
|
|
69
|
+
errors.push({
|
|
70
|
+
file: filePath,
|
|
71
|
+
line: lineNum,
|
|
72
|
+
message: 'require() is not allowed in ES modules. Use import instead.',
|
|
73
|
+
type: 'hard',
|
|
74
|
+
signature: `hard:${filePath}:${lineNum}:require-in-esm`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Detect document/window in server-side code
|
|
79
|
+
if (filePath.startsWith('server/') && (/\bdocument\b/.test(line) || /\bwindow\b/.test(line))) {
|
|
80
|
+
const trimmed = line.trim();
|
|
81
|
+
if (!trimmed.startsWith('//') && !trimmed.startsWith('*')) {
|
|
82
|
+
errors.push({
|
|
83
|
+
file: filePath,
|
|
84
|
+
line: lineNum,
|
|
85
|
+
message: 'Browser APIs (document/window) cannot be used in server-side code.',
|
|
86
|
+
type: 'hard',
|
|
87
|
+
signature: `hard:${filePath}:${lineNum}:browser-api-in-server`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return errors;
|
|
93
|
+
}
|
|
94
|
+
runTsc(filterFiles) {
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const args = ['tsc', '--noEmit', '--pretty', 'false'];
|
|
97
|
+
// If filtering specific files, pass them directly
|
|
98
|
+
// Otherwise use the project tsconfig
|
|
99
|
+
if (filterFiles && filterFiles.length > 0 && filterFiles.length <= 10) {
|
|
100
|
+
// For a small number of files, check them directly
|
|
101
|
+
// This is faster than checking the whole project
|
|
102
|
+
args.push('--project', path.join(this.projectDir, 'tsconfig.json'));
|
|
103
|
+
}
|
|
104
|
+
const proc = spawn('npx', args, {
|
|
105
|
+
cwd: this.projectDir,
|
|
106
|
+
env: { ...process.env, NODE_OPTIONS: '--max-old-space-size=512' },
|
|
107
|
+
shell: true,
|
|
108
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
109
|
+
});
|
|
110
|
+
let stdout = '';
|
|
111
|
+
let stderr = '';
|
|
112
|
+
proc.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
113
|
+
proc.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
114
|
+
proc.on('close', () => {
|
|
115
|
+
// tsc outputs errors to stdout
|
|
116
|
+
resolve(stdout || stderr);
|
|
117
|
+
});
|
|
118
|
+
proc.on('error', () => {
|
|
119
|
+
resolve(stderr || stdout);
|
|
120
|
+
});
|
|
121
|
+
// Timeout after 30 seconds
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
try {
|
|
124
|
+
proc.kill();
|
|
125
|
+
}
|
|
126
|
+
catch { }
|
|
127
|
+
resolve(stdout || stderr || 'Type check timed out');
|
|
128
|
+
}, 30_000);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
parseTscOutput(output, filterFiles) {
|
|
132
|
+
if (!output.trim())
|
|
133
|
+
return [];
|
|
134
|
+
const lines = output.split('\n').filter(l => l.trim());
|
|
135
|
+
const errors = [];
|
|
136
|
+
const filterSet = filterFiles ? new Set(filterFiles.map(f => f.replace(/^\.\//, ''))) : null;
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
// Skip non-error lines
|
|
139
|
+
if (!line.includes('error TS') && !line.includes('warning TS'))
|
|
140
|
+
continue;
|
|
141
|
+
const parsed = parseErrorString(line, 'type');
|
|
142
|
+
// Filter to relevant files if specified
|
|
143
|
+
if (filterSet && parsed.file && !filterSet.has(parsed.file)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
errors.push(parsed);
|
|
147
|
+
}
|
|
148
|
+
return errors;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=checker.js.map
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nstantpage-agent CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* nstantpage login ā Authenticate with nstantpage.com
|
|
7
|
+
* nstantpage start [dir] ā Start agent for a project directory
|
|
8
|
+
* nstantpage stop ā Stop running agent
|
|
9
|
+
* nstantpage status ā Show agent status
|
|
10
|
+
*
|
|
11
|
+
* The agent replaces Docker containers ā your project runs natively on your
|
|
12
|
+
* machine with full performance, and the cloud editor connects through a tunnel.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nstantpage-agent CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* nstantpage login ā Authenticate with nstantpage.com
|
|
7
|
+
* nstantpage start [dir] ā Start agent for a project directory
|
|
8
|
+
* nstantpage stop ā Stop running agent
|
|
9
|
+
* nstantpage status ā Show agent status
|
|
10
|
+
*
|
|
11
|
+
* The agent replaces Docker containers ā your project runs natively on your
|
|
12
|
+
* machine with full performance, and the cloud editor connects through a tunnel.
|
|
13
|
+
*/
|
|
14
|
+
import { Command } from 'commander';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { loginCommand } from './commands/login.js';
|
|
17
|
+
import { startCommand } from './commands/start.js';
|
|
18
|
+
import { statusCommand } from './commands/status.js';
|
|
19
|
+
const program = new Command();
|
|
20
|
+
program
|
|
21
|
+
.name('nstantpage')
|
|
22
|
+
.description('Local development agent for nstantpage.com ā run projects on your machine, preview in the cloud')
|
|
23
|
+
.version('0.2.0');
|
|
24
|
+
program
|
|
25
|
+
.command('login')
|
|
26
|
+
.description('Authenticate with nstantpage.com')
|
|
27
|
+
.action(loginCommand);
|
|
28
|
+
program
|
|
29
|
+
.command('start')
|
|
30
|
+
.description('Start the agent for a project (replaces cloud containers)')
|
|
31
|
+
.argument('[directory]', 'Project directory (defaults to current directory)', '.')
|
|
32
|
+
.option('-p, --port <port>', 'Local dev server port', '3000')
|
|
33
|
+
.option('-a, --api-port <port>', 'Local API server port (internal)', '18924')
|
|
34
|
+
.option('--project-id <id>', 'Link to a specific project ID')
|
|
35
|
+
.option('--gateway <url>', 'Gateway URL', 'wss://webprev.live')
|
|
36
|
+
.option('--no-dev', 'Skip starting the dev server (start manually later)')
|
|
37
|
+
.action(startCommand);
|
|
38
|
+
program
|
|
39
|
+
.command('stop')
|
|
40
|
+
.description('Stop the running agent')
|
|
41
|
+
.action(async () => {
|
|
42
|
+
console.log(chalk.yellow('Stopping agent...'));
|
|
43
|
+
// Send SIGTERM to running agent process
|
|
44
|
+
const { getConfig } = await import('./config.js');
|
|
45
|
+
const conf = getConfig();
|
|
46
|
+
const pid = conf.get('agentPid');
|
|
47
|
+
if (pid) {
|
|
48
|
+
try {
|
|
49
|
+
process.kill(pid, 'SIGTERM');
|
|
50
|
+
conf.delete('agentPid');
|
|
51
|
+
console.log(chalk.green('Agent stopped'));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
console.log(chalk.gray('Agent was not running'));
|
|
55
|
+
conf.delete('agentPid');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(chalk.gray('No agent running'));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
program
|
|
63
|
+
.command('status')
|
|
64
|
+
.description('Show agent status')
|
|
65
|
+
.action(statusCommand);
|
|
66
|
+
program.parse();
|
|
67
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login command ā authenticate with nstantpage.com
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import open from 'open';
|
|
6
|
+
import http from 'http';
|
|
7
|
+
import { getConfig } from '../config.js';
|
|
8
|
+
export async function loginCommand() {
|
|
9
|
+
const conf = getConfig();
|
|
10
|
+
// Check if already logged in
|
|
11
|
+
const existingToken = conf.get('token');
|
|
12
|
+
if (existingToken) {
|
|
13
|
+
console.log(chalk.green('ā Already authenticated'));
|
|
14
|
+
console.log(chalk.gray(' Run "nstantpage login --force" to re-authenticate'));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
console.log(chalk.blue('š Authenticating with nstantpage.com...\n'));
|
|
18
|
+
// Start local callback server
|
|
19
|
+
const callbackPort = 18923;
|
|
20
|
+
const token = await new Promise((resolve, reject) => {
|
|
21
|
+
const server = http.createServer((req, res) => {
|
|
22
|
+
const url = new URL(req.url, `http://localhost:${callbackPort}`);
|
|
23
|
+
const token = url.searchParams.get('token');
|
|
24
|
+
if (token) {
|
|
25
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
26
|
+
res.end(`
|
|
27
|
+
<html>
|
|
28
|
+
<body style="font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #0f172a; color: #f8fafc;">
|
|
29
|
+
<div style="text-align: center;">
|
|
30
|
+
<h1>ā Authenticated!</h1>
|
|
31
|
+
<p>You can close this tab and return to the terminal.</p>
|
|
32
|
+
</div>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
35
|
+
`);
|
|
36
|
+
server.close();
|
|
37
|
+
resolve(token);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
res.writeHead(400);
|
|
41
|
+
res.end('Missing token');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
server.listen(callbackPort, () => {
|
|
45
|
+
const loginUrl = `https://nstantpage.com/auth/agent?callback=http://localhost:${callbackPort}/callback`;
|
|
46
|
+
console.log(chalk.gray(` Opening browser to authenticate...`));
|
|
47
|
+
console.log(chalk.gray(` If browser doesn't open, visit: ${loginUrl}\n`));
|
|
48
|
+
open(loginUrl).catch(() => {
|
|
49
|
+
// Browser didn't open, user can copy URL
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// Timeout after 5 minutes
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
server.close();
|
|
55
|
+
reject(new Error('Authentication timed out'));
|
|
56
|
+
}, 5 * 60 * 1000);
|
|
57
|
+
});
|
|
58
|
+
conf.set('token', token);
|
|
59
|
+
console.log(chalk.green('\nā Successfully authenticated!'));
|
|
60
|
+
console.log(chalk.gray(' Run "nstantpage start" to connect a project'));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start command ā launch the nstantpage agent
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* 1. Start local API server (handles /live/* requests for file sync, checks, etc.)
|
|
6
|
+
* 2. Start local dev server (Vite/Next.js ā runs project on user's machine)
|
|
7
|
+
* 3. Connect tunnel to gateway (relays requests from cloud to local machine)
|
|
8
|
+
*
|
|
9
|
+
* The agent fully replaces Docker containers:
|
|
10
|
+
* - Files are on the user's disk (no docker cp needed)
|
|
11
|
+
* - Dev server runs natively (no container overhead)
|
|
12
|
+
* - Type checking runs locally (full IDE speed)
|
|
13
|
+
* - Package installation uses local npm/pnpm
|
|
14
|
+
*/
|
|
15
|
+
interface StartOptions {
|
|
16
|
+
port: string;
|
|
17
|
+
apiPort: string;
|
|
18
|
+
projectId?: string;
|
|
19
|
+
gateway: string;
|
|
20
|
+
noDev?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function startCommand(directory: string, options: StartOptions): Promise<void>;
|
|
23
|
+
export {};
|