mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-27 19:28:29 +00:00
Feat: cli for init, start and stop
This commit is contained in:
parent
f026f09fea
commit
502b26882e
@ -83,9 +83,9 @@ export function LogTextCollapse({
|
|||||||
isLong ? "max-h-16 overflow-hidden" : "",
|
isLong ? "max-h-16 overflow-hidden" : "",
|
||||||
)}
|
)}
|
||||||
style={{ lineHeight: "1.5" }}
|
style={{ lineHeight: "1.5" }}
|
||||||
>
|
dangerouslySetInnerHTML={{ __html: text }}
|
||||||
{displayText}
|
/>
|
||||||
</p>
|
|
||||||
{isLong && (
|
{isLong && (
|
||||||
<>
|
<>
|
||||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||||
|
|||||||
@ -58,44 +58,52 @@ export default function LogsActivity() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<div className="flex h-[calc(100vh_-_56px)] flex-col space-y-6 p-4 px-5">
|
<div className="flex h-[calc(100vh_-_56px)] flex-col space-y-6 p-4 px-5">
|
||||||
{logs.length > 0 && (
|
{isInitialLoad ? (
|
||||||
<LogsFilters
|
<>
|
||||||
availableSources={availableSources}
|
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />{" "}
|
||||||
selectedSource={selectedSource}
|
</>
|
||||||
selectedStatus={selectedStatus}
|
) : (
|
||||||
onSourceChange={setSelectedSource}
|
<>
|
||||||
onStatusChange={setSelectedStatus}
|
{logs.length > 0 && (
|
||||||
/>
|
<LogsFilters
|
||||||
)}
|
availableSources={availableSources}
|
||||||
|
selectedSource={selectedSource}
|
||||||
|
selectedStatus={selectedStatus}
|
||||||
|
onSourceChange={setSelectedSource}
|
||||||
|
onStatusChange={setSelectedStatus}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Logs List */}
|
{/* Logs List */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{logs.length === 0 ? (
|
{logs.length === 0 ? (
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="bg-background-2 flex items-center justify-center py-16">
|
<CardContent className="bg-background-2 flex items-center justify-center py-16">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Activity className="text-muted-foreground mx-auto mb-4 h-12 w-12" />
|
<Activity className="text-muted-foreground mx-auto mb-4 h-12 w-12" />
|
||||||
<h3 className="mb-2 text-lg font-semibold">
|
<h3 className="mb-2 text-lg font-semibold">
|
||||||
No activity logs found
|
No activity logs found
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
{selectedSource || selectedStatus
|
{selectedSource || selectedStatus
|
||||||
? "Try adjusting your filters to see more results."
|
? "Try adjusting your filters to see more results."
|
||||||
: "No activity ingestion logs are available yet."}
|
: "No activity ingestion logs are available yet."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
<VirtualLogsList
|
<VirtualLogsList
|
||||||
logs={logs}
|
logs={logs}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
height={600}
|
height={600}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -26,18 +26,6 @@ export default function LogsAll() {
|
|||||||
status: selectedStatus,
|
status: selectedStatus,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isInitialLoad) {
|
|
||||||
return (
|
|
||||||
<AppContainer>
|
|
||||||
<PageContainer>
|
|
||||||
<div className="flex h-[calc(100vh_-_16px)] items-center justify-center">
|
|
||||||
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />
|
|
||||||
</div>
|
|
||||||
</PageContainer>
|
|
||||||
</AppContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
@ -58,43 +46,53 @@ export default function LogsAll() {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<div className="h-[calc(100vh_-_56px)] space-y-6 p-4 px-5">
|
<div className="h-[calc(100vh_-_56px)] space-y-6 p-4 px-5">
|
||||||
{/* Filters */}
|
{isInitialLoad ? (
|
||||||
{logs.length > 0 && (
|
<>
|
||||||
<LogsFilters
|
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />{" "}
|
||||||
availableSources={availableSources}
|
</>
|
||||||
selectedSource={selectedSource}
|
) : (
|
||||||
selectedStatus={selectedStatus}
|
<>
|
||||||
onSourceChange={setSelectedSource}
|
{" "}
|
||||||
onStatusChange={setSelectedStatus}
|
{/* Filters */}
|
||||||
/>
|
{logs.length > 0 && (
|
||||||
|
<LogsFilters
|
||||||
|
availableSources={availableSources}
|
||||||
|
selectedSource={selectedSource}
|
||||||
|
selectedStatus={selectedStatus}
|
||||||
|
onSourceChange={setSelectedSource}
|
||||||
|
onStatusChange={setSelectedStatus}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Logs List */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
{logs.length === 0 ? (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="bg-background-2 flex items-center justify-center py-16">
|
||||||
|
<div className="text-center">
|
||||||
|
<Database className="text-muted-foreground mx-auto mb-4 h-12 w-12" />
|
||||||
|
<h3 className="mb-2 text-lg font-semibold">
|
||||||
|
No logs found
|
||||||
|
</h3>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
{selectedSource || selectedStatus
|
||||||
|
? "Try adjusting your filters to see more results."
|
||||||
|
: "No ingestion logs are available yet."}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<VirtualLogsList
|
||||||
|
logs={logs}
|
||||||
|
hasMore={hasMore}
|
||||||
|
loadMore={loadMore}
|
||||||
|
isLoading={isLoading}
|
||||||
|
height={600}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Logs List */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
{logs.length === 0 ? (
|
|
||||||
<Card>
|
|
||||||
<CardContent className="bg-background-2 flex items-center justify-center py-16">
|
|
||||||
<div className="text-center">
|
|
||||||
<Database className="text-muted-foreground mx-auto mb-4 h-12 w-12" />
|
|
||||||
<h3 className="mb-2 text-lg font-semibold">No logs found</h3>
|
|
||||||
<p className="text-muted-foreground">
|
|
||||||
{selectedSource || selectedStatus
|
|
||||||
? "Try adjusting your filters to see more results."
|
|
||||||
: "No ingestion logs are available yet."}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
) : (
|
|
||||||
<VirtualLogsList
|
|
||||||
logs={logs}
|
|
||||||
hasMore={hasMore}
|
|
||||||
loadMore={loadMore}
|
|
||||||
isLoading={isLoading}
|
|
||||||
height={600}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
193
packages/core-cli/README.md
Normal file
193
packages/core-cli/README.md
Normal file
@ -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!** 🎉
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@redplanethq/core",
|
"name": "@redplanethq/core",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"description": "A Command-Line Interface for Core",
|
"description": "A Command-Line Interface for Core",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@ -1,10 +1,25 @@
|
|||||||
import { Command } from "commander";
|
import { Command } from "commander";
|
||||||
import { initCommand } from "../commands/init.js";
|
import { initCommand } from "../commands/init.js";
|
||||||
|
import { startCommand } from "../commands/start.js";
|
||||||
|
import { stopCommand } from "../commands/stop.js";
|
||||||
|
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
|
|
||||||
program.name("core").description("Core CLI - A Command-Line Interface for Core").version("0.1.0");
|
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);
|
program.parse(process.argv);
|
||||||
|
|||||||
@ -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 { isValidCoreRepo } from "../utils/git.js";
|
||||||
import { fileExists, updateEnvFile } from "../utils/file.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 { printCoreBrainLogo } from "../utils/ascii.js";
|
||||||
import { setupEnvFile } from "../utils/env.js";
|
import { setupEnvFile } from "../utils/env.js";
|
||||||
import { execSync } from "child_process";
|
import { hasTriggerConfig } from "../utils/env-checker.js";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
export async function initCommand() {
|
export async function initCommand() {
|
||||||
@ -15,10 +16,40 @@ export async function initCommand() {
|
|||||||
|
|
||||||
// Step 1: Validate repository
|
// Step 1: Validate repository
|
||||||
if (!isValidCoreRepo()) {
|
if (!isValidCoreRepo()) {
|
||||||
outro(
|
log.warning("This directory is not a Core repository");
|
||||||
"L Error: This command must be run in the https://github.com/redplanethq/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();
|
const rootDir = process.cwd();
|
||||||
@ -45,14 +76,13 @@ export async function initCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Docker compose up -d in root
|
// Step 3: Docker compose up -d in root
|
||||||
const s2 = spinner();
|
|
||||||
s2.start("Starting Docker containers in root...");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await executeDockerCommand("docker compose up -d", rootDir);
|
await executeDockerCommandInteractive("docker compose up -d", {
|
||||||
s2.stop("Docker containers started");
|
cwd: rootDir,
|
||||||
|
message: "Starting Docker containers in root...",
|
||||||
|
showOutput: true,
|
||||||
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
s2.stop("L Failed to start Docker containers");
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,93 +128,118 @@ export async function initCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: Docker compose up for trigger
|
// Step 6: Docker compose up for trigger
|
||||||
const s5 = spinner();
|
|
||||||
s5.start("Starting Trigger.dev containers...");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await executeDockerCommand("docker compose up -d", triggerDir);
|
await executeDockerCommandInteractive("docker compose up -d", {
|
||||||
s5.stop("Trigger.dev containers started");
|
cwd: triggerDir,
|
||||||
|
message: "Starting Trigger.dev containers...",
|
||||||
|
showOutput: true,
|
||||||
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
s5.stop("L Failed to start Trigger.dev containers");
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7: Show login instructions
|
// Step 7: Check if Trigger.dev configuration already exists
|
||||||
outro("< Docker containers are now running!");
|
const triggerConfigExists = await hasTriggerConfig(envPath);
|
||||||
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...");
|
|
||||||
|
|
||||||
await confirm({
|
if (triggerConfigExists) {
|
||||||
message: "Have you logged in to Trigger.dev and ready to continue?",
|
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
|
const loginConfirmed = await confirm({
|
||||||
console.log("\n= In Trigger.dev (http://localhost:8030):");
|
message: "Have you logged in to Trigger.dev successfully?",
|
||||||
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");
|
|
||||||
|
|
||||||
await confirm({
|
if (!loginConfirmed) {
|
||||||
message: "Press Enter to continue after creating org and project...",
|
outro("❌ Setup cancelled. Please login to Trigger.dev first and run the command again.");
|
||||||
});
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 9: Get project ID and secret
|
// Step 9: Get project details
|
||||||
const projectId = await text({
|
note(
|
||||||
message: "Enter your Trigger.dev Project ID:",
|
"1. Create a new organization and project\n2. Go to project settings\n3. Copy the Project ID and Secret Key",
|
||||||
validate: (value) => {
|
"In Trigger.dev (http://localhost:8030)"
|
||||||
if (!value || value.length === 0) {
|
);
|
||||||
return "Project ID is required";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const secretKey = await text({
|
const projectCreated = await confirm({
|
||||||
message: "Enter your Trigger.dev Secret Key for production:",
|
message: "Have you created an organization and project in Trigger.dev?",
|
||||||
validate: (value) => {
|
});
|
||||||
if (!value || value.length === 0) {
|
|
||||||
return "Secret Key is required";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Step 10: Update .env with project details
|
if (!projectCreated) {
|
||||||
const s6 = spinner();
|
outro(
|
||||||
s6.start("Updating .env with Trigger.dev configuration...");
|
"❌ Setup cancelled. Please create an organization and project first and run the command again."
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
// Step 10: Get project ID and secret
|
||||||
await updateEnvFile(envPath, "TRIGGER_PROJECT_ID", projectId as string);
|
const projectId = await text({
|
||||||
await updateEnvFile(envPath, "TRIGGER_SECRET_KEY", secretKey as string);
|
message: "Enter your Trigger.dev Project ID:",
|
||||||
s6.stop("Updated .env with Trigger.dev configuration");
|
validate: (value) => {
|
||||||
} catch (error: any) {
|
if (!value || value.length === 0) {
|
||||||
s6.stop("L Failed to update .env file");
|
return "Project ID is required";
|
||||||
throw error;
|
}
|
||||||
|
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
|
// Step 13: Show docker login instructions
|
||||||
const s7 = spinner();
|
note("Run the following command to login to Docker registry:", "🐳 Docker Registry Login");
|
||||||
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:");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Read env file to get docker registry details
|
// 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 envLines = envContent.split("\n");
|
||||||
|
|
||||||
const getEnvValue = (key: string) => {
|
const getEnvValue = (key: string) => {
|
||||||
@ -196,26 +251,74 @@ export async function initCommand() {
|
|||||||
const dockerRegistryUsername = getEnvValue("DOCKER_REGISTRY_USERNAME");
|
const dockerRegistryUsername = getEnvValue("DOCKER_REGISTRY_USERNAME");
|
||||||
const dockerRegistryPassword = getEnvValue("DOCKER_REGISTRY_PASSWORD");
|
const dockerRegistryPassword = getEnvValue("DOCKER_REGISTRY_PASSWORD");
|
||||||
|
|
||||||
console.log(
|
log.info(
|
||||||
`\ndocker login ${dockerRegistryUrl} -u ${dockerRegistryUsername} -p ${dockerRegistryPassword}`
|
`docker login ${dockerRegistryUrl} -u ${dockerRegistryUsername} -p ${dockerRegistryPassword}`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("docker login <REGISTRY_URL> -u <USERNAME> -p <PASSWORD>");
|
log.info("docker login <REGISTRY_URL> -u <USERNAME> -p <PASSWORD>");
|
||||||
}
|
}
|
||||||
|
|
||||||
await confirm({
|
const dockerLoginConfirmed = await confirm({
|
||||||
message: "Press Enter after completing Docker login...",
|
message: "Have you completed the Docker login successfully?",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 13: Final instructions
|
if (!dockerLoginConfirmed) {
|
||||||
outro("< Setup Complete!");
|
outro("❌ Setup cancelled. Please complete Docker login first and run the command again.");
|
||||||
console.log("\n< Your services are now running:");
|
process.exit(1);
|
||||||
console.log('" Core Application: http://localhost:3033');
|
}
|
||||||
console.log('" Trigger.dev: http://localhost:8030');
|
|
||||||
console.log('" PostgreSQL: localhost:5432');
|
// Step 14: Deploy Trigger.dev tasks
|
||||||
console.log("\n( You can now start developing with Core!");
|
note(
|
||||||
|
"We'll now deploy the trigger tasks to your Trigger.dev instance.",
|
||||||
|
"🚀 Deploying Trigger.dev tasks"
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Login to trigger.dev CLI
|
||||||
|
await executeDockerCommandInteractive(
|
||||||
|
"npx -y trigger.dev@v4-beta login -a http://localhost:8030",
|
||||||
|
{
|
||||||
|
cwd: rootDir,
|
||||||
|
message: "Logging in to Trigger.dev CLI...",
|
||||||
|
showOutput: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy trigger tasks
|
||||||
|
await executeDockerCommandInteractive("pnpm trigger:deploy", {
|
||||||
|
cwd: rootDir,
|
||||||
|
message: "Deploying Trigger.dev tasks...",
|
||||||
|
showOutput: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
log.success("Trigger.dev tasks deployed successfully!");
|
||||||
|
} catch (error: any) {
|
||||||
|
log.warning("Failed to deploy Trigger.dev tasks:");
|
||||||
|
note(
|
||||||
|
`${error.message}\n\nYou can deploy them manually later with:\n1. npx trigger.dev@v4-beta login -a http://localhost:8030\n2. pnpm trigger:deploy`,
|
||||||
|
"Manual Deployment"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 15: Final instructions
|
||||||
|
outro("🎉 Setup Complete!");
|
||||||
|
note(
|
||||||
|
[
|
||||||
|
"Your services are now running:",
|
||||||
|
"",
|
||||||
|
"• Core Application: http://localhost:3033",
|
||||||
|
"• Trigger.dev: http://localhost:8030",
|
||||||
|
"• PostgreSQL: localhost:5432",
|
||||||
|
"",
|
||||||
|
"You can now start developing with Core!",
|
||||||
|
"",
|
||||||
|
"ℹ️ When logging in to the Core Application, you can find the login URL in the Docker container logs:",
|
||||||
|
" docker logs core-app --tail 50",
|
||||||
|
].join("\n"),
|
||||||
|
"🚀 Services Running"
|
||||||
|
);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
outro(`L Setup failed: ${error.message}`);
|
outro(`❌ Setup failed: ${error.message}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
packages/core-cli/src/commands/start.ts
Normal file
72
packages/core-cli/src/commands/start.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { intro, outro, note, log, confirm } from '@clack/prompts';
|
||||||
|
import { isValidCoreRepo } from '../utils/git.js';
|
||||||
|
import { executeDockerCommandInteractive } from '../utils/docker-interactive.js';
|
||||||
|
import { printCoreBrainLogo } from '../utils/ascii.js';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export async function startCommand() {
|
||||||
|
// Display the CORE brain logo
|
||||||
|
printCoreBrainLogo();
|
||||||
|
|
||||||
|
intro('🚀 Starting Core Development Environment');
|
||||||
|
|
||||||
|
// Step 1: Validate repository
|
||||||
|
if (!isValidCoreRepo()) {
|
||||||
|
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');
|
||||||
|
|
||||||
|
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('You can now run "core start" to start 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();
|
||||||
|
const triggerDir = path.join(rootDir, 'trigger');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Start main services
|
||||||
|
await executeDockerCommandInteractive('docker compose up -d', {
|
||||||
|
cwd: rootDir,
|
||||||
|
message: 'Starting Core services...',
|
||||||
|
showOutput: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start trigger services
|
||||||
|
await executeDockerCommandInteractive('docker compose up -d', {
|
||||||
|
cwd: triggerDir,
|
||||||
|
message: 'Starting Trigger.dev services...',
|
||||||
|
showOutput: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Final success message
|
||||||
|
outro('🎉 Core Development Environment Started!');
|
||||||
|
note('• Core Application: http://localhost:3033\n• Trigger.dev: http://localhost:8030\n• PostgreSQL: localhost:5432', '🌐 Your services are now running');
|
||||||
|
log.success('Happy coding!');
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
outro(`❌ Failed to start services: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
packages/core-cli/src/commands/stop.ts
Normal file
72
packages/core-cli/src/commands/stop.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { intro, outro, log, confirm, note } from '@clack/prompts';
|
||||||
|
import { isValidCoreRepo } from '../utils/git.js';
|
||||||
|
import { executeDockerCommandInteractive } from '../utils/docker-interactive.js';
|
||||||
|
import { printCoreBrainLogo } from '../utils/ascii.js';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export async function stopCommand() {
|
||||||
|
// Display the CORE brain logo
|
||||||
|
printCoreBrainLogo();
|
||||||
|
|
||||||
|
intro('🛑 Stopping Core Development Environment');
|
||||||
|
|
||||||
|
// Step 1: Validate repository
|
||||||
|
if (!isValidCoreRepo()) {
|
||||||
|
log.warning('This directory is not a Core repository');
|
||||||
|
note('The Core repository is required to stop the development environment.\nWould you like to clone it in the current directory?', '🔍 Repository Not Found');
|
||||||
|
|
||||||
|
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('You can now run "core stop" to stop 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();
|
||||||
|
const triggerDir = path.join(rootDir, 'trigger');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Stop trigger services first
|
||||||
|
await executeDockerCommandInteractive('docker compose down', {
|
||||||
|
cwd: triggerDir,
|
||||||
|
message: 'Stopping Trigger.dev services...',
|
||||||
|
showOutput: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stop main services
|
||||||
|
await executeDockerCommandInteractive('docker compose down', {
|
||||||
|
cwd: rootDir,
|
||||||
|
message: 'Stopping Core services...',
|
||||||
|
showOutput: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Final success message
|
||||||
|
outro('🎉 Core Development Environment Stopped!');
|
||||||
|
log.success('All services have been stopped.');
|
||||||
|
log.info('Run "core start" to start services again.');
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
outro(`❌ Failed to stop services: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
108
packages/core-cli/src/utils/docker-interactive.ts
Normal file
108
packages/core-cli/src/utils/docker-interactive.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { spawn, ChildProcess } from 'child_process';
|
||||||
|
import { spinner } from '@clack/prompts';
|
||||||
|
|
||||||
|
export interface DockerCommandOptions {
|
||||||
|
cwd: string;
|
||||||
|
message: string;
|
||||||
|
showOutput?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function executeDockerCommandInteractive(
|
||||||
|
command: string,
|
||||||
|
options: DockerCommandOptions
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const s = spinner();
|
||||||
|
s.start(options.message);
|
||||||
|
|
||||||
|
// Split command into parts
|
||||||
|
const parts = command.split(' ');
|
||||||
|
const cmd = parts[0];
|
||||||
|
const args = parts.slice(1);
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
reject(new Error('Invalid command'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const child: ChildProcess = spawn(cmd, args, {
|
||||||
|
cwd: options.cwd,
|
||||||
|
stdio: options.showOutput ? ['ignore', 'pipe', 'pipe'] : 'ignore',
|
||||||
|
detached: false
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
// Handle stdout
|
||||||
|
if (child.stdout && options.showOutput) {
|
||||||
|
child.stdout.on('data', (data: Buffer) => {
|
||||||
|
const text = data.toString();
|
||||||
|
output += text;
|
||||||
|
|
||||||
|
// Update spinner with latest output line
|
||||||
|
const lines = text.trim().split('\n');
|
||||||
|
const lastLine = lines[lines.length - 1];
|
||||||
|
if (lastLine && lastLine.trim()) {
|
||||||
|
s.message(`${options.message}\n${lastLine.trim()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle stderr
|
||||||
|
if (child.stderr && options.showOutput) {
|
||||||
|
child.stderr.on('data', (data: Buffer) => {
|
||||||
|
const text = data.toString();
|
||||||
|
output += text;
|
||||||
|
|
||||||
|
// Update spinner with error output
|
||||||
|
const lines = text.trim().split('\n');
|
||||||
|
const lastLine = lines[lines.length - 1];
|
||||||
|
if (lastLine && lastLine.trim()) {
|
||||||
|
s.message(`${options.message}\n❌ ${lastLine.trim()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle process exit
|
||||||
|
child.on('exit', (code: number | null) => {
|
||||||
|
if (code === 0) {
|
||||||
|
s.stop(`✅ ${options.message.replace(/\.\.\.$/, '')} completed`);
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
s.stop(`❌ ${options.message.replace(/\.\.\.$/, '')} failed (exit code: ${code})`);
|
||||||
|
if (options.showOutput && output) {
|
||||||
|
console.log('\nOutput:');
|
||||||
|
console.log(output);
|
||||||
|
}
|
||||||
|
reject(new Error(`Command failed with exit code ${code}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
child.on('error', (error: Error) => {
|
||||||
|
s.stop(`❌ ${options.message.replace(/\.\.\.$/, '')} failed`);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Ctrl+C
|
||||||
|
const handleSigint = () => {
|
||||||
|
s.stop(`⏹️ ${options.message.replace(/\.\.\.$/, '')} interrupted`);
|
||||||
|
child.kill('SIGTERM');
|
||||||
|
|
||||||
|
// Give the process time to clean up
|
||||||
|
setTimeout(() => {
|
||||||
|
if (child.killed === false) {
|
||||||
|
child.kill('SIGKILL');
|
||||||
|
}
|
||||||
|
process.exit(130); // Standard exit code for SIGINT
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on('SIGINT', handleSigint);
|
||||||
|
|
||||||
|
// Clean up event listener when done
|
||||||
|
child.on('exit', () => {
|
||||||
|
process.off('SIGINT', handleSigint);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
23
packages/core-cli/src/utils/env-checker.ts
Normal file
23
packages/core-cli/src/utils/env-checker.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import fs from 'fs/promises';
|
||||||
|
|
||||||
|
export async function checkEnvValue(filePath: string, key: string): Promise<string | null> {
|
||||||
|
try {
|
||||||
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
|
const lines = content.split('\n');
|
||||||
|
const line = lines.find(l => l.startsWith(`${key}=`));
|
||||||
|
if (line) {
|
||||||
|
const value = line.split('=')[1]?.trim();
|
||||||
|
return value && value.length > 0 ? value : null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hasTriggerConfig(envPath: string): Promise<boolean> {
|
||||||
|
const projectId = await checkEnvValue(envPath, 'TRIGGER_PROJECT_ID');
|
||||||
|
const secretKey = await checkEnvValue(envPath, 'TRIGGER_SECRET_KEY');
|
||||||
|
|
||||||
|
return !!(projectId && secretKey);
|
||||||
|
}
|
||||||
@ -47,7 +47,7 @@ services:
|
|||||||
MAGIC_LINK_SECRET: ${MAGIC_LINK_SECRET}
|
MAGIC_LINK_SECRET: ${MAGIC_LINK_SECRET}
|
||||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||||
MANAGED_WORKER_SECRET: ${MANAGED_WORKER_SECRET}
|
MANAGED_WORKER_SECRET: ${MANAGED_WORKER_SECRET}
|
||||||
REDIS_HOST: trigger-redis
|
REDIS_HOST: host.docker.internal
|
||||||
REDIS_PORT: 6379
|
REDIS_PORT: 6379
|
||||||
REDIS_TLS_DISABLED: true
|
REDIS_TLS_DISABLED: true
|
||||||
APP_LOG_LEVEL: info
|
APP_LOG_LEVEL: info
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user