Files
lifeforge/scripts/forge/utils/helpers.ts
Melvin Chia 9f17cfd33b feat(cli): implement module management commands (add, remove, list) and enhance CLI logging
Former-commit-id: a27df1846c1fbc898c62a97e34f5f30eaa25325d [formerly ffc7fa7d80b1036f7f0fb4021fc166a58c413d40] [formerly e65c86c6674076e461d8cb804c009161aad7006d [formerly 64368a36e380a93f2d62808d6255826f11da9fee]]
Former-commit-id: c0efbb95a1243aa8c1316a34ce852c98b9b0cd66 [formerly 2c7aa0860c82d25d90901e89a7d70f161308d027]
Former-commit-id: c3e346e2d6b78be92c66c348e5f9df003a15dadf
2025-10-10 13:20:33 +08:00

151 lines
3.4 KiB
TypeScript

import { execSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import type { CommandExecutionOptions } from '../types'
import { CLILoggingService } from './logging'
/**
* Validates if the provided projects are valid
*/
export function validateProjects(
projects: string[],
validProjects: string[]
): { isValid: boolean; invalidProjects: string[] } {
const invalidProjects = projects.filter(
project => !validProjects.includes(project)
)
return {
isValid: invalidProjects.length === 0,
invalidProjects
}
}
/**
* Resolves project list, handling 'all' keyword
*/
export function resolveProjects<T extends string>(
projects: string[],
allProjects: T[]
): T[] {
const isAll = projects.includes('all')
return isAll ? allProjects : (projects as T[])
}
/**
* Executes a shell command with proper error handling
*/
export function executeCommand(
command: string | (() => string),
options: CommandExecutionOptions = {}
): string {
const cmd = typeof command === 'function' ? command() : command
try {
CLILoggingService.info(`Executing: ${cmd}`)
const result = execSync(cmd, {
stdio: 'inherit',
...options
})
CLILoggingService.info(`Completed: ${cmd}`)
return result?.toString().trim()
} catch (error) {
if (!options.exitOnError) {
throw error
}
CLILoggingService.error(`Failed: ${cmd}`)
CLILoggingService.error(`${error}`)
process.exit(1)
}
}
/**
* Validates environment variables
*/
export function validateEnvironment(requiredVars: string[]): void {
const missingVars = requiredVars.filter(varName => !process.env[varName])
if (missingVars.length > 0) {
CLILoggingService.error(
`Missing required environment variables: ${missingVars.join(', ')}`
)
CLILoggingService.error('Please set them in your .env file.')
process.exit(1)
}
}
/**
* Formats project list for display
*/
export function formatProjectList(projects: string[]): string {
return projects.join(', ')
}
/**
* Logs a process start message
*/
export function logProcessStart(processType: string, projects: string[]): void {
CLILoggingService.info(
`Running ${processType} for ${projects.length} project(s): ${formatProjectList(projects)}`
)
}
/**
* Logs a process completion message
*/
export function logProcessComplete(processType: string): void {
CLILoggingService.info(`All projects ${processType} completed successfully.`)
}
/**
* Kills existing processes matching the given keyword
*/
export function killExistingProcess(processKeyword: string): void {
try {
const serverInstance = executeCommand(`pgrep -f "${processKeyword}"`, {
exitOnError: false,
stdio: 'pipe'
})
if (serverInstance) {
executeCommand(`pkill -f "${processKeyword}"`)
}
} catch {
// No existing server instance found
}
}
type PathConfig = {
path: string
type: 'file' | 'directory'
}
export function validateFilePaths(
paths: PathConfig[],
basedir: string
): boolean {
for (const p of paths) {
const { path: pth, type } = p
const fullPath = path.resolve(basedir, pth)
if (!fs.existsSync(fullPath)) {
return false
}
const stats = fs.lstatSync(fullPath)
if (type === 'file' && !stats.isFile()) {
return false
}
if (type === 'directory' && !stats.isDirectory()) {
return false
}
}
return true
}