myaidev-method 0.2.8 → 0.2.10

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 (158) 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 +70 -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/coolify-deploy.md +50 -50
  144. package/src/templates/claude/agents/payloadcms-publish.md +46 -18
  145. package/src/templates/codex/commands/myai-astro-publish.md +8 -2
  146. package/src/templates/codex/commands/myai-content-writer.md +8 -2
  147. package/src/templates/codex/commands/myai-coolify-deploy.md +8 -2
  148. package/src/templates/codex/commands/myai-dev-architect.md +8 -2
  149. package/src/templates/codex/commands/myai-dev-code.md +8 -2
  150. package/src/templates/codex/commands/myai-dev-docs.md +8 -2
  151. package/src/templates/codex/commands/myai-dev-review.md +8 -2
  152. package/src/templates/codex/commands/myai-dev-test.md +8 -2
  153. package/src/templates/codex/commands/myai-docusaurus-publish.md +8 -2
  154. package/src/templates/codex/commands/myai-mintlify-publish.md +8 -2
  155. package/src/templates/codex/commands/myai-payloadcms-publish.md +17 -3
  156. package/src/templates/codex/commands/myai-sparc-workflow.md +8 -2
  157. package/src/templates/codex/commands/myai-wordpress-admin.md +8 -2
  158. package/src/templates/codex/commands/myai-wordpress-publish.md +8 -2
