ninja-terminals 2.3.4 → 2.3.5

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 CHANGED
@@ -175,97 +175,6 @@ async function runSetup() {
175
175
 
176
176
  console.log(`
177
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
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
269
178
  ✨ Setup complete!
270
179
 
271
180
  Next: Restart Claude Code, then tell Claude:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninja-terminals",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
4
4
  "description": "MCP server for multi-terminal Claude Code orchestration with DAG task management, parallel execution, and self-improvement",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -1402,48 +1402,10 @@ function setupLearnings() {
1402
1402
  // ── Initialize ───────────────────────────────────────────────
1403
1403
 
1404
1404
  async function init() {
1405
- // Setup auth form handlers
1406
- setupAuthForms();
1407
-
1408
- // Check for existing valid session (local JWT check only — fast)
1409
- if (auth.init()) {
1410
- // Valid local token — hide overlay immediately, start app
1411
- hideAuthOverlay();
1412
- startApp();
1413
-
1414
- // Validate tier in background (network call to backend)
1415
- auth.validateTier()
1416
- .then(result => {
1417
- if (result?.needsLogin) {
1418
- // Token was rejected by backend — need fresh login
1419
- showAuthOverlay();
1420
- }
1421
- })
1422
- .catch(err => {
1423
- console.warn('Tier validation failed:', err);
1424
- // Network error — continue with cached token
1425
- })
1426
- .finally(() => {
1427
- sessionReadyResolve();
1428
- });
1429
- } else {
1430
- // No valid local token — try bootstrap from saved server token
1431
- const bootstrapped = await auth.tryBootstrap();
1432
- if (bootstrapped) {
1433
- hideAuthOverlay();
1434
- startApp();
1435
- auth.validateTier()
1436
- .then(result => {
1437
- if (result?.needsLogin) showAuthOverlay();
1438
- })
1439
- .catch(err => console.warn('Tier validation failed:', err))
1440
- .finally(() => sessionReadyResolve());
1441
- } else {
1442
- // No saved token — show login
1443
- showAuthOverlay();
1444
- sessionReadyResolve();
1445
- }
1446
- }
1405
+ // Auth disabled app is free, start immediately
1406
+ hideAuthOverlay();
1407
+ startApp();
1408
+ sessionReadyResolve();
1447
1409
  }
1448
1410
 
1449
1411
  init();
package/public/index.html CHANGED
@@ -26,8 +26,8 @@
26
26
  </div>
27
27
  </div>
28
28
 
29
- <!-- Auth Overlay -->
30
- <div id="auth-overlay">
29
+ <!-- Auth Overlay (disabled - app is free) -->
30
+ <div id="auth-overlay" style="display:none;">
31
31
  <div class="auth-card">
32
32
  <div class="auth-stripes">
33
33
  <div class="stripe s1"></div>
package/server.js CHANGED
@@ -88,17 +88,8 @@ const terminals = new Map();
88
88
  const sessionCache = new Map(); // token -> { tier, terminalsMax, features, validatedAt }
89
89
  let activeSession = null; // { token, tier, terminalsMax, features, terminalIds: [] }
90
90
 
91
- // Auth middlewareskip for static, health, and public endpoints
92
- const authMiddleware = createAuthMiddleware(sessionCache);
93
- const requireAuth = (req, res, next) => {
94
- // Skip auth for these paths
95
- const skipPaths = ['/', '/health', '/api/events'];
96
- if (skipPaths.includes(req.path)) {
97
- return next();
98
- }
99
- // Apply auth
100
- return authMiddleware(req, res, next);
101
- };
91
+ // Auth disabledapp is free, no login required
92
+ const requireAuth = (req, res, next) => next();
102
93
 
103
94
  // Loopback check for local-only endpoints (e.g., auth bootstrap)
104
95
  function isLoopbackRequest(req) {
@@ -412,20 +403,7 @@ server.on('upgrade', async (req, socket, head) => {
412
403
  return;
413
404
  }
414
405
 
415
- // Validate token from query param
416
- const token = urlParts.searchParams.get('token');
417
- if (!token) {
418
- socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
419
- socket.destroy();
420
- return;
421
- }
422
-
423
- const validation = await validateWebSocketToken(token, sessionCache);
424
- if (!validation.valid) {
425
- socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
426
- socket.destroy();
427
- return;
428
- }
406
+ // Auth disabled — no token validation needed
429
407
 
430
408
  const id = parseInt(match[1], 10);
431
409
  const terminal = terminals.get(id);