@cloudgrid-io/cli 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2094 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
- package/shared-services.yaml +14 -0
- package/templates/CLOUDGRID.md +94 -0
- package/templates/dockerfiles/cron.Dockerfile +7 -0
- package/templates/dockerfiles/nextjs.Dockerfile +17 -0
- package/templates/dockerfiles/node.Dockerfile +8 -0
- package/templates/dockerfiles/python.Dockerfile +8 -0
- package/templates/dockerfiles/static.Dockerfile +4 -0
- package/templates/dockerfiles/static.nginx.conf +12 -0
- package/templates/dockerfiles/typescript.Dockerfile +10 -0
- package/templates/samples/full-stack.yaml +11 -0
- package/templates/samples/multi-service.yaml +14 -0
- package/templates/samples/node-api.yaml +7 -0
- package/templates/samples/python-worker.yaml +9 -0
- package/templates/samples/static-site.yaml +5 -0
- package/templates/stubs/cron.stub.js +14 -0
- package/templates/stubs/cron.stub.package.json +9 -0
- package/templates/stubs/nextjs.stub/next.config.js +5 -0
- package/templates/stubs/nextjs.stub/package.json +15 -0
- package/templates/stubs/nextjs.stub/src/app/health/route.js +3 -0
- package/templates/stubs/nextjs.stub/src/app/layout.js +4 -0
- package/templates/stubs/nextjs.stub/src/app/page.js +3 -0
- package/templates/stubs/node.stub.js +13 -0
- package/templates/stubs/node.stub.package.json +12 -0
- package/templates/stubs/python.stub.py +16 -0
- package/templates/stubs/python.stub.requirements.txt +2 -0
- package/templates/stubs/static.stub/index.html +8 -0
- package/templates/stubs/typescript.stub.package.json +19 -0
- package/templates/stubs/typescript.stub.ts +14 -0
- package/templates/stubs/typescript.stub.tsconfig.json +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../../shared/src/errors.ts","../../shared/src/paths.ts","../src/commands/init.ts","../src/config.ts","../src/api-client.ts","../src/commands/create.ts","../../shared/src/generator/index.ts","../../shared/src/validate.ts","../../shared/src/utils.ts","../../shared/src/generator/dockerfile.ts","../../shared/src/generator/stubs.ts","../../shared/src/generator/ports.ts","../../shared/src/generator/dev-env.ts","../src/commands/dev.ts","../../shared/src/generator/docker-compose.ts","../src/commands/deploy.ts","../src/commands/list.ts","../src/commands/remove.ts","../src/commands/logs.ts","../src/commands/status.ts","../src/commands/doctor.ts","../src/commands/connect.ts","../src/commands/disconnect.ts","../src/commands/builds.ts","../src/commands/open.ts","../src/commands/ssh.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/admin.ts","../src/commands/secrets.ts","../src/commands/env-cmd.ts","../src/commands/usage.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { CloudGridError, setVerbose, isVerbose } from './utils.js';\nimport { initCommand } from './commands/init.js';\nimport { createCommand } from './commands/create.js';\nimport { devCommand } from './commands/dev.js';\nimport { deployCommand } from './commands/deploy.js';\nimport { listCommand } from './commands/list.js';\nimport { removeCommand } from './commands/remove.js';\nimport { logsCommand } from './commands/logs.js';\nimport { statusCommand } from './commands/status.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { connectCommand } from './commands/connect.js';\nimport { disconnectCommand } from './commands/disconnect.js';\nimport { buildsCommand } from './commands/builds.js';\nimport { openCommand } from './commands/open.js';\nimport { sshCommand } from './commands/ssh.js';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { adminCommand } from './commands/admin.js';\nimport { secretsCommand } from './commands/secrets.js';\nimport { envCommand } from './commands/env-cmd.js';\nimport { usageCommand } from './commands/usage.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));\n\nconst program = new Command();\n\nprogram\n .name('cloudgrid')\n .description('Deploy apps with a single YAML file')\n .version(pkg.version)\n .option('-v, --verbose', 'Show detailed output');\n\n// Parse verbose flag early via hook so all subcommands can read it\nprogram.hook('preAction', (_thisCommand, _actionCommand) => {\n const opts = program.opts();\n if (opts.verbose) setVerbose(true);\n});\n\nprogram.addCommand(initCommand);\nprogram.addCommand(createCommand);\nprogram.addCommand(devCommand);\nprogram.addCommand(deployCommand);\nprogram.addCommand(listCommand);\nprogram.addCommand(removeCommand);\nprogram.addCommand(logsCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(doctorCommand);\nprogram.addCommand(connectCommand);\nprogram.addCommand(disconnectCommand);\nprogram.addCommand(buildsCommand);\nprogram.addCommand(openCommand);\nprogram.addCommand(sshCommand);\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(adminCommand);\nprogram.addCommand(secretsCommand);\nprogram.addCommand(envCommand);\nprogram.addCommand(usageCommand);\n\n// Set verbose early so it works even if parseAsync fails\nif (process.argv.includes('--verbose') || process.argv.includes('-v')) {\n setVerbose(true);\n}\n\ntry {\n await program.parseAsync();\n} catch (e) {\n if (e instanceof CloudGridError) process.exit(1);\n if (isVerbose()) {\n console.error(e);\n } else if (e instanceof Error) {\n console.error(`Error: ${e.message}`);\n }\n process.exit(1);\n}\n","import { execa, type Options as ExecaOptions } from 'execa';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { CloudGridError } from '../../shared/src/errors.js';\n\n// Re-export from shared package\nexport { TEMPLATES_DIR, SHARED_SERVICES_PATH } from '../../shared/src/paths.js';\nexport { CloudGridError };\n\n// ── Verbose flag ────────────────────────────────────────────────\n\nlet _verbose = false;\n\nexport function setVerbose(v: boolean) { _verbose = v; }\nexport function isVerbose(): boolean { return _verbose; }\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function exec(cmd: string, args: string[], opts?: ExecaOptions): Promise<any> {\n return execa(cmd, args, { ...opts, stdio: opts?.stdio ?? 'pipe' });\n}\n\nexport async function execQuiet(cmd: string, args: string[]): Promise<string | null> {\n try {\n const result = await execa(cmd, args, { stdio: 'pipe' });\n return result.stdout;\n } catch {\n return null;\n }\n}\n\nexport const log = {\n info: (msg: string) => console.log(chalk.blue(' ' + msg)),\n success: (msg: string) => console.log(chalk.green(' ' + msg)),\n warn: (msg: string) => console.log(chalk.yellow(' ' + msg)),\n error: (msg: string) => console.error(chalk.red('ERROR: ' + msg)),\n step: (msg: string) => console.log(chalk.gray(' ' + msg)),\n};\n\nexport function spinner(text: string) {\n return ora({ text, color: 'cyan' });\n}\n\nexport function die(msg: string): never {\n log.error(msg);\n throw new CloudGridError(msg);\n}\n\nexport function upperSnake(name: string): string {\n return name.replace(/-/g, '_').toUpperCase();\n}\n\nexport function parseEnvFile(content: string): Record<string, string> {\n const values: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const stripped = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eq = stripped.indexOf('=');\n if (eq < 1) continue;\n let val = stripped.slice(eq + 1);\n if ((val.startsWith('\"') && val.endsWith('\"')) || (val.startsWith(\"'\") && val.endsWith(\"'\"))) {\n val = val.slice(1, -1);\n }\n values[stripped.slice(0, eq)] = val;\n }\n return values;\n}\n","export class CloudGridError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CloudGridError';\n }\n}\n\nexport function die(msg: string): never {\n throw new CloudGridError(msg);\n}\n","import { existsSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nfunction findPackageRoot(): string {\n // Walk up from current file until we find package.json\n let dir = dirname(fileURLToPath(import.meta.url));\n while (!existsSync(join(dir, 'package.json'))) {\n const parent = dirname(dir);\n if (parent === dir) throw new Error('Cannot find package root');\n dir = parent;\n }\n return dir;\n}\n\nconst PKG_ROOT = findPackageRoot();\nexport const TEMPLATES_DIR = join(PKG_ROOT, 'templates');\nexport const SHARED_SERVICES_PATH = join(PKG_ROOT, 'shared-services.yaml');\n","import { Command } from 'commander';\nimport inquirer from 'inquirer';\nimport { saveConfig, detectConfig, configExists, loadConfig } from '../config.js';\nimport { log } from '../utils.js';\n\nexport const initCommand = new Command('init')\n .description('Configure API URL (for non-default setups)')\n .action(async () => {\n const detected = detectConfig();\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'api_url',\n message: 'Cloud Grid API URL:',\n default: detected.api_url || 'https://api.cloudgrid.io',\n },\n ]);\n\n const existing = configExists() ? loadConfig() : {};\n saveConfig({ ...existing, ...answers } as any);\n log.success('Config saved. Run `cloudgrid login` to authenticate.');\n });\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport { CloudGridApiClient } from './api-client.js';\n\nexport interface CloudGridConfig {\n api_url: string;\n api_key?: string;\n registry: string;\n domain: string;\n jwt?: string;\n}\n\nconst CONFIG_DIR = join(homedir(), '.cloudgrid');\nconst CONFIG_PATH = join(CONFIG_DIR, 'config.yaml');\nconst APPS_DIR = join(CONFIG_DIR, 'apps');\n\nexport function getConfigDir() { return CONFIG_DIR; }\nexport function getAppsDir() { return APPS_DIR; }\nexport function configExists() { return existsSync(CONFIG_PATH); }\n\nexport function loadConfig(): CloudGridConfig {\n if (!existsSync(CONFIG_PATH)) {\n throw new Error('No CLI config found. Run: cloudgrid init');\n }\n return parseYaml(readFileSync(CONFIG_PATH, 'utf-8'));\n}\n\nexport function saveConfig(config: CloudGridConfig) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_PATH, stringifyYaml(config));\n}\n\nexport function detectConfig(): Partial<CloudGridConfig> {\n return {\n api_url: 'https://api.cloudgrid.io',\n domain: 'cloudgrid.io',\n };\n}\n\nexport function ensureAppsDir() {\n mkdirSync(APPS_DIR, { recursive: true });\n}\n\n/**\n * Create an API client from the loaded config.\n */\nexport function createApiClient(config?: CloudGridConfig): CloudGridApiClient {\n const cfg = config || loadConfig();\n if (!cfg.api_url) throw new Error('api_url not set. Run: cloudgrid login');\n if (!cfg.jwt) throw new Error('Not authenticated. Run: cloudgrid login');\n return new CloudGridApiClient(cfg.api_url, cfg.jwt);\n}\n","import * as net from 'net';\nimport WebSocket from 'ws';\nimport { isVerbose } from './utils.js';\n\n// ── Response types ──────────────────────────────────────────────\n\nexport interface DeployResult {\n status: string;\n url: string;\n services: { name: string; image: string; ready: boolean }[];\n}\n\nexport interface AppEntry {\n name: string;\n domain: string;\n services: { name: string; image: string }[];\n deployed_at: string;\n deployed_by: string;\n}\n\nexport interface PodInfo {\n name: string;\n status: string;\n ready: boolean;\n restarts: number;\n}\n\nexport interface ServiceInfo {\n name: string;\n type: string;\n ports: string;\n}\n\nexport interface IngressInfo {\n host: string;\n ip: string;\n}\n\nexport interface AppStatus {\n name: string;\n domain: string;\n pods: PodInfo[];\n services: ServiceInfo[];\n ingress: IngressInfo | null;\n}\n\nexport interface ApiErrorBody {\n error: string;\n code: string;\n}\n\n// ── Error class ─────────────────────────────────────────────────\n\nexport class ApiError extends Error {\n constructor(\n public readonly status: number,\n public readonly code: string,\n message: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\n// ── Client ──────────────────────────────────────────────────────\n\nexport class CloudGridApiClient {\n private baseUrl: string;\n private jwt: string;\n\n constructor(\n apiUrl: string,\n jwt: string,\n ) {\n // Strip trailing slash\n this.baseUrl = apiUrl.replace(/\\/+$/, '');\n this.jwt = jwt;\n }\n\n // ── HTTP helpers ────────────────────────────────────────────\n\n public async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'authorization': `Bearer ${this.jwt}`,\n };\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n if (isVerbose()) {\n console.error(` [verbose] ${method} ${url}`);\n }\n\n const res = await fetch(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (isVerbose()) {\n console.error(` [verbose] ${res.status} ${res.statusText}`);\n }\n\n if (!res.ok) {\n let errBody: ApiErrorBody;\n try {\n errBody = (await res.json()) as ApiErrorBody;\n } catch {\n errBody = { error: res.statusText, code: 'UNKNOWN' };\n }\n throw new ApiError(res.status, errBody.code, errBody.error);\n }\n\n // 204 No Content\n if (res.status === 204) return undefined as T;\n\n return (await res.json()) as T;\n }\n\n // ── Public API methods ──────────────────────────────────────\n\n async build(\n name: string,\n services: Record<string, string>,\n cloudgridYaml: string,\n tag?: string,\n ): Promise<any> {\n return this.request<any>('POST', `/apps/${name}/build`, {\n cloudgrid_yaml: cloudgridYaml,\n services,\n tag,\n });\n }\n\n async deploy(\n name: string,\n images: Record<string, string>,\n cloudgridYaml: string,\n ): Promise<DeployResult> {\n return this.request<DeployResult>('POST', `/apps/${name}/deploy`, {\n images,\n cloudgrid_yaml: cloudgridYaml,\n });\n }\n\n async list(): Promise<{ apps: AppEntry[] }> {\n return this.request<{ apps: AppEntry[] }>('GET', '/apps');\n }\n\n async status(name: string): Promise<AppStatus> {\n return this.request<AppStatus>('GET', `/apps/${name}`);\n }\n\n async logs(\n name: string,\n opts?: { service?: string; tail?: number },\n ): Promise<string> {\n const params = new URLSearchParams();\n if (opts?.service) params.set('service', opts.service);\n if (opts?.tail) params.set('tail', String(opts.tail));\n const qs = params.toString();\n const path = `/apps/${name}/logs${qs ? `?${qs}` : ''}`;\n const result = await this.request<{ logs: string }>('GET', path);\n return result.logs;\n }\n\n async remove(name: string): Promise<void> {\n await this.request<{ status: string }>('DELETE', `/apps/${name}`);\n }\n\n async listRepos(): Promise<{ repos: { full_name: string; default_branch: string }[] }> {\n return this.request('GET', '/github/repos');\n }\n\n async connect(name: string, repo: string, branch: string): Promise<any> {\n return this.request('POST', `/apps/${name}/connect`, { repo, branch });\n }\n\n async disconnect(name: string): Promise<any> {\n return this.request('DELETE', `/apps/${name}/connect`);\n }\n\n async listBuilds(name: string): Promise<any> {\n return this.request('GET', `/apps/${name}/builds`);\n }\n\n async listSecrets(name: string): Promise<any> {\n return this.request('GET', `/apps/${name}/secrets`);\n }\n\n async setSecrets(name: string, values: Record<string, string>): Promise<any> {\n return this.request('POST', `/apps/${name}/secrets`, { values });\n }\n\n async getSecret(name: string, key: string): Promise<any> {\n return this.request('GET', `/apps/${name}/secrets/${encodeURIComponent(key)}`);\n }\n\n async removeSecret(name: string, key: string): Promise<any> {\n return this.request('DELETE', `/apps/${name}/secrets/${encodeURIComponent(key)}`);\n }\n\n async listEnv(name: string): Promise<any> {\n return this.request('GET', `/apps/${name}/env`);\n }\n\n async setEnv(name: string, values: Record<string, string>): Promise<any> {\n return this.request('POST', `/apps/${name}/env`, { values });\n }\n\n async removeEnv(name: string, key: string): Promise<any> {\n return this.request('DELETE', `/apps/${name}/env/${encodeURIComponent(key)}`);\n }\n\n async listEvents(name: string): Promise<any> {\n return this.request('GET', `/apps/${name}/events`);\n }\n\n async getUsage(name: string): Promise<any> {\n return this.request('GET', `/apps/${name}/usage`);\n }\n\n // ── WebSocket tunnel ────────────────────────────────────────\n\n /**\n * Opens a local TCP server on `localPort`. For each incoming connection,\n * opens a WebSocket to the API tunnel endpoint and bridges data\n * bidirectionally between the local TCP socket and the WebSocket.\n *\n * Returns the TCP server so the caller can close it.\n */\n openTunnel(service: string, localPort: number): Promise<net.Server> {\n return new Promise((resolve, reject) => {\n const server = net.createServer((tcpSocket) => {\n // Build WebSocket URL: wss for https, ws for http\n const wsProto = this.baseUrl.startsWith('https') ? 'wss' : 'ws';\n const host = this.baseUrl.replace(/^https?:\\/\\//, '');\n const wsUrl = `${wsProto}://${host}/tunnel/${service}`;\n\n const wsHeaders: Record<string, string> = {\n 'authorization': `Bearer ${this.jwt}`,\n };\n const ws = new WebSocket(wsUrl, { headers: wsHeaders });\n ws.binaryType = 'nodebuffer';\n\n ws.on('open', () => {\n // Bridge TCP → WebSocket\n tcpSocket.on('data', (data) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(data);\n }\n });\n\n // Bridge WebSocket → TCP\n ws.on('message', (data: Buffer) => {\n if (!tcpSocket.destroyed) {\n tcpSocket.write(data);\n }\n });\n });\n\n ws.on('close', () => {\n if (!tcpSocket.destroyed) tcpSocket.destroy();\n });\n\n ws.on('error', () => {\n if (!tcpSocket.destroyed) tcpSocket.destroy();\n });\n\n tcpSocket.on('close', () => {\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n });\n\n tcpSocket.on('error', () => {\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n });\n });\n\n server.on('error', reject);\n\n server.listen(localPort, '127.0.0.1', () => {\n server.removeListener('error', reject);\n server.on('error', (err) => {\n console.error(`Tunnel server error: ${err.message}`);\n });\n resolve(server);\n });\n });\n }\n}\n","import { Command } from 'commander';\nimport inquirer from 'inquirer';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync } from 'fs';\nimport { join } from 'path';\nimport { stringify as stringifyYaml } from 'yaml';\nimport { log, die, TEMPLATES_DIR } from '../utils.js';\nimport { getAppsDir, ensureAppsDir, loadConfig, configExists } from '../config.js';\nimport { generate } from '../generator/index.js';\nimport { validateName } from '../generator/types.js';\nimport type { CloudGridYaml } from '../generator/types.js';\n\nconst SAMPLES = [\n { name: 'Full-stack dashboard (Next.js + API + MongoDB)', value: 'full-stack' },\n { name: 'Static site (HTML/React/Vue)', value: 'static-site' },\n { name: 'Node.js API with MongoDB', value: 'node-api' },\n { name: 'Python microservice with Redis', value: 'python-worker' },\n { name: 'Multi-service with n8n integration', value: 'multi-service' },\n { name: 'Blank', value: 'blank' },\n];\n\nfunction validateAppName(name: string) {\n validateName(name, 'app name');\n}\n\nexport const createCommand = new Command('create')\n .argument('[name]', 'App name')\n .option('--interactive', 'Use interactive wizard instead of template picker')\n .option('--dir <path>', 'Target directory')\n .description('Create a new Cloud Grid app')\n .action(async (nameArg: string | undefined, opts: { interactive?: boolean; dir?: string }) => {\n // Get app name\n let name = nameArg;\n if (!name) {\n const answer = await inquirer.prompt([\n { type: 'input', name: 'name', message: 'App name:' },\n ]);\n name = answer.name;\n }\n validateAppName(name!);\n\n // Determine target directory\n // Use `git rev-parse --show-toplevel` to detect git repos (not just checking .git in cwd)\n let appDir: string;\n if (opts.dir) {\n appDir = opts.dir;\n } else {\n let isInGitRepo = false;\n try {\n const { execaSync } = await import('execa');\n execaSync('git', ['rev-parse', '--show-toplevel'], { stdio: 'pipe' });\n isInGitRepo = true;\n } catch {\n isInGitRepo = false;\n }\n\n if (isInGitRepo) {\n // Tier 2: inside a git repo — create in current directory\n appDir = join(process.cwd(), name!);\n } else {\n // Tier 1: no git context — create in ~/.cloudgrid/apps/\n ensureAppsDir();\n appDir = join(getAppsDir(), name!);\n }\n }\n\n if (existsSync(appDir)) {\n die(`Directory already exists: ${appDir}`);\n }\n\n mkdirSync(appDir, { recursive: true });\n\n if (opts.interactive) {\n await interactiveWizard(name!, appDir);\n } else {\n await templatePicker(name!, appDir);\n }\n\n // Generate all files from cloudgrid.yaml\n // TODO: generator integration — real generator creates docker-compose, Dockerfiles, stubs\n log.step('Generating files...');\n if (configExists()) {\n const config = loadConfig();\n await generate(appDir, {\n environment: 'local',\n registry: config.registry,\n domain: `${name}.${config.domain}`,\n });\n } else {\n log.warn('No CLI config found. Skipping file generation. Run: cloudgrid init');\n }\n\n // Copy CLOUDGRID.md for AI coding assistants\n const cloudgridMdSrc = join(TEMPLATES_DIR, 'CLOUDGRID.md');\n if (existsSync(cloudgridMdSrc)) {\n copyFileSync(cloudgridMdSrc, join(appDir, 'CLOUDGRID.md'));\n }\n\n // Generate .gitignore\n writeFileSync(join(appDir, '.gitignore'), [\n 'node_modules/',\n '.next/',\n '.cloudgrid-dev.lock',\n '',\n ].join('\\n'));\n\n console.log('');\n log.success(`Created ${name} at ${appDir}`);\n console.log('');\n console.log(' Next steps:');\n console.log(` cd ${appDir}`);\n console.log(' cloudgrid dev # start local development');\n console.log(' cloudgrid deploy # deploy to production');\n console.log('');\n });\n\nasync function templatePicker(name: string, appDir: string) {\n const { template } = await inquirer.prompt([\n { type: 'list', name: 'template', message: 'Pick a starting template:', choices: SAMPLES },\n ]);\n\n if (template === 'blank') {\n const yaml = `name: ${name}\\n\\nservices:\\n app:\\n type: node\\n path: /\\n`;\n writeFileSync(join(appDir, 'cloudgrid.yaml'), yaml);\n } else {\n const samplePath = join(TEMPLATES_DIR, 'samples', `${template}.yaml`);\n if (existsSync(samplePath)) {\n let content = readFileSync(samplePath, 'utf-8');\n content = content.replace(/__APP_NAME__/g, name);\n writeFileSync(join(appDir, 'cloudgrid.yaml'), content);\n } else {\n // Templates not yet bundled — generate minimal yaml\n log.warn(`Template ${template} not found, using blank template`);\n const yaml = `name: ${name}\\n\\nservices:\\n app:\\n type: node\\n path: /\\n`;\n writeFileSync(join(appDir, 'cloudgrid.yaml'), yaml);\n }\n }\n}\n\nasync function interactiveWizard(name: string, appDir: string) {\n const services: Record<string, any> = {};\n const requires: any[] = [];\n\n let addMore = true;\n while (addMore) {\n const svc = await inquirer.prompt([\n { type: 'input', name: 'name', message: 'Service name:' },\n { type: 'list', name: 'type', message: 'Service type:', choices: ['nextjs', 'node', 'python', 'static', 'cron'] },\n { type: 'input', name: 'path', message: 'Public path (or enter to skip):', default: '', when: (a: any) => a.type !== 'cron' },\n { type: 'input', name: 'schedule', message: 'Cron schedule (e.g. \"0 2 * * *\"):', when: (a: any) => a.type === 'cron' },\n { type: 'list', name: 'runMode', message: 'Run mode:', choices: [\n { name: 'Run code (src/job.js)', value: 'job' },\n { name: 'Call HTTP URL', value: 'http' },\n ], when: (a: any) => a.type === 'cron' },\n { type: 'input', name: 'runUrl', message: 'HTTP URL to call:', when: (a: any) => a.type === 'cron' && a.runMode === 'http' },\n ]);\n services[svc.name] = { type: svc.type } as any;\n if (svc.type === 'node') {\n const { lang } = await inquirer.prompt([\n {\n type: 'list', name: 'lang', message: 'Language:',\n choices: [\n { name: 'JavaScript (default)', value: 'javascript' },\n { name: 'TypeScript', value: 'typescript' },\n ],\n },\n ]);\n if (lang === 'typescript') {\n services[svc.name].lang = 'typescript';\n }\n }\n if (svc.path) services[svc.name].path = svc.path;\n if (svc.type === 'cron') {\n if (svc.schedule) services[svc.name].schedule = svc.schedule;\n if (svc.runMode === 'http' && svc.runUrl) {\n services[svc.name].run = svc.runUrl;\n }\n }\n\n const { more } = await inquirer.prompt([\n { type: 'confirm', name: 'more', message: 'Add another service?', default: false },\n ]);\n addMore = more;\n }\n\n const { sharedSvcs } = await inquirer.prompt([\n {\n type: 'checkbox', name: 'sharedSvcs', message: 'Shared services:',\n choices: [\n { name: 'MongoDB', value: 'mongodb' },\n { name: 'Redis (shared)', value: 'redis' },\n { name: 'Redis (private, app-scoped)', value: 'redis-private' },\n { name: 'n8n webhooks', value: 'n8n' },\n ],\n },\n ]);\n\n for (const svc of sharedSvcs) {\n if (svc === 'redis-private') requires.push({ redis: 'private' });\n else requires.push(svc);\n }\n\n const yaml: CloudGridYaml = {\n name,\n services,\n ...(requires.length > 0 ? { requires } : {}),\n };\n writeFileSync(join(appDir, 'cloudgrid.yaml'), stringifyYaml(yaml));\n}\n","import { readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { parse as parseYaml } from 'yaml';\nimport { CloudGridYaml, SharedServicesRegistry, ParsedRequires } from '../types.js';\nimport { validateConfig, parseRequires } from '../validate.js';\nimport { generateKustomize } from './kustomize.js';\nimport { generateDockerfiles } from './dockerfile.js';\nimport { generateStubs } from './stubs.js';\nimport { die } from '../errors.js';\nimport { SHARED_SERVICES_PATH } from '../paths.js';\n\nexport function loadCloudGridYaml(appDir: string): CloudGridYaml {\n const yamlPath = join(appDir, 'cloudgrid.yaml');\n if (!existsSync(yamlPath)) {\n die(`No cloudgrid.yaml found at ${yamlPath}`);\n }\n return parseYaml(readFileSync(yamlPath, 'utf-8'));\n}\n\nexport function loadSharedServices(): SharedServicesRegistry {\n return parseYaml(readFileSync(SHARED_SERVICES_PATH, 'utf-8'));\n}\n\n/**\n * Generate all local dev files: Dockerfiles, stubs, docker-compose, .env.dev\n */\nexport async function generate(\n appDir: string,\n opts: { environment: 'local' | 'production'; registry: string; domain: string },\n): Promise<{\n config: CloudGridYaml;\n requires: ParsedRequires;\n sharedServices: SharedServicesRegistry;\n}> {\n const config = loadCloudGridYaml(appDir);\n validateConfig(config);\n const sharedServices = loadSharedServices();\n const requires = parseRequires(config.requires, sharedServices);\n\n generateDockerfiles({ appDir, config });\n generateStubs({ appDir, config });\n\n return { config, requires, sharedServices };\n}\n\n/**\n * Generate K8s configs in a temp directory for deployment.\n */\nexport async function generateForDeploy(\n appDir: string,\n tmpDir: string,\n opts: { registry: string; domain: string },\n): Promise<{ config: CloudGridYaml; requires: ParsedRequires }> {\n const config = loadCloudGridYaml(appDir);\n validateConfig(config);\n const sharedServices = loadSharedServices();\n const requires = parseRequires(config.requires, sharedServices);\n\n await generateKustomize({\n targetDir: tmpDir,\n config,\n requires,\n sharedServices,\n registry: opts.registry,\n domain: opts.domain,\n });\n\n return { config, requires };\n}\n\n// Re-export for convenience\nexport { computePortAssignments, computePortAssignmentsSync } from './ports.js';\nexport { computeDevEnv } from './dev-env.js';\nexport type { CloudGridYaml, ParsedRequires, SharedServicesRegistry } from '../types.js';\n","import { CloudGridYaml, GcpRequires, ParsedRequires, SharedServicesRegistry } from './types.js';\nimport { die } from './errors.js';\n\nconst NAME_REGEX = /^[a-z][a-z0-9-]{0,40}[a-z0-9]$/;\n\nconst RESERVED_NAMES = [\n 'default', 'kube-system', 'kube-public', 'kube-node-lease',\n 'n8n', 'sharedgrid', 'sharedgrid-dev', 'cloudgrid', 'cloudgrid-system',\n 'istio-system', 'cert-manager', 'ingress-nginx', 'monitoring',\n];\n\nconst VALID_TYPES = ['node', 'nextjs', 'python', 'static', 'cron'] as const;\n\nconst VALID_TIMEZONES = ['UTC', 'EST', 'PST'] as const;\n\nconst VALID_GCP_SERVICES = ['bigquery', 'pubsub', 'storage'] as const;\n\nexport function validateName(name: string, label: string): void {\n if (!NAME_REGEX.test(name)) {\n die(`Invalid ${label}: ${name} (must be 2-42 chars, lowercase alphanumeric + hyphens, no trailing hyphen)`);\n }\n if (label === 'app name' && RESERVED_NAMES.includes(name)) {\n die(`Reserved ${label}: ${name} (conflicts with system namespace)`);\n }\n}\n\nexport function validateConfig(config: CloudGridYaml): void {\n validateName(config.name, 'app name');\n\n if (!config.services || Object.keys(config.services).length === 0) {\n die('No services defined in cloudgrid.yaml');\n }\n\n const paths = new Set<string>();\n for (const [name, svc] of Object.entries(config.services)) {\n validateName(name, 'service name');\n\n if (!VALID_TYPES.includes(svc.type as any)) {\n die(`Service '${name}' has invalid type '${svc.type}'. Must be ${VALID_TYPES.join('|')}`);\n }\n\n if (svc.lang !== undefined) {\n if (svc.lang !== 'javascript' && svc.lang !== 'typescript') {\n die(`Service '${name}' has invalid lang '${svc.lang}'. Must be javascript|typescript`);\n }\n if (svc.type !== 'node') {\n die(`Service '${name}' uses lang but type is '${svc.type}'. lang is only valid for type: node`);\n }\n }\n\n if (svc.path !== undefined) {\n if (!svc.path.startsWith('/')) {\n die(`Service '${name}' path '${svc.path}' must start with /`);\n }\n if (paths.has(svc.path)) {\n die(`Duplicate path '${svc.path}'`);\n }\n paths.add(svc.path);\n }\n\n // Cron-specific validation\n if (svc.type === 'cron') {\n if (!svc.schedule) {\n die(`Service '${name}' is type 'cron' but missing required 'schedule' field`);\n }\n if (svc.path !== undefined) {\n die(`Service '${name}' is type 'cron' and must not have a 'path' field`);\n }\n if (svc.timezone !== undefined && !VALID_TIMEZONES.includes(svc.timezone as any)) {\n die(`Service '${name}' has invalid timezone '${svc.timezone}'. Must be ${VALID_TIMEZONES.join('|')}`);\n }\n if (svc.run !== undefined && svc.run !== 'job' && !svc.run.startsWith('http://') && !svc.run.startsWith('https://')) {\n die(`Service '${name}' has invalid run '${svc.run}'. Must be 'job', 'http://...', or 'https://...'`);\n }\n }\n }\n}\n\nexport function parseRequires(\n requires: CloudGridYaml['requires'],\n registry: SharedServicesRegistry,\n): ParsedRequires {\n const result: ParsedRequires = { shared: [], privateRedis: false };\n if (!requires) return result;\n\n let hasSharedRedis = false;\n\n for (const entry of requires) {\n if (typeof entry === 'string') {\n if (!registry[entry]) {\n die(`Unknown shared service: ${entry} (not in shared-services.yaml)`);\n }\n result.shared.push(entry);\n if (entry === 'redis') hasSharedRedis = true;\n } else if (typeof entry === 'object' && entry !== null) {\n const key = Object.keys(entry)[0];\n if (key === 'gcp' && isGcpRequires(entry)) {\n const gcpEntry = entry as GcpRequires;\n if (!Array.isArray(gcpEntry.gcp.services) || gcpEntry.gcp.services.length === 0) {\n die('gcp.services must be a non-empty array');\n }\n for (const svc of gcpEntry.gcp.services) {\n if (!VALID_GCP_SERVICES.includes(svc as any)) {\n die(`Invalid GCP service: '${svc}'. Must be one of: ${VALID_GCP_SERVICES.join(', ')}`);\n }\n }\n result.gcp = { services: [...gcpEntry.gcp.services] };\n } else if (key === 'redis' && (entry as Record<string, string>)[key] === 'private') {\n result.privateRedis = true;\n } else {\n const val = (entry as Record<string, string>)[key];\n die(`Unsupported requires modifier: ${key}: ${val} (only 'redis: private' and 'gcp: { services: [...] }' are supported)`);\n }\n } else {\n die(`Invalid requires entry: ${JSON.stringify(entry)}`);\n }\n }\n\n if (hasSharedRedis && result.privateRedis) {\n die('Cannot use both shared and private Redis. Choose one.');\n }\n\n return result;\n}\n\nfunction isGcpRequires(entry: unknown): entry is GcpRequires {\n return (\n typeof entry === 'object' &&\n entry !== null &&\n 'gcp' in entry &&\n typeof (entry as any).gcp === 'object' &&\n (entry as any).gcp !== null &&\n Array.isArray((entry as any).gcp.services)\n );\n}\n","export function upperSnake(name: string): string {\n return name.replace(/-/g, '_').toUpperCase();\n}\n","import { existsSync, copyFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { CloudGridYaml } from '../types.js';\nimport { die } from '../errors.js';\nimport { TEMPLATES_DIR } from '../paths.js';\n\nexport interface DockerfileLogger {\n step: (msg: string) => void;\n}\n\nconst defaultLogger: DockerfileLogger = {\n step: () => {},\n};\n\nexport function generateDockerfiles(opts: {\n appDir: string;\n config: CloudGridYaml;\n logger?: DockerfileLogger;\n}): void {\n const { appDir, config, logger = defaultLogger } = opts;\n\n for (const [svcName, svc] of Object.entries(config.services)) {\n // HTTP-mode cron services use curlimages/curl — no Dockerfile needed\n if (svc.type === 'cron' && svc.run && svc.run !== 'job') {\n logger.step(`Dockerfile: services/${svcName}/ skipped (cron HTTP mode)`);\n continue;\n }\n\n const svcDir = join(appDir, 'services', svcName);\n mkdirSync(svcDir, { recursive: true });\n\n const dockerfilePath = join(svcDir, 'Dockerfile');\n if (existsSync(dockerfilePath)) {\n logger.step(`Dockerfile: services/${svcName}/Dockerfile exists, skipping`);\n } else {\n const templateName = svc.lang === 'typescript' ? 'typescript' : svc.type;\n const templatePath = join(TEMPLATES_DIR, 'dockerfiles', `${templateName}.Dockerfile`);\n if (!existsSync(templatePath)) {\n die(`Dockerfile template not found: ${templatePath}. Is @cloudgrid/cli installed correctly?`);\n }\n copyFileSync(templatePath, dockerfilePath);\n logger.step(`Dockerfile: services/${svcName}/Dockerfile (${svc.type})`);\n }\n\n // Static type: also copy nginx.conf\n if (svc.type === 'static') {\n const nginxPath = join(svcDir, 'nginx.conf');\n if (!existsSync(nginxPath)) {\n const templatePath = join(TEMPLATES_DIR, 'dockerfiles', 'static.nginx.conf');\n if (existsSync(templatePath)) {\n copyFileSync(templatePath, nginxPath);\n }\n }\n }\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync, copyFileSync } from 'fs';\nimport { join } from 'path';\nimport { CloudGridYaml } from '../types.js';\nimport { TEMPLATES_DIR } from '../paths.js';\n\nexport interface StubsLogger {\n step: (msg: string) => void;\n}\n\nconst defaultLogger: StubsLogger = {\n step: () => {},\n};\n\nfunction replacePlaceholders(content: string, appName: string, svcName: string): string {\n return content.replace(/__APP_NAME__/g, appName).replace(/__SERVICE_NAME__/g, svcName);\n}\n\nfunction copyDirRecursive(src: string, dest: string, appName: string, svcName: string): void {\n mkdirSync(dest, { recursive: true });\n const entries = readdirSync(src);\n\n for (const entry of entries) {\n const srcPath = join(src, entry);\n const destPath = join(dest, entry);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDirRecursive(srcPath, destPath, appName, svcName);\n } else {\n // Replace placeholders in text files\n if (/\\.(js|json|ts|tsx|md|html)$/.test(entry)) {\n const content = readFileSync(srcPath, 'utf-8');\n writeFileSync(destPath, replacePlaceholders(content, appName, svcName));\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n }\n}\n\nexport function generateStubs(opts: {\n appDir: string;\n config: CloudGridYaml;\n logger?: StubsLogger;\n}): void {\n const { appDir, config, logger = defaultLogger } = opts;\n const stubsDir = join(TEMPLATES_DIR, 'stubs');\n\n for (const [svcName, svc] of Object.entries(config.services)) {\n const svcDir = join(appDir, 'services', svcName);\n mkdirSync(svcDir, { recursive: true });\n\n switch (svc.type) {\n case 'node': {\n if (!existsSync(join(svcDir, 'src')) && !existsSync(join(svcDir, 'package.json'))) {\n mkdirSync(join(svcDir, 'src'), { recursive: true });\n if (svc.lang === 'typescript') {\n const pkg = readFileSync(join(stubsDir, 'typescript.stub.package.json'), 'utf-8');\n writeFileSync(join(svcDir, 'package.json'), replacePlaceholders(pkg, config.name, svcName));\n const tsconfig = readFileSync(join(stubsDir, 'typescript.stub.tsconfig.json'), 'utf-8');\n writeFileSync(join(svcDir, 'tsconfig.json'), tsconfig);\n const src = readFileSync(join(stubsDir, 'typescript.stub.ts'), 'utf-8');\n writeFileSync(join(svcDir, 'src/index.ts'), replacePlaceholders(src, config.name, svcName));\n logger.step(`Stub: services/${svcName}/ (typescript)`);\n } else {\n const pkg = readFileSync(join(stubsDir, 'node.stub.package.json'), 'utf-8');\n writeFileSync(join(svcDir, 'package.json'), replacePlaceholders(pkg, config.name, svcName));\n const src = readFileSync(join(stubsDir, 'node.stub.js'), 'utf-8');\n writeFileSync(join(svcDir, 'src/index.js'), replacePlaceholders(src, config.name, svcName));\n logger.step(`Stub: services/${svcName}/ (node)`);\n }\n }\n break;\n }\n case 'nextjs': {\n if (!existsSync(join(svcDir, 'src')) && !existsSync(join(svcDir, 'package.json'))) {\n const nextjsStubDir = join(stubsDir, 'nextjs.stub');\n if (existsSync(nextjsStubDir)) {\n copyDirRecursive(nextjsStubDir, svcDir, config.name, svcName);\n }\n logger.step(`Stub: services/${svcName}/ (nextjs)`);\n }\n break;\n }\n case 'python': {\n if (!existsSync(join(svcDir, 'src')) && !existsSync(join(svcDir, 'requirements.txt'))) {\n mkdirSync(join(svcDir, 'src'), { recursive: true });\n const reqs = readFileSync(join(stubsDir, 'python.stub.requirements.txt'), 'utf-8');\n writeFileSync(join(svcDir, 'requirements.txt'), reqs);\n const src = readFileSync(join(stubsDir, 'python.stub.py'), 'utf-8');\n writeFileSync(join(svcDir, 'src/main.py'), replacePlaceholders(src, config.name, svcName));\n logger.step(`Stub: services/${svcName}/ (python)`);\n }\n break;\n }\n case 'static': {\n if (!existsSync(join(svcDir, 'public'))) {\n mkdirSync(join(svcDir, 'public'), { recursive: true });\n const staticStubDir = join(stubsDir, 'static.stub');\n if (existsSync(join(staticStubDir, 'index.html'))) {\n const html = readFileSync(join(staticStubDir, 'index.html'), 'utf-8');\n writeFileSync(join(svcDir, 'public/index.html'), replacePlaceholders(html, config.name, svcName));\n }\n logger.step(`Stub: services/${svcName}/ (static)`);\n }\n break;\n }\n case 'cron': {\n // Only generate stubs for code mode (run=job or default), not HTTP mode\n const runMode = svc.run || 'job';\n if (runMode === 'job' && !existsSync(join(svcDir, 'src')) && !existsSync(join(svcDir, 'package.json'))) {\n mkdirSync(join(svcDir, 'src'), { recursive: true });\n const pkg = readFileSync(join(stubsDir, 'cron.stub.package.json'), 'utf-8');\n writeFileSync(join(svcDir, 'package.json'), replacePlaceholders(pkg, config.name, svcName));\n const src = readFileSync(join(stubsDir, 'cron.stub.js'), 'utf-8');\n writeFileSync(join(svcDir, 'src/job.js'), replacePlaceholders(src, config.name, svcName));\n logger.step(`Stub: services/${svcName}/ (cron)`);\n }\n break;\n }\n }\n }\n}\n","import * as net from 'net';\nimport { CloudGridYaml } from '../types.js';\n\nconst BASE_PORTS: Record<string, number> = {\n nextjs: 3000,\n node: 5000,\n python: 5000,\n static: 8000,\n};\n\n/**\n * Check if a port is free on the host.\n * Checks 0.0.0.0 (not 127.0.0.1) because Docker binds on all interfaces.\n */\nexport function isPortFree(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port, '0.0.0.0');\n });\n}\n\n/**\n * Assign local dev ports for each service + tunnel ports.\n * Checks both inter-service collisions AND host port availability.\n *\n * Returns a Map with entries like:\n * \"web\" → 3002, \"api\" → 5000 (service ports)\n * \"_tunnel_mongodb\" → 27017 (tunnel ports)\n * \"_tunnel_redis\" → 6379 (tunnel ports)\n */\nexport async function computePortAssignments(config: CloudGridYaml): Promise<Map<string, number>> {\n const used = new Set<number>();\n const portMap = new Map<string, number>();\n\n // Service ports (skip cron — they don't listen on any port)\n for (const [name, svc] of Object.entries(config.services)) {\n if (svc.type === 'cron') continue;\n let port = BASE_PORTS[svc.type] || 8080;\n while (used.has(port) || !(await isPortFree(port))) port++;\n used.add(port);\n portMap.set(name, port);\n }\n\n // Tunnel ports for shared services\n const requires = config.requires || [];\n\n const hasMongodb = requires.some((r) => r === 'mongodb');\n const hasRedis = requires.some((r) =>\n r === 'redis' ||\n (typeof r === 'object' && Object.keys(r)[0] === 'redis'), // includes redis: private\n );\n\n if (hasMongodb) {\n let port = 27017;\n while (used.has(port) || !(await isPortFree(port))) port++;\n used.add(port);\n portMap.set('_tunnel_mongodb', port);\n }\n\n if (hasRedis) {\n let port = 6379;\n while (used.has(port) || !(await isPortFree(port))) port++;\n used.add(port);\n portMap.set('_tunnel_redis', port);\n }\n\n return portMap;\n}\n\n/**\n * Synchronous version — only checks inter-service collisions, no host availability.\n * Used by non-dev code paths (deploy, etc.)\n */\nexport function computePortAssignmentsSync(config: CloudGridYaml): Map<string, number> {\n const used = new Set<number>();\n const portMap = new Map<string, number>();\n\n for (const [name, svc] of Object.entries(config.services)) {\n if (svc.type === 'cron') continue;\n let port = BASE_PORTS[svc.type] || 8080;\n while (used.has(port)) port++;\n used.add(port);\n portMap.set(name, port);\n }\n\n return portMap;\n}\n","import { CloudGridYaml, ParsedRequires, SharedServicesRegistry } from '../types.js';\nimport { upperSnake } from '../utils.js';\n\n/**\n * Compute environment variables for dev mode (in-memory, no disk write).\n * Returns a Map of service name → env vars record.\n */\nexport function computeDevEnv(opts: {\n config: CloudGridYaml;\n portMap: Map<string, number>;\n requires: ParsedRequires;\n sharedServices: SharedServicesRegistry;\n mode: 'native' | 'compose';\n token?: string;\n apiUrl?: string;\n}): Map<string, Record<string, string>> {\n const { config, portMap, requires, sharedServices, mode, token, apiUrl } = opts;\n const svcNames = Object.keys(config.services);\n const result = new Map<string, Record<string, string>>();\n\n const mongoPort = portMap.get('_tunnel_mongodb') || 27017;\n const redisPort = portMap.get('_tunnel_redis') || 6379;\n\n for (const svcName of svcNames) {\n const svc = config.services[svcName];\n const env: Record<string, string> = {};\n\n // Standard vars (cron services don't have a port)\n const assignedPort = portMap.get(svcName);\n env.PORT = mode === 'native' ? String(assignedPort ?? '0') : '8080';\n env.APP_NAME = config.name;\n env.SERVICE_NAME = svcName;\n env.NODE_ENV = 'development';\n\n // AI gateway — point to the JWT-authenticated dev endpoint\n const baseApiUrl = apiUrl || 'https://api.cloudgrid.io';\n env.AI_GATEWAY_URL = `${baseApiUrl}/ai-dev`;\n if (token) {\n env.CLOUDGRID_TOKEN = token;\n }\n\n // Sibling URLs (skip cron services — they don't have URLs)\n for (const other of svcNames) {\n if (config.services[other].type === 'cron') continue;\n const upper = upperSnake(other);\n if (mode === 'native') {\n env[`${upper}_URL`] = `http://localhost:${portMap.get(other)!}`;\n } else {\n env[`${upper}_URL`] = `http://${other}:8080`;\n }\n }\n\n // Shared service URLs\n const host = mode === 'native' ? 'localhost' : 'host.docker.internal';\n\n for (const req of requires.shared) {\n const svcDef = sharedServices[req];\n if (req === 'mongodb') {\n env[svcDef.env_var] = `mongodb://${host}:${mongoPort}/${config.name}?directConnection=true`;\n } else if (req === 'redis') {\n env[svcDef.env_var] = `redis://${host}:${redisPort}`;\n } else if (req === 'n8n') {\n env[svcDef.env_var] = svcDef.local;\n }\n }\n\n // Private Redis: tunnel to dev cluster Redis (same tunnel for all)\n if (requires.privateRedis) {\n env.REDIS_URL = `redis://${host}:${redisPort}`;\n }\n\n // Developer-defined env vars\n if (svc.env) {\n for (const [key, val] of Object.entries(svc.env)) {\n env[key] = val;\n }\n }\n\n result.set(svcName, env);\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { existsSync, writeFileSync, readFileSync, unlinkSync } from 'fs';\nimport { join } from 'path';\nimport { tmpdir } from 'os';\nimport { createInterface } from 'readline';\nimport type * as net from 'net';\nimport { execa, type ResultPromise } from 'execa';\nimport chalk from 'chalk';\nimport { log, exec, die, spinner } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\n// Import from shared via re-exports (tsup-compatible)\nimport { computePortAssignments } from '../../../shared/src/generator/ports.js';\nimport { computeDevEnv } from '../../../shared/src/generator/dev-env.js';\nimport { generateDockerCompose } from '../../../shared/src/generator/docker-compose.js';\nimport { parseRequires } from '../../../shared/src/validate.js';\nimport { loadSharedServices } from '../../../shared/src/generator/index.js';\n\nconst LOCK_FILE = '.cloudgrid-dev.lock';\n\nconst SERVICE_COLORS = [chalk.cyan, chalk.magenta, chalk.yellow, chalk.green, chalk.blue, chalk.red];\n\nconst RUNNERS: Record<string, (port: number) => { cmd: string; args: string[] }> = {\n node: () => ({ cmd: 'node', args: ['--watch', 'src/index.js'] }),\n nextjs: (port) => ({ cmd: 'npx', args: ['next', 'dev', '-p', String(port)] }),\n python: () => ({ cmd: 'python', args: ['src/main.py'] }),\n static: (port) => ({ cmd: 'npx', args: ['serve', 'public/', '-l', String(port)] }),\n};\n\n// ── Lock file management ───────────────────────────────────\n\nfunction checkDevLock(appDir: string): void {\n const lockPath = join(appDir, LOCK_FILE);\n if (!existsSync(lockPath)) return;\n try {\n const lock = JSON.parse(readFileSync(lockPath, 'utf-8'));\n try {\n process.kill(lock.pid, 0);\n die(`Dev already running for this app (PID ${lock.pid}). Stop it first (Ctrl+C) or use --force`);\n } catch {\n unlinkSync(lockPath);\n }\n } catch {\n try { unlinkSync(lockPath); } catch {}\n }\n}\n\nfunction writeDevLock(appDir: string, ports: Map<string, number>): void {\n writeFileSync(join(appDir, LOCK_FILE), JSON.stringify({\n pid: process.pid,\n ports: Object.fromEntries(ports),\n startedAt: new Date().toISOString(),\n }, null, 2));\n}\n\nfunction removeDevLock(appDir: string): void {\n try { unlinkSync(join(appDir, LOCK_FILE)); } catch {}\n}\n\n// ── Prefixed output ────────────────────────────────────────\n\nfunction prefixStream(stream: NodeJS.ReadableStream, name: string, color: typeof chalk.cyan) {\n const rl = createInterface({ input: stream });\n rl.on('line', (line) => {\n console.log(`${color(`[${name}]`)} ${line}`);\n });\n}\n\n// ── Command ────────────────────────────────────────────────\n\nexport const devCommand = new Command('dev')\n .description('Start local development')\n .option('--compose', 'Use docker-compose instead of native processes')\n .option('--force', 'Ignore existing dev lock')\n .action(async (opts: { compose?: boolean; force?: boolean }) => {\n const appDir = process.cwd();\n if (!existsSync(join(appDir, 'cloudgrid.yaml'))) {\n die('No cloudgrid.yaml found. Run: cloudgrid create <name>');\n }\n\n if (!opts.force) checkDevLock(appDir);\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const cliConfig = loadConfig();\n if (!cliConfig.jwt) {\n log.warn('Not logged in — AI features will not work in dev mode. Run: cloudgrid login');\n }\n const apiClient = createApiClient(cliConfig);\n const config = loadCloudGridYaml(appDir);\n const sharedServices = loadSharedServices();\n const requires = parseRequires(config.requires, sharedServices);\n\n // 1. Assign ports (services + tunnels)\n const s1 = spinner('Checking available ports...');\n s1.start();\n const portMap = await computePortAssignments(config);\n s1.succeed('Ports assigned');\n\n // 2. Write lock\n writeDevLock(appDir, portMap);\n\n // 3. Open tunnels\n const tunnels: net.Server[] = [];\n const mongoPort = portMap.get('_tunnel_mongodb');\n const redisPort = portMap.get('_tunnel_redis');\n\n if (mongoPort || redisPort) {\n log.info('Opening tunnels via Cloud Grid API...');\n }\n if (mongoPort) {\n try {\n const t = await apiClient.openTunnel('mongodb', mongoPort);\n tunnels.push(t);\n log.step(`MongoDB: localhost:${mongoPort}`);\n } catch (err: any) {\n log.warn(`MongoDB tunnel failed: ${err.message}`);\n }\n }\n if (redisPort) {\n try {\n const t = await apiClient.openTunnel('redis', redisPort);\n tunnels.push(t);\n log.step(`Redis: localhost:${redisPort}`);\n } catch (err: any) {\n log.warn(`Redis tunnel failed: ${err.message}`);\n }\n }\n\n // 4. Cleanup handler\n const children: ResultPromise[] = [];\n let tmpComposePath: string | null = null;\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n for (const child of children) { try { child.kill(); } catch {} }\n for (const tunnel of tunnels) {\n try {\n if ('closeAllConnections' in tunnel) (tunnel as any).closeAllConnections();\n tunnel.close();\n } catch {}\n }\n if (tmpComposePath) { try { unlinkSync(tmpComposePath); } catch {} }\n removeDevLock(appDir);\n };\n process.once('SIGTERM', () => { cleanup(); process.exit(0); });\n process.once('SIGINT', () => { cleanup(); process.exit(0); });\n\n if (opts.compose) {\n // ── Compose mode ──────────────────────────────────\n tmpComposePath = join(tmpdir(), `cloudgrid-${config.name}-compose.yaml`);\n\n log.info('Starting docker-compose...');\n generateDockerCompose({\n outputPath: tmpComposePath,\n appDir,\n config,\n requires,\n sharedServices,\n portMap,\n token: cliConfig.jwt,\n apiUrl: cliConfig.api_url,\n });\n\n console.log('');\n const svcNames = Object.keys(config.services);\n for (const name of svcNames) {\n log.info(`${name}: http://localhost:${portMap.get(name)}`);\n }\n console.log('');\n\n try {\n await exec('docker', ['compose', '-f', tmpComposePath, 'up', '--build'], { stdio: 'inherit' });\n } finally {\n cleanup();\n }\n } else {\n // ── Native mode ───────────────────────────────────\n const envMap = computeDevEnv({ config, portMap, requires, sharedServices, mode: 'native', token: cliConfig.jwt, apiUrl: cliConfig.api_url });\n const svcNames = Object.keys(config.services);\n\n // Handle cron services first (before spawning long-running processes)\n for (const svcName of svcNames) {\n const svc = config.services[svcName];\n if (svc.type !== 'cron') continue;\n const runMode = svc.run || 'job';\n const color = SERVICE_COLORS[svcNames.indexOf(svcName) % SERVICE_COLORS.length];\n\n if (runMode === 'job') {\n // Run the job once\n const svcDir = join(appDir, 'services', svcName);\n const svcEnv = envMap.get(svcName) || {};\n log.info(`${color(svcName)}: Running cron job once...`);\n try {\n const result = await execa('node', ['src/job.js'], {\n cwd: svcDir,\n env: { ...process.env, ...svcEnv },\n stdio: 'pipe',\n });\n if (result.stdout) {\n for (const line of result.stdout.split('\\n')) {\n console.log(`${color(`[${svcName}]`)} ${line}`);\n }\n }\n } catch (err: any) {\n if (err.stdout) {\n for (const line of err.stdout.split('\\n')) {\n console.log(`${color(`[${svcName}]`)} ${line}`);\n }\n }\n if (err.stderr) {\n for (const line of err.stderr.split('\\n')) {\n console.log(`${color(`[${svcName}]`)} ${line}`);\n }\n }\n }\n log.info(`${color(svcName)}: Job completed. It will run on schedule in production.`);\n } else {\n // HTTP mode\n log.info(`${color(svcName)}: Cron '${svcName}' triggers ${runMode} on schedule '${svc.schedule}'. In dev, call the URL manually.`);\n }\n }\n\n // Auto-install dependencies\n for (const svcName of svcNames) {\n const svcDir = join(appDir, 'services', svcName);\n const svcType = config.services[svcName].type;\n if (svcType === 'cron') continue; // cron services don't need npm install for dev\n if ((svcType === 'node' || svcType === 'nextjs') && !existsSync(join(svcDir, 'node_modules'))) {\n const si = spinner(`Installing dependencies for ${svcName}...`);\n si.start();\n try {\n await exec('npm', ['install'], { cwd: svcDir, stdio: 'pipe' });\n si.succeed(`Dependencies installed for ${svcName}`);\n } catch {\n si.fail(`Failed to install dependencies for ${svcName}`);\n cleanup();\n die(`npm install failed for ${svcName}. Fix the issue and retry.`);\n }\n }\n }\n\n // Print URLs (skip cron services — they don't listen on ports)\n console.log('');\n for (let i = 0; i < svcNames.length; i++) {\n const name = svcNames[i];\n if (config.services[name].type === 'cron') continue;\n const port = portMap.get(name)!;\n const color = SERVICE_COLORS[i % SERVICE_COLORS.length];\n log.info(`${color(name)}: http://localhost:${port}`);\n }\n console.log('');\n log.info('Hot reload enabled. Press Ctrl+C to stop.');\n console.log('');\n\n // Spawn services (skip cron — they don't need persistent processes)\n for (let i = 0; i < svcNames.length; i++) {\n const svcName = svcNames[i];\n const svc = config.services[svcName];\n if (svc.type === 'cron') continue;\n const port = portMap.get(svcName)!;\n const svcDir = join(appDir, 'services', svcName);\n const svcEnv = envMap.get(svcName)!;\n let runner = RUNNERS[svc.type];\n const color = SERVICE_COLORS[i % SERVICE_COLORS.length];\n\n if (svc.lang === 'typescript') {\n runner = () => ({ cmd: 'npx', args: ['tsx', 'watch', 'src/index.ts'] });\n }\n\n if (!runner) {\n log.warn(`Unknown service type: ${svc.type} for ${svcName}`);\n continue;\n }\n\n const { cmd, args } = runner(port);\n const child = execa(cmd, args, {\n cwd: svcDir,\n env: { ...process.env, ...svcEnv },\n stdio: 'pipe',\n });\n\n if (child.stdout) prefixStream(child.stdout, svcName, color);\n if (child.stderr) prefixStream(child.stderr, svcName, color);\n\n child.catch(() => {}); // don't crash on individual process exit\n children.push(child);\n }\n\n // Wait for Ctrl+C (hang forever until signal)\n await new Promise(() => {});\n }\n });\n","import { writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { CloudGridYaml, ParsedRequires, SharedServicesRegistry } from '../types.js';\nimport { upperSnake } from '../utils.js';\nimport { computePortAssignmentsSync } from './ports.js';\n\n/**\n * Generate a docker-compose YAML for --compose dev mode.\n * Writes to the specified outputPath (temp dir, NOT the app folder).\n * All data services use host.docker.internal (tunneled from cluster).\n */\nexport function generateDockerCompose(opts: {\n outputPath: string;\n appDir: string;\n config: CloudGridYaml;\n requires: ParsedRequires;\n sharedServices: SharedServicesRegistry;\n portMap: Map<string, number>;\n token?: string;\n apiUrl?: string;\n}): void {\n const { outputPath, appDir, config, requires, sharedServices, portMap, token, apiUrl } = opts;\n const svcNames = Object.keys(config.services);\n\n const mongoPort = portMap.get('_tunnel_mongodb') || 27017;\n const redisPort = portMap.get('_tunnel_redis') || 6379;\n\n let yaml = 'services:\\n';\n\n for (const svcName of svcNames) {\n const svc = config.services[svcName];\n if (svc.type === 'cron') continue; // cron services don't run as compose services\n const localPort = portMap.get(svcName)!;\n const containerPort = svc.type === 'static' ? 80 : 8080;\n\n yaml += ` ${svcName}:\\n`;\n yaml += ` build: ${join(appDir, 'services', svcName)}\\n`;\n yaml += ` ports:\\n`;\n yaml += ` - \"${localPort}:${containerPort}\"\\n`;\n\n // TypeScript: override command for hot reload in compose mode\n if (svc.lang === 'typescript') {\n yaml += ` command: [\"npx\", \"tsx\", \"watch\", \"src/index.ts\"]\\n`;\n }\n\n // Volume mount\n if (svc.type === 'static') {\n yaml += ` volumes:\\n`;\n yaml += ` - ${join(appDir, 'services', svcName, 'public')}:/usr/share/nginx/html\\n`;\n } else {\n yaml += ` volumes:\\n`;\n yaml += ` - ${join(appDir, 'services', svcName, 'src')}:/app/src\\n`;\n }\n\n // Environment\n yaml += ` environment:\\n`;\n yaml += ` PORT: \"8080\"\\n`;\n yaml += ` APP_NAME: \"${config.name}\"\\n`;\n yaml += ` SERVICE_NAME: \"${svcName}\"\\n`;\n yaml += ` NODE_ENV: development\\n`;\n\n // AI dev mode: route AI calls through the Cloud Grid API with JWT auth\n if (apiUrl && token) {\n const aiDevUrl = `${apiUrl.replace(/\\/$/, '')}/ai-dev`;\n yaml += ` AI_GATEWAY_URL: \"${aiDevUrl}\"\\n`;\n yaml += ` CLOUDGRID_TOKEN: \"${token}\"\\n`;\n }\n\n // Sibling URLs (compose service names)\n for (const other of svcNames) {\n const upper = upperSnake(other);\n yaml += ` ${upper}_URL: \"http://${other}:8080\"\\n`;\n }\n\n // Shared service URLs (via host.docker.internal + tunnel ports)\n for (const req of requires.shared) {\n const svcDef = sharedServices[req];\n if (req === 'mongodb') {\n yaml += ` ${svcDef.env_var}: \"mongodb://host.docker.internal:${mongoPort}/${config.name}?directConnection=true\"\\n`;\n } else if (req === 'redis') {\n yaml += ` ${svcDef.env_var}: \"redis://host.docker.internal:${redisPort}\"\\n`;\n } else if (req === 'n8n') {\n yaml += ` ${svcDef.env_var}: \"${svcDef.local}\"\\n`;\n }\n }\n\n // Private Redis: tunnel to dev cluster (not a local container)\n if (requires.privateRedis) {\n yaml += ` REDIS_URL: \"redis://host.docker.internal:${redisPort}\"\\n`;\n }\n\n // Developer-defined env vars\n if (svc.env) {\n for (const [key, val] of Object.entries(svc.env)) {\n yaml += ` ${key}: \"${val}\"\\n`;\n }\n }\n }\n\n // No private Redis container — all Redis via tunnel\n\n writeFileSync(outputPath, yaml);\n}\n","import { Command } from 'commander';\nimport { existsSync, readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { log, die, spinner } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\nimport { ApiError } from '../api-client.js';\n\nexport const deployCommand = new Command('deploy')\n .description('Deploy app to production')\n .action(async () => {\n if (!existsSync('cloudgrid.yaml')) die('No cloudgrid.yaml in current directory');\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const cliConfig = loadConfig();\n const config = loadCloudGridYaml(process.cwd());\n const apiClient = createApiClient(cliConfig);\n\n console.log(`\\nDeploying ${config.name} to production...\\n`);\n\n await serverBuild(config, apiClient);\n });\n\nasync function serverBuild(config: any, apiClient: any) {\n const cloudgridYaml = readFileSync('cloudgrid.yaml', 'utf-8');\n const services: Record<string, string> = {};\n\n for (const [svcName, svc] of Object.entries(config.services) as any[]) {\n if (svc.type === 'cron' && svc.run && (svc.run.startsWith('http://') || svc.run.startsWith('https://'))) {\n log.step(`${svcName}: HTTP cron — no build needed`);\n continue;\n }\n\n const svcDir = `services/${svcName}`;\n if (!existsSync(svcDir)) {\n die(`Service directory not found: ${svcDir}`);\n }\n\n const s = spinner(`Packaging ${svcName}...`);\n s.start();\n\n const excludes = ['node_modules', '.git', '.next', 'dist', '__pycache__', '.venv']\n .map(d => `--exclude=${d}`).join(' ');\n\n const tarball = execSync(\n `tar -czf - ${excludes} -C ${svcDir} .`,\n { maxBuffer: 100 * 1024 * 1024 },\n );\n\n const sizeMB = (tarball.length / 1024 / 1024).toFixed(1);\n if (tarball.length > 80 * 1024 * 1024) {\n s.warn(`${svcName}: ${sizeMB}MB — consider adding .dockerignore to exclude unnecessary files`);\n } else {\n s.succeed(`${svcName}: packaged (${sizeMB}MB)`);\n }\n\n services[svcName] = tarball.toString('base64');\n }\n\n if (Object.keys(services).length === 0) {\n log.step('No services to build');\n }\n\n const s2 = spinner('Building and deploying via Cloud Grid API...');\n s2.start();\n\n try {\n const result = await apiClient.build(config.name, services, cloudgridYaml);\n s2.succeed('Deployed');\n\n for (const svc of result.services) {\n const status = svc.ready ? ' ready' : ' pending';\n log.step(`${svc.name}: ${status}`);\n }\n console.log(`\\n Live at ${result.url}\\n`);\n } catch (err) {\n s2.fail('Deploy failed');\n if (err instanceof ApiError) {\n if (err.code === 'BUILD_FAILED') die(`Build failed: ${err.message}`);\n if (err.code === 'DEPLOY_IN_PROGRESS') die('Another deploy is in progress. Try again shortly.');\n if (err.code === 'DEPLOY_TIMEOUT') {\n log.warn('Deploy timed out. Check status with: cloudgrid status');\n return;\n }\n die(`API error (${err.code}): ${err.message}`);\n }\n throw err;\n }\n}\n\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\nimport { die } from '../utils.js';\n\nexport const listCommand = new Command('list')\n .description('Show all deployed apps')\n .action(async () => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const apiClient = createApiClient(loadConfig());\n const { apps } = await apiClient.list();\n\n if (apps.length === 0) {\n console.log('No apps deployed.');\n return;\n }\n\n console.log('');\n console.log(chalk.bold('NAME'.padEnd(20) + 'DOMAIN'.padEnd(35) + 'DEPLOYED'));\n for (const app of apps) {\n const ago = timeAgo(app.deployed_at);\n console.log(`${app.name.padEnd(20)}${app.domain.padEnd(35)}${ago} by ${app.deployed_by}`);\n }\n console.log('');\n });\n\nfunction timeAgo(iso: string): string {\n const ms = Date.now() - new Date(iso).getTime();\n const mins = Math.floor(ms / 60000);\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.floor(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n return `${Math.floor(hrs / 24)}d ago`;\n}\n","import { Command } from 'commander';\nimport inquirer from 'inquirer';\nimport { log, spinner, die } from '../utils.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\nimport { ApiError } from '../api-client.js';\n\nexport const removeCommand = new Command('remove')\n .argument('<name>', 'App name to remove')\n .description('Remove an app from the cluster')\n .action(async (name: string) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: `Remove ${name}? This deletes all pods, services, and data.`,\n default: false,\n },\n ]);\n if (!confirm) return;\n\n const apiClient = createApiClient(loadConfig());\n\n const s = spinner(`Removing ${name}...`);\n s.start();\n try {\n await apiClient.remove(name);\n s.succeed(`${name} removed.`);\n } catch (err) {\n s.fail('Remove failed');\n if (err instanceof ApiError && err.code === 'NOT_FOUND') {\n die(`App \"${name}\" not found`);\n }\n if (err instanceof ApiError) {\n die(`API error (${err.code}): ${err.message}`);\n }\n throw err;\n }\n });\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport { die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\nimport { ApiError } from '../api-client.js';\n\nexport const logsCommand = new Command('logs')\n .argument('[name]', 'App name (auto-detected from cloudgrid.yaml if in app dir)')\n .option('-s, --service <service>', 'Filter by service name')\n .option('-t, --tail <lines>', 'Number of lines to show', '100')\n .description('Show app logs')\n .action(async (name: string | undefined, opts: { service?: string; tail?: string }) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const appName = name || (existsSync('cloudgrid.yaml') ? loadCloudGridYaml(process.cwd()).name : null);\n if (!appName) {\n die('Provide app name or run from app directory');\n }\n\n const apiClient = createApiClient(loadConfig());\n\n try {\n const logs = await apiClient.logs(appName, {\n service: opts.service,\n tail: opts.tail ? parseInt(opts.tail, 10) : 100,\n });\n\n if (logs) {\n process.stdout.write(logs);\n // Ensure trailing newline\n if (!logs.endsWith('\\n')) process.stdout.write('\\n');\n } else {\n console.log('No logs available.');\n }\n } catch (err) {\n if (err instanceof ApiError && err.code === 'NOT_FOUND') {\n die(`App \"${appName}\" not found`);\n }\n throw err;\n }\n });\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport chalk from 'chalk';\nimport { die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\nimport { ApiError } from '../api-client.js';\n\nexport const statusCommand = new Command('status')\n .argument('[name]', 'App name (auto-detected from cloudgrid.yaml if in app dir)')\n .description('Show app status')\n .action(async (name?: string) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const appName = name || (existsSync('cloudgrid.yaml') ? loadCloudGridYaml(process.cwd()).name : null);\n if (!appName) {\n die('Provide app name or run from app directory');\n }\n\n const apiClient = createApiClient(loadConfig());\n\n try {\n const status = await apiClient.status(appName);\n\n console.log('');\n console.log(chalk.bold(`App: ${status.name}`));\n console.log(`Domain: ${status.domain}`);\n console.log('');\n\n // Pods table\n console.log(chalk.bold('PODS'));\n console.log('NAME'.padEnd(40) + 'STATUS'.padEnd(12) + 'READY'.padEnd(8) + 'RESTARTS');\n for (const pod of status.pods) {\n const readyStr = pod.ready ? 'Yes' : 'No';\n console.log(\n `${pod.name.padEnd(40)}${pod.status.padEnd(12)}${readyStr.padEnd(8)}${pod.restarts}`,\n );\n }\n console.log('');\n\n // Services table\n if (status.services.length > 0) {\n console.log(chalk.bold('SERVICES'));\n console.log('NAME'.padEnd(30) + 'TYPE'.padEnd(15) + 'PORTS');\n for (const svc of status.services) {\n const portsStr = Array.isArray(svc.ports)\n ? svc.ports.map((p: any) => `${p.port}→${p.targetPort}`).join(', ')\n : String(svc.ports);\n console.log(`${svc.name.padEnd(30)}${svc.type.padEnd(15)}${portsStr}`);\n }\n console.log('');\n }\n\n // Cron Jobs\n if (status.cronJobs && status.cronJobs.length > 0) {\n console.log(chalk.bold('CRON JOBS'));\n console.log(\n 'NAME'.padEnd(20) +\n 'SCHEDULE'.padEnd(18) +\n 'LAST RUN'.padEnd(14) +\n 'NEXT RUN'.padEnd(14) +\n 'STATUS'.padEnd(16) +\n 'TIMEZONE',\n );\n for (const cj of status.cronJobs) {\n console.log(\n `${(cj.name || '').padEnd(20)}${(cj.schedule || '').padEnd(18)}${(cj.lastRun || '-').padEnd(14)}${(cj.nextRun || '-').padEnd(14)}${(cj.status || '-').padEnd(16)}${cj.timezone || 'UTC'}`,\n );\n }\n console.log('');\n }\n\n // Ingress\n if (status.ingress) {\n console.log(chalk.bold('INGRESS'));\n const hosts = status.ingress.hosts?.join(', ') || status.ingress.host || 'unknown';\n console.log(`Host: ${hosts} IP: ${status.ingress.ip}`);\n console.log('');\n }\n\n // Env + secrets counts\n try {\n const [envResult, secretsResult] = await Promise.all([\n apiClient.listEnv(appName),\n apiClient.listSecrets(appName),\n ]);\n const envCount = envResult.env?.length || 0;\n const secretsCount = secretsResult.secrets?.length || 0;\n if (envCount > 0 || secretsCount > 0) {\n console.log(`\\n ENV: ${envCount} vars | SECRETS: ${secretsCount} keys`);\n }\n } catch { /* ignore */ }\n\n // Last deploy\n try {\n const eventsResult = await apiClient.listEvents(appName);\n const events = eventsResult.events || [];\n if (events.length > 0) {\n const last = events[0];\n const icon = last.status === 'success' ? '\\u2713' : last.status === 'failed' ? '\\u2717' : '\\u23F3';\n console.log('\\n LAST DEPLOY');\n console.log(` ${icon} ${last.status} ${last.sha ? last.sha.slice(0, 7) : 'N/A'} by ${last.triggered_by} (${last.source})`);\n if (last.status === 'failed' && last.error) {\n console.log(` Error: ${last.error.slice(0, 100)}`);\n }\n }\n } catch { /* ignore */ }\n } catch (err) {\n if (err instanceof ApiError && err.code === 'NOT_FOUND') {\n die(`App \"${appName}\" not found`);\n }\n throw err;\n }\n });\n","import { Command } from 'commander';\nimport { existsSync, readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport * as net from 'net';\nimport chalk from 'chalk';\nimport { loadConfig, configExists, type CloudGridConfig } from '../config.js';\n\ninterface CheckResult {\n label: string;\n ok: boolean;\n detail: string;\n}\n\nexport const doctorCommand = new Command('doctor')\n .description('Run diagnostic checks')\n .action(async () => {\n console.log(`\\n ${chalk.bold('Cloud Grid Doctor')}\\n`);\n\n const results: CheckResult[] = [];\n\n // 1. Node.js version\n results.push(checkNode());\n\n // 2. Docker running\n results.push(await checkDocker());\n\n // 3. CLI config\n const configResult = checkConfig();\n results.push(configResult.result);\n\n // 4. API reachable\n if (configResult.config) {\n results.push(await checkApiReachable(configResult.config));\n\n // 5. API auth\n results.push(await checkApiAuth(configResult.config));\n }\n\n // 6. Common ports\n const ports = [3000, 5000, 27017, 6379];\n for (const port of ports) {\n results.push(await checkPort(port));\n }\n\n // Print results\n const passed = results.filter((r) => r.ok).length;\n const total = results.length;\n for (const r of results) {\n const icon = r.ok ? chalk.green('\\u2713') : chalk.red('\\u2717');\n console.log(` ${icon} ${r.label}: ${r.detail}`);\n }\n\n const warnings = total - passed;\n console.log(\n `\\n ${passed}/${total} checks passed.${warnings > 0 ? ` ${warnings} warning${warnings > 1 ? 's' : ''}.` : ''}\\n`,\n );\n });\n\nfunction checkNode(): CheckResult {\n const version = process.version;\n const major = parseInt(version.slice(1), 10);\n return {\n label: 'Node.js',\n ok: major >= 20,\n detail: major >= 20 ? version : `${version} (need 20+)`,\n };\n}\n\nasync function checkDocker(): Promise<CheckResult> {\n try {\n execSync('docker info', { stdio: 'pipe' });\n return { label: 'Docker', ok: true, detail: 'running' };\n } catch {\n return { label: 'Docker', ok: false, detail: 'not running or not installed' };\n }\n}\n\nfunction checkConfig(): { result: CheckResult; config: CloudGridConfig | null } {\n if (!configExists()) {\n return {\n result: { label: 'CLI config', ok: false, detail: '~/.cloudgrid/config.yaml not found' },\n config: null,\n };\n }\n try {\n const config = loadConfig();\n if (!config.api_url || !config.jwt) {\n return {\n result: { label: 'CLI config', ok: false, detail: 'missing api_url or jwt' },\n config: null,\n };\n }\n return {\n result: { label: 'CLI config', ok: true, detail: '~/.cloudgrid/config.yaml found' },\n config,\n };\n } catch {\n return {\n result: { label: 'CLI config', ok: false, detail: 'failed to parse config' },\n config: null,\n };\n }\n}\n\nasync function checkApiReachable(config: CloudGridConfig): Promise<CheckResult> {\n try {\n const url = `${config.api_url.replace(/\\/+$/, '')}/healthz`;\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n return {\n label: 'API',\n ok: res.ok,\n detail: res.ok\n ? `${config.api_url} reachable (${res.status} OK)`\n : `${config.api_url} returned ${res.status}`,\n };\n } catch (err: any) {\n return { label: 'API', ok: false, detail: `${config.api_url} unreachable (${err.message})` };\n }\n}\n\nasync function checkApiAuth(config: CloudGridConfig): Promise<CheckResult> {\n try {\n const url = `${config.api_url.replace(/\\/+$/, '')}/apps`;\n const res = await fetch(url, {\n headers: { 'authorization': `Bearer ${config.jwt}` },\n signal: AbortSignal.timeout(5000),\n });\n return {\n label: 'API auth',\n ok: res.ok,\n detail: res.ok ? 'valid' : `rejected (${res.status})`,\n };\n } catch (err: any) {\n return { label: 'API auth', ok: false, detail: `failed (${err.message})` };\n }\n}\n\nfunction checkPort(port: number): Promise<CheckResult> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n resolve({ label: `Port ${port}`, ok: false, detail: 'in use' });\n } else {\n resolve({ label: `Port ${port}`, ok: false, detail: err.message });\n }\n });\n server.once('listening', () => {\n server.close(() => {\n resolve({ label: `Port ${port}`, ok: true, detail: 'free' });\n });\n });\n server.listen(port, '127.0.0.1');\n });\n}\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport inquirer from 'inquirer';\nimport { log, die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\nexport const connectCommand = new Command('connect')\n .description('Connect app to a GitHub repo for auto-deploy on push')\n .action(async () => {\n if (!existsSync('cloudgrid.yaml')) die('No cloudgrid.yaml in current directory');\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const cliConfig = loadConfig();\n const config = loadCloudGridYaml(process.cwd());\n const apiClient = createApiClient(cliConfig);\n\n let repos;\n try {\n const result = await apiClient.listRepos();\n repos = result.repos;\n } catch (err: any) {\n die(`Failed to list repos: ${err.message}`);\n }\n\n if (!repos || repos.length === 0) {\n die('No repos found. Check that the Cloud Grid GitHub App is installed on your org.');\n }\n\n const { repo } = await inquirer.prompt([{\n type: 'list',\n name: 'repo',\n message: 'Select repository:',\n choices: repos.map((r: any) => r.full_name),\n }]);\n\n const selectedRepo = repos.find((r: any) => r.full_name === repo);\n const { branch } = await inquirer.prompt([{\n type: 'input',\n name: 'branch',\n message: 'Branch to deploy:',\n default: selectedRepo?.default_branch || 'main',\n }]);\n\n try {\n await apiClient.connect(config.name, repo, branch);\n log.success(`Connected ${repo} (${branch}) → ${config.name}.cloudgrid.io`);\n log.step('Push to this branch to auto-deploy.');\n } catch (err: any) {\n die(`Failed to connect: ${err.message}`);\n }\n });\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport { log, die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\nexport const disconnectCommand = new Command('disconnect')\n .description('Disconnect app from GitHub repo (stop auto-deploy)')\n .action(async () => {\n if (!existsSync('cloudgrid.yaml')) die('No cloudgrid.yaml in current directory');\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const cliConfig = loadConfig();\n const config = loadCloudGridYaml(process.cwd());\n const apiClient = createApiClient(cliConfig);\n\n try {\n await apiClient.disconnect(config.name);\n log.success(`Disconnected ${config.name} from GitHub. Auto-deploy disabled.`);\n } catch (err: any) {\n die(`Failed to disconnect: ${err.message}`);\n }\n });\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport { log, die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\nexport const buildsCommand = new Command('builds')\n .description('Show build history')\n .argument('[name]', 'App name (defaults to current directory)')\n .option('--logs', 'Show build logs for latest build')\n .action(async (name, opts) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const cliConfig = loadConfig();\n const apiClient = createApiClient(cliConfig);\n\n const appName = name || (existsSync('cloudgrid.yaml') ? loadCloudGridYaml(process.cwd()).name : null);\n if (!appName) die('Specify app name or run from a directory with cloudgrid.yaml');\n\n try {\n const result = await apiClient.listBuilds(appName);\n const builds = result.builds || [];\n\n if (builds.length === 0) {\n log.info('No builds yet.');\n return;\n }\n\n console.log('\\n BUILDS');\n console.log(' ' + '-'.repeat(60));\n for (const b of builds) {\n const icon = b.status === 'SUCCESS' ? '\\u2713' : '\\u2717';\n console.log(` ${icon} ${b.sha || 'N/A'} ${b.status} ${b.duration_s || '?'}s ${b.started_at || ''}`);\n }\n console.log('');\n } catch (err: any) {\n die(`Failed to list builds: ${err.message}`);\n }\n });\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport { spawn } from 'child_process';\nimport { log, die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\nexport const openCommand = new Command('open')\n .description('Open app in browser')\n .argument('[name]', 'App name (defaults to current directory)')\n .action(async (name) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const appName = name || (existsSync('cloudgrid.yaml') ? loadCloudGridYaml(process.cwd()).name : null);\n if (!appName) die('Specify app name or run from a directory with cloudgrid.yaml');\n\n const cliConfig = loadConfig();\n const apiClient = createApiClient(cliConfig);\n\n try {\n const status = await apiClient.status(appName);\n const domain = status.domain || `${appName}.cloudgrid.io`;\n const url = `https://${domain}`;\n\n const platform = process.platform;\n if (platform === 'darwin' || platform === 'linux' || platform === 'win32') {\n const opener = platform === 'darwin' ? 'open' : platform === 'linux' ? 'xdg-open' : 'start';\n spawn(opener, [url], { detached: true, stdio: 'ignore' }).unref();\n } else {\n log.info(`Open: ${url}`);\n return;\n }\n log.success(`Opened ${url}`);\n } catch (err: any) {\n die(`Failed to open app: ${err.message}`);\n }\n });\n","import { Command } from 'commander';\nimport { WebSocket } from 'ws';\nimport { log, die } from '../utils.js';\nimport { loadConfig, configExists } from '../config.js';\n\nexport const sshCommand = new Command('ssh')\n .description('Open a shell in a running pod')\n .argument('<name>', 'App name')\n .option('-s, --service <service>', 'Service name (defaults to first)')\n .action(async (name, opts) => {\n if (!configExists()) die('No CLI config. Run: cloudgrid init');\n\n const config = loadConfig();\n const baseUrl = config.api_url.replace(/^http/, 'ws');\n const serviceParam = opts.service ? `?service=${encodeURIComponent(opts.service)}` : '';\n const wsUrl = `${baseUrl}/apps/${name}/exec${serviceParam}`;\n\n const headers: Record<string, string> = {};\n if (config.jwt) {\n headers['authorization'] = `Bearer ${config.jwt}`;\n }\n\n const ws = new WebSocket(wsUrl, { headers });\n\n ws.on('open', () => {\n log.info(`Connected to ${name}${opts.service ? `/${opts.service}` : ''}. Type 'exit' to disconnect.\\n`);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n\n process.stdin.on('data', (data) => {\n if (ws.readyState === ws.OPEN) ws.send(data);\n });\n });\n\n ws.on('message', (data: Buffer) => {\n process.stdout.write(data);\n });\n\n ws.on('close', () => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdin.pause();\n console.log('\\nDisconnected.');\n process.exit(0);\n });\n\n ws.on('error', (err) => {\n die(`Connection failed: ${err.message}`);\n });\n });\n","import { Command } from 'commander';\nimport { randomUUID } from 'crypto';\nimport { execSync } from 'child_process';\nimport { log, die } from '../utils.js';\nimport { saveConfig, loadConfig, configExists, detectConfig } from '../config.js';\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with Google')\n .action(async () => {\n let config: any;\n if (configExists()) {\n config = loadConfig();\n } else {\n const defaults = detectConfig();\n config = {\n api_url: defaults.api_url || 'https://api.cloudgrid.io',\n registry: defaults.registry || '',\n domain: defaults.domain || 'cloudgrid.io',\n };\n }\n\n const apiUrl = config.api_url;\n const sessionCode = randomUUID();\n const loginUrl = `${apiUrl}/auth/login?code=${sessionCode}`;\n\n log.info('Opening browser for Google authentication...');\n\n try {\n const platform = process.platform;\n if (platform === 'darwin') execSync(`open \"${loginUrl}\"`);\n else if (platform === 'linux') execSync(`xdg-open \"${loginUrl}\"`);\n else if (platform === 'win32') execSync(`start \"${loginUrl}\"`);\n else log.info(`Open this URL: ${loginUrl}`);\n } catch {\n log.info(`Open this URL: ${loginUrl}`);\n }\n\n log.info('Waiting for authentication...');\n\n const maxAttempts = 150;\n for (let i = 0; i < maxAttempts; i++) {\n await new Promise((r) => setTimeout(r, 2000));\n\n try {\n const res = await fetch(`${apiUrl}/auth/status?code=${sessionCode}`);\n const data = await res.json() as any;\n\n if (data.status === 'authenticated' && data.jwt) {\n const fullConfig = { ...config, jwt: data.jwt };\n saveConfig(fullConfig);\n\n const payload = JSON.parse(\n Buffer.from(data.jwt.split('.')[1], 'base64').toString(),\n );\n log.success(`Logged in as ${payload.email} (${payload.role})`);\n return;\n }\n\n if (data.status === 'expired') {\n die('Authentication timed out. Run `cloudgrid login` to try again.');\n }\n } catch {\n // Network error — continue polling\n }\n }\n\n die('Authentication timed out. Run `cloudgrid login` to try again.');\n });\n","import { Command } from 'commander';\nimport { log, die } from '../utils.js';\nimport { loadConfig, saveConfig, configExists } from '../config.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Log out of Cloud Grid')\n .action(async () => {\n if (!configExists()) die('Not logged in.');\n\n const config = loadConfig() as any;\n delete config.jwt;\n saveConfig(config);\n log.success('Logged out. Run `cloudgrid login` to authenticate.');\n });\n","import { Command } from 'commander';\nimport { log, die } from '../utils.js';\nimport { loadConfig, configExists, createApiClient } from '../config.js';\n\nconst adminCommand = new Command('admin')\n .description('Admin commands (invite, users, revoke)');\n\nadminCommand\n .command('invite <email>')\n .description('Invite a user')\n .requiredOption('--role <role>', 'Role: admin, developer, or viewer')\n .action(async (email, opts) => {\n if (!configExists()) die('Run: cloudgrid login');\n const apiClient = createApiClient();\n\n try {\n await apiClient.request('POST', '/admin/invite', { email, role: opts.role });\n log.success(`Invited ${email} as ${opts.role}`);\n } catch (err: any) {\n die(`Failed to invite: ${err.message}`);\n }\n });\n\nadminCommand\n .command('users')\n .description('List all users')\n .action(async () => {\n if (!configExists()) die('Run: cloudgrid login');\n const apiClient = createApiClient();\n\n try {\n const result = await apiClient.request('GET', '/admin/users') as any;\n console.log('\\n USERS');\n console.log(' ' + '-'.repeat(60));\n for (const u of result.users) {\n const status = u.last_login ? u.role : `${u.role} (pending)`;\n console.log(` ${u.email.padEnd(30)} ${status.padEnd(20)} ${u.created_at?.slice(0, 10) || ''}`);\n }\n console.log('');\n } catch (err: any) {\n die(`Failed to list users: ${err.message}`);\n }\n });\n\nadminCommand\n .command('revoke <email>')\n .description('Revoke user access')\n .action(async (email) => {\n if (!configExists()) die('Run: cloudgrid login');\n const apiClient = createApiClient();\n\n try {\n await apiClient.request('DELETE', `/admin/users/${encodeURIComponent(email)}`);\n log.success(`Revoked access for ${email}`);\n } catch (err: any) {\n die(`Failed to revoke: ${err.message}`);\n }\n });\n\nexport { adminCommand };\n","import { Command } from 'commander';\nimport { existsSync, readFileSync } from 'fs';\nimport { log, die, parseEnvFile } from '../utils.js';\nimport { configExists, createApiClient } from '../config.js';\n\nconst secretsCommand = new Command('secrets').description('Manage app secrets');\n\nsecretsCommand.command('set <name> [pairs...]').description('Set secrets (KEY=VALUE)')\n .action(async (name, pairs) => {\n if (!configExists()) die('Run: cloudgrid login');\n if (!pairs.length) die('Specify at least one KEY=VALUE pair');\n const values: Record<string, string> = {};\n for (const pair of pairs) {\n const eq = pair.indexOf('=');\n if (eq < 1) die(`Invalid format: '${pair}'. Use KEY=VALUE`);\n values[pair.slice(0, eq)] = pair.slice(eq + 1);\n }\n try {\n const result = await createApiClient().setSecrets(name, values);\n log.success(`Set ${result.keys.length} secret(s). Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nsecretsCommand.command('list <name>').description('List secret names')\n .action(async (name) => {\n if (!configExists()) die('Run: cloudgrid login');\n try {\n const result = await createApiClient().listSecrets(name);\n if (result.secrets.length === 0) { log.info('No secrets set.'); return; }\n console.log('\\n SECRETS');\n console.log(' ' + '-'.repeat(40));\n for (const s of result.secrets) console.log(` ${s.key}`);\n console.log('');\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nsecretsCommand.command('get <name> <key>').description('Show partial reveal of a secret')\n .action(async (name, key) => {\n if (!configExists()) die('Run: cloudgrid login');\n try {\n const result = await createApiClient().getSecret(name, key);\n console.log(`\\n ${result.key}: ${result.preview}\\n`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nsecretsCommand.command('remove <name> <key>').description('Remove a secret')\n .action(async (name, key) => {\n if (!configExists()) die('Run: cloudgrid login');\n try {\n await createApiClient().removeSecret(name, key);\n log.success(`Removed secret '${key}'. Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nsecretsCommand.command('import <name> <file>').description('Import secrets from .env file')\n .action(async (name, file) => {\n if (!configExists()) die('Run: cloudgrid login');\n if (!existsSync(file)) die(`File not found: ${file}`);\n const values = parseEnvFile(readFileSync(file, 'utf-8'));\n if (Object.keys(values).length === 0) die('No valid KEY=VALUE pairs found');\n try {\n const result = await createApiClient().setSecrets(name, values);\n log.success(`Imported ${result.keys.length} secret(s). Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nexport { secretsCommand };\n","import { Command } from 'commander';\nimport { existsSync, readFileSync } from 'fs';\nimport { log, die, parseEnvFile } from '../utils.js';\nimport { configExists, createApiClient } from '../config.js';\n\nconst envCommand = new Command('env').description('Manage app environment variables');\n\nenvCommand.command('set <name> [pairs...]').description('Set env vars (KEY=VALUE)')\n .action(async (name, pairs) => {\n if (!configExists()) die('Run: cloudgrid login');\n if (!pairs.length) die('Specify at least one KEY=VALUE pair');\n const values: Record<string, string> = {};\n for (const pair of pairs) {\n const eq = pair.indexOf('=');\n if (eq < 1) die(`Invalid format: '${pair}'. Use KEY=VALUE`);\n values[pair.slice(0, eq)] = pair.slice(eq + 1);\n }\n try {\n const result = await createApiClient().setEnv(name, values);\n log.success(`Set ${result.keys.length} env var(s). Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nenvCommand.command('list <name>').description('List env vars (key=value)')\n .action(async (name) => {\n if (!configExists()) die('Run: cloudgrid login');\n try {\n const result = await createApiClient().listEnv(name);\n if (result.env.length === 0) { log.info('No env vars set.'); return; }\n console.log('\\n ENV');\n console.log(' ' + '-'.repeat(50));\n for (const e of result.env) console.log(` ${e.key}=${e.value}`);\n console.log('');\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nenvCommand.command('remove <name> <key>').description('Remove an env var')\n .action(async (name, key) => {\n if (!configExists()) die('Run: cloudgrid login');\n try {\n await createApiClient().removeEnv(name, key);\n log.success(`Removed '${key}'. Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nenvCommand.command('import <name> <file>').description('Import env vars from .env file')\n .action(async (name, file) => {\n if (!configExists()) die('Run: cloudgrid login');\n if (!existsSync(file)) die(`File not found: ${file}`);\n const values = parseEnvFile(readFileSync(file, 'utf-8'));\n if (Object.keys(values).length === 0) die('No valid KEY=VALUE pairs found');\n try {\n const result = await createApiClient().setEnv(name, values);\n log.success(`Imported ${result.keys.length} env var(s). Pods restarting.`);\n } catch (err: any) { die(`Failed: ${err.message}`); }\n });\n\nexport { envCommand };\n","import { Command } from 'commander';\nimport { existsSync } from 'fs';\nimport { log, die } from '../utils.js';\nimport { loadCloudGridYaml } from '../generator/index.js';\nimport { configExists, createApiClient } from '../config.js';\n\nexport const usageCommand = new Command('usage')\n .description('Show AI usage for an app')\n .argument('[name]', 'App name (defaults to current directory)')\n .action(async (name) => {\n if (!configExists()) die('Run: cloudgrid login');\n const appName = name || (existsSync('cloudgrid.yaml') ? loadCloudGridYaml(process.cwd()).name : null);\n if (!appName) die('Specify app name or run from a directory with cloudgrid.yaml');\n\n const apiClient = createApiClient();\n try {\n const usage = await apiClient.getUsage(appName);\n const models = usage.models || {};\n const month = usage.month || new Date().toISOString().slice(0, 7);\n\n console.log(`\\n AI USAGE — ${appName} (${month})\\n`);\n\n if (!usage.total_requests || usage.total_requests === 0) {\n log.info('No AI usage this month.');\n return;\n }\n\n console.log(' MODEL REQUESTS TOKENS EST. COST');\n console.log(' ' + '-'.repeat(58));\n for (const [model, data] of Object.entries(models) as any[]) {\n const tokens = (data.input_tokens || 0) + (data.output_tokens || 0);\n const cost = (data.estimated_cost_usd || 0).toFixed(2);\n console.log(` ${model.padEnd(20)} ${String(data.requests || 0).padEnd(10)} ${String(tokens).padEnd(12)} $${cost}`);\n }\n\n const totalCost = Object.values(models).reduce((sum: number, m: any) => sum + (m.estimated_cost_usd || 0), 0);\n console.log(' ' + '-'.repeat(58));\n console.log(` Total: ${usage.total_requests} requests | ${usage.total_tokens} tokens | $${totalCost.toFixed(2)}\\n`);\n } catch (err: any) {\n die(`Failed: ${err.message}`);\n }\n });\n"],"mappings":"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","names":["Command","readFileSync","fileURLToPath","dirname","join","die","existsSync","join","join","existsSync","Command","inquirer","readFileSync","writeFileSync","mkdirSync","existsSync","copyFileSync","join","stringifyYaml","readFileSync","existsSync","join","parseYaml","existsSync","mkdirSync","join","join","mkdirSync","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","copyFileSync","join","defaultLogger","mkdirSync","join","readFileSync","writeFileSync","copyFileSync","existsSync","pkg","net","join","existsSync","parseYaml","readFileSync","Command","inquirer","join","existsSync","die","mkdirSync","copyFileSync","writeFileSync","readFileSync","stringifyYaml","Command","existsSync","writeFileSync","readFileSync","join","execa","chalk","writeFileSync","join","join","writeFileSync","chalk","join","existsSync","readFileSync","die","writeFileSync","Command","execa","Command","existsSync","readFileSync","Command","existsSync","die","readFileSync","Command","chalk","Command","die","chalk","Command","inquirer","Command","die","inquirer","Command","existsSync","Command","die","existsSync","Command","existsSync","chalk","Command","die","existsSync","chalk","Command","execSync","net","chalk","Command","chalk","execSync","Command","existsSync","inquirer","Command","existsSync","die","inquirer","Command","existsSync","Command","existsSync","die","Command","existsSync","Command","die","existsSync","Command","existsSync","Command","die","existsSync","Command","WebSocket","Command","die","WebSocket","Command","execSync","Command","execSync","die","Command","Command","die","Command","Command","die","Command","existsSync","readFileSync","Command","die","existsSync","readFileSync","Command","existsSync","readFileSync","Command","die","existsSync","readFileSync","Command","existsSync","Command","die","existsSync","dirname","fileURLToPath","readFileSync","join","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudgrid-io/cli",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Deploy apps with a single YAML file",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"registry": "https://registry.npmjs.org/"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"cloudgrid": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
14
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"test": "vitest"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"chalk": "^5.4.0",
|
|
20
|
+
"commander": "^13.0.0",
|
|
21
|
+
"execa": "^9.5.0",
|
|
22
|
+
"inquirer": "^12.0.0",
|
|
23
|
+
"ora": "^8.2.0",
|
|
24
|
+
"ws": "^8.20.0",
|
|
25
|
+
"yaml": "^2.7.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^22.0.0",
|
|
29
|
+
"@types/ws": "^8.18.1",
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"typescript": "^5.7.0",
|
|
32
|
+
"vitest": "^3.0.0"
|
|
33
|
+
},
|
|
34
|
+
"type": "module",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/",
|
|
40
|
+
"templates/",
|
|
41
|
+
"shared-services.yaml"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
redis:
|
|
2
|
+
env_var: REDIS_URL
|
|
3
|
+
local: redis://redis.sharedgrid-dev.svc.cluster.local:6379
|
|
4
|
+
production: redis://redis.sharedgrid.svc.cluster.local:6379
|
|
5
|
+
|
|
6
|
+
mongodb:
|
|
7
|
+
env_var: MONGODB_URL
|
|
8
|
+
local: mongodb://mongodb-0.mongodb.sharedgrid-dev.svc.cluster.local:27017/{app-name}?replicaSet=rs0-dev
|
|
9
|
+
production: mongodb://mongodb-0.mongodb.sharedgrid.svc.cluster.local:27017/{app-name}?replicaSet=rs0
|
|
10
|
+
|
|
11
|
+
n8n:
|
|
12
|
+
env_var: N8N_WEBHOOK_URL
|
|
13
|
+
local: http://n8n.n8n.svc.cluster.local:5678/webhook
|
|
14
|
+
production: http://n8n.n8n.svc.cluster.local:5678/webhook
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# CLOUDGRID.md — Cloud Grid Platform Instructions
|
|
2
|
+
|
|
3
|
+
## RULES
|
|
4
|
+
- Every service MUST listen on process.env.PORT (default 8080)
|
|
5
|
+
- Every service MUST expose GET /health returning HTTP 200 with JSON body
|
|
6
|
+
- NEVER hardcode API keys or secrets in source code
|
|
7
|
+
- Use cloudgrid secrets for sensitive values, cloudgrid env for config
|
|
8
|
+
- Builds are server-side — do NOT require Docker locally
|
|
9
|
+
- AI access: require('@cloudgrid/ai') — zero config, no API keys
|
|
10
|
+
|
|
11
|
+
## ENVIRONMENT VARIABLES (auto-injected, do not set manually)
|
|
12
|
+
PORT=8080
|
|
13
|
+
APP_NAME={app name from cloudgrid.yaml}
|
|
14
|
+
SERVICE_NAME={this service's key in cloudgrid.yaml}
|
|
15
|
+
NODE_ENV=production
|
|
16
|
+
AI_GATEWAY_URL=http://cloudgrid-api.cloudgrid-system.svc.cluster.local:80/ai
|
|
17
|
+
{SIBLING_SERVICE}_URL=http://{name}-app.{app}.svc.cluster.local:80
|
|
18
|
+
MONGODB_URL=mongodb://... (if requires: [mongodb])
|
|
19
|
+
REDIS_URL=redis://... (if requires: [redis] or [redis: private])
|
|
20
|
+
|
|
21
|
+
## AI SDK (@cloudgrid/ai)
|
|
22
|
+
Install: npm install @cloudgrid/ai
|
|
23
|
+
Usage:
|
|
24
|
+
const { ai } = require('@cloudgrid/ai');
|
|
25
|
+
const result = await ai.chat(prompt); // { text, model, usage }
|
|
26
|
+
const result = await ai.chat(prompt, { stream: true }); // AsyncIterable<{ text }>
|
|
27
|
+
const result = await ai.chat(messages[]); // multi-turn
|
|
28
|
+
const result = await ai.generate(prompt); // { text, model, usage }
|
|
29
|
+
const result = await ai.vision(imageBuffer, prompt); // { text, model, usage }
|
|
30
|
+
Models: claude-sonnet (default), claude-haiku (fast), claude-opus (powerful)
|
|
31
|
+
Options: { model, maxTokens, temperature, stream, system }
|
|
32
|
+
Default max_tokens: 1024 (override with { maxTokens: 4096 })
|
|
33
|
+
Timeout: 2 minutes for AI requests
|
|
34
|
+
|
|
35
|
+
## CLOUDGRID.YAML SCHEMA
|
|
36
|
+
name: string (required) — app name, becomes {name}.apps.cloudgrid.io
|
|
37
|
+
domain: string (optional) — custom domain
|
|
38
|
+
services:
|
|
39
|
+
{name}:
|
|
40
|
+
type: node | nextjs | python | static | cron (required)
|
|
41
|
+
lang: javascript | typescript (optional, node type only)
|
|
42
|
+
path: string (optional) — URL path, omit for internal-only
|
|
43
|
+
env: Record<string, string> (optional) — static env vars
|
|
44
|
+
schedule: string (cron type only) — cron expression
|
|
45
|
+
run: string (cron type only) — job | http://... | https://...
|
|
46
|
+
timezone: UTC | EST | PST (cron type only)
|
|
47
|
+
requires:
|
|
48
|
+
- mongodb
|
|
49
|
+
- redis | redis: private
|
|
50
|
+
- gcp: { services: [bigquery, pubsub, storage] }
|
|
51
|
+
|
|
52
|
+
## FILE STRUCTURE
|
|
53
|
+
cloudgrid.yaml — app config (single source of truth)
|
|
54
|
+
services/{name}/src/ — service source code
|
|
55
|
+
services/{name}/package.json — dependencies
|
|
56
|
+
services/{name}/Dockerfile — optional (auto-generated from type if missing)
|
|
57
|
+
|
|
58
|
+
## COMMANDS
|
|
59
|
+
cloudgrid login — authenticate via Google OAuth
|
|
60
|
+
cloudgrid logout — clear credentials
|
|
61
|
+
cloudgrid create <name> — create app from template or --interactive
|
|
62
|
+
cloudgrid dev — local development with hot reload + tunnels
|
|
63
|
+
cloudgrid deploy — server-side build + deploy (no Docker needed)
|
|
64
|
+
cloudgrid connect — link GitHub repo for auto-deploy on push
|
|
65
|
+
cloudgrid disconnect — stop auto-deploy
|
|
66
|
+
cloudgrid builds [name] — show build history
|
|
67
|
+
cloudgrid list — list all deployed apps
|
|
68
|
+
cloudgrid status {app} — check pods, services, deploy status
|
|
69
|
+
cloudgrid logs {app} — view logs
|
|
70
|
+
cloudgrid remove {app} — tear down app + DNS
|
|
71
|
+
cloudgrid open {app} — open app URL in browser
|
|
72
|
+
cloudgrid ssh {app} — shell into running pod
|
|
73
|
+
cloudgrid doctor — run diagnostic checks
|
|
74
|
+
cloudgrid admin invite <email> — invite user (admin only)
|
|
75
|
+
cloudgrid admin users — list users (admin only)
|
|
76
|
+
cloudgrid admin revoke <email> — revoke access (admin only)
|
|
77
|
+
cloudgrid secrets set KEY=VALUE — set sensitive config (stored in K8s Secret)
|
|
78
|
+
cloudgrid secrets list — list secret names
|
|
79
|
+
cloudgrid secrets get KEY — get secret value
|
|
80
|
+
cloudgrid secrets remove KEY — remove secret
|
|
81
|
+
cloudgrid secrets import <file> — bulk import from .env file
|
|
82
|
+
cloudgrid env set KEY=VALUE — set runtime config (no rebuild)
|
|
83
|
+
cloudgrid env list — list env vars
|
|
84
|
+
cloudgrid env remove KEY — remove env var
|
|
85
|
+
cloudgrid env import <file> — bulk import from .env file
|
|
86
|
+
cloudgrid usage — view AI token usage for current app
|
|
87
|
+
|
|
88
|
+
## HEALTH CHECK PATTERN
|
|
89
|
+
app.get('/health', (req, res) => res.json({ status: 'ok' }));
|
|
90
|
+
|
|
91
|
+
## SERVICE DISCOVERY
|
|
92
|
+
Sibling services are accessible via auto-injected URLs:
|
|
93
|
+
const apiUrl = process.env.API_URL;
|
|
94
|
+
const res = await fetch(apiUrl + '/endpoint');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM node:22-alpine AS builder
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
COPY package.json package-lock.json* ./
|
|
4
|
+
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
|
|
5
|
+
COPY . .
|
|
6
|
+
RUN mkdir -p public
|
|
7
|
+
RUN npm run build
|
|
8
|
+
|
|
9
|
+
FROM node:22-alpine
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
COPY --from=builder /app/.next/standalone ./
|
|
12
|
+
COPY --from=builder /app/.next/static ./.next/static
|
|
13
|
+
COPY --from=builder /app/public ./public
|
|
14
|
+
USER node
|
|
15
|
+
EXPOSE 8080
|
|
16
|
+
ENV PORT=8080
|
|
17
|
+
CMD ["node", "server.js"]
|