myaidev-method 0.2.8 → 0.2.9

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.
Files changed (157) hide show
  1. package/.claude/agents/wordpress-admin.md +271 -0
  2. package/.env.example +0 -1
  3. package/PACKAGE_FIXES_SUMMARY.md +319 -0
  4. package/PAYLOADCMS_AUTH_UPDATE.md +248 -0
  5. package/USER_GUIDE.md +260 -0
  6. package/bin/cli.js +36 -0
  7. package/dist/server/.tsbuildinfo +1 -0
  8. package/dist/server/auth/controllers/AuthController.d.ts +34 -0
  9. package/dist/server/auth/controllers/AuthController.d.ts.map +1 -0
  10. package/dist/server/auth/controllers/AuthController.js +43 -0
  11. package/dist/server/auth/controllers/AuthController.js.map +1 -0
  12. package/dist/server/auth/example-usage.d.ts +53 -0
  13. package/dist/server/auth/example-usage.d.ts.map +1 -0
  14. package/dist/server/auth/example-usage.js +129 -0
  15. package/dist/server/auth/example-usage.js.map +1 -0
  16. package/dist/server/auth/index.d.ts +11 -0
  17. package/dist/server/auth/index.d.ts.map +1 -0
  18. package/dist/server/auth/index.js +15 -0
  19. package/dist/server/auth/index.js.map +1 -0
  20. package/dist/server/auth/layers.d.ts +19 -0
  21. package/dist/server/auth/layers.d.ts.map +1 -0
  22. package/dist/server/auth/layers.js +33 -0
  23. package/dist/server/auth/layers.js.map +1 -0
  24. package/dist/server/auth/middleware/authMiddleware.d.ts +24 -0
  25. package/dist/server/auth/middleware/authMiddleware.d.ts.map +1 -0
  26. package/dist/server/auth/middleware/authMiddleware.js +65 -0
  27. package/dist/server/auth/middleware/authMiddleware.js.map +1 -0
  28. package/dist/server/auth/routes/authRoutes.d.ts +11 -0
  29. package/dist/server/auth/routes/authRoutes.d.ts.map +1 -0
  30. package/dist/server/auth/routes/authRoutes.js +213 -0
  31. package/dist/server/auth/routes/authRoutes.js.map +1 -0
  32. package/dist/server/auth/services/AuditLogService.d.ts +21 -0
  33. package/dist/server/auth/services/AuditLogService.d.ts.map +1 -0
  34. package/dist/server/auth/services/AuditLogService.js +28 -0
  35. package/dist/server/auth/services/AuditLogService.js.map +1 -0
  36. package/dist/server/auth/services/AuthService.d.ts +27 -0
  37. package/dist/server/auth/services/AuthService.d.ts.map +1 -0
  38. package/dist/server/auth/services/AuthService.js +246 -0
  39. package/dist/server/auth/services/AuthService.js.map +1 -0
  40. package/dist/server/auth/services/PasswordService.d.ts +12 -0
  41. package/dist/server/auth/services/PasswordService.d.ts.map +1 -0
  42. package/dist/server/auth/services/PasswordService.js +31 -0
  43. package/dist/server/auth/services/PasswordService.js.map +1 -0
  44. package/dist/server/auth/services/SessionRepository.d.ts +24 -0
  45. package/dist/server/auth/services/SessionRepository.d.ts.map +1 -0
  46. package/dist/server/auth/services/SessionRepository.js +101 -0
  47. package/dist/server/auth/services/SessionRepository.js.map +1 -0
  48. package/dist/server/auth/services/TokenService.d.ts +12 -0
  49. package/dist/server/auth/services/TokenService.d.ts.map +1 -0
  50. package/dist/server/auth/services/TokenService.js +86 -0
  51. package/dist/server/auth/services/TokenService.js.map +1 -0
  52. package/dist/server/auth/services/UserRepository.d.ts +23 -0
  53. package/dist/server/auth/services/UserRepository.d.ts.map +1 -0
  54. package/dist/server/auth/services/UserRepository.js +168 -0
  55. package/dist/server/auth/services/UserRepository.js.map +1 -0
  56. package/dist/server/auth/services/example.d.ts +26 -0
  57. package/dist/server/auth/services/example.d.ts.map +1 -0
  58. package/dist/server/auth/services/example.js +221 -0
  59. package/dist/server/auth/services/example.js.map +1 -0
  60. package/dist/server/auth/services/index.d.ts +6 -0
  61. package/dist/server/auth/services/index.d.ts.map +1 -0
  62. package/dist/server/auth/services/index.js +7 -0
  63. package/dist/server/auth/services/index.js.map +1 -0
  64. package/dist/server/database/db.d.ts +28 -0
  65. package/dist/server/database/db.d.ts.map +1 -0
  66. package/dist/server/database/db.js +91 -0
  67. package/dist/server/database/db.js.map +1 -0
  68. package/dist/server/database/schema.sql +95 -0
  69. package/dist/server/hono/app.d.ts +10 -0
  70. package/dist/server/hono/app.d.ts.map +1 -0
  71. package/dist/server/hono/app.js +26 -0
  72. package/dist/server/hono/app.js.map +1 -0
  73. package/dist/server/hono/routes.d.ts +12 -0
  74. package/dist/server/hono/routes.d.ts.map +1 -0
  75. package/dist/server/hono/routes.js +40 -0
  76. package/dist/server/hono/routes.js.map +1 -0
  77. package/dist/server/main.d.ts +2 -0
  78. package/dist/server/main.d.ts.map +1 -0
  79. package/dist/server/main.js +94 -0
  80. package/dist/server/main.js.map +1 -0
  81. package/dist/server/user-management/DirectoryService.d.ts +62 -0
  82. package/dist/server/user-management/DirectoryService.d.ts.map +1 -0
  83. package/dist/server/user-management/DirectoryService.js +201 -0
  84. package/dist/server/user-management/DirectoryService.js.map +1 -0
  85. package/dist/server/user-management/LinuxUserService.d.ts +71 -0
  86. package/dist/server/user-management/LinuxUserService.d.ts.map +1 -0
  87. package/dist/server/user-management/LinuxUserService.js +192 -0
  88. package/dist/server/user-management/LinuxUserService.js.map +1 -0
  89. package/dist/server/user-management/QuotaService.d.ts +59 -0
  90. package/dist/server/user-management/QuotaService.d.ts.map +1 -0
  91. package/dist/server/user-management/QuotaService.js +148 -0
  92. package/dist/server/user-management/QuotaService.js.map +1 -0
  93. package/dist/server/user-management/UserManagementService.d.ts +74 -0
  94. package/dist/server/user-management/UserManagementService.d.ts.map +1 -0
  95. package/dist/server/user-management/UserManagementService.js +122 -0
  96. package/dist/server/user-management/UserManagementService.js.map +1 -0
  97. package/dist/server/user-management/index.d.ts +26 -0
  98. package/dist/server/user-management/index.d.ts.map +1 -0
  99. package/dist/server/user-management/index.js +26 -0
  100. package/dist/server/user-management/index.js.map +1 -0
  101. package/dist/server/user-management/layers.d.ts +27 -0
  102. package/dist/server/user-management/layers.d.ts.map +1 -0
  103. package/dist/server/user-management/layers.js +37 -0
  104. package/dist/server/user-management/layers.js.map +1 -0
  105. package/dist/shared/types.d.ts +94 -0
  106. package/dist/shared/types.d.ts.map +1 -0
  107. package/dist/shared/types.js +32 -0
  108. package/dist/shared/types.js.map +1 -0
  109. package/package.json +25 -5
  110. package/src/lib/payloadcms-utils.js +5 -12
  111. package/src/server/auth/ARCHITECTURE.md +575 -0
  112. package/src/server/auth/IMPLEMENTATION_SUMMARY.md +287 -0
  113. package/src/server/auth/QUICK_START.md +283 -0
  114. package/src/server/auth/README.md +290 -0
  115. package/src/server/auth/controllers/AuthController.ts +129 -0
  116. package/src/server/auth/example-usage.ts +159 -0
  117. package/src/server/auth/index.ts +19 -0
  118. package/src/server/auth/layers.ts +57 -0
  119. package/src/server/auth/middleware/authMiddleware.ts +118 -0
  120. package/src/server/auth/routes/authRoutes.ts +319 -0
  121. package/src/server/auth/services/AuditLogService.ts +81 -0
  122. package/src/server/auth/services/AuthService.ts +408 -0
  123. package/src/server/auth/services/IMPLEMENTATION_SUMMARY.md +404 -0
  124. package/src/server/auth/services/PasswordService.ts +85 -0
  125. package/src/server/auth/services/README.md +361 -0
  126. package/src/server/auth/services/SessionRepository.ts +227 -0
  127. package/src/server/auth/services/TokenService.ts +174 -0
  128. package/src/server/auth/services/UserRepository.ts +318 -0
  129. package/src/server/auth/services/example.ts +346 -0
  130. package/src/server/auth/services/index.ts +6 -0
  131. package/src/server/database/db.ts +161 -0
  132. package/src/server/database/schema.sql +95 -0
  133. package/src/server/hono/app.ts +41 -0
  134. package/src/server/main.ts +115 -0
  135. package/src/server/user-management/DirectoryService.ts +348 -0
  136. package/src/server/user-management/LinuxUserService.ts +338 -0
  137. package/src/server/user-management/QuotaService.ts +256 -0
  138. package/src/server/user-management/README.md +333 -0
  139. package/src/server/user-management/UserManagementService.ts +335 -0
  140. package/src/server/user-management/index.ts +26 -0
  141. package/src/server/user-management/layers.ts +51 -0
  142. package/src/shared/types.ts +111 -0
  143. package/src/templates/claude/agents/payloadcms-publish.md +34 -14
  144. package/src/templates/codex/commands/myai-astro-publish.md +8 -2
  145. package/src/templates/codex/commands/myai-content-writer.md +8 -2
  146. package/src/templates/codex/commands/myai-coolify-deploy.md +8 -2
  147. package/src/templates/codex/commands/myai-dev-architect.md +8 -2
  148. package/src/templates/codex/commands/myai-dev-code.md +8 -2
  149. package/src/templates/codex/commands/myai-dev-docs.md +8 -2
  150. package/src/templates/codex/commands/myai-dev-review.md +8 -2
  151. package/src/templates/codex/commands/myai-dev-test.md +8 -2
  152. package/src/templates/codex/commands/myai-docusaurus-publish.md +8 -2
  153. package/src/templates/codex/commands/myai-mintlify-publish.md +8 -2
  154. package/src/templates/codex/commands/myai-payloadcms-publish.md +17 -3
  155. package/src/templates/codex/commands/myai-sparc-workflow.md +8 -2
  156. package/src/templates/codex/commands/myai-wordpress-admin.md +8 -2
  157. package/src/templates/codex/commands/myai-wordpress-publish.md +8 -2
