@ian2018cs/agenthub 0.1.34 → 0.1.36

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.
@@ -348,4 +348,4 @@ import{a as s}from"./vendor-react-BeVl62c0.js";/**
348
348
  *
349
349
  * This source code is licensed under the ISC license.
350
350
  * See the LICENSE file in the root directory of this source tree.
351
- */const C1=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],G2=e("zap",C1);export{Y1 as $,Z1 as A,S1 as B,T1 as C,O1 as D,W1 as E,a2 as F,o2 as G,T2 as H,s2 as I,I1 as J,y2 as K,r2 as L,M2 as M,E2 as N,P2 as O,m2 as P,l2 as Q,g2 as R,f2 as S,A2 as T,U2 as U,A1 as V,B2 as W,D2 as X,S2 as Y,G2 as Z,K1 as _,t2 as a,c2 as a0,H2 as a1,v2 as a2,C2 as a3,R1 as a4,i2 as a5,n2 as a6,F1 as a7,z2 as a8,V1 as a9,d2 as aa,k2 as ab,e2 as b,U1 as c,j2 as d,P1 as e,E1 as f,G1 as g,u2 as h,$2 as i,q2 as j,D1 as k,B1 as l,N2 as m,x2 as n,p2 as o,h2 as p,L2 as q,X1 as r,J1 as s,Q1 as t,_2 as u,V2 as v,Z2 as w,b2 as x,w2 as y,F2 as z};
351
+ */const C1=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],G2=e("zap",C1);export{K1 as $,F2 as A,S1 as B,T1 as C,O1 as D,W1 as E,a2 as F,c2 as G,Z1 as H,s2 as I,T2 as J,I1 as K,r2 as L,M2 as M,y2 as N,E2 as O,m2 as P,P2 as Q,g2 as R,f2 as S,A2 as T,U2 as U,l2 as V,A1 as W,D2 as X,B2 as Y,G2 as Z,S2 as _,t2 as a,Y1 as a0,H2 as a1,v2 as a2,C2 as a3,R1 as a4,i2 as a5,n2 as a6,F1 as a7,z2 as a8,V1 as a9,d2 as aa,k2 as ab,e2 as b,U1 as c,j2 as d,P1 as e,E1 as f,G1 as g,u2 as h,$2 as i,q2 as j,D1 as k,B1 as l,N2 as m,x2 as n,p2 as o,h2 as p,L2 as q,X1 as r,J1 as s,Q1 as t,_2 as u,V2 as v,Z2 as w,b2 as x,w2 as y,o2 as z};
package/dist/index.html CHANGED
@@ -25,16 +25,16 @@
25
25
 
26
26
  <!-- Prevent zoom on iOS -->
27
27
  <meta name="format-detection" content="telephone=no" />
28
- <script type="module" crossorigin src="/assets/index-Dtp8bFzY.js"></script>
28
+ <script type="module" crossorigin src="/assets/index-IiiL0NTz.js"></script>
29
29
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-BeVl62c0.js">
30
30
  <link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-C_VWDoZS.js">
31
31
  <link rel="modulepreload" crossorigin href="/assets/vendor-utils-00TdZexr.js">
32
- <link rel="modulepreload" crossorigin href="/assets/vendor-icons-CX_nKP5H.js">
32
+ <link rel="modulepreload" crossorigin href="/assets/vendor-icons-CDkQcAKw.js">
33
33
  <link rel="modulepreload" crossorigin href="/assets/vendor-katex-DK8hFnhL.js">
34
34
  <link rel="modulepreload" crossorigin href="/assets/vendor-markdown-VwNYkg_0.js">
35
35
  <link rel="modulepreload" crossorigin href="/assets/vendor-syntax-CdGaPJRS.js">
36
36
  <link rel="modulepreload" crossorigin href="/assets/vendor-xterm-CvdiG4-n.js">
37
- <link rel="stylesheet" crossorigin href="/assets/index-Cuc7jDbP.css">
37
+ <link rel="stylesheet" crossorigin href="/assets/index-BFl_Dhvn.css">
38
38
  </head>
39
39
  <body>
40
40
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ian2018cs/agenthub",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "A web-based UI for AI Agents",
5
5
  "type": "module",
6
6
  "main": "server/index.js",
package/server/cli.js CHANGED
@@ -153,11 +153,12 @@ Usage:
153
153
  cloudcli [command] [options]
154
154
 
155
155
  Commands:
156
- start Start the Claude Code UI server (default)
157
- status Show configuration and data locations
158
- update Update to the latest version
159
- help Show this help information
160
- version Show version information
156
+ start Start the Claude Code UI server (default)
157
+ status Show configuration and data locations
158
+ update Update to the latest version
159
+ invalidate-sessions Invalidate all user sessions (force re-login)
160
+ help Show this help information
161
+ version Show version information
161
162
 
162
163
  Options:
163
164
  -p, --port <port> Set server port (default: 3001)
@@ -247,6 +248,41 @@ async function updatePackage() {
247
248
  }
248
249
  }
249
250
 
