- {logs.length > 0 && (
-
- )}
+ {isInitialLoad ? (
+ <>
+
{" "}
+ >
+ ) : (
+ <>
+ {logs.length > 0 && (
+
+ )}
- {/* Logs List */}
-
- {logs.length === 0 ? (
-
-
-
-
-
- No activity logs found
-
-
- {selectedSource || selectedStatus
- ? "Try adjusting your filters to see more results."
- : "No activity ingestion logs are available yet."}
-
-
-
-
- ) : (
-
- )}
-
+ {/* Logs List */}
+
+ {logs.length === 0 ? (
+
+
+
+
+
+ No activity logs found
+
+
+ {selectedSource || selectedStatus
+ ? "Try adjusting your filters to see more results."
+ : "No activity ingestion logs are available yet."}
+
+
+
+
+ ) : (
+
+ )}
+
+ >
+ )}
);
diff --git a/apps/webapp/app/routes/home.logs.all.tsx b/apps/webapp/app/routes/home.logs.all.tsx
index 6d09992..2797967 100644
--- a/apps/webapp/app/routes/home.logs.all.tsx
+++ b/apps/webapp/app/routes/home.logs.all.tsx
@@ -26,18 +26,6 @@ export default function LogsAll() {
status: selectedStatus,
});
- if (isInitialLoad) {
- return (
-
- {/* Filters */}
- {logs.length > 0 && (
-
+ {isInitialLoad ? (
+ <>
+
{" "}
+ >
+ ) : (
+ <>
+ {" "}
+ {/* Filters */}
+ {logs.length > 0 && (
+
+ )}
+ {/* Logs List */}
+
+ {logs.length === 0 ? (
+
+
+
+
+
+ No logs found
+
+
+ {selectedSource || selectedStatus
+ ? "Try adjusting your filters to see more results."
+ : "No ingestion logs are available yet."}
+
+
+
+
+ ) : (
+
+ )}
+
+ >
)}
-
- {/* Logs List */}
-
- {logs.length === 0 ? (
-
-
-
-
-
No logs found
-
- {selectedSource || selectedStatus
- ? "Try adjusting your filters to see more results."
- : "No ingestion logs are available yet."}
-
-
-
-
- ) : (
-
- )}
-
>
);
diff --git a/packages/core-cli/README.md b/packages/core-cli/README.md
new file mode 100644
index 0000000..21451fd
--- /dev/null
+++ b/packages/core-cli/README.md
@@ -0,0 +1,193 @@
+# Core CLI
+
+š§ **CORE - Contextual Observation & Recall Engine**
+
+A Command-Line Interface for setting up and managing the Core development environment.
+
+## Installation
+
+```bash
+npm install -g @redplanethq/core
+```
+
+## Commands
+
+### `core init`
+
+**One-time setup command** - Initializes the Core development environment with full configuration.
+
+### `core start`
+
+**Daily usage command** - Starts all Core services (Docker containers).
+
+### `core stop`
+
+**Daily usage command** - Stops all Core services (Docker containers).
+
+## Getting Started
+
+### Prerequisites
+
+- **Node.js** (v18.20.0 or higher)
+- **Docker** and **Docker Compose**
+- **Git**
+- **pnpm** package manager
+
+### Initial Setup
+
+1. **Run the initialization command:**
+
+ ```bash
+ core init
+ ```
+
+2. **The CLI will guide you through the complete setup process:**
+
+#### Step 1: Repository Validation
+
+- The CLI checks if you're in the Core repository
+- If not, it offers to clone the repository for you
+- Choose **Yes** to clone automatically, or **No** to clone manually
+
+#### Step 2: Environment Configuration
+
+- Copies `.env.example` to `.env` in the root directory
+- Copies `trigger/.env.example` to `trigger/.env`
+- Skips copying if `.env` files already exist
+
+#### Step 3: Docker Services Startup
+
+- Starts main Core services: `docker compose up -d`
+- Starts Trigger.dev services: `docker compose up -d` (in trigger/ directory)
+- Shows real-time output with progress indicators
+
+#### Step 4: Database Health Check
+
+- Verifies PostgreSQL is running on `localhost:5432`
+- Retries for up to 60 seconds if needed
+
+#### Step 5: Trigger.dev Setup (Interactive)
+
+- **If Trigger.dev is not configured:**
+
+ 1. Prompts you to open http://localhost:8030
+ 2. Asks you to login to Trigger.dev
+ 3. Guides you to create an organization and project
+ 4. Collects your Project ID and Secret Key
+ 5. Updates `.env` with your Trigger.dev configuration
+ 6. Restarts Core services with new configuration
+
+- **If Trigger.dev is already configured:**
+ - Skips setup and shows "Configuration already exists" message
+
+#### Step 6: Docker Registry Login
+
+- Displays docker login command with credentials from `.env`
+- Waits for you to complete the login process
+
+#### Step 7: Trigger.dev Task Deployment
+
+- Automatically runs: `npx trigger.dev@v4-beta login -a http://localhost:8030`
+- Deploys tasks with: `pnpm trigger:deploy`
+- Shows manual deployment instructions if automatic deployment fails
+
+#### Step 8: Setup Complete!
+
+- Confirms all services are running
+- Shows service URLs and connection information
+
+## Daily Usage
+
+After initial setup, use these commands for daily development:
+
+### Start Services
+
+```bash
+core start
+```
+
+Starts all Docker containers for Core development.
+
+### Stop Services
+
+```bash
+core stop
+```
+
+Stops all Docker containers.
+
+## Service URLs
+
+After setup, these services will be available:
+
+- **Core Application**: http://localhost:3033
+- **Trigger.dev**: http://localhost:8030
+- **PostgreSQL**: localhost:5432
+
+## Troubleshooting
+
+### Repository Not Found
+
+If you run commands outside the Core repository:
+
+- The CLI will offer to clone the repository automatically
+- Choose **Yes** to clone in the current directory
+- Or navigate to the Core repository manually
+
+### Docker Issues
+
+- Ensure Docker is running
+- Check Docker Compose is installed
+- Verify you have sufficient system resources
+
+### Trigger.dev Setup Issues
+
+- Check container logs: `docker logs trigger-webapp --tail 50`
+- Ensure you can access http://localhost:8030
+- Verify your network allows connections to localhost
+
+### Environment Variables
+
+The CLI automatically manages these environment variables:
+
+- `TRIGGER_PROJECT_ID` - Your Trigger.dev project ID
+- `TRIGGER_SECRET_KEY` - Your Trigger.dev secret key
+- Docker registry credentials for deployment
+
+### Manual Trigger.dev Deployment
+
+If automatic deployment fails, run manually:
+
+```bash
+npx trigger.dev@v4-beta login -a http://localhost:8030
+pnpm trigger:deploy
+```
+
+## Development Workflow
+
+1. **First time setup:** `core init`
+2. **Daily development:**
+ - `core start` - Start your development environment
+ - Do your development work
+ - `core stop` - Stop services when done
+
+## Support
+
+For issues and questions:
+
+- Check the main Core repository: https://github.com/redplanethq/core
+- Review Docker container logs for troubleshooting
+- Ensure all prerequisites are properly installed
+
+## Features
+
+- š **One-command setup** - Complete environment initialization
+- š **Smart configuration** - Skips already configured components
+- š± **Real-time feedback** - Live progress indicators and output
+- š³ **Docker integration** - Full container lifecycle management
+- š§ **Interactive setup** - Guided configuration process
+- šÆ **Error handling** - Graceful failure with recovery instructions
+
+---
+
+**Happy coding with Core!** š
diff --git a/packages/core-cli/package.json b/packages/core-cli/package.json
index bdf4585..f2c905e 100644
--- a/packages/core-cli/package.json
+++ b/packages/core-cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@redplanethq/core",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "A Command-Line Interface for Core",
"type": "module",
"license": "MIT",
diff --git a/packages/core-cli/src/cli/index.ts b/packages/core-cli/src/cli/index.ts
index 554f06c..5b145cf 100644
--- a/packages/core-cli/src/cli/index.ts
+++ b/packages/core-cli/src/cli/index.ts
@@ -1,10 +1,25 @@
import { Command } from "commander";
import { initCommand } from "../commands/init.js";
+import { startCommand } from "../commands/start.js";
+import { stopCommand } from "../commands/stop.js";
const program = new Command();
program.name("core").description("Core CLI - A Command-Line Interface for Core").version("0.1.0");
-program.command("init").description("Initialize Core development environment").action(initCommand);
+program
+ .command("init")
+ .description("Initialize Core development environment (run once)")
+ .action(initCommand);
+
+program
+ .command("start")
+ .description("Start Core development environment")
+ .action(startCommand);
+
+program
+ .command("stop")
+ .description("Stop Core development environment")
+ .action(stopCommand);
program.parse(process.argv);
diff --git a/packages/core-cli/src/commands/init.ts b/packages/core-cli/src/commands/init.ts
index 9128496..5c790b3 100644
--- a/packages/core-cli/src/commands/init.ts
+++ b/packages/core-cli/src/commands/init.ts
@@ -1,10 +1,11 @@
-import { intro, outro, text, confirm, spinner } from "@clack/prompts";
+import { intro, outro, text, confirm, spinner, note, log } from "@clack/prompts";
import { isValidCoreRepo } from "../utils/git.js";
import { fileExists, updateEnvFile } from "../utils/file.js";
-import { checkPostgresHealth, executeDockerCommand } from "../utils/docker.js";
+import { checkPostgresHealth } from "../utils/docker.js";
+import { executeDockerCommandInteractive } from "../utils/docker-interactive.js";
import { printCoreBrainLogo } from "../utils/ascii.js";
import { setupEnvFile } from "../utils/env.js";
-import { execSync } from "child_process";
+import { hasTriggerConfig } from "../utils/env-checker.js";
import path from "path";
export async function initCommand() {
@@ -15,10 +16,40 @@ export async function initCommand() {
// Step 1: Validate repository
if (!isValidCoreRepo()) {
- outro(
- "L Error: This command must be run in the https://github.com/redplanethq/core repository"
+ log.warning("This directory is not a Core repository");
+ note(
+ "The Core repository is required to run the development environment.\nWould you like to clone it in the current directory?",
+ "š Repository Not Found"
);
- process.exit(1);
+
+ const shouldClone = await confirm({
+ message: "Clone the Core repository here?",
+ });
+
+ if (!shouldClone) {
+ outro("ā Setup cancelled. Please navigate to the Core repository or clone it first.");
+ process.exit(1);
+ }
+
+ // Clone the repository
+ try {
+ await executeDockerCommandInteractive("git clone https://github.com/redplanethq/core.git .", {
+ cwd: process.cwd(),
+ message: "Cloning Core repository...",
+ showOutput: true,
+ });
+
+ log.success("Core repository cloned successfully!");
+ note(
+ 'Please run "core init" again to initialize the development environment.',
+ "ā
Repository Ready"
+ );
+ outro("š Core repository is now available!");
+ process.exit(0);
+ } catch (error: any) {
+ outro(`ā Failed to clone repository: ${error.message}`);
+ process.exit(1);
+ }
}
const rootDir = process.cwd();
@@ -45,14 +76,13 @@ export async function initCommand() {
}
// Step 3: Docker compose up -d in root
- const s2 = spinner();
- s2.start("Starting Docker containers in root...");
-
try {
- await executeDockerCommand("docker compose up -d", rootDir);
- s2.stop("Docker containers started");
+ await executeDockerCommandInteractive("docker compose up -d", {
+ cwd: rootDir,
+ message: "Starting Docker containers in root...",
+ showOutput: true,
+ });
} catch (error: any) {
- s2.stop("L Failed to start Docker containers");
throw error;
}
@@ -98,93 +128,118 @@ export async function initCommand() {
}
// Step 6: Docker compose up for trigger
- const s5 = spinner();
- s5.start("Starting Trigger.dev containers...");
-
try {
- await executeDockerCommand("docker compose up -d", triggerDir);
- s5.stop("Trigger.dev containers started");
+ await executeDockerCommandInteractive("docker compose up -d", {
+ cwd: triggerDir,
+ message: "Starting Trigger.dev containers...",
+ showOutput: true,
+ });
} catch (error: any) {
- s5.stop("L Failed to start Trigger.dev containers");
throw error;
}
- // Step 7: Show login instructions
- outro("< Docker containers are now running!");
- console.log("\n= Next steps:");
- console.log("1. Open http://localhost:8030 in your browser");
- console.log(
- "2. Login to Trigger.dev (check container logs with: docker logs trigger-webapp --tail 50)"
- );
- console.log("3. Press Enter when ready to continue...");
+ // Step 7: Check if Trigger.dev configuration already exists
+ const triggerConfigExists = await hasTriggerConfig(envPath);
- await confirm({
- message: "Have you logged in to Trigger.dev and ready to continue?",
- });
+ if (triggerConfigExists) {
+ note(
+ "ā
Trigger.dev configuration already exists in .env file\n Skipping Trigger.dev setup steps...",
+ "Configuration Found"
+ );
+ } else {
+ // Step 8: Show login instructions
+ outro("š Docker containers are now running!");
+ note(
+ "1. Open http://localhost:8030 in your browser\n2. Login to Trigger.dev (check container logs with: docker logs trigger-webapp --tail 50)",
+ "Next Steps"
+ );
- // Step 8: Get project details
- console.log("\n= In Trigger.dev (http://localhost:8030):");
- console.log("1. Create a new organization and project");
- console.log("2. Go to project settings");
- console.log("3. Copy the Project ID and Secret Key");
+ const loginConfirmed = await confirm({
+ message: "Have you logged in to Trigger.dev successfully?",
+ });
- await confirm({
- message: "Press Enter to continue after creating org and project...",
- });
+ if (!loginConfirmed) {
+ outro("ā Setup cancelled. Please login to Trigger.dev first and run the command again.");
+ process.exit(1);
+ }
- // Step 9: Get project ID and secret
- const projectId = await text({
- message: "Enter your Trigger.dev Project ID:",
- validate: (value) => {
- if (!value || value.length === 0) {
- return "Project ID is required";
- }
- return;
- },
- });
+ // Step 9: Get project details
+ note(
+ "1. Create a new organization and project\n2. Go to project settings\n3. Copy the Project ID and Secret Key",
+ "In Trigger.dev (http://localhost:8030)"
+ );
- const secretKey = await text({
- message: "Enter your Trigger.dev Secret Key for production:",
- validate: (value) => {
- if (!value || value.length === 0) {
- return "Secret Key is required";
- }
- return;
- },
- });
+ const projectCreated = await confirm({
+ message: "Have you created an organization and project in Trigger.dev?",
+ });
- // Step 10: Update .env with project details
- const s6 = spinner();
- s6.start("Updating .env with Trigger.dev configuration...");
+ if (!projectCreated) {
+ outro(
+ "ā Setup cancelled. Please create an organization and project first and run the command again."
+ );
+ process.exit(1);
+ }
- try {
- await updateEnvFile(envPath, "TRIGGER_PROJECT_ID", projectId as string);
- await updateEnvFile(envPath, "TRIGGER_SECRET_KEY", secretKey as string);
- s6.stop("Updated .env with Trigger.dev configuration");
- } catch (error: any) {
- s6.stop("L Failed to update .env file");
- throw error;
+ // Step 10: Get project ID and secret
+ const projectId = await text({
+ message: "Enter your Trigger.dev Project ID:",
+ validate: (value) => {
+ if (!value || value.length === 0) {
+ return "Project ID is required";
+ }
+ return;
+ },
+ });
+
+ const secretKey = await text({
+ message: "Enter your Trigger.dev Secret Key for production:",
+ validate: (value) => {
+ if (!value || value.length === 0) {
+ return "Secret Key is required";
+ }
+ return;
+ },
+ });
+
+ // Step 11: Update .env with project details
+ const s6 = spinner();
+ s6.start("Updating .env with Trigger.dev configuration...");
+
+ try {
+ await updateEnvFile(envPath, "TRIGGER_PROJECT_ID", projectId as string);
+ await updateEnvFile(envPath, "TRIGGER_SECRET_KEY", secretKey as string);
+ s6.stop("ā
Updated .env with Trigger.dev configuration");
+ } catch (error: any) {
+ s6.stop("ā Failed to update .env file");
+ throw error;
+ }
+
+ // Step 12: Restart root docker-compose with new configuration
+ try {
+ await executeDockerCommandInteractive("docker compose down", {
+ cwd: rootDir,
+ message: "Stopping Core services...",
+ showOutput: true,
+ });
+
+ await executeDockerCommandInteractive("docker compose up -d", {
+ cwd: rootDir,
+ message: "Starting Core services with new Trigger.dev configuration...",
+ showOutput: true,
+ });
+ } catch (error: any) {
+ throw error;
+ }
}
- // Step 11: Restart docker-compose in root
- const s7 = spinner();
- s7.start("Restarting Docker containers with new configuration...");
-
- try {
- await executeDockerCommand("docker compose down && docker compose up -d", rootDir);
- s7.stop("Docker containers restarted");
- } catch (error: any) {
- s7.stop("L Failed to restart Docker containers");
- throw error;
- }
-
- // Step 12: Show docker login instructions
- console.log("\n=3 Docker Registry Login:");
- console.log("Run the following command to login to Docker registry:");
+ // Step 13: Show docker login instructions
+ note("Run the following command to login to Docker registry:", "š³ Docker Registry Login");
try {
// Read env file to get docker registry details
- const envContent = await import("fs").then((fs) => fs.promises.readFile(envPath, "utf8"));
+ const envContent = await import("fs").then((fs) =>
+ fs.promises.readFile(triggerEnvPath, "utf8")
+ );
const envLines = envContent.split("\n");
const getEnvValue = (key: string) => {
@@ -196,26 +251,74 @@ export async function initCommand() {
const dockerRegistryUsername = getEnvValue("DOCKER_REGISTRY_USERNAME");
const dockerRegistryPassword = getEnvValue("DOCKER_REGISTRY_PASSWORD");
- console.log(
- `\ndocker login ${dockerRegistryUrl} -u ${dockerRegistryUsername} -p ${dockerRegistryPassword}`
+ log.info(
+ `docker login ${dockerRegistryUrl} -u ${dockerRegistryUsername} -p ${dockerRegistryPassword}`
);
} catch (error) {
- console.log("docker login