ninja-terminals 2.3.2 → 2.3.3
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/cli.js +109 -18
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -54,6 +54,10 @@ if (hasFlag('--version') || hasFlag('-v')) {
|
|
|
54
54
|
|
|
55
55
|
// ── Setup command ───────────────────────────────────────────
|
|
56
56
|
if (hasFlag('--setup')) {
|
|
57
|
+
runSetup().then(() => process.exit(0)).catch(e => { console.error(e); process.exit(1); });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function runSetup() {
|
|
57
61
|
const fs = require('fs');
|
|
58
62
|
const path = require('path');
|
|
59
63
|
const os = require('os');
|
|
@@ -100,8 +104,13 @@ if (hasFlag('--setup')) {
|
|
|
100
104
|
}
|
|
101
105
|
};
|
|
102
106
|
|
|
103
|
-
// Get npm root for copying orchestrator prompt
|
|
104
|
-
|
|
107
|
+
// Get npm root for copying orchestrator prompt (works in dev and installed mode)
|
|
108
|
+
let npmRoot;
|
|
109
|
+
try {
|
|
110
|
+
npmRoot = path.dirname(require.resolve('ninja-terminals/package.json'));
|
|
111
|
+
} catch {
|
|
112
|
+
npmRoot = __dirname; // Dev mode fallback
|
|
113
|
+
}
|
|
105
114
|
|
|
106
115
|
fs.writeFileSync(settingsPath, JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
107
116
|
console.log(`✅ Added ninja-terminals to ${settingsPath}`);
|
|
@@ -166,28 +175,108 @@ if (hasFlag('--setup')) {
|
|
|
166
175
|
|
|
167
176
|
console.log(`
|
|
168
177
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
178
|
+
✅ MCP configured!
|
|
179
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
180
|
+
`);
|
|
181
|
+
|
|
182
|
+
// Now prompt for login
|
|
183
|
+
const readline = require('readline');
|
|
184
|
+
const https = require('https');
|
|
185
|
+
const { execSync } = require('child_process');
|
|
186
|
+
const { writeAuthToken } = require('./lib/runtime-session');
|
|
187
|
+
|
|
188
|
+
const BACKEND_URL = process.env.NINJA_BACKEND_URL || 'https://emtchat-backend.onrender.com';
|
|
189
|
+
|
|
190
|
+
function prompt(question) {
|
|
191
|
+
return new Promise((resolve) => {
|
|
192
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
193
|
+
rl.question(question, (answer) => { rl.close(); resolve(answer); });
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function promptPassword(question) {
|
|
198
|
+
return new Promise((resolve) => {
|
|
199
|
+
try { execSync('stty -echo', { stdio: 'pipe' }); } catch {}
|
|
200
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
201
|
+
process.stdout.write(question);
|
|
202
|
+
rl.question('', (answer) => {
|
|
203
|
+
try { execSync('stty echo', { stdio: 'pipe' }); } catch {}
|
|
204
|
+
console.log();
|
|
205
|
+
rl.close();
|
|
206
|
+
resolve(answer);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function postJson(url, body) {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
const parsed = new URL(url);
|
|
214
|
+
const payload = JSON.stringify(body);
|
|
215
|
+
const req = https.request({
|
|
216
|
+
hostname: parsed.hostname,
|
|
217
|
+
port: parsed.port || 443,
|
|
218
|
+
path: parsed.pathname,
|
|
219
|
+
method: 'POST',
|
|
220
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
|
|
221
|
+
}, (res) => {
|
|
222
|
+
let data = '';
|
|
223
|
+
res.on('data', chunk => { data += chunk; });
|
|
224
|
+
res.on('end', () => {
|
|
225
|
+
try { resolve({ status: res.statusCode, body: JSON.parse(data) }); }
|
|
226
|
+
catch { resolve({ status: res.statusCode, body: data }); }
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
req.on('error', reject);
|
|
230
|
+
req.write(payload);
|
|
231
|
+
req.end();
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function doLogin() {
|
|
236
|
+
console.log('Login to your Ninja Terminals account:\n');
|
|
237
|
+
const username = await prompt('Username or email: ');
|
|
238
|
+
const password = await promptPassword('Password: ');
|
|
239
|
+
|
|
240
|
+
if (!username || !password) {
|
|
241
|
+
console.log('\n⚠️ Skipped login. Run `npx ninja-login` later to authenticate.');
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log('Authenticating...');
|
|
246
|
+
try {
|
|
247
|
+
const res = await postJson(`${BACKEND_URL}/api/auth/login`, { username, password });
|
|
248
|
+
if (res.status === 200 && res.body.token) {
|
|
249
|
+
writeAuthToken(res.body.token);
|
|
250
|
+
console.log(`\n✅ Logged in as ${username}`);
|
|
251
|
+
console.log(` Token saved to ~/.ninja/token`);
|
|
252
|
+
return true;
|
|
253
|
+
} else {
|
|
254
|
+
console.log(`\n❌ Login failed: ${res.body.message || res.body.error || 'Unknown error'}`);
|
|
255
|
+
console.log(' Run `npx ninja-login` to try again.');
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.log(`\n❌ Connection failed: ${err.message}`);
|
|
260
|
+
console.log(' Run `npx ninja-login` to try again.');
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
await doLogin();
|
|
266
|
+
|
|
267
|
+
console.log(`
|
|
268
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
169
269
|
✨ Setup complete!
|
|
170
270
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
• playwright - browser automation (screenshots, clicks, reading)
|
|
174
|
-
• fetch - API calls to /api/terminals
|
|
175
|
-
|
|
176
|
-
Next steps:
|
|
177
|
-
1. Restart Claude Code to load MCP servers
|
|
178
|
-
2. Run: npx ninja-terminals
|
|
179
|
-
3. Or use MCP tools directly in Claude Code
|
|
180
|
-
|
|
181
|
-
MCP tools available after restart:
|
|
182
|
-
mcp__ninja-terminals__spawn_terminal
|
|
183
|
-
mcp__ninja-terminals__send_input
|
|
184
|
-
mcp__ninja-terminals__list_terminals
|
|
185
|
-
... and 9 more
|
|
271
|
+
Next: Restart Claude Code, then tell Claude:
|
|
272
|
+
"use ninja terminals"
|
|
186
273
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
187
274
|
`);
|
|
188
|
-
process.exit(0);
|
|
189
275
|
}
|
|
190
276
|
|
|
277
|
+
// If setup mode was requested, we're done (setup function calls process.exit)
|
|
278
|
+
if (!hasFlag('--setup')) {
|
|
279
|
+
|
|
191
280
|
const port = parseInt(getArg('--port', '3300'), 10);
|
|
192
281
|
const terminals = parseInt(getArg('--terminals', '2'), 10); // Free tier default
|
|
193
282
|
const cwd = getArg('--cwd', process.cwd());
|
|
@@ -267,3 +356,5 @@ setTimeout(() => {
|
|
|
267
356
|
// ── Start the server ─────────────────────────────────────────
|
|
268
357
|
|
|
269
358
|
require('./server.js');
|
|
359
|
+
|
|
360
|
+
} // end if (!hasFlag('--setup'))
|
package/package.json
CHANGED