myaidev-method 0.2.7 → 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.
- package/.claude/agents/wordpress-admin.md +271 -0
- package/.env.example +0 -1
- package/COOLIFY_DEPLOYMENT.md +1 -1
- package/DEV_WORKFLOW_GUIDE.md +1 -1
- package/PACKAGE_FIXES_SUMMARY.md +319 -0
- package/PAYLOADCMS_AUTH_UPDATE.md +248 -0
- package/PUBLISHING_GUIDE.md +1 -1
- package/README.md +7 -7
- package/USER_GUIDE.md +261 -1
- package/WORDPRESS_ADMIN_SCRIPTS.md +1 -1
- package/bin/cli.js +36 -0
- package/dist/server/.tsbuildinfo +1 -0
- package/dist/server/auth/controllers/AuthController.d.ts +34 -0
- package/dist/server/auth/controllers/AuthController.d.ts.map +1 -0
- package/dist/server/auth/controllers/AuthController.js +43 -0
- package/dist/server/auth/controllers/AuthController.js.map +1 -0
- package/dist/server/auth/example-usage.d.ts +53 -0
- package/dist/server/auth/example-usage.d.ts.map +1 -0
- package/dist/server/auth/example-usage.js +129 -0
- package/dist/server/auth/example-usage.js.map +1 -0
- package/dist/server/auth/index.d.ts +11 -0
- package/dist/server/auth/index.d.ts.map +1 -0
- package/dist/server/auth/index.js +15 -0
- package/dist/server/auth/index.js.map +1 -0
- package/dist/server/auth/layers.d.ts +19 -0
- package/dist/server/auth/layers.d.ts.map +1 -0
- package/dist/server/auth/layers.js +33 -0
- package/dist/server/auth/layers.js.map +1 -0
- package/dist/server/auth/middleware/authMiddleware.d.ts +24 -0
- package/dist/server/auth/middleware/authMiddleware.d.ts.map +1 -0
- package/dist/server/auth/middleware/authMiddleware.js +65 -0
- package/dist/server/auth/middleware/authMiddleware.js.map +1 -0
- package/dist/server/auth/routes/authRoutes.d.ts +11 -0
- package/dist/server/auth/routes/authRoutes.d.ts.map +1 -0
- package/dist/server/auth/routes/authRoutes.js +213 -0
- package/dist/server/auth/routes/authRoutes.js.map +1 -0
- package/dist/server/auth/services/AuditLogService.d.ts +21 -0
- package/dist/server/auth/services/AuditLogService.d.ts.map +1 -0
- package/dist/server/auth/services/AuditLogService.js +28 -0
- package/dist/server/auth/services/AuditLogService.js.map +1 -0
- package/dist/server/auth/services/AuthService.d.ts +27 -0
- package/dist/server/auth/services/AuthService.d.ts.map +1 -0
- package/dist/server/auth/services/AuthService.js +246 -0
- package/dist/server/auth/services/AuthService.js.map +1 -0
- package/dist/server/auth/services/PasswordService.d.ts +12 -0
- package/dist/server/auth/services/PasswordService.d.ts.map +1 -0
- package/dist/server/auth/services/PasswordService.js +31 -0
- package/dist/server/auth/services/PasswordService.js.map +1 -0
- package/dist/server/auth/services/SessionRepository.d.ts +24 -0
- package/dist/server/auth/services/SessionRepository.d.ts.map +1 -0
- package/dist/server/auth/services/SessionRepository.js +101 -0
- package/dist/server/auth/services/SessionRepository.js.map +1 -0
- package/dist/server/auth/services/TokenService.d.ts +12 -0
- package/dist/server/auth/services/TokenService.d.ts.map +1 -0
- package/dist/server/auth/services/TokenService.js +86 -0
- package/dist/server/auth/services/TokenService.js.map +1 -0
- package/dist/server/auth/services/UserRepository.d.ts +23 -0
- package/dist/server/auth/services/UserRepository.d.ts.map +1 -0
- package/dist/server/auth/services/UserRepository.js +168 -0
- package/dist/server/auth/services/UserRepository.js.map +1 -0
- package/dist/server/auth/services/example.d.ts +26 -0
- package/dist/server/auth/services/example.d.ts.map +1 -0
- package/dist/server/auth/services/example.js +221 -0
- package/dist/server/auth/services/example.js.map +1 -0
- package/dist/server/auth/services/index.d.ts +6 -0
- package/dist/server/auth/services/index.d.ts.map +1 -0
- package/dist/server/auth/services/index.js +7 -0
- package/dist/server/auth/services/index.js.map +1 -0
- package/dist/server/database/db.d.ts +28 -0
- package/dist/server/database/db.d.ts.map +1 -0
- package/dist/server/database/db.js +91 -0
- package/dist/server/database/db.js.map +1 -0
- package/dist/server/database/schema.sql +95 -0
- package/dist/server/hono/app.d.ts +10 -0
- package/dist/server/hono/app.d.ts.map +1 -0
- package/dist/server/hono/app.js +26 -0
- package/dist/server/hono/app.js.map +1 -0
- package/dist/server/hono/routes.d.ts +12 -0
- package/dist/server/hono/routes.d.ts.map +1 -0
- package/dist/server/hono/routes.js +40 -0
- package/dist/server/hono/routes.js.map +1 -0
- package/dist/server/main.d.ts +2 -0
- package/dist/server/main.d.ts.map +1 -0
- package/dist/server/main.js +94 -0
- package/dist/server/main.js.map +1 -0
- package/dist/server/user-management/DirectoryService.d.ts +62 -0
- package/dist/server/user-management/DirectoryService.d.ts.map +1 -0
- package/dist/server/user-management/DirectoryService.js +201 -0
- package/dist/server/user-management/DirectoryService.js.map +1 -0
- package/dist/server/user-management/LinuxUserService.d.ts +71 -0
- package/dist/server/user-management/LinuxUserService.d.ts.map +1 -0
- package/dist/server/user-management/LinuxUserService.js +192 -0
- package/dist/server/user-management/LinuxUserService.js.map +1 -0
- package/dist/server/user-management/QuotaService.d.ts +59 -0
- package/dist/server/user-management/QuotaService.d.ts.map +1 -0
- package/dist/server/user-management/QuotaService.js +148 -0
- package/dist/server/user-management/QuotaService.js.map +1 -0
- package/dist/server/user-management/UserManagementService.d.ts +74 -0
- package/dist/server/user-management/UserManagementService.d.ts.map +1 -0
- package/dist/server/user-management/UserManagementService.js +122 -0
- package/dist/server/user-management/UserManagementService.js.map +1 -0
- package/dist/server/user-management/index.d.ts +26 -0
- package/dist/server/user-management/index.d.ts.map +1 -0
- package/dist/server/user-management/index.js +26 -0
- package/dist/server/user-management/index.js.map +1 -0
- package/dist/server/user-management/layers.d.ts +27 -0
- package/dist/server/user-management/layers.d.ts.map +1 -0
- package/dist/server/user-management/layers.js +37 -0
- package/dist/server/user-management/layers.js.map +1 -0
- package/dist/shared/types.d.ts +94 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +32 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +26 -6
- package/src/lib/payloadcms-utils.js +5 -12
- package/src/server/auth/ARCHITECTURE.md +575 -0
- package/src/server/auth/IMPLEMENTATION_SUMMARY.md +287 -0
- package/src/server/auth/QUICK_START.md +283 -0
- package/src/server/auth/README.md +290 -0
- package/src/server/auth/controllers/AuthController.ts +129 -0
- package/src/server/auth/example-usage.ts +159 -0
- package/src/server/auth/index.ts +19 -0
- package/src/server/auth/layers.ts +57 -0
- package/src/server/auth/middleware/authMiddleware.ts +118 -0
- package/src/server/auth/routes/authRoutes.ts +319 -0
- package/src/server/auth/services/AuditLogService.ts +81 -0
- package/src/server/auth/services/AuthService.ts +408 -0
- package/src/server/auth/services/IMPLEMENTATION_SUMMARY.md +404 -0
- package/src/server/auth/services/PasswordService.ts +85 -0
- package/src/server/auth/services/README.md +361 -0
- package/src/server/auth/services/SessionRepository.ts +227 -0
- package/src/server/auth/services/TokenService.ts +174 -0
- package/src/server/auth/services/UserRepository.ts +318 -0
- package/src/server/auth/services/example.ts +346 -0
- package/src/server/auth/services/index.ts +6 -0
- package/src/server/database/db.ts +161 -0
- package/src/server/database/schema.sql +95 -0
- package/src/server/hono/app.ts +41 -0
- package/src/server/main.ts +115 -0
- package/src/server/user-management/DirectoryService.ts +348 -0
- package/src/server/user-management/LinuxUserService.ts +338 -0
- package/src/server/user-management/QuotaService.ts +256 -0
- package/src/server/user-management/README.md +333 -0
- package/src/server/user-management/UserManagementService.ts +335 -0
- package/src/server/user-management/index.ts +26 -0
- package/src/server/user-management/layers.ts +51 -0
- package/src/shared/types.ts +111 -0
- package/src/templates/claude/agents/payloadcms-publish.md +34 -14
- package/src/templates/codex/commands/myai-astro-publish.md +8 -2
- package/src/templates/codex/commands/myai-content-writer.md +8 -2
- package/src/templates/codex/commands/myai-coolify-deploy.md +8 -2
- package/src/templates/codex/commands/myai-dev-architect.md +8 -2
- package/src/templates/codex/commands/myai-dev-code.md +8 -2
- package/src/templates/codex/commands/myai-dev-docs.md +8 -2
- package/src/templates/codex/commands/myai-dev-review.md +8 -2
- package/src/templates/codex/commands/myai-dev-test.md +8 -2
- package/src/templates/codex/commands/myai-docusaurus-publish.md +8 -2
- package/src/templates/codex/commands/myai-mintlify-publish.md +8 -2
- package/src/templates/codex/commands/myai-payloadcms-publish.md +17 -3
- package/src/templates/codex/commands/myai-sparc-workflow.md +8 -2
- package/src/templates/codex/commands/myai-wordpress-admin.md +8 -2
- package/src/templates/codex/commands/myai-wordpress-publish.md +8 -2
- package/src/templates/docs/wordpress-troubleshoot.js +2 -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
|
+
}
|