ninja-terminals 2.1.4 → 2.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ninja-terminals",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
4
4
  "description": "Multi-terminal Claude Code orchestrator with DAG task management, permission hooks, and resilience",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -62,6 +62,26 @@ const auth = {
62
62
  return data;
63
63
  },
64
64
 
65
+ async register(username, email, password) {
66
+ const res = await fetch(`${AUTH_API}/auth/register`, {
67
+ method: 'POST',
68
+ headers: { 'Content-Type': 'application/json' },
69
+ body: JSON.stringify({ username, email, password }),
70
+ });
71
+
72
+ if (!res.ok) {
73
+ const err = await res.json().catch(() => ({}));
74
+ throw new Error(err.message || 'Registration failed');
75
+ }
76
+
77
+ const data = await res.json();
78
+ this.token = data.token || data.accessToken;
79
+ localStorage.setItem(TOKEN_KEY, this.token);
80
+
81
+ await this.validateTier();
82
+ return data;
83
+ },
84
+
65
85
  async activateLicense(key) {
66
86
  const res = await fetch(`${AUTH_API}/ninja/activate-license`, {
67
87
  method: 'POST',
@@ -143,10 +163,45 @@ function hideAuthOverlay() {
143
163
 
144
164
  function setupAuthForms() {
145
165
  const loginForm = document.getElementById('login-form');
166
+ const registerForm = document.getElementById('register-form');
146
167
  const licenseForm = document.getElementById('license-form');
147
168
  const loginError = document.getElementById('login-error');
169
+ const registerError = document.getElementById('register-error');
148
170
  const logoutBtn = document.getElementById('logout-btn');
171
+ const showRegisterLink = document.getElementById('show-register');
172
+ const authToggleText = document.getElementById('auth-toggle-text');
173
+
174
+ // Toggle between login and register
175
+ let showingRegister = false;
176
+
177
+ function toggleAuthMode() {
178
+ showingRegister = !showingRegister;
179
+ if (showingRegister) {
180
+ loginForm.classList.add('hidden');
181
+ registerForm.classList.remove('hidden');
182
+ authToggleText.innerHTML = 'Already have an account? <a href="#" id="show-register">Sign in</a>';
183
+ document.getElementById('register-username').focus();
184
+ } else {
185
+ registerForm.classList.add('hidden');
186
+ loginForm.classList.remove('hidden');
187
+ authToggleText.innerHTML = 'Don\'t have an account? <a href="#" id="show-register">Sign up</a>';
188
+ document.getElementById('login-email').focus();
189
+ }
190
+ // Re-attach click handler to new link
191
+ document.getElementById('show-register').addEventListener('click', (e) => {
192
+ e.preventDefault();
193
+ toggleAuthMode();
194
+ });
195
+ loginError.textContent = '';
196
+ registerError.textContent = '';
197
+ }
198
+
199
+ showRegisterLink.addEventListener('click', (e) => {
200
+ e.preventDefault();
201
+ toggleAuthMode();
202
+ });
149
203
 
204
+ // Login form
150
205
  loginForm.addEventListener('submit', async (e) => {
151
206
  e.preventDefault();
152
207
  loginError.textContent = '';
@@ -163,6 +218,30 @@ function setupAuthForms() {
163
218
  }
164
219
  });
165
220
 
221
+ // Register form
222
+ registerForm.addEventListener('submit', async (e) => {
223
+ e.preventDefault();
224
+ registerError.textContent = '';
225
+
226
+ const username = document.getElementById('register-username').value.trim();
227
+ const email = document.getElementById('register-email').value.trim();
228
+ const password = document.getElementById('register-password').value;
229
+
230
+ if (password.length < 8) {
231
+ registerError.textContent = 'Password must be at least 8 characters';
232
+ return;
233
+ }
234
+
235
+ try {
236
+ await auth.register(username, email, password);
237
+ hideAuthOverlay();
238
+ startApp();
239
+ } catch (err) {
240
+ registerError.textContent = err.message;
241
+ }
242
+ });
243
+
244
+ // License form
166
245
  licenseForm.addEventListener('submit', async (e) => {
167
246
  e.preventDefault();
168
247
  loginError.textContent = '';
package/public/index.html CHANGED
@@ -38,18 +38,29 @@
38
38
  <div class="auth-card-inner">
39
39
  <h1 class="logo-text">NINJA TERMINALS</h1>
40
40
  <p class="auth-subtitle">Multi-Agent Claude Code Orchestrator</p>
41
+ <!-- Login Form -->
41
42
  <form id="login-form">
42
43
  <input type="text" id="login-email" placeholder="Email or username" required autocomplete="username">
43
44
  <input type="password" id="login-password" placeholder="Password" required autocomplete="current-password">
44
45
  <button type="submit" class="auth-btn">Sign In</button>
45
46
  <p class="auth-error" id="login-error"></p>
46
47
  </form>
48
+
49
+ <!-- Register Form (hidden by default) -->
50
+ <form id="register-form" class="hidden">
51
+ <input type="text" id="register-username" placeholder="Username" required autocomplete="username">
52
+ <input type="email" id="register-email" placeholder="Email" required autocomplete="email">
53
+ <input type="password" id="register-password" placeholder="Password (min 8 chars)" required autocomplete="new-password" minlength="8">
54
+ <button type="submit" class="auth-btn">Create Account</button>
55
+ <p class="auth-error" id="register-error"></p>
56
+ </form>
57
+
47
58
  <div class="auth-divider"><span>or</span></div>
48
59
  <form id="license-form">
49
60
  <input type="text" id="license-key" placeholder="Enter license key" autocomplete="off">
50
61
  <button type="submit" class="auth-btn auth-btn-secondary">Activate License</button>
51
62
  </form>
52
- <p class="auth-footer">Don't have an account? <a href="https://ninjaterminals.com" target="_blank">Sign up</a></p>
63
+ <p class="auth-footer" id="auth-toggle-text">Don't have an account? <a href="#" id="show-register">Sign up</a></p>
53
64
  </div>
54
65
  </div>
55
66
  </div>
package/public/style.css CHANGED
@@ -1,5 +1,7 @@
1
1
  * { margin: 0; padding: 0; box-sizing: border-box; }
2
2
 
3
+ .hidden { display: none !important; }
4
+
3
5
  :root {
4
6
  /* ── Retro Command Cards palette ── */
5
7
  --bg: #0C0C0C;