diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..fe6ec6d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,62 @@ +# AeThex-OS Copilot Coding Agent Instructions + +## Project Overview +AeThex-OS is a modular web desktop platform built with TypeScript, React, Vite, Drizzle ORM, and Supabase. It features a multi-service architecture with clear separation between client, server, shared schema, and data migration layers. The system is designed for extensibility, rapid prototyping, and integration with external APIs and authentication providers. + +## Key Architectural Patterns +- **Client/Server Split:** + - `client/` contains the React SPA, UI components, hooks, and page logic. + - `server/` contains API routes, static asset serving, websocket logic, and Supabase integration. + - `shared/schema.ts` defines all database tables and Zod validation schemas, used by both client and server. +- **Drizzle ORM:** + - All database schema and types are defined in `shared/schema.ts` using Drizzle's `pgTable` and Zod schemas. + - Migrations are managed in `migrations/`. +- **Authentication:** + - Supabase Auth is used for user management. Profiles are linked to `auth.users(id)`. +- **Component Organization:** + - UI components are in `client/src/components/` and subfolders. Shared hooks are in `client/src/hooks/`. + - Pages are in `client/src/pages/`. + +## Developer Workflows +- **Build:** + - Use Vite for client builds: `npm run build` (see `vite.config.ts`). + - Server scripts are in `script/` and `server/`. +- **Test:** + - Run shell script `./test-implementation.sh` for implementation checks. +- **Migrations:** + - Database migrations are in `migrations/`. Use Drizzle migration commands as per project docs. +- **Debugging:** + - Client debugging via Vite dev server. Server debugging via direct script execution or API route testing. + +## Project-Specific Conventions +- **Type Safety:** + - All data models use Zod schemas for validation and type inference. +- **Default Values:** + - Most tables use `.default()` for status, roles, and timestamps. See `shared/schema.ts` for examples. +- **Extensibility:** + - New features should be added as new tables in `shared/schema.ts` and new components/pages in `client/src/`. +- **Naming:** + - Use `aethex_*` prefix for core tables and features (e.g., `aethex_sites`, `aethex_projects`). + +## Integration Points +- **Supabase:** + - Used for authentication and storage. See `client/src/lib/supabase.ts` and `server/supabase.ts`. +- **Websockets:** + - Real-time features via `client/src/hooks/use-websocket.ts` and `server/websocket.ts`. +- **API:** + - API logic in `server/routes.ts` and `client/src/lib/api.ts`. + +## Examples +- **Schema Definition:** See `shared/schema.ts` for Drizzle/Zod table patterns. +- **Component Usage:** See `client/src/components/Chatbot.tsx` for AI integration. +- **Migration:** See `migrations/` for SQL migration examples. + +## Recommendations for AI Agents +- Always update both schema and Zod types when adding new tables or fields. +- Reference existing patterns for new features (e.g., achievements, profiles, projects). +- Use default values and type-safe patterns as shown in `shared/schema.ts`. +- When in doubt, follow the naming and structure conventions in existing files. + +--- + +*If any section is unclear or missing, please provide feedback for further refinement.* diff --git a/package-lock.json b/package-lock.json index b35339b..89263f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", + "commander": "^14.0.2", "connect-pg-simple": "^10.0.0", "date-fns": "^3.6.0", "dotenv": "^17.2.3", @@ -73,6 +74,7 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", "tw-animate-css": "^1.4.0", "vaul": "^1.1.2", "wouter": "^3.3.5", @@ -400,6 +402,28 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@date-fns/tz": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", @@ -4406,6 +4430,30 @@ "react": "^18 || ^19" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4627,6 +4675,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz", "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -4785,6 +4834,36 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" + }, "node_modules/aria-hidden": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", @@ -5038,6 +5117,15 @@ "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/connect-pg-simple": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/connect-pg-simple/-/connect-pg-simple-10.0.0.tgz", @@ -5106,6 +5194,12 @@ "node": ">= 0.10" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -5321,6 +5415,15 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -6536,6 +6639,12 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7883,6 +7992,49 @@ "node": ">=0.6" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7936,8 +8088,8 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8063,6 +8215,12 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -8241,6 +8399,15 @@ "dev": true, "license": "ISC" }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/package.json b/package.json index baea0a6..9a4627c 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", + "commander": "^14.0.2", "connect-pg-simple": "^10.0.0", "date-fns": "^3.6.0", "dotenv": "^17.2.3", @@ -76,6 +77,7 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", "tw-animate-css": "^1.4.0", "vaul": "^1.1.2", "wouter": "^3.3.5", diff --git a/script/cli-commands.ts b/script/cli-commands.ts new file mode 100644 index 0000000..cb472bd --- /dev/null +++ b/script/cli-commands.ts @@ -0,0 +1,37 @@ +import { execSync } from "child_process"; + +export function build() { + execSync("npm run build", { stdio: "inherit" }); +} + +export function test() { + execSync("./test-implementation.sh", { stdio: "inherit" }); +} + +export function migrate() { + execSync("npx drizzle-kit migrate:push", { stdio: "inherit" }); +} + +export function dev() { + execSync("npm run dev", { stdio: "inherit" }); +} + +export function server() { + execSync("ts-node server/index.ts", { stdio: "inherit" }); +} + +export function lint() { + execSync("npm run lint", { stdio: "inherit" }); +} + +export function format() { + execSync("npm run format", { stdio: "inherit" }); +} + +export function migrateStatus() { + execSync("npx drizzle-kit status", { stdio: "inherit" }); +} + +export function seed() { + execSync("ts-node script/seed.ts", { stdio: "inherit" }); +} diff --git a/script/cli.ts b/script/cli.ts new file mode 100644 index 0000000..d6312b5 --- /dev/null +++ b/script/cli.ts @@ -0,0 +1,122 @@ +#!/usr/bin/env node +import { Command } from "commander"; + +import { + build, + test, + migrate, + dev, + server, + lint, + format, + migrateStatus, + seed, +} from "./cli-commands"; + + + + + + + + + +const AETHEX_LOGO = `\n\x1b[36m + $$$$$$\ $$$$$$$$\ $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$\ $$\ +$$ __$$\ $$ _____|\__$$ __|$$ | $$ |$$ _____|$$ | $$ | +$$ / $$ |$$ | $$ | $$ | $$ |$$ | \$$\ $$ | +$$$$$$$$ |$$$$$\ $$ | $$$$$$$$ |$$$$$\ \$$$$ / +$$ __$$ |$$ __| $$ | $$ __$$ |$$ __| $$ $$< +$$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ /\$$\ +$$ | $$ |$$$$$$$$\ $$ | $$ | $$ |$$$$$$$$\ $$ / $$ | +\__| \__|\________| \__| \__| \__|\________|\__| \__| +\x1b[0m\nAeThex-OS CLI\n`; + +const program = new Command(); +program + .name("aethex") + .description("AeThex-OS CLI: Modular Web Desktop Platform") + .version("0.1.0") + .addHelpText("beforeAll", AETHEX_LOGO); +import readline from "readline"; +program + .command("shell") + .description("Launch interactive AeThex shell (REPL)") + .action(() => { + console.log(AETHEX_LOGO); + console.log("Type any shell command. Type 'exit' to quit.\n"); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + prompt: "aethex> " + }); + rl.prompt(); + rl.on("line", (line) => { + if (line.trim() === "exit") { + rl.close(); + return; + } + try { + const result = require("child_process").execSync(line, { stdio: "inherit" }); + } catch (err) { + console.error("Error executing command."); + } + rl.prompt(); + }); + rl.on("close", () => { + console.log("Exiting AeThex shell."); + process.exit(0); + }); + }); + + +program + .command("build") + .description("Build the client app using Vite") + .action(build); + + +program + .command("test") + .description("Run implementation tests") + .action(test); + + +program + .command("migrate") + .description("Run Drizzle migrations") + .action(migrate); + + +program + .command("dev") + .description("Start Vite dev server for client") + .action(dev); + + +program + .command("server") + .description("Start the server (index.ts)") + .action(server); + +program + .command("lint") + .description("Run linter on the codebase") + .action(lint); + +program + .command("format") + .description("Format codebase using Prettier or configured formatter") + .action(format); + +program + .command("migrate-status") + .description("Show Drizzle migration status") + .action(migrateStatus); + +program + .command("seed") + .description("Seed the database with initial data") + .action(seed); + +program.parse(process.argv);