mirror of
https://github.com/coder/registry.git
synced 2026-06-03 13:08:14 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60372ff797 | |||
| f28bcdb713 | |||
| cb553209a5 |
@@ -13,7 +13,7 @@ Run [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-c
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
}
|
||||
@@ -51,7 +51,7 @@ data "coder_parameter" "ai_prompt" {
|
||||
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
|
||||
@@ -71,7 +71,7 @@ Customize tool permissions, MCP servers, and Copilot settings:
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
|
||||
@@ -142,7 +142,7 @@ variable "github_token" {
|
||||
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder/projects"
|
||||
github_token = var.github_token
|
||||
@@ -156,7 +156,7 @@ Run Copilot as a command-line tool without task reporting or web interface. This
|
||||
```tf
|
||||
module "copilot" {
|
||||
source = "registry.coder.com/coder-labs/copilot/coder"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
agent_id = coder_agent.example.id
|
||||
workdir = "/home/coder"
|
||||
report_tasks = false
|
||||
|
||||
@@ -253,6 +253,7 @@ module "agentapi" {
|
||||
web_app_display_name = var.web_app_display_name
|
||||
cli_app = var.cli_app
|
||||
cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
|
||||
cli_app_icon = var.cli_app ? var.icon : null
|
||||
cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
|
||||
agentapi_subdomain = var.subdomain
|
||||
module_dir_name = local.module_dir_name
|
||||
|
||||
@@ -14,7 +14,7 @@ This module allows you to automatically clone a repository by URL and skip if it
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.com/coder/coder"
|
||||
}
|
||||
@@ -28,7 +28,7 @@ module "git-clone" {
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.com/coder/coder"
|
||||
base_dir = "~/projects/coder"
|
||||
@@ -43,12 +43,12 @@ To use with [Git Authentication](https://coder.com/docs/v2/latest/admin/git-prov
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.com/coder/coder"
|
||||
}
|
||||
|
||||
data "coder_git_auth" "github" {
|
||||
data "coder_external_auth" "github" {
|
||||
id = "github"
|
||||
}
|
||||
```
|
||||
@@ -69,7 +69,7 @@ data "coder_parameter" "git_repo" {
|
||||
module "git_clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = data.coder_parameter.git_repo.value
|
||||
}
|
||||
@@ -103,7 +103,7 @@ Configuring `git-clone` for a self-hosted GitHub Enterprise Server running at `g
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.example.com/coder/coder/tree/feat/example"
|
||||
git_providers = {
|
||||
@@ -122,7 +122,7 @@ To GitLab clone with a specific branch like `feat/example`
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://gitlab.com/coder/coder/-/tree/feat/example"
|
||||
}
|
||||
@@ -134,7 +134,7 @@ Configuring `git-clone` for a self-hosted GitLab running at `gitlab.example.com`
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://gitlab.example.com/coder/coder/-/tree/feat/example"
|
||||
git_providers = {
|
||||
@@ -155,7 +155,7 @@ For example, to clone the `feat/example` branch:
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.com/coder/coder"
|
||||
branch_name = "feat/example"
|
||||
@@ -173,7 +173,7 @@ For example, this will clone into the `~/projects/coder/coder-dev` folder:
|
||||
module "git-clone" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/git-clone/coder"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
agent_id = coder_agent.example.id
|
||||
url = "https://github.com/coder/coder"
|
||||
folder_name = "coder-dev"
|
||||
|
||||
@@ -19,3 +19,4 @@ participating in LFX CNCF programs, and helping the developer community grow.
|
||||
## Modules
|
||||
|
||||
- **aws-ami-snapshot**: Create and manage AMI snapshots for Coder workspaces with restore capabilities
|
||||
- [auto-start-dev-server](modules/auto-start-dev-server/README.md) - Automatically detect and start development servers for various project types
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
display_name: Auto-Start Development Servers
|
||||
description: Automatically detect and start development servers for various project types
|
||||
icon: ../../../../.icons/server.svg
|
||||
verified: false
|
||||
tags: [development, automation, servers]
|
||||
---
|
||||
|
||||
# Auto-Start Development Servers
|
||||
|
||||
Automatically detect and start development servers for various project types when a workspace starts. This module scans your workspace for common project structures and starts the appropriate development servers in the background without manual intervention.
|
||||
|
||||
```tf
|
||||
module "auto_start_dev_servers" {
|
||||
source = "registry.coder.com/mavrickrishi/auto-start-dev-server/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-language support**: Detects and starts servers for Node.js, Python (Django/Flask), Ruby (Rails), Java (Spring Boot), Go, PHP, Rust, and .NET projects
|
||||
- **Smart script prioritization**: Prioritizes `dev` scripts over `start` scripts for better development experience
|
||||
- **Intelligent frontend detection**: Automatically identifies frontend projects (React, Vue, Angular, Next.js, Nuxt, Svelte, Vite) and prioritizes them for preview apps
|
||||
- **Devcontainer integration**: Respects custom start commands defined in `.devcontainer/devcontainer.json`
|
||||
- **Configurable scanning**: Adjustable directory scan depth and project type toggles
|
||||
- **Non-blocking startup**: Servers start in the background with configurable startup delay
|
||||
- **Comprehensive logging**: All server output and detection results logged to a central file
|
||||
- **Smart detection**: Uses project-specific files and configurations to identify project types
|
||||
- **Integrated live preview**: Automatically creates a preview app for the primary frontend project
|
||||
|
||||
## Supported Project Types
|
||||
|
||||
| Framework/Language | Detection Files | Start Commands (in priority order) |
|
||||
| ------------------ | -------------------------------------------- | ----------------------------------------------------- |
|
||||
| **Node.js/npm** | `package.json` | `npm run dev`, `npm run serve`, `npm start` (or yarn) |
|
||||
| **Ruby on Rails** | `Gemfile` with rails gem | `bundle exec rails server` |
|
||||
| **Django** | `manage.py` | `python manage.py runserver` |
|
||||
| **Flask** | `requirements.txt` with Flask | `python app.py/main.py/run.py` |
|
||||
| **Spring Boot** | `pom.xml` or `build.gradle` with spring-boot | `mvn spring-boot:run`, `gradle bootRun` |
|
||||
| **Go** | `go.mod` | `go run main.go` |
|
||||
| **PHP** | `composer.json` | `php -S 0.0.0.0:8080` |
|
||||
| **Rust** | `Cargo.toml` | `cargo run` |
|
||||
| **.NET** | `*.csproj` | `dotnet run` |
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```hcl
|
||||
module "auto_start" {
|
||||
source = "./modules/auto-start-dev-server"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
```hcl
|
||||
module "auto_start_dev_servers" {
|
||||
source = "./modules/auto-start-dev-server"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Optional: Configure which project types to detect
|
||||
enable_npm = true
|
||||
enable_rails = true
|
||||
enable_django = true
|
||||
enable_flask = true
|
||||
enable_spring_boot = true
|
||||
enable_go = true
|
||||
enable_php = true
|
||||
enable_rust = true
|
||||
enable_dotnet = true
|
||||
|
||||
# Optional: Enable devcontainer.json integration
|
||||
enable_devcontainer = true
|
||||
|
||||
# Optional: Workspace directory to scan (supports environment variables)
|
||||
workspace_directory = "$HOME"
|
||||
|
||||
# Optional: Directory scan depth (1-5)
|
||||
scan_depth = 2
|
||||
|
||||
# Optional: Startup delay in seconds
|
||||
startup_delay = 10
|
||||
|
||||
# Optional: Log file path
|
||||
log_path = "/tmp/dev-servers.log"
|
||||
|
||||
# Optional: Enable automatic preview app (default: true)
|
||||
enable_preview_app = true
|
||||
}
|
||||
```
|
||||
|
||||
### Disable Preview App
|
||||
|
||||
```hcl
|
||||
module "auto_start" {
|
||||
source = "./modules/auto-start-dev-server"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Disable automatic preview app creation
|
||||
enable_preview_app = false
|
||||
}
|
||||
```
|
||||
|
||||
### Selective Project Types
|
||||
|
||||
```hcl
|
||||
module "auto_start" {
|
||||
source = "./modules/auto-start-dev-server"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
# Only enable web development projects
|
||||
enable_npm = true
|
||||
enable_rails = true
|
||||
enable_django = true
|
||||
enable_flask = true
|
||||
|
||||
# Disable other project types
|
||||
enable_spring_boot = false
|
||||
enable_go = false
|
||||
enable_php = false
|
||||
enable_rust = false
|
||||
enable_dotnet = false
|
||||
}
|
||||
```
|
||||
|
||||
### Deep Workspace Scanning
|
||||
|
||||
```hcl
|
||||
module "auto_start" {
|
||||
source = "./modules/auto-start-dev-server"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.main.id
|
||||
|
||||
workspace_directory = "/workspaces"
|
||||
scan_depth = 3
|
||||
startup_delay = 5
|
||||
log_path = "/var/log/dev-servers.log"
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This module is provided under the same license as the Coder Registry.
|
||||
@@ -0,0 +1,109 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import {
|
||||
runTerraformApply,
|
||||
runTerraformInit,
|
||||
testRequiredVariables,
|
||||
} from "~test";
|
||||
|
||||
describe("auto-start-dev-server", async () => {
|
||||
await runTerraformInit(import.meta.dir);
|
||||
|
||||
testRequiredVariables(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
});
|
||||
|
||||
it("validates scan_depth range", () => {
|
||||
const t1 = async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
scan_depth: "0",
|
||||
});
|
||||
};
|
||||
expect(t1).toThrow("Scan depth must be between 1 and 5");
|
||||
|
||||
const t2 = async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
scan_depth: "6",
|
||||
});
|
||||
};
|
||||
expect(t2).toThrow("Scan depth must be between 1 and 5");
|
||||
});
|
||||
|
||||
it("applies successfully with default values", async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies successfully with all project types enabled", async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
enable_npm: "true",
|
||||
enable_rails: "true",
|
||||
enable_django: "true",
|
||||
enable_flask: "true",
|
||||
enable_spring_boot: "true",
|
||||
enable_go: "true",
|
||||
enable_php: "true",
|
||||
enable_rust: "true",
|
||||
enable_dotnet: "true",
|
||||
enable_devcontainer: "true",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies successfully with all project types disabled", async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
enable_npm: "false",
|
||||
enable_rails: "false",
|
||||
enable_django: "false",
|
||||
enable_flask: "false",
|
||||
enable_spring_boot: "false",
|
||||
enable_go: "false",
|
||||
enable_php: "false",
|
||||
enable_rust: "false",
|
||||
enable_dotnet: "false",
|
||||
enable_devcontainer: "false",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies successfully with custom configuration", async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
workspace_directory: "/custom/workspace",
|
||||
scan_depth: "3",
|
||||
startup_delay: "5",
|
||||
log_path: "/var/log/custom-dev-servers.log",
|
||||
display_name: "Custom Dev Server Startup",
|
||||
});
|
||||
});
|
||||
|
||||
it("validates scan_depth boundary values", async () => {
|
||||
// Test valid boundary values
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
scan_depth: "1",
|
||||
});
|
||||
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
scan_depth: "5",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies with selective project type configuration", async () => {
|
||||
await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "test-agent-123",
|
||||
enable_npm: "true",
|
||||
enable_django: "true",
|
||||
enable_go: "true",
|
||||
enable_rails: "false",
|
||||
enable_flask: "false",
|
||||
enable_spring_boot: "false",
|
||||
enable_php: "false",
|
||||
enable_rust: "false",
|
||||
enable_dotnet: "false",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,195 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "agent_id" {
|
||||
type = string
|
||||
description = "The ID of a Coder agent."
|
||||
}
|
||||
|
||||
variable "workspace_directory" {
|
||||
type = string
|
||||
description = "The directory to scan for development projects."
|
||||
default = "$HOME"
|
||||
}
|
||||
|
||||
variable "project_detection" {
|
||||
type = bool
|
||||
description = "Enable automatic project detection for all supported types. When true, all project types are detected unless individually disabled. When false, only explicitly enabled project types are detected."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_npm" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of npm projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_rails" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Rails projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_django" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Django projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_flask" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Flask projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_spring_boot" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Spring Boot projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_go" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Go projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_php" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of PHP projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_rust" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of Rust projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_dotnet" {
|
||||
type = bool
|
||||
description = "Enable auto-detection and startup of .NET projects."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_devcontainer" {
|
||||
type = bool
|
||||
description = "Enable integration with devcontainer.json configuration."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "log_path" {
|
||||
type = string
|
||||
description = "The path to log development server output to."
|
||||
default = "/tmp/dev-servers.log"
|
||||
}
|
||||
|
||||
variable "scan_depth" {
|
||||
type = number
|
||||
description = "Maximum directory depth to scan for projects (1-5)."
|
||||
default = 2
|
||||
validation {
|
||||
condition = var.scan_depth >= 1 && var.scan_depth <= 5
|
||||
error_message = "Scan depth must be between 1 and 5."
|
||||
}
|
||||
}
|
||||
|
||||
variable "startup_delay" {
|
||||
type = number
|
||||
description = "Delay in seconds before starting dev servers (allows other setup to complete)."
|
||||
default = 10
|
||||
}
|
||||
|
||||
variable "display_name" {
|
||||
type = string
|
||||
description = "Display name for the auto-start dev server script."
|
||||
default = "Auto-Start Dev Servers"
|
||||
}
|
||||
|
||||
variable "enable_preview_app" {
|
||||
type = bool
|
||||
description = "Enable automatic creation of a preview app for the first detected project."
|
||||
default = true
|
||||
}
|
||||
|
||||
# Read the detected port from the file written by the script
|
||||
locals {
|
||||
detected_port = var.enable_preview_app ? try(tonumber(trimspace(file("/tmp/detected-port.txt"))), 3000) : 3000
|
||||
# Attempt to read project information for better preview naming
|
||||
detected_projects = try(jsondecode(file("/tmp/detected-projects.json")), [])
|
||||
preview_project = length(local.detected_projects) > 0 ? local.detected_projects[0] : null
|
||||
}
|
||||
|
||||
resource "coder_script" "auto_start_dev_server" {
|
||||
agent_id = var.agent_id
|
||||
display_name = var.display_name
|
||||
icon = "/icon/server.svg"
|
||||
script = templatefile("${path.module}/run.sh", {
|
||||
WORKSPACE_DIR = var.workspace_directory
|
||||
ENABLE_NPM = coalesce(var.enable_npm, var.project_detection)
|
||||
ENABLE_RAILS = coalesce(var.enable_rails, var.project_detection)
|
||||
ENABLE_DJANGO = coalesce(var.enable_django, var.project_detection)
|
||||
ENABLE_FLASK = coalesce(var.enable_flask, var.project_detection)
|
||||
ENABLE_SPRING_BOOT = coalesce(var.enable_spring_boot, var.project_detection)
|
||||
ENABLE_GO = coalesce(var.enable_go, var.project_detection)
|
||||
ENABLE_PHP = coalesce(var.enable_php, var.project_detection)
|
||||
ENABLE_RUST = coalesce(var.enable_rust, var.project_detection)
|
||||
ENABLE_DOTNET = coalesce(var.enable_dotnet, var.project_detection)
|
||||
ENABLE_DEVCONTAINER = coalesce(var.enable_devcontainer, var.project_detection)
|
||||
LOG_PATH = var.log_path
|
||||
SCAN_DEPTH = var.scan_depth
|
||||
STARTUP_DELAY = var.startup_delay
|
||||
})
|
||||
run_on_start = true
|
||||
}
|
||||
|
||||
# Create preview app for first detected project
|
||||
resource "coder_app" "preview" {
|
||||
count = var.enable_preview_app ? 1 : 0
|
||||
agent_id = var.agent_id
|
||||
slug = "dev-preview"
|
||||
display_name = "Live Preview"
|
||||
url = "http://localhost:${local.detected_port}"
|
||||
icon = "/icon/globe.svg"
|
||||
subdomain = true
|
||||
share = "owner"
|
||||
}
|
||||
|
||||
output "log_path" {
|
||||
value = var.log_path
|
||||
description = "Path to the log file for dev server output"
|
||||
}
|
||||
|
||||
# Example output values for common port mappings
|
||||
output "common_ports" {
|
||||
value = {
|
||||
nodejs = 3000
|
||||
rails = 3000
|
||||
django = 8000
|
||||
flask = 5000
|
||||
spring = 8080
|
||||
go = 8080
|
||||
php = 8080
|
||||
rust = 8000
|
||||
dotnet = 5000
|
||||
}
|
||||
description = "Common default ports for different project types"
|
||||
}
|
||||
|
||||
output "preview_url" {
|
||||
value = var.enable_preview_app ? try(coder_app.preview[0].url, null) : null
|
||||
description = "URL of the live preview app (if enabled)"
|
||||
}
|
||||
|
||||
output "detected_port" {
|
||||
value = local.detected_port
|
||||
description = "Port of the first detected development server"
|
||||
}
|
||||
+468
@@ -0,0 +1,468 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Color codes for output
|
||||
BOLD='\033[0;1m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
RESET='\033[0m'
|
||||
|
||||
echo -e "$${BOLD}🚀 Auto-Start Development Servers$${RESET}"
|
||||
echo "Workspace Directory: ${WORKSPACE_DIR}"
|
||||
echo "Log Path: ${LOG_PATH}"
|
||||
echo "Scan Depth: ${SCAN_DEPTH}"
|
||||
|
||||
# Wait for startup delay to allow other setup to complete
|
||||
if [ "${STARTUP_DELAY}" -gt 0 ]; then
|
||||
echo -e "$${YELLOW}⏳ Waiting ${STARTUP_DELAY} seconds for system initialization...$${RESET}"
|
||||
sleep "${STARTUP_DELAY}"
|
||||
fi
|
||||
|
||||
# Initialize log file
|
||||
echo "=== Auto-Start Dev Servers Log ===" > "${LOG_PATH}"
|
||||
echo "Started at: $(date)" >> "${LOG_PATH}"
|
||||
|
||||
# Initialize detected projects JSON file
|
||||
DETECTED_PROJECTS_FILE="/tmp/detected-projects.json"
|
||||
echo '[]' > "$DETECTED_PROJECTS_FILE"
|
||||
|
||||
# Initialize detected port file for preview app
|
||||
DETECTED_PORT_FILE="/tmp/detected-port.txt"
|
||||
FIRST_PORT_DETECTED=false
|
||||
FRONTEND_PROJECT_DETECTED=false
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
echo -e "$1"
|
||||
echo "$1" >> "${LOG_PATH}"
|
||||
}
|
||||
|
||||
# Function to determine if a project is likely a frontend project
|
||||
is_frontend_project() {
|
||||
local project_dir="$1"
|
||||
local project_type="$2"
|
||||
|
||||
# Check for common frontend indicators
|
||||
if [ "$project_type" = "nodejs" ]; then
|
||||
# Check package.json for frontend dependencies
|
||||
if [ -f "$project_dir/package.json" ] && command -v jq &> /dev/null; then
|
||||
# Check for common frontend frameworks
|
||||
local has_react=$(jq '.dependencies.react // .devDependencies.react // empty' "$project_dir/package.json")
|
||||
local has_vue=$(jq '.dependencies.vue // .devDependencies.vue // empty' "$project_dir/package.json")
|
||||
local has_angular=$(jq '.dependencies["@angular/core"] // .devDependencies["@angular/core"] // empty' "$project_dir/package.json")
|
||||
local has_next=$(jq '.dependencies.next // .devDependencies.next // empty' "$project_dir/package.json")
|
||||
local has_nuxt=$(jq '.dependencies.nuxt // .devDependencies.nuxt // empty' "$project_dir/package.json")
|
||||
local has_svelte=$(jq '.dependencies.svelte // .devDependencies.svelte // empty' "$project_dir/package.json")
|
||||
local has_vite=$(jq '.dependencies.vite // .devDependencies.vite // empty' "$project_dir/package.json")
|
||||
|
||||
if [ -n "$has_react" ] || [ -n "$has_vue" ] || [ -n "$has_angular" ] \
|
||||
|| [ -n "$has_next" ] || [ -n "$has_nuxt" ] || [ -n "$has_svelte" ] \
|
||||
|| [ -n "$has_vite" ]; then
|
||||
return 0 # It's a frontend project
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for common frontend directory structures
|
||||
if [ -d "$project_dir/src/components" ] || [ -d "$project_dir/components" ] \
|
||||
|| [ -d "$project_dir/pages" ] || [ -d "$project_dir/views" ] \
|
||||
|| [ -f "$project_dir/index.html" ] || [ -f "$project_dir/public/index.html" ]; then
|
||||
return 0 # It's likely a frontend project
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rails projects with webpack/webpacker are frontend-enabled
|
||||
if [ "$project_type" = "rails" ]; then
|
||||
if [ -f "$project_dir/config/webpacker.yml" ] || [ -f "$project_dir/webpack.config.js" ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Django projects with static/templates are frontend-enabled
|
||||
if [ "$project_type" = "django" ]; then
|
||||
if [ -d "$project_dir/static" ] || [ -d "$project_dir/templates" ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1 # Not a frontend project
|
||||
}
|
||||
|
||||
# Function to add detected project to JSON
|
||||
add_detected_project() {
|
||||
local project_dir="$1"
|
||||
local project_type="$2"
|
||||
local port="$3"
|
||||
local command="$4"
|
||||
|
||||
# Check if this is a frontend project
|
||||
local is_frontend=false
|
||||
if is_frontend_project "$project_dir" "$project_type"; then
|
||||
is_frontend=true
|
||||
log_message "$${BLUE}🎨 Detected frontend project at $project_dir$${RESET}"
|
||||
fi
|
||||
|
||||
# Prioritize frontend projects for the preview app
|
||||
# Set port if: 1) No port set yet, OR 2) This is frontend and no frontend detected yet
|
||||
if [ "$FIRST_PORT_DETECTED" = false ] || ([ "$is_frontend" = true ] && [ "$FRONTEND_PROJECT_DETECTED" = false ]); then
|
||||
echo "$port" > "$DETECTED_PORT_FILE"
|
||||
FIRST_PORT_DETECTED=true
|
||||
if [ "$is_frontend" = true ]; then
|
||||
FRONTEND_PROJECT_DETECTED=true
|
||||
log_message "$${BLUE}🎯 Frontend project detected - Preview app will be available on port $port$${RESET}"
|
||||
else
|
||||
log_message "$${BLUE}🎯 Project detected - Preview app will be available on port $port$${RESET}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create JSON entry for this project
|
||||
local project_json=$(jq -n \
|
||||
--arg dir "$project_dir" \
|
||||
--arg type "$project_type" \
|
||||
--arg port "$port" \
|
||||
--arg cmd "$command" \
|
||||
--arg frontend "$is_frontend" \
|
||||
'{"directory": $dir, "type": $type, "port": $port, "command": $cmd, "is_frontend": ($frontend == "true")}')
|
||||
|
||||
# Append to the detected projects file
|
||||
jq ". += [$project_json]" "$DETECTED_PROJECTS_FILE" > "$DETECTED_PROJECTS_FILE.tmp" \
|
||||
&& mv "$DETECTED_PROJECTS_FILE.tmp" "$DETECTED_PROJECTS_FILE"
|
||||
}
|
||||
|
||||
# Function to detect and start npm/yarn projects
|
||||
detect_npm_projects() {
|
||||
if [ "${ENABLE_NPM}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Node.js/npm projects...$${RESET}"
|
||||
|
||||
# Use find with maxdepth to respect scan depth
|
||||
while IFS= read -r -d '' package_json; do
|
||||
project_dir=$(dirname "$package_json")
|
||||
log_message "$${GREEN}📦 Found Node.js project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Check package.json for start script
|
||||
if [ -f "package.json" ] && command -v jq &> /dev/null; then
|
||||
start_script=$(jq -r '.scripts.start // empty' package.json)
|
||||
dev_script=$(jq -r '.scripts.dev // empty' package.json)
|
||||
serve_script=$(jq -r '.scripts.serve // empty' package.json)
|
||||
|
||||
# Determine port (check for common port configurations)
|
||||
local project_port=3000
|
||||
if [ -n "$dev_script" ] && echo "$dev_script" | grep -q "\-\-port"; then
|
||||
project_port=$(echo "$dev_script" | grep -oE "\-\-port[[:space:]]+[0-9]+" | grep -oE "[0-9]+$" || echo "3000")
|
||||
fi
|
||||
|
||||
# Use yarn if yarn.lock exists
|
||||
local pkg_manager="npm"
|
||||
local cmd_prefix=""
|
||||
if [ -f "yarn.lock" ] && command -v yarn &> /dev/null; then
|
||||
pkg_manager="yarn"
|
||||
cmd_prefix=""
|
||||
else
|
||||
cmd_prefix="run "
|
||||
fi
|
||||
|
||||
# Prioritize scripts: 'dev' > 'serve' > 'start' for development environments
|
||||
if [ -n "$dev_script" ]; then
|
||||
if [ "$pkg_manager" = "yarn" ]; then
|
||||
log_message "$${GREEN}🟢 Starting project with 'yarn dev' in $project_dir$${RESET}"
|
||||
nohup yarn dev >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "yarn dev"
|
||||
else
|
||||
log_message "$${GREEN}🟢 Starting project with 'npm run dev' in $project_dir$${RESET}"
|
||||
nohup npm run dev >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "npm run dev"
|
||||
fi
|
||||
elif [ -n "$serve_script" ]; then
|
||||
if [ "$pkg_manager" = "yarn" ]; then
|
||||
log_message "$${GREEN}🟢 Starting project with 'yarn serve' in $project_dir$${RESET}"
|
||||
nohup yarn serve >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "yarn serve"
|
||||
else
|
||||
log_message "$${GREEN}🟢 Starting project with 'npm run serve' in $project_dir$${RESET}"
|
||||
nohup npm run serve >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "npm run serve"
|
||||
fi
|
||||
elif [ -n "$start_script" ]; then
|
||||
if [ "$pkg_manager" = "yarn" ]; then
|
||||
log_message "$${GREEN}🟢 Starting project with 'yarn start' in $project_dir$${RESET}"
|
||||
nohup yarn start >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "yarn start"
|
||||
else
|
||||
log_message "$${GREEN}🟢 Starting project with 'npm start' in $project_dir$${RESET}"
|
||||
nohup npm start >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "nodejs" "$project_port" "npm start"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "package.json" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Rails projects
|
||||
detect_rails_projects() {
|
||||
if [ "${ENABLE_RAILS}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Ruby on Rails projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' gemfile; do
|
||||
project_dir=$(dirname "$gemfile")
|
||||
log_message "$${GREEN}💎 Found Rails project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Check if it's actually a Rails project
|
||||
if grep -q "gem ['\"]rails['\"]" Gemfile 2> /dev/null; then
|
||||
log_message "$${GREEN}🟢 Starting Rails server in $project_dir$${RESET}"
|
||||
nohup bundle exec rails server >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "rails" "3000" "bundle exec rails server"
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "Gemfile" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Django projects
|
||||
detect_django_projects() {
|
||||
if [ "${ENABLE_DJANGO}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Django projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' manage_py; do
|
||||
project_dir=$(dirname "$manage_py")
|
||||
log_message "$${GREEN}🐍 Found Django project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
log_message "$${GREEN}🟢 Starting Django development server in $project_dir$${RESET}"
|
||||
nohup python manage.py runserver 0.0.0.0:8000 >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "django" "8000" "python manage.py runserver"
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "manage.py" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Flask projects
|
||||
detect_flask_projects() {
|
||||
if [ "${ENABLE_FLASK}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Flask projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' requirements_txt; do
|
||||
project_dir=$(dirname "$requirements_txt")
|
||||
|
||||
# Check if Flask is in requirements
|
||||
if grep -q -i "flask" "$requirements_txt" 2> /dev/null; then
|
||||
log_message "$${GREEN}🌶️ Found Flask project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Look for common Flask app files
|
||||
for app_file in app.py main.py run.py; do
|
||||
if [ -f "$app_file" ]; then
|
||||
log_message "$${GREEN}🟢 Starting Flask application ($app_file) in $project_dir$${RESET}"
|
||||
export FLASK_ENV=development
|
||||
nohup python "$app_file" >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "flask" "5000" "python $app_file"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "requirements.txt" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Spring Boot projects
|
||||
detect_spring_boot_projects() {
|
||||
if [ "${ENABLE_SPRING_BOOT}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Spring Boot projects...$${RESET}"
|
||||
|
||||
# Maven projects
|
||||
while IFS= read -r -d '' pom_xml; do
|
||||
project_dir=$(dirname "$pom_xml")
|
||||
|
||||
# Check if it's a Spring Boot project
|
||||
if grep -q "spring-boot" "$pom_xml" 2> /dev/null; then
|
||||
log_message "$${GREEN}🍃 Found Spring Boot Maven project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
if command -v ./mvnw &> /dev/null; then
|
||||
log_message "$${GREEN}🟢 Starting Spring Boot application with Maven wrapper in $project_dir$${RESET}"
|
||||
nohup ./mvnw spring-boot:run >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "spring-boot" "8080" "./mvnw spring-boot:run"
|
||||
elif command -v mvn &> /dev/null; then
|
||||
log_message "$${GREEN}🟢 Starting Spring Boot application with Maven in $project_dir$${RESET}"
|
||||
nohup mvn spring-boot:run >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "spring-boot" "8080" "mvn spring-boot:run"
|
||||
fi
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "pom.xml" -type f -print0)
|
||||
|
||||
# Gradle projects
|
||||
while IFS= read -r -d '' build_gradle; do
|
||||
project_dir=$(dirname "$build_gradle")
|
||||
|
||||
# Check if it's a Spring Boot project
|
||||
if grep -q "spring-boot" "$build_gradle" 2> /dev/null; then
|
||||
log_message "$${GREEN}🍃 Found Spring Boot Gradle project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
if command -v ./gradlew &> /dev/null; then
|
||||
log_message "$${GREEN}🟢 Starting Spring Boot application with Gradle wrapper in $project_dir$${RESET}"
|
||||
nohup ./gradlew bootRun >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "spring-boot" "8080" "./gradlew bootRun"
|
||||
elif command -v gradle &> /dev/null; then
|
||||
log_message "$${GREEN}🟢 Starting Spring Boot application with Gradle in $project_dir$${RESET}"
|
||||
nohup gradle bootRun >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "spring-boot" "8080" "gradle bootRun"
|
||||
fi
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "build.gradle" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Go projects
|
||||
detect_go_projects() {
|
||||
if [ "${ENABLE_GO}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Go projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' go_mod; do
|
||||
project_dir=$(dirname "$go_mod")
|
||||
log_message "$${GREEN}🐹 Found Go project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Look for main.go or check if there's a main function
|
||||
if [ -f "main.go" ]; then
|
||||
log_message "$${GREEN}🟢 Starting Go application in $project_dir$${RESET}"
|
||||
nohup go run main.go >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "go" "8080" "go run main.go"
|
||||
elif [ -f "cmd/main.go" ]; then
|
||||
log_message "$${GREEN}🟢 Starting Go application (cmd/main.go) in $project_dir$${RESET}"
|
||||
nohup go run cmd/main.go >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "go" "8080" "go run cmd/main.go"
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "go.mod" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start PHP projects
|
||||
detect_php_projects() {
|
||||
if [ "${ENABLE_PHP}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for PHP projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' composer_json; do
|
||||
project_dir=$(dirname "$composer_json")
|
||||
log_message "$${GREEN}🐘 Found PHP project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Look for common PHP entry points
|
||||
for entry_file in index.php public/index.php; do
|
||||
if [ -f "$entry_file" ]; then
|
||||
log_message "$${GREEN}🟢 Starting PHP development server in $project_dir$${RESET}"
|
||||
nohup php -S 0.0.0.0:8080 -t "$(dirname "$entry_file")" >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "php" "8080" "php -S 0.0.0.0:8080"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "composer.json" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start Rust projects
|
||||
detect_rust_projects() {
|
||||
if [ "${ENABLE_RUST}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for Rust projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' cargo_toml; do
|
||||
project_dir=$(dirname "$cargo_toml")
|
||||
log_message "$${GREEN}🦀 Found Rust project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
# Check if it's a binary project (has [[bin]] or default main.rs)
|
||||
if grep -q "\[\[bin\]\]" Cargo.toml 2> /dev/null || [ -f "src/main.rs" ]; then
|
||||
log_message "$${GREEN}🟢 Starting Rust application in $project_dir$${RESET}"
|
||||
nohup cargo run >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "rust" "8000" "cargo run"
|
||||
fi
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "Cargo.toml" -type f -print0)
|
||||
}
|
||||
|
||||
# Function to detect and start .NET projects
|
||||
detect_dotnet_projects() {
|
||||
if [ "${ENABLE_DOTNET}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_message "$${BLUE}🔍 Scanning for .NET projects...$${RESET}"
|
||||
|
||||
while IFS= read -r -d '' csproj; do
|
||||
project_dir=$(dirname "$csproj")
|
||||
log_message "$${GREEN}🔷 Found .NET project: $project_dir$${RESET}"
|
||||
|
||||
cd "$project_dir"
|
||||
log_message "$${GREEN}🟢 Starting .NET application in $project_dir$${RESET}"
|
||||
nohup dotnet run >> "${LOG_PATH}" 2>&1 &
|
||||
add_detected_project "$project_dir" "dotnet" "5000" "dotnet run"
|
||||
|
||||
done < <(find "${WORKSPACE_DIR}" -maxdepth "${SCAN_DEPTH}" -name "*.csproj" -type f -print0)
|
||||
}
|
||||
|
||||
log_message "Starting auto-detection of development projects..."
|
||||
|
||||
# Expand workspace directory if it contains variables
|
||||
WORKSPACE_DIR=$(eval echo "${WORKSPACE_DIR}")
|
||||
|
||||
# Check if workspace directory exists
|
||||
if [ ! -d "$WORKSPACE_DIR" ]; then
|
||||
log_message "$${RED}❌ Workspace directory does not exist: $WORKSPACE_DIR$${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$WORKSPACE_DIR"
|
||||
|
||||
# Run all detection functions
|
||||
detect_npm_projects
|
||||
detect_rails_projects
|
||||
detect_django_projects
|
||||
detect_flask_projects
|
||||
detect_spring_boot_projects
|
||||
detect_go_projects
|
||||
detect_php_projects
|
||||
detect_rust_projects
|
||||
detect_dotnet_projects
|
||||
|
||||
log_message "$${GREEN}✅ Auto-start scan completed!$${RESET}"
|
||||
log_message "$${YELLOW}💡 Check running processes with 'ps aux | grep -E \"(npm|rails|python|java|go|php|cargo|dotnet)\"'$${RESET}"
|
||||
log_message "$${YELLOW}💡 View logs: tail -f ${LOG_PATH}$${RESET}"
|
||||
|
||||
# Set default port if no projects were detected
|
||||
if [ "$FIRST_PORT_DETECTED" = false ]; then
|
||||
echo "3000" > "$DETECTED_PORT_FILE"
|
||||
log_message "$${YELLOW}⚠️ No projects detected - Preview app will default to port 3000$${RESET}"
|
||||
fi
|
||||
Reference in New Issue
Block a user