@@ -0,0 +1,115 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { Effect, ManagedRuntime } from "effect";
3
+ import { NodeContext } from "@effect/platform-node";
4
+ import { createApp } from "./hono/app.js";
5
+ import { createAuthRoutes } from "./auth/routes/authRoutes.js";
6
+ import { createAuthMiddleware } from "./auth/middleware/authMiddleware.js";
7
+ import { createAppLayer } from "./auth/layers.js";
8
+ import type { AppRuntimeContext } from "./auth/middleware/authMiddleware.js";
9
+ import * as path from "node:path";
10
+ import { homedir } from "node:os";
11
+
12
+ const getDefaultDbPath = (): string => {
13
+ const sqliteDbPath = process.env["SQLITE_DB_PATH"];
14
+ if (sqliteDbPath) {
15
+ return sqliteDbPath;
16
+ }
17
+
18
+ if (process.env["SINGLE_USER_MODE"] === "true") {
19
+ const home = homedir();
20
+ return path.join(home, ".myaidev-web", "users.db");
21
+ }
22
+
23
+ return path.join(process.cwd(), "data", "users.db");
24
+ };
25
+
26
+ // Create the application layer with auth services
27
+ const AppLayer = createAppLayer({
28
+ path: getDefaultDbPath(),
29
+ timeout: 5000,
30
+ verbose: false, // Disable verbose mode to prevent schema logging on every request
31
+ });
32
+
33
+ // Build the managed runtime once at startup (memoization with automatic scope management)
34
+ const AppRuntime = ManagedRuntime.make(AppLayer) as ManagedRuntime.ManagedRuntime<AppRuntimeContext, never>;
35
+
36
+ // Create middleware and routes with the memoized runtime
37
+ const authMiddleware = createAuthMiddleware(AppRuntime);
38
+ const authRouter = createAuthRoutes(AppRuntime, authMiddleware);
39
+
40
+ const program = Effect.gen(function* () {
41
+ const port = Number.parseInt(process.env["PORT"] ?? "3400", 10);
42
+ const dbPath = getDefaultDbPath();
43
+
44
+ console.log(`🔧 Initializing MyAIDev Method Web Server`);
45
+ console.log(`📂 Database path: ${dbPath}`);
46
+ console.log(`🌐 Server port: ${port}`);
47
+ console.log(`✅ Application layer initialized successfully`);
48
+
49
+ const app = createApp();
50
+
51
+ console.log(`🚀 Starting server on port ${port}...`);
52
+
53
+ // Mount authentication routes (already created with AppLayer)
54
+ app.route("/api/auth", authRouter);
55
+
56
+ // Example protected route
57
+ app.get("/api/protected", authMiddleware, (c) => {
58
+ const user = c.get("user");
59
+ const session = c.get("session");
60
+
61
+ return c.json({
62
+ message: "This is a protected route",
63
+ user: {
64
+ id: user?.id,
65
+ username: user?.username,
66
+ email: user?.email,
67
+ },
68
+ session: {
69
+ id: session?.id,
70
+ expiresAt: session?.expiresAt,
71
+ },
72
+ });
73
+ });
74
+
75
+ console.log("✅ Routes configured successfully");
76
+ console.log(" 📍 POST /api/auth/register - User registration");
77
+ console.log(" 📍 POST /api/auth/login - User login");
78
+ console.log(" 📍 POST /api/auth/logout - User logout (protected)");
79
+ console.log(" 📍 GET /api/auth/me - Current user info (protected)");
80
+ console.log(" 📍 GET /api/protected - Example protected route");
81
+
82
+ const server = serve({
83
+ fetch: app.fetch,
84
+ port,
85
+ });
86
+
87
+ console.log(`✅ Server running at http://localhost:${port}`);
88
+ console.log(`📊 Health check: http://localhost:${port}/health`);
89
+
90
+ yield* Effect.async<void, never>(() => {
91
+ process.on("SIGTERM", () => {
92
+ console.log("\n🛑 SIGTERM received, shutting down gracefully...");
93
+ server.close(() => {
94
+ console.log("✅ Server closed");
95
+ process.exit(0);
96
+ });
97
+ });
98
+
99
+ process.on("SIGINT", () => {
100
+ console.log("\n🛑 SIGINT received, shutting down gracefully...");
101
+ server.close(() => {
102
+ console.log("✅ Server closed");
103
+ process.exit(0);
104
+ });
105
+ });
106
+ });
107
+ });
108
+
109
+ // Program only needs Node context
110
+ Effect.runPromise(
111
+ Effect.provide(program, NodeContext.layer) as Effect.Effect<void, never, never>
112
+ ).catch((error) => {
113
+ console.error("❌ Fatal error:", error);
114
+ process.exit(1);
115
+ });
@@ -0,0 +1,348 @@
1
+ import { Effect, Context, Layer } from "effect";
2
+ import { execSync } from "child_process";
3
+ import * as fs from "fs/promises";
4
+ import * as path from "path";
5
+
6
+ /**
7
+ * Directory Management Service
8
+ *
9
+ * Handles creation and management of user home directories,
10
+ * Claude Code configurations, and workspace setup for isolated
11
+ * multi-user environments.
12
+ *
13
+ * Directory Structure:
14
+ * /home/{username}/
15
+ * ├── .claude/ # Claude Code configuration
16
+ * │ ├── config.json # User-specific Claude settings
17
+ * │ ├── sessions/ # Session storage
18
+ * │ └── cache/ # Cache directory
19
+ * ├── workspace/ # User's workspace directory
20
+ * └── .bashrc # Shell configuration
21
+ */
22
+
23
+ export interface DirectorySetupOptions {
24
+ username: string;
25
+ homeDir: string;
26
+ uid: number;
27
+ gid: number;
28
+ claudeConfig?: ClaudeConfig;
29
+ }
30
+
31
+ export interface ClaudeConfig {
32
+ apiKey?: string;
33
+ model?: string;
34
+ maxTokens?: number;
35
+ temperature?: number;
36
+ }
37
+
38
+ export interface DirectoryError {
39
+ readonly _tag: "DirectoryError";
40
+ readonly message: string;
41
+ readonly cause?: unknown;
42
+ }
43
+
44
+ const DirectoryError = (message: string, cause?: unknown): DirectoryError => ({
45
+ _tag: "DirectoryError",
46
+ message,
47
+ cause,
48
+ });
49
+
50
+ export class DirectoryService extends Context.Tag("DirectoryService")<
51
+ DirectoryService,
52
+ {
53
+ /**
54
+ * Set up complete home directory structure for a user
55
+ */
56
+ readonly setupHomeDirectory: (
57
+ options: DirectorySetupOptions
58
+ ) => Effect.Effect<void, DirectoryError>;
59
+
60
+ /**
61
+ * Create Claude Code configuration directory
62
+ */
63
+ readonly createClaudeConfig: (
64
+ homeDir: string,
65
+ config: ClaudeConfig,
66
+ uid: number,
67
+ gid: number
68
+ ) => Effect.Effect<void, DirectoryError>;
69
+
70
+ /**
71
+ * Create user workspace directory
72
+ */
73
+ readonly createWorkspace: (
74
+ homeDir: string,
75
+ uid: number,
76
+ gid: number
77
+ ) => Effect.Effect<void, DirectoryError>;
78
+
79
+ /**
80
+ * Set proper ownership and permissions
81
+ */
82
+ readonly setOwnership: (
83
+ dirPath: string,
84
+ uid: number,
85
+ gid: number,
86
+ recursive?: boolean
87
+ ) => Effect.Effect<void, DirectoryError>;
88
+
89
+ /**
90
+ * Clean up user directories
91
+ */
92
+ readonly cleanupDirectories: (
93
+ homeDir: string
94
+ ) => Effect.Effect<void, DirectoryError>;
95
+ }
96
+ >() {
97
+ static Live = Layer.succeed(this, {
98
+ setupHomeDirectory: (options: DirectorySetupOptions) =>
99
+ Effect.gen(function* () {
100
+ const { username, homeDir, uid, gid, claudeConfig } = options;
101
+
102
+ // Ensure home directory exists (should be created by useradd)
103
+ yield* Effect.tryPromise({
104
+ try: async () => {
105
+ await fs.access(homeDir);
106
+ },
107
+ catch: (error) =>
108
+ DirectoryError(
109
+ `Home directory ${homeDir} does not exist. Create user first.`,
110
+ error
111
+ ),
112
+ });
113
+
114
+ // Create .claude directory
115
+ const claudeDir = path.join(homeDir, ".claude");
116
+ yield* Effect.tryPromise({
117
+ try: async () => {
118
+ await fs.mkdir(claudeDir, { recursive: true, mode: 0o755 });
119
+ },
120
+ catch: (error) =>
121
+ DirectoryError(`Failed to create .claude directory`, error),
122
+ });
123
+
124
+ // Create subdirectories
125
+ const subdirs = ["sessions", "cache", "workspace"];
126
+ for (const subdir of subdirs) {
127
+ const subdirPath =
128
+ subdir === "workspace"
129
+ ? path.join(homeDir, subdir)
130
+ : path.join(claudeDir, subdir);
131
+
132
+ yield* Effect.tryPromise({
133
+ try: async () => {
134
+ await fs.mkdir(subdirPath, { recursive: true, mode: 0o755 });
135
+ },
136
+ catch: (error) =>
137
+ DirectoryError(`Failed to create ${subdir} directory`, error),
138
+ });
139
+ }
140
+
141
+ // Create Claude config file
142
+ if (claudeConfig) {
143
+ const configPath = path.join(claudeDir, "config.json");
144
+ const configContent = JSON.stringify(
145
+ {
146
+ apiKey: claudeConfig.apiKey || "",
147
+ model: claudeConfig.model || "claude-sonnet-4-20250514",
148
+ maxTokens: claudeConfig.maxTokens || 8192,
149
+ temperature: claudeConfig.temperature || 1.0,
150
+ username,
151
+ createdAt: new Date().toISOString(),
152
+ },
153
+ null,
154
+ 2
155
+ );
156
+
157
+ yield* Effect.tryPromise({
158
+ try: async () => {
159
+ await fs.writeFile(configPath, configContent, {
160
+ mode: 0o600,
161
+ });
162
+ },
163
+ catch: (error) =>
164
+ DirectoryError("Failed to create Claude config file", error),
165
+ });
166
+ }
167
+
168
+ // Create .bashrc with helpful aliases
169
+ const bashrcPath = path.join(homeDir, ".bashrc");
170
+ const bashrcContent = `# MyAIDev Method User Environment
171
+ # Generated on ${new Date().toISOString()}
172
+
173
+ # Helpful aliases
174
+ alias ll='ls -alh'
175
+ alias workspace='cd ~/workspace'
176
+ alias claude='cd ~/.claude'
177
+
178
+ # Environment
179
+ export PATH="$HOME/.local/bin:$PATH"
180
+ export CLAUDE_CONFIG_DIR="$HOME/.claude"
181
+
182
+ # Workspace directory
183
+ export WORKSPACE="$HOME/workspace"
184
+
185
+ # Welcome message
186
+ echo "Welcome to MyAIDev Method, ${username}!"
187
+ echo "Your workspace is in: ~/workspace"
188
+ `;
189
+
190
+ yield* Effect.tryPromise({
191
+ try: async () => {
192
+ await fs.writeFile(bashrcPath, bashrcContent, { mode: 0o644 });
193
+ },
194
+ catch: (error) =>
195
+ DirectoryError("Failed to create .bashrc file", error),
196
+ });
197
+
198
+ // Set ownership of all created files/directories
199
+ yield* Effect.tryPromise({
200
+ try: async () => {
201
+ execSync(`sudo chown -R ${uid}:${gid} ${homeDir}`, {
202
+ stdio: "pipe",
203
+ });
204
+ },
205
+ catch: (error) =>
206
+ DirectoryError(
207
+ `Failed to set ownership for ${homeDir}`,
208
+ error
209
+ ),
210
+ });
211
+
212
+ // Set proper permissions
213
+ yield* Effect.tryPromise({
214
+ try: async () => {
215
+ execSync(`sudo chmod 755 ${homeDir}`, { stdio: "pipe" });
216
+ execSync(`sudo chmod 700 ${claudeDir}`, { stdio: "pipe" });
217
+ execSync(`sudo chmod 755 ${path.join(homeDir, "workspace")}`, {
218
+ stdio: "pipe",
219
+ });
220
+ },
221
+ catch: (error) =>
222
+ DirectoryError("Failed to set directory permissions", error),
223
+ });
224
+ }),
225
+
226
+ createClaudeConfig: (
227
+ homeDir: string,
228
+ config: ClaudeConfig,
229
+ uid: number,
230
+ gid: number
231
+ ) =>
232
+ Effect.gen(function* () {
233
+ const claudeDir = path.join(homeDir, ".claude");
234
+ const configPath = path.join(claudeDir, "config.json");
235
+
236
+ // Ensure .claude directory exists
237
+ yield* Effect.tryPromise({
238
+ try: async () => {
239
+ await fs.mkdir(claudeDir, { recursive: true, mode: 0o700 });
240
+ },
241
+ catch: (error) =>
242
+ DirectoryError("Failed to create .claude directory", error),
243
+ });
244
+
245
+ // Write config file
246
+ const configContent = JSON.stringify(config, null, 2);
247
+ yield* Effect.tryPromise({
248
+ try: async () => {
249
+ await fs.writeFile(configPath, configContent, { mode: 0o600 });
250
+ },
251
+ catch: (error) =>
252
+ DirectoryError("Failed to write Claude config", error),
253
+ });
254
+
255
+ // Set ownership
256
+ yield* Effect.tryPromise({
257
+ try: async () => {
258
+ execSync(`sudo chown -R ${uid}:${gid} ${claudeDir}`, {
259
+ stdio: "pipe",
260
+ });
261
+ },
262
+ catch: (error) =>
263
+ DirectoryError("Failed to set config ownership", error),
264
+ });
265
+ }),
266
+
267
+ createWorkspace: (homeDir: string, uid: number, gid: number) =>
268
+ Effect.gen(function* () {
269
+ const workspaceDir = path.join(homeDir, "workspace");
270
+
271
+ // Create workspace directory
272
+ yield* Effect.tryPromise({
273
+ try: async () => {
274
+ await fs.mkdir(workspaceDir, { recursive: true, mode: 0o755 });
275
+ },
276
+ catch: (error) =>
277
+ DirectoryError("Failed to create workspace directory", error),
278
+ });
279
+
280
+ // Create a README file
281
+ const readmePath = path.join(workspaceDir, "README.md");
282
+ const readmeContent = `# Welcome to Your MyAIDev Method Workspace
283
+
284
+ This is your personal workspace for AI-assisted development with Claude Code.
285
+
286
+ ## Directory Structure
287
+
288
+ - Use this workspace to create and manage your projects
289
+ - Claude Code will have access to files in this directory
290
+ - Your work is isolated from other users
291
+
292
+ ## Getting Started
293
+
294
+ 1. Create a new project directory
295
+ 2. Initialize your project (git init, npm init, etc.)
296
+ 3. Start working with Claude Code assistance
297
+
298
+ Happy coding!
299
+ `;
300
+
301
+ yield* Effect.tryPromise({
302
+ try: async () => {
303
+ await fs.writeFile(readmePath, readmeContent, { mode: 0o644 });
304
+ },
305
+ catch: (error) =>
306
+ DirectoryError("Failed to create workspace README", error),
307
+ });
308
+
309
+ // Set ownership
310
+ yield* Effect.tryPromise({
311
+ try: async () => {
312
+ execSync(`sudo chown -R ${uid}:${gid} ${workspaceDir}`, {
313
+ stdio: "pipe",
314
+ });
315
+ },
316
+ catch: (error) =>
317
+ DirectoryError("Failed to set workspace ownership", error),
318
+ });
319
+ }),
320
+
321
+ setOwnership: (
322
+ dirPath: string,
323
+ uid: number,
324
+ gid: number,
325
+ recursive: boolean = false
326
+ ) =>
327
+ Effect.tryPromise({
328
+ try: async () => {
329
+ const recursiveFlag = recursive ? "-R" : "";
330
+ execSync(`sudo chown ${recursiveFlag} ${uid}:${gid} ${dirPath}`, {
331
+ stdio: "pipe",
332
+ });
333
+ },
334
+ catch: (error) =>
335
+ DirectoryError(`Failed to set ownership for ${dirPath}`, error),
336
+ }),
337
+
338
+ cleanupDirectories: (homeDir: string) =>
339
+ Effect.tryPromise({
340
+ try: async () => {
341
+ // Remove home directory and all contents
342
+ execSync(`sudo rm -rf ${homeDir}`, { stdio: "pipe" });
343
+ },
344
+ catch: (error) =>
345
+ DirectoryError(`Failed to cleanup directories for ${homeDir}`, error),
346
+ }),
347
+ });
348
+ }