@ian2018cs/agenthub 0.1.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/LICENSE +675 -0
- package/README.md +330 -0
- package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/index-B4ru3EJb.css +32 -0
- package/dist/assets/index-DDFuyrpY.js +154 -0
- package/dist/assets/vendor-codemirror-C_VWDoZS.js +39 -0
- package/dist/assets/vendor-icons-CJV4dnDL.js +326 -0
- package/dist/assets/vendor-katex-DK8hFnhL.js +261 -0
- package/dist/assets/vendor-markdown-VwNYkg_0.js +35 -0
- package/dist/assets/vendor-react-BeVl62c0.js +59 -0
- package/dist/assets/vendor-syntax-CdGaPJRS.js +16 -0
- package/dist/assets/vendor-utils-00TdZexr.js +1 -0
- package/dist/assets/vendor-xterm-CvdiG4-n.js +66 -0
- package/dist/clear-cache.html +85 -0
- package/dist/convert-icons.md +53 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +9 -0
- package/dist/generate-icons.js +49 -0
- package/dist/icons/claude-ai-icon.svg +1 -0
- package/dist/icons/codex-white.svg +3 -0
- package/dist/icons/codex.svg +3 -0
- package/dist/icons/cursor-white.svg +12 -0
- package/dist/icons/cursor.svg +1 -0
- package/dist/icons/generate-icons.md +19 -0
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +12 -0
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +12 -0
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +12 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +12 -0
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +12 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +12 -0
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +12 -0
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +12 -0
- package/dist/icons/icon-template.svg +12 -0
- package/dist/index.html +57 -0
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo.svg +17 -0
- package/dist/manifest.json +61 -0
- package/dist/screenshots/cli-selection.png +0 -0
- package/dist/screenshots/desktop-main.png +0 -0
- package/dist/screenshots/mobile-chat.png +0 -0
- package/dist/screenshots/tools-modal.png +0 -0
- package/dist/sw.js +49 -0
- package/package.json +113 -0
- package/server/claude-sdk.js +791 -0
- package/server/cli.js +330 -0
- package/server/database/auth.db +0 -0
- package/server/database/db.js +523 -0
- package/server/database/init.sql +23 -0
- package/server/index.js +1678 -0
- package/server/load-env.js +27 -0
- package/server/middleware/auth.js +118 -0
- package/server/projects.js +899 -0
- package/server/routes/admin.js +89 -0
- package/server/routes/auth.js +144 -0
- package/server/routes/commands.js +570 -0
- package/server/routes/mcp-utils.js +37 -0
- package/server/routes/mcp.js +593 -0
- package/server/routes/projects.js +216 -0
- package/server/routes/skills.js +891 -0
- package/server/routes/usage.js +206 -0
- package/server/services/pricing.js +196 -0
- package/server/services/usage-scanner.js +283 -0
- package/server/services/user-directories.js +123 -0
- package/server/utils/commandParser.js +303 -0
- package/server/utils/mcp-detector.js +73 -0
- package/shared/modelConstants.js +23 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { userDb } from '../database/db.js';
|
|
3
|
+
import { authenticateToken } from '../middleware/auth.js';
|
|
4
|
+
import { deleteUserDirectories } from '../services/user-directories.js';
|
|
5
|
+
|
|
6
|
+
const router = express.Router();
|
|
7
|
+
|
|
8
|
+
// Admin middleware
|
|
9
|
+
const requireAdmin = (req, res, next) => {
|
|
10
|
+
if (req.user.role !== 'admin') {
|
|
11
|
+
return res.status(403).json({ error: 'Admin access required' });
|
|
12
|
+
}
|
|
13
|
+
next();
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Apply auth and admin middleware to all routes
|
|
17
|
+
router.use(authenticateToken);
|
|
18
|
+
router.use(requireAdmin);
|
|
19
|
+
|
|
20
|
+
// Get all users
|
|
21
|
+
router.get('/users', (req, res) => {
|
|
22
|
+
try {
|
|
23
|
+
const users = userDb.getAllUsers();
|
|
24
|
+
res.json({ users });
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('Error fetching users:', error);
|
|
27
|
+
res.status(500).json({ error: 'Failed to fetch users' });
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Update user status
|
|
32
|
+
router.patch('/users/:id', (req, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const { id } = req.params;
|
|
35
|
+
const { status } = req.body;
|
|
36
|
+
|
|
37
|
+
if (!['active', 'disabled'].includes(status)) {
|
|
38
|
+
return res.status(400).json({ error: 'Invalid status' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Prevent self-disable
|
|
42
|
+
if (parseInt(id) === req.user.id) {
|
|
43
|
+
return res.status(400).json({ error: 'Cannot modify your own status' });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const user = userDb.getUserById(id);
|
|
47
|
+
if (!user) {
|
|
48
|
+
return res.status(404).json({ error: 'User not found' });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
userDb.updateUserStatus(id, status);
|
|
52
|
+
res.json({ success: true, message: `User status updated to ${status}` });
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Error updating user status:', error);
|
|
55
|
+
res.status(500).json({ error: 'Failed to update user status' });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Delete user
|
|
60
|
+
router.delete('/users/:id', async (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const { id } = req.params;
|
|
63
|
+
|
|
64
|
+
// Prevent self-delete
|
|
65
|
+
if (parseInt(id) === req.user.id) {
|
|
66
|
+
return res.status(400).json({ error: 'Cannot delete your own account' });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const user = userDb.getUserById(id);
|
|
70
|
+
if (!user) {
|
|
71
|
+
return res.status(404).json({ error: 'User not found' });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Delete user directories
|
|
75
|
+
if (user.uuid) {
|
|
76
|
+
await deleteUserDirectories(user.uuid);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Delete from database
|
|
80
|
+
userDb.deleteUserById(id);
|
|
81
|
+
|
|
82
|
+
res.json({ success: true, message: 'User deleted successfully' });
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error('Error deleting user:', error);
|
|
85
|
+
res.status(500).json({ error: 'Failed to delete user' });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
export default router;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import bcrypt from 'bcrypt';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { userDb, db } from '../database/db.js';
|
|
5
|
+
import { generateToken, authenticateToken } from '../middleware/auth.js';
|
|
6
|
+
import { initUserDirectories } from '../services/user-directories.js';
|
|
7
|
+
|
|
8
|
+
const router = express.Router();
|
|
9
|
+
|
|
10
|
+
// Check auth status and setup requirements
|
|
11
|
+
router.get('/status', async (req, res) => {
|
|
12
|
+
try {
|
|
13
|
+
const hasUsers = await userDb.hasUsers();
|
|
14
|
+
res.json({
|
|
15
|
+
needsSetup: !hasUsers,
|
|
16
|
+
isAuthenticated: false // Will be overridden by frontend if token exists
|
|
17
|
+
});
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error('Auth status error:', error);
|
|
20
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// User registration - first user becomes admin
|
|
25
|
+
router.post('/register', async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const { username, password } = req.body;
|
|
28
|
+
|
|
29
|
+
if (!username || !password) {
|
|
30
|
+
return res.status(400).json({ error: 'Username and password are required' });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (username.length < 3 || password.length < 6) {
|
|
34
|
+
return res.status(400).json({
|
|
35
|
+
error: 'Username must be at least 3 characters, password at least 6 characters'
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check if this is the first user (becomes admin)
|
|
40
|
+
const userCount = userDb.getUserCount();
|
|
41
|
+
const role = userCount === 0 ? 'admin' : 'user';
|
|
42
|
+
const uuid = uuidv4();
|
|
43
|
+
|
|
44
|
+
// Hash password
|
|
45
|
+
const saltRounds = 12;
|
|
46
|
+
const passwordHash = await bcrypt.hash(password, saltRounds);
|
|
47
|
+
|
|
48
|
+
// Create user with full details
|
|
49
|
+
const user = userDb.createUserFull(username, passwordHash, uuid, role);
|
|
50
|
+
|
|
51
|
+
// Initialize user directories (creates .claude.json with hasCompletedOnboarding=true)
|
|
52
|
+
await initUserDirectories(uuid);
|
|
53
|
+
|
|
54
|
+
// Generate token
|
|
55
|
+
const token = generateToken(user);
|
|
56
|
+
|
|
57
|
+
// Update last login
|
|
58
|
+
userDb.updateLastLogin(user.id);
|
|
59
|
+
|
|
60
|
+
res.json({
|
|
61
|
+
success: true,
|
|
62
|
+
user: {
|
|
63
|
+
id: user.id,
|
|
64
|
+
username: user.username,
|
|
65
|
+
uuid: user.uuid,
|
|
66
|
+
role: user.role
|
|
67
|
+
},
|
|
68
|
+
token
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Registration error:', error);
|
|
73
|
+
if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') {
|
|
74
|
+
res.status(409).json({ error: 'Username already exists' });
|
|
75
|
+
} else {
|
|
76
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// User login
|
|
82
|
+
router.post('/login', async (req, res) => {
|
|
83
|
+
try {
|
|
84
|
+
const { username, password } = req.body;
|
|
85
|
+
|
|
86
|
+
if (!username || !password) {
|
|
87
|
+
return res.status(400).json({ error: 'Username and password are required' });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const user = userDb.getUserByUsername(username);
|
|
91
|
+
if (!user) {
|
|
92
|
+
return res.status(401).json({ error: 'Invalid username or password' });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if user is disabled
|
|
96
|
+
if (user.status === 'disabled') {
|
|
97
|
+
return res.status(403).json({ error: 'Account has been disabled' });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isValidPassword = await bcrypt.compare(password, user.password_hash);
|
|
101
|
+
if (!isValidPassword) {
|
|
102
|
+
return res.status(401).json({ error: 'Invalid username or password' });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const token = generateToken(user);
|
|
106
|
+
userDb.updateLastLogin(user.id);
|
|
107
|
+
|
|
108
|
+
res.json({
|
|
109
|
+
success: true,
|
|
110
|
+
user: {
|
|
111
|
+
id: user.id,
|
|
112
|
+
username: user.username,
|
|
113
|
+
uuid: user.uuid,
|
|
114
|
+
role: user.role
|
|
115
|
+
},
|
|
116
|
+
token
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('Login error:', error);
|
|
121
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Get current user (protected route)
|
|
126
|
+
router.get('/user', authenticateToken, (req, res) => {
|
|
127
|
+
res.json({
|
|
128
|
+
user: {
|
|
129
|
+
id: req.user.id,
|
|
130
|
+
username: req.user.username,
|
|
131
|
+
uuid: req.user.uuid,
|
|
132
|
+
role: req.user.role
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Logout (client-side token removal, but this endpoint can be used for logging)
|
|
138
|
+
router.post('/logout', authenticateToken, (req, res) => {
|
|
139
|
+
// In a simple JWT system, logout is mainly client-side
|
|
140
|
+
// This endpoint exists for consistency and potential future logging
|
|
141
|
+
res.json({ success: true, message: 'Logged out successfully' });
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export default router;
|