251
+ // Invalidate all user sessions by writing a timestamp to the database
252
+ async function invalidateSessions() {
253
+ loadEnvFile();
254
+ const dbPath = getDatabasePath();
255
+
256
+ if (!fs.existsSync(dbPath)) {
257
+ console.error(`${c.error('[ERROR]')} Database not found: ${dbPath}`);
258
+ console.log(` Please start the server at least once to initialize the database.`);
259
+ process.exit(1);
260
+ }
261
+
262
+ try {
263
+ const { default: Database } = await import('better-sqlite3');
264
+ const db = new Database(dbPath);
265
+
266
+ const now = new Date().toISOString();
267
+ db.prepare(`
268
+ INSERT INTO system_settings (key, value, updated_at)
269
+ VALUES ('sessions_invalidated_before', ?, CURRENT_TIMESTAMP)
270
+ ON CONFLICT(key) DO UPDATE SET
271
+ value = excluded.value,
272
+ updated_at = excluded.updated_at
273
+ `).run(now);
274
+
275
+ db.close();
276
+
277
+ console.log(`${c.ok('[OK]')} All user sessions have been invalidated.`);
278
+ console.log(` Users will need to log in again.`);
279
+ console.log(` Invalidated at: ${c.dim(now)}`);
280
+ } catch (e) {
281
+ console.error(`${c.error('[ERROR]')} Failed to invalidate sessions: ${e.message}`);
282
+ process.exit(1);
283
+ }
284
+ }
285
+
250
286
  // Start the server
251
287
  async function startServer() {
252
288
  // Check for updates silently on startup
@@ -317,6 +353,9 @@ async function main() {
317
353
  case 'update':
318
354
  await updatePackage();
319
355
  break;
356
+ case 'invalidate-sessions':
357
+ await invalidateSessions();
358
+ break;
320
359
  default:
321
360
  console.error(`\n❌ Unknown command: ${command}`);
322
361
  console.log(' Run "cloudcli help" for usage information.\n');
package/server/index.js CHANGED
@@ -53,6 +53,7 @@ import projectsRoutes from './routes/projects.js';
53
53
  import adminRoutes from './routes/admin.js';
54
54
  import usageRoutes from './routes/usage.js';
55
55
  import skillsRoutes from './routes/skills.js';
56
+ import mcpReposRoutes from './routes/mcp-repos.js';
56
57
  import settingsRoutes from './routes/settings.js';
57
58
  import { initializeDatabase, userDb } from './database/db.js';
58
59
  import { validateApiKey, authenticateToken, authenticateWebSocket } from './middleware/auth.js';
@@ -324,6 +325,9 @@ app.use('/api/admin/usage', usageRoutes);
324
325
  // Skills API Routes (protected)
325
326
  app.use('/api/skills', authenticateToken, skillsRoutes);
326
327
 
328
+ // MCP Repos API Routes (protected)
329
+ app.use('/api/mcp-repos', authenticateToken, mcpReposRoutes);
330
+
327
331
  // Settings API Routes (protected)
328
332
  app.use('/api/settings', authenticateToken, settingsRoutes);
329
333
 
@@ -1,5 +1,5 @@
1
1
  import jwt from 'jsonwebtoken';
2
- import { userDb } from '../database/db.js';
2
+ import { userDb, settingsDb } from '../database/db.js';
3
3
 
4
4
  // Get JWT secret from environment or use default (for development)
5
5
  const JWT_SECRET = process.env.JWT_SECRET || 'claude-ui-dev-secret-change-in-production';
@@ -46,6 +46,12 @@ const authenticateToken = async (req, res, next) => {
46
46
  try {
47
47
  const decoded = jwt.verify(token, JWT_SECRET);
48
48
 
49
+ // Check if token was issued before a global session invalidation
50
+ const invalidatedBefore = settingsDb.get('sessions_invalidated_before');
51
+ if (invalidatedBefore && decoded.iat * 1000 < new Date(invalidatedBefore).getTime()) {
52
+ return res.status(401).json({ error: 'Session has been invalidated. Please log in again.' });
53
+ }
54
+
49
55
  // Verify user still exists and is active
50
56
  const user = userDb.getUserById(decoded.userId);
51
57
  if (!user) {
@@ -103,6 +109,13 @@ const authenticateWebSocket = (token) => {
103
109
 
104
110
  try {
105
111
  const decoded = jwt.verify(token, JWT_SECRET);
112
+
113
+ // Check if token was issued before a global session invalidation
114
+ const invalidatedBefore = settingsDb.get('sessions_invalidated_before');
115
+ if (invalidatedBefore && decoded.iat * 1000 < new Date(invalidatedBefore).getTime()) {
116
+ return null;
117
+ }
118
+
106
119
  return decoded;
107
120
  } catch (error) {
108
121
  console.error('WebSocket token verification error:', error);
@@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid';
5
5
  import { userDb, verificationDb, domainWhitelistDb, usageDb, settingsDb } from '../database/db.js';
6
6
  import { generateToken, authenticateToken, JWT_SECRET } from '../middleware/auth.js';
7
7
  import { initUserDirectories } from '../services/user-directories.js';
8
- import { initBuiltinSkills } from '../services/builtin-skills.js';
8
+ import { initSystemRepoForUser } from '../services/system-repo.js';
9
9
  import { sendVerificationCode, isSmtpConfigured } from '../services/email.js';
10
10
 
11
11
  const router = express.Router();
@@ -126,8 +126,8 @@ router.post('/verify-code', async (req, res) => {
126
126
  // Initialize user directories
127
127
  await initUserDirectories(uuid);
128
128
  } else {
129
- // Sync built-in skills for existing user (clean up dangling + add new)
130
- await initBuiltinSkills(user.uuid);
129
+ // Ensure system repo is linked for existing user
130
+ await initSystemRepoForUser(user.uuid);
131
131
  }
132
132
 
133
133
  // Check if user is disabled