@@ -0,0 +1,333 @@
1
+ # User Management Module
2
+
3
+ Linux user management system for multi-user MyAIDev Method deployment with isolated user environments.
4
+
5
+ ## Overview
6
+
7
+ This module provides comprehensive Linux user management capabilities including:
8
+
9
+ - **User Creation**: Create Linux system users with restricted shells
10
+ - **Directory Management**: Set up isolated home directories with Claude Code configurations
11
+ - **Resource Limits**: Apply CPU, memory, and process limits
12
+ - **Disk Quotas**: Manage storage limits per user
13
+ - **Cleanup**: Safe deletion of users and their resources
14
+
15
+ ## Architecture
16
+
17
+ ### Services
18
+
19
+ #### LinuxUserService
20
+ Low-level Linux user operations using system commands (`useradd`, `userdel`, `id`).
21
+
22
+ **Features:**
23
+ - Create/delete Linux users
24
+ - Username sanitization
25
+ - Resource limit enforcement via `/etc/security/limits.d/`
26
+ - User existence checks
27
+
28
+ #### DirectoryService
29
+ Home directory and workspace management.
30
+
31
+ **Features:**
32
+ - `.claude/` configuration directory setup
33
+ - Workspace directory creation
34
+ - Ownership and permission management
35
+ - Shell configuration (`.bashrc`)
36
+
37
+ #### QuotaService
38
+ Disk quota management (optional - requires quota tools).
39
+
40
+ **Features:**
41
+ - Set soft/hard disk limits
42
+ - Monitor usage
43
+ - Fallback to directory size calculation if quotas unavailable
44
+
45
+ #### UserManagementService
46
+ High-level orchestration service integrating all components.
47
+
48
+ **Features:**
49
+ - Complete user environment setup
50
+ - Integrated error handling
51
+ - Automatic username sanitization
52
+ - Graceful degradation (quotas optional)
53
+
54
+ ## Usage
55
+
56
+ ### Basic User Creation
57
+
58
+ ```typescript
59
+ import { Effect, ManagedRuntime } from "effect";
60
+ import { UserManagementService } from "./user-management";
61
+ import { createUserManagementLayer } from "./user-management/layers";
62
+
63
+ const layer = createUserManagementLayer();
64
+ const runtime = ManagedRuntime.make(layer);
65
+
66
+ const result = await runtime.runPromise(
67
+ Effect.gen(function* () {
68
+ const userMgmt = yield* UserManagementService;
69
+
70
+ return yield* userMgmt.createUser({
71
+ username: "john",
72
+ email: "john@example.com",
73
+ claudeApiKey: "sk-...",
74
+ diskQuotaMB: 2048, // 2GB quota
75
+ shell: "/bin/rbash", // Restricted bash
76
+ });
77
+ })
78
+ );
79
+
80
+ console.log(result);
81
+ // {
82
+ // linuxUser: { username: "john", uid: 1001, gid: 1001, homeDir: "/home/john", ... },
83
+ // homeDir: "/home/john",
84
+ // claudeConfigPath: "/home/john/.claude",
85
+ // workspacePath: "/home/john/workspace",
86
+ // quotaApplied: true,
87
+ // limitsApplied: true
88
+ // }
89
+ ```
90
+
91
+ ### Check Username Availability
92
+
93
+ ```typescript
94
+ const available = await runtime.runPromise(
95
+ Effect.gen(function* () {
96
+ const userMgmt = yield* UserManagementService;
97
+ return yield* userMgmt.isUsernameAvailable("john");
98
+ })
99
+ );
100
+ ```
101
+
102
+ ### Delete User
103
+
104
+ ```typescript
105
+ await runtime.runPromise(
106
+ Effect.gen(function* () {
107
+ const userMgmt = yield* UserManagementService;
108
+ yield* userMgmt.deleteUser("john");
109
+ })
110
+ );
111
+ ```
112
+
113
+ ## Integration with Authentication
114
+
115
+ The user management system is automatically integrated with the authentication system in `AuthService`:
116
+
117
+ ```typescript
118
+ // In AuthService.register()
119
+ yield* userManagement.createUser({
120
+ username: linuxUsername,
121
+ email,
122
+ shell: "/bin/rbash",
123
+ diskQuotaMB: 2048,
124
+ }).pipe(
125
+ Effect.catchAll((error) => {
126
+ // Gracefully handle errors - don't fail registration
127
+ console.error(`Failed to create Linux user:`, error);
128
+ return Effect.succeed(void 0);
129
+ })
130
+ );
131
+ ```
132
+
133
+ When a user registers:
134
+ 1. Database user record created
135
+ 2. Linux user created with sanitized username
136
+ 3. Home directory structure set up
137
+ 4. Claude Code configuration initialized
138
+ 5. Resource limits applied
139
+ 6. Disk quotas set (if available)
140
+
141
+ ## Directory Structure
142
+
143
+ Created for each user:
144
+
145
+ ```
146
+ /home/{username}/
147
+ ├── .claude/ # Claude Code configuration
148
+ │ ├── config.json # API key, model settings
149
+ │ ├── sessions/ # Session storage
150
+ │ └── cache/ # Cache directory
151
+ ├── workspace/ # User workspace
152
+ │ └── README.md # Welcome message
153
+ └── .bashrc # Shell configuration
154
+ ```
155
+
156
+ ## Security Features
157
+
158
+ ### Restricted Shell
159
+ Users are created with `/bin/rbash` (restricted bash) by default:
160
+ - No `cd` command
161
+ - No path modification
162
+ - No redirection
163
+ - No command substitution
164
+
165
+ ### Resource Limits
166
+ Per-user limits enforced via `/etc/security/limits.d/{username}.conf`:
167
+ - **Max open files**: 1024 (soft) / 2048 (hard)
168
+ - **Max processes**: 256 (soft) / 512 (hard)
169
+ - **Max memory**: 2GB (soft) / 4GB (hard)
170
+ - **Max CPU time**: 60s (soft) / 120s (hard) per process
171
+
172
+ ### Disk Quotas (Optional)
173
+ If quota tools installed:
174
+ - **Soft limit**: 2GB (warning threshold)
175
+ - **Hard limit**: 3GB (absolute maximum)
176
+
177
+ ### No Sudo Access
178
+ Created users have no sudo privileges and cannot escalate permissions.
179
+
180
+ ## System Requirements
181
+
182
+ ### Required
183
+ - Linux operating system (Ubuntu/Debian recommended)
184
+ - Node.js 18+
185
+ - Sudo access for server process
186
+
187
+ ### Optional
188
+ - `quota` package for disk quota management
189
+
190
+ ```bash
191
+ # Install quota tools (optional)
192
+ sudo apt-get install quota
193
+ sudo quotacheck -cum /
194
+ sudo quotaon -v /
195
+ ```
196
+
197
+ ## Error Handling
198
+
199
+ All services use Effect-TS for structured error handling:
200
+
201
+ ```typescript
202
+ // LinuxUserError
203
+ {
204
+ _tag: "LinuxUserError",
205
+ message: "Failed to create user",
206
+ cause: Error
207
+ }
208
+
209
+ // DirectoryError
210
+ {
211
+ _tag: "DirectoryError",
212
+ message: "Failed to setup home directory",
213
+ cause: Error
214
+ }
215
+
216
+ // QuotaError
217
+ {
218
+ _tag: "QuotaError",
219
+ message: "Failed to set quota",
220
+ cause: Error
221
+ }
222
+
223
+ // UserManagementError
224
+ {
225
+ _tag: "UserManagementError",
226
+ message: "Failed to create user environment",
227
+ cause: Error
228
+ }
229
+ ```
230
+
231
+ ## Username Sanitization
232
+
233
+ Usernames are automatically sanitized to meet Linux requirements:
234
+
235
+ ```typescript
236
+ // Example sanitization
237
+ "John Doe" → "john_doe"
238
+ "user@email.com" → "user_email_com"
239
+ "123user" → "u_123user" // Must start with letter
240
+ "very-long-username-that-exceeds-limit" → "very_long_username_that_exce" // Truncated to 32 chars
241
+ ```
242
+
243
+ ## Testing
244
+
245
+ ```bash
246
+ # Run type checking
247
+ npm run typecheck:server
248
+
249
+ # Build
250
+ npm run build:server
251
+
252
+ # Test user creation (requires sudo)
253
+ node -e "
254
+ import('./dist/server/user-management/index.js').then(async ({ UserManagementService }) => {
255
+ const { Effect, ManagedRuntime } = await import('effect');
256
+ const { createUserManagementLayer } = await import('./dist/server/user-management/layers.js');
257
+
258
+ const layer = createUserManagementLayer();
259
+ const runtime = ManagedRuntime.make(layer);
260
+
261
+ const result = await runtime.runPromise(
262
+ Effect.gen(function* () {
263
+ const userMgmt = yield* UserManagementService;
264
+ return yield* userMgmt.createUser({
265
+ username: 'testuser',
266
+ email: 'test@example.com',
267
+ diskQuotaMB: 1024,
268
+ });
269
+ })
270
+ );
271
+
272
+ console.log('User created:', result);
273
+ });
274
+ "
275
+ ```
276
+
277
+ ## Production Considerations
278
+
279
+ ### Security
280
+ - ✅ Users run with restricted shells
281
+ - ✅ Resource limits prevent DoS
282
+ - ✅ No sudo access
283
+ - ✅ Directory isolation
284
+ - ⚠️ Consider additional AppArmor/SELinux profiles
285
+
286
+ ### Performance
287
+ - User creation takes 1-3 seconds
288
+ - Quota checks are fast if using quota tools
289
+ - Directory size calculation (fallback) can be slow for large directories
290
+
291
+ ### Monitoring
292
+ - Check `/etc/security/limits.d/` for limit configurations
293
+ - Monitor disk usage with `quota` command
294
+ - Audit log records user creation in database
295
+
296
+ ### Cleanup
297
+ When deleting users:
298
+ 1. Home directory removed (`rm -rf /home/{username}`)
299
+ 2. User deleted from system (`userdel`)
300
+ 3. Limits configuration removed
301
+ 4. Database records remain for audit trail
302
+
303
+ ## Troubleshooting
304
+
305
+ ### "Failed to create Linux user"
306
+ - Ensure server has sudo access
307
+ - Check if username already exists: `id username`
308
+ - Verify useradd command available
309
+
310
+ ### "Quota system not available"
311
+ - Install quota tools: `sudo apt-get install quota`
312
+ - Or system will fallback to directory size monitoring
313
+
314
+ ### "Permission denied" errors
315
+ - Server process needs sudo for user management
316
+ - Consider running with sudo or configuring sudoers file
317
+
318
+ ### "Directory already exists"
319
+ - Previous user not fully cleaned up
320
+ - Manually remove: `sudo rm -rf /home/username`
321
+
322
+ ## Future Enhancements
323
+
324
+ - [ ] User suspension/reactivation
325
+ - [ ] Disk usage monitoring dashboard
326
+ - [ ] Automated cleanup of inactive users
327
+ - [ ] User groups for shared resources
328
+ - [ ] Network namespace isolation
329
+ - [ ] Container-based isolation option
330
+
331
+ ## License
332
+
333
+ Same as MyAIDev Method project.
@@ -0,0 +1,335 @@
1
+ import { Effect, Context, Layer } from "effect";
2
+ import { LinuxUserService, LinuxUser } from "./LinuxUserService";
3
+ import { DirectoryService, ClaudeConfig } from "./DirectoryService";
4
+ import { QuotaService, DiskQuota } from "./QuotaService";
5
+
6
+ /**
7
+ * User Management Service
8
+ *
9
+ * High-level orchestration service that coordinates Linux user creation,
10
+ * directory setup, and resource management for multi-user environments.
11
+ *
12
+ * This service integrates:
13
+ * - LinuxUserService: System user creation and management
14
+ * - DirectoryService: Home directory and Claude config setup
15
+ * - QuotaService: Disk quotas and resource limits
16
+ *
17
+ * Workflow:
18
+ * 1. Sanitize and validate username
19
+ * 2. Create Linux system user
20
+ * 3. Set up home directory structure
21
+ * 4. Configure Claude Code environment
22
+ * 5. Apply resource limits and quotas
23
+ * 6. Return complete user setup information
24
+ */
25
+
26
+ export interface CreateUserRequest {
27
+ username: string;
28
+ email: string;
29
+ claudeApiKey?: string;
30
+ diskQuotaMB?: number;
31
+ shell?: "/bin/rbash" | "/usr/sbin/nologin" | "/bin/bash";
32
+ }
33
+
34
+ export interface UserSetupResult {
35
+ linuxUser: LinuxUser;
36
+ homeDir: string;
37
+ claudeConfigPath: string;
38
+ workspacePath: string;
39
+ quotaApplied: boolean;
40
+ limitsApplied: boolean;
41
+ }
42
+
43
+ export interface UserManagementError {
44
+ readonly _tag: "UserManagementError";
45
+ readonly message: string;
46
+ readonly cause?: unknown;
47
+ }
48
+
49
+ const UserManagementError = (
50
+ message: string,
51
+ cause?: unknown
52
+ ): UserManagementError => ({
53
+ _tag: "UserManagementError",
54
+ message,
55
+ cause,
56
+ });
57
+
58
+ export class UserManagementService extends Context.Tag("UserManagementService")<
59
+ UserManagementService,
60
+ {
61
+ /**
62
+ * Create a complete user environment
63
+ * - Creates Linux user
64
+ * - Sets up home directory
65
+ * - Configures Claude Code
66
+ * - Applies quotas and limits
67
+ */
68
+ readonly createUser: (
69
+ request: CreateUserRequest
70
+ ) => Effect.Effect<UserSetupResult, UserManagementError>;
71
+
72
+ /**
73
+ * Delete user and clean up all resources
74
+ */
75
+ readonly deleteUser: (
76
+ username: string
77
+ ) => Effect.Effect<void, UserManagementError>;
78
+
79
+ /**
80
+ * Get user information
81
+ */
82
+ readonly getUserInfo: (
83
+ username: string
84
+ ) => Effect.Effect<LinuxUser, UserManagementError>;
85
+
86
+ /**
87
+ * Update user quotas
88
+ */
89
+ readonly updateQuota: (
90
+ username: string,
91
+ quota: DiskQuota
92
+ ) => Effect.Effect<void, UserManagementError>;
93
+
94
+ /**
95
+ * Check if username is available
96
+ */
97
+ readonly isUsernameAvailable: (
98
+ username: string
99
+ ) => Effect.Effect<boolean, UserManagementError>;
100
+ }
101
+ >() {
102
+ static Live = Layer.effect(
103
+ this,
104
+ Effect.gen(function* () {
105
+ const linuxUserService = yield* LinuxUserService;
106
+ const directoryService = yield* DirectoryService;
107
+ const quotaService = yield* QuotaService;
108
+
109
+ return {
110
+ createUser: (request: CreateUserRequest) =>
111
+ Effect.gen(function* () {
112
+ const {
113
+ username,
114
+ claudeApiKey,
115
+ diskQuotaMB = 2048,
116
+ shell = "/bin/rbash",
117
+ } = request;
118
+
119
+ // Step 1: Sanitize username for Linux compatibility
120
+ const linuxUsername = yield* linuxUserService
121
+ .sanitizeUsername(username)
122
+ .pipe(
123
+ Effect.mapError((err) =>
124
+ UserManagementError(
125
+ `Failed to sanitize username: ${err.message}`,
126
+ err
127
+ )
128
+ )
129
+ );
130
+
131
+ // Step 2: Check if user already exists
132
+ const exists = yield* linuxUserService.userExists(linuxUsername).pipe(
133
+ Effect.mapError((err) =>
134
+ UserManagementError(
135
+ `Failed to check user existence: ${err.message}`,
136
+ err
137
+ )
138
+ )
139
+ );
140
+
141
+ if (exists) {
142
+ return yield* Effect.fail(
143
+ UserManagementError(
144
+ `Linux user ${linuxUsername} already exists`
145
+ )
146
+ );
147
+ }
148
+
149
+ // Step 3: Create Linux user
150
+ const linuxUser = yield* linuxUserService
151
+ .createUser({
152
+ username: linuxUsername,
153
+ shell,
154
+ createHome: true,
155
+ groups: ["myaidev"], // Optional: create this group for MyAIDev users
156
+ })
157
+ .pipe(
158
+ Effect.mapError((err) =>
159
+ UserManagementError(
160
+ `Failed to create Linux user: ${err.message}`,
161
+ err
162
+ )
163
+ )
164
+ );
165
+
166
+ // Step 4: Set up home directory structure
167
+ const claudeConfig: ClaudeConfig = {
168
+ apiKey: claudeApiKey || "",
169
+ model: "claude-sonnet-4-20250514",
170
+ maxTokens: 8192,
171
+ temperature: 1.0,
172
+ };
173
+
174
+ yield* directoryService
175
+ .setupHomeDirectory({
176
+ username: linuxUsername,
177
+ homeDir: linuxUser.homeDir,
178
+ uid: linuxUser.uid,
179
+ gid: linuxUser.gid,
180
+ claudeConfig,
181
+ })
182
+ .pipe(
183
+ Effect.mapError((err) =>
184
+ UserManagementError(
185
+ `Failed to setup home directory: ${err.message}`,
186
+ err
187
+ )
188
+ )
189
+ );
190
+
191
+ // Step 5: Apply resource limits
192
+ yield* linuxUserService
193
+ .setResourceLimits(linuxUsername, {
194
+ maxOpenFiles: 1024,
195
+ maxProcesses: 256,
196
+ maxMemoryKB: 2097152, // 2GB
197
+ maxCPUTime: 120, // 2 minutes per process
198
+ })
199
+ .pipe(
200
+ Effect.mapError((err) =>
201
+ UserManagementError(
202
+ `Failed to set resource limits: ${err.message}`,
203
+ err
204
+ )
205
+ )
206
+ );
207
+
208
+ // Step 6: Try to apply disk quotas (optional - may not be available)
209
+ const quotaAvailable = yield* quotaService
210
+ .isQuotaAvailable()
211
+ .pipe(Effect.orElseSucceed(() => false));
212
+
213
+ let quotaApplied = false;
214
+ if (quotaAvailable) {
215
+ yield* quotaService
216
+ .setDiskQuota(linuxUsername, {
217
+ softLimitMB: diskQuotaMB,
218
+ hardLimitMB: diskQuotaMB * 1.5, // 50% buffer
219
+ })
220
+ .pipe(
221
+ Effect.catchAll(() => Effect.succeed(void 0)) // Don't fail if quota setup fails
222
+ );
223
+ quotaApplied = true;
224
+ }
225
+
226
+ // Return complete setup information
227
+ return {
228
+ linuxUser,
229
+ homeDir: linuxUser.homeDir,
230
+ claudeConfigPath: `${linuxUser.homeDir}/.claude`,
231
+ workspacePath: `${linuxUser.homeDir}/workspace`,
232
+ quotaApplied,
233
+ limitsApplied: true,
234
+ };
235
+ }),
236
+
237
+ deleteUser: (username: string) =>
238
+ Effect.gen(function* () {
239
+ // Get user info first
240
+ const userInfo = yield* linuxUserService.getUserInfo(username).pipe(
241
+ Effect.mapError((err) =>
242
+ UserManagementError(
243
+ `Failed to get user info: ${err.message}`,
244
+ err
245
+ )
246
+ )
247
+ );
248
+
249
+ // Clean up directories
250
+ yield* directoryService
251
+ .cleanupDirectories(userInfo.homeDir)
252
+ .pipe(
253
+ Effect.mapError((err) =>
254
+ UserManagementError(
255
+ `Failed to cleanup directories: ${err.message}`,
256
+ err
257
+ )
258
+ )
259
+ );
260
+
261
+ // Delete Linux user
262
+ yield* linuxUserService.deleteUser(username, true).pipe(
263
+ Effect.mapError((err) =>
264
+ UserManagementError(
265
+ `Failed to delete user: ${err.message}`,
266
+ err
267
+ )
268
+ )
269
+ );
270
+
271
+ // Remove resource limits file
272
+ yield* Effect.tryPromise({
273
+ try: async () => {
274
+ const { execSync } = await import("child_process");
275
+ execSync(`sudo rm -f /etc/security/limits.d/${username}.conf`, {
276
+ stdio: "pipe",
277
+ });
278
+ },
279
+ catch: () =>
280
+ UserManagementError("Failed to remove limits configuration"),
281
+ });
282
+ }),
283
+
284
+ getUserInfo: (username: string) =>
285
+ linuxUserService.getUserInfo(username).pipe(
286
+ Effect.mapError((err) =>
287
+ UserManagementError(
288
+ `Failed to get user info: ${err.message}`,
289
+ err
290
+ )
291
+ )
292
+ ),
293
+
294
+ updateQuota: (username: string, quota: DiskQuota) =>
295
+ quotaService.setDiskQuota(username, quota).pipe(
296
+ Effect.mapError((err) =>
297
+ UserManagementError(
298
+ `Failed to update quota: ${err.message}`,
299
+ err
300
+ )
301
+ )
302
+ ),
303
+
304
+ isUsernameAvailable: (username: string) =>
305
+ Effect.gen(function* () {
306
+ // Sanitize username first
307
+ const linuxUsername = yield* linuxUserService
308
+ .sanitizeUsername(username)
309
+ .pipe(
310
+ Effect.mapError((err) =>
311
+ UserManagementError(
312
+ `Failed to sanitize username: ${err.message}`,
313
+ err
314
+ )
315
+ )
316
+ );
317
+
318
+ // Check if exists
319
+ const exists = yield* linuxUserService
320
+ .userExists(linuxUsername)
321
+ .pipe(
322
+ Effect.mapError((err) =>
323
+ UserManagementError(
324
+ `Failed to check availability: ${err.message}`,
325
+ err
326
+ )
327
+ )
328
+ );
329
+
330
+ return !exists;
331
+ }),
332
+ };
333
+ })
334
+ );
335
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * User Management Module
3
+ *
4
+ * Provides Linux user management capabilities for multi-user MyAIDev Method deployment.
5
+ *
6
+ * Features:
7
+ * - Create and delete Linux system users
8
+ * - Set up isolated home directories
9
+ * - Configure Claude Code environments
10
+ * - Apply disk quotas and resource limits
11
+ * - Clean up user resources
12
+ *
13
+ * Services:
14
+ * - LinuxUserService: Low-level Linux user operations
15
+ * - DirectoryService: Home directory and config management
16
+ * - QuotaService: Disk quota and storage limits
17
+ * - UserManagementService: High-level orchestration
18
+ *
19
+ * @module user-management
20
+ */
21
+
22
+ export * from "./LinuxUserService";
23
+ export * from "./DirectoryService";
24
+ export * from "./QuotaService";
25
+ export * from "./UserManagementService";
26
+ export * from "./layers";