@studiometa/forge-cli 0.5.4 → 0.5.5

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/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/audit.ts","../src/utils/command-router.ts","../src/utils/resolve.ts","../src/commands/backups/options.ts","../src/commands/backups/handlers.ts","../src/commands/backups/command.ts","../src/commands/backups/help.ts","../src/commands/completion.ts","../src/commands/certificates/handlers.ts","../src/commands/certificates/command.ts","../src/commands/certificates/help.ts","../src/commands/commands/handlers.ts","../src/commands/commands/command.ts","../src/commands/commands/help.ts","../src/commands/config.ts","../src/commands/daemons/handlers.ts","../src/commands/daemons/command.ts","../src/commands/daemons/help.ts","../src/commands/databases/handlers.ts","../src/commands/databases/command.ts","../src/commands/databases/help.ts","../src/commands/database-users/handlers.ts","../src/commands/database-users/command.ts","../src/commands/database-users/help.ts","../src/utils/content-source.ts","../src/utils/drift.ts","../src/utils/print-content.ts","../src/commands/deployments/handlers.ts","../src/commands/deployments/command.ts","../src/commands/deployments/help.ts","../src/commands/env/env-diff.ts","../src/commands/env/handlers.ts","../src/commands/env/command.ts","../src/commands/env/help.ts","../src/commands/firewall-rules/handlers.ts","../src/commands/firewall-rules/command.ts","../src/commands/firewall-rules/help.ts","../src/commands/monitors/handlers.ts","../src/commands/monitors/command.ts","../src/commands/monitors/help.ts","../src/commands/nginx/handlers.ts","../src/commands/nginx/command.ts","../src/commands/nginx/help.ts","../src/commands/nginx-templates/handlers.ts","../src/commands/nginx-templates/command.ts","../src/commands/nginx-templates/help.ts","../src/commands/php/handlers.ts","../src/commands/php/command.ts","../src/commands/php/help.ts","../src/commands/recipes/handlers.ts","../src/commands/recipes/command.ts","../src/commands/recipes/help.ts","../src/commands/redirect-rules/handlers.ts","../src/commands/redirect-rules/command.ts","../src/commands/redirect-rules/help.ts","../src/commands/scheduled-jobs/handlers.ts","../src/commands/scheduled-jobs/command.ts","../src/commands/scheduled-jobs/help.ts","../src/commands/security-rules/handlers.ts","../src/commands/security-rules/command.ts","../src/commands/security-rules/help.ts","../src/commands/servers/handlers.ts","../src/commands/servers/command.ts","../src/commands/servers/help.ts","../src/commands/services/handlers.ts","../src/commands/services/command.ts","../src/commands/services/help.ts","../src/commands/sites/apply/ownership.ts","../src/commands/sites/apply/plan.ts","../src/commands/sites/apply/nginx.ts","../src/commands/sites/apply/apply.ts","../src/commands/sites/apply/site-file.ts","../src/commands/sites/apply/handler.ts","../src/commands/sites/handlers.ts","../src/commands/sites/command.ts","../src/commands/sites/help.ts","../src/commands/ssh/ssh-target.ts","../src/commands/ssh/handlers.ts","../src/commands/ssh/command.ts","../src/commands/ssh/help.ts","../src/commands/ssh-keys/handlers.ts","../src/commands/ssh-keys/sync-plan.ts","../src/commands/ssh-keys/sync.ts","../src/commands/ssh-keys/command.ts","../src/commands/ssh-keys/help.ts","../src/commands/storage-providers/handlers.ts","../src/commands/storage-providers/command.ts","../src/commands/storage-providers/help.ts","../src/commands/user/handlers.ts","../src/commands/user/command.ts","../src/commands/user/help.ts","../src/utils/args.ts","../src/cli.ts"],"sourcesContent":["import { createAuditLogger } from \"@studiometa/forge-core\";\nimport type { AuditLogger } from \"@studiometa/forge-core\";\n\n/**\n * Shared audit logger for CLI write operations.\n * Lazily initialized on first use.\n */\nlet _auditLogger: AuditLogger | null = null;\n\nexport function getCliAuditLogger(): AuditLogger {\n if (!_auditLogger) _auditLogger = createAuditLogger(\"cli\");\n return _auditLogger;\n}\n","/**\n * Generic command router factory for CLI commands.\n *\n * Eliminates boilerplate switch/case pattern in command routing.\n *\n * @example\n * ```typescript\n * import { createCommandRouter } from '../../utils/command-router.ts';\n * import { serversList, serversGet } from './handlers.ts';\n *\n * export const handleServersCommand = createCommandRouter({\n * resource: 'servers',\n * handlers: {\n * list: serversList,\n * ls: serversList,\n * get: [serversGet, 'args'],\n * },\n * });\n * ```\n */\n\nimport type { CommandContext } from \"../context.ts\";\nimport { type OutputFormat, isOutputFormat } from \"../types.ts\";\n\nimport { createContext } from \"../context.ts\";\nimport { OutputFormatter } from \"../output.ts\";\nimport { getCliAuditLogger } from \"../audit.ts\";\n\n/**\n * Handler that only receives context (e.g., list commands)\n */\nexport type ListHandler = (ctx: CommandContext) => Promise<void>;\n\n/**\n * Handler that receives args and context (e.g., get/update commands)\n */\nexport type ArgsHandler = (args: string[], ctx: CommandContext) => Promise<void>;\n\n/**\n * Handler definition - either a ListHandler or an ArgsHandler marked with 'args'\n */\nexport type Handler = ListHandler | [ArgsHandler, \"args\"];\n\n/**\n * Configuration for the command router\n */\nexport interface CommandRouterConfig {\n /** Resource name for error messages (e.g., 'servers', 'sites') */\n resource: string;\n /** Map of subcommand names to handlers */\n handlers: Record<string, Handler>;\n /**\n * Set of subcommand names that are write operations.\n * These will be recorded in the audit log on success or failure.\n */\n writeSubcommands?: ReadonlyArray<string>;\n}\n\n/**\n * Creates a command router function that dispatches to the appropriate handler.\n */\nexport function createCommandRouter(config: CommandRouterConfig) {\n return async function (\n subcommand: string,\n args: string[],\n options: Record<string, string | boolean | string[]>,\n ): Promise<void> {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const formatter = new OutputFormatter(format, options[\"no-color\"] === true);\n\n const ctx = createContext(options);\n\n const handler = config.handlers[subcommand];\n if (!handler) {\n formatter.error(`Unknown ${config.resource} subcommand: ${subcommand}`);\n process.exit(1);\n return; // Unreachable in production, but needed for tests where process.exit is mocked\n }\n\n const isWrite = config.writeSubcommands?.includes(subcommand) ?? false;\n\n if (isWrite) {\n // Sanitized args for audit log (strip token)\n const { token: _token, ...safeOptions } = options;\n try {\n if (Array.isArray(handler)) {\n await handler[0](args, ctx);\n } else {\n await handler(ctx);\n }\n getCliAuditLogger().log({\n source: \"cli\",\n resource: config.resource,\n action: subcommand,\n args: safeOptions,\n status: \"success\",\n });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n getCliAuditLogger().log({\n source: \"cli\",\n resource: config.resource,\n action: subcommand,\n args: safeOptions,\n status: \"error\",\n error: errorMessage,\n });\n throw err;\n }\n } else {\n if (Array.isArray(handler)) {\n // ArgsHandler - receives args and context\n await handler[0](args, ctx);\n } else {\n // ListHandler - receives only context\n await handler(ctx);\n }\n }\n };\n}\n","/**\n * Smart resolution utilities for --server and --site options.\n *\n * Accepts numeric IDs (used as-is) or plain strings (resolved by name/partial match).\n * In exact mode (`--exact` or `FORGE_EXACT_MATCH=1`), a plain string must match a name exactly.\n */\n\nimport { listServers, listSites, matchByName } from \"@studiometa/forge-core\";\nimport type { CliExecutorContext } from \"../context.ts\";\nimport { ValidationError } from \"../errors.ts\";\n\ninterface NamedResource {\n id: number;\n name: string;\n}\n\nconst EXACT_MATCH_HINT =\n \"Pass the numeric ID or the exact name, or turn off exact matching: remove --exact and unset FORGE_EXACT_MATCH\";\n\nfunction formatResources(resources: NamedResource[]): string {\n return resources.map((r) => ` ${r.name} (${r.id})`).join(\"\\n\");\n}\n\n/**\n * Match a --server or --site value against a list of resources.\n *\n * - Numeric string → returned as-is\n * - Exact name (case-insensitive) → its ID\n * - Exact mode: no exact name → ValidationError listing the near (partial) matches\n * - Otherwise one partial match → its ID; 0 or 2+ partial matches → ValidationError\n */\nfunction matchResourceId(\n value: string,\n resources: NamedResource[],\n kind: \"server\" | \"site\",\n scope: string,\n exactMatch: boolean,\n): string {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const { exact, partial } = matchByName(resources, value, (r) => r.name);\n\n if (exact.length === 1) {\n return String(exact[0].id);\n }\n\n if (exactMatch && exact.length === 0) {\n const candidates =\n partial.length > 0\n ? `Near matches:\\n${formatResources(partial)}`\n : `Available ${kind}s:\\n${formatResources(resources)}`;\n throw new ValidationError(`No ${kind} named \"${value}\"${scope} (exact match required)`, kind, [\n candidates,\n EXACT_MATCH_HINT,\n ]);\n }\n\n if (partial.length === 0) {\n throw new ValidationError(`No ${kind} found matching \"${value}\"${scope}`, kind, [\n `Available ${kind}s:\\n${formatResources(resources)}`,\n ]);\n }\n\n if (partial.length > 1) {\n throw new ValidationError(\n `Ambiguous ${kind} name \"${value}\" — ${partial.length} matches found`,\n kind,\n [\n `Matching ${kind}s:\\n${formatResources(partial)}`,\n \"Use a more specific name or pass the numeric ID\",\n ],\n );\n }\n\n return String(partial[0].id);\n}\n\n/**\n * Resolve a --server value to a numeric server ID string.\n *\n * - Numeric string → returned as-is (no API call)\n * - Plain string → fetch all servers, then see {@link matchServerId}\n */\nexport async function resolveServerId(value: string, execCtx: CliExecutorContext): Promise<string> {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const result = await listServers({}, execCtx);\n return matchServerId(value, result.data, execCtx.exactMatch);\n}\n\n/**\n * Resolve a --server value to a numeric server ID string, against a list of servers\n * that is already loaded, with no API call.\n *\n * - Exact name match first, then a single partial match (unless `exactMatch`)\n * - 0 matches → ValidationError listing available servers (near matches in exact mode)\n * - 2+ matches → ValidationError listing ambiguous matches\n */\nexport function matchServerId(\n value: string,\n servers: NamedResource[],\n exactMatch: boolean,\n): string {\n return matchResourceId(value, servers, \"server\", \"\", exactMatch);\n}\n\n/**\n * Resolve a --site value to a numeric site ID string.\n *\n * - Numeric string → returned as-is (no API call)\n * - Plain string → fetch all sites for the server, exact domain match first, then a single\n * partial match (unless `execCtx.exactMatch`)\n * - 0 matches → ValidationError listing available sites (near matches in exact mode)\n * - 2+ matches → ValidationError listing ambiguous matches\n */\nexport async function resolveSiteId(\n value: string,\n serverId: string,\n execCtx: CliExecutorContext,\n): Promise<string> {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const result = await listSites({ server_id: serverId }, execCtx);\n return matchResourceId(value, result.data, \"site\", ` on server ${serverId}`, execCtx.exactMatch);\n}\n","/**\n * Read and resolve the options shared by `forge backups create` and `forge backups update`.\n */\n\nimport type { ExecutorContext } from \"@studiometa/forge-core\";\nimport type { CreateBackupConfigData } from \"@studiometa/forge-api\";\n\nimport { listDatabases, listStorageProviders } from \"@studiometa/forge-core\";\n\nimport type { CommandOptions } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** Backup frequencies accepted by Forge. */\nexport const BACKUP_FREQUENCIES = [\"hourly\", \"daily\", \"weekly\", \"custom\"] as const;\n\n/**\n * Read a list option: repeated and/or comma separated (`--databases 1,2 --databases app`).\n */\nexport function listValues(value: unknown): string[] {\n return [value]\n .flat()\n .filter((v): v is string => typeof v === \"string\")\n .flatMap((v) => v.split(\",\"))\n .map((v) => v.trim())\n .filter(Boolean);\n}\n\n/**\n * Whether a value is a numeric ID.\n */\nfunction isId(value: string): boolean {\n return /^\\d+$/.test(value);\n}\n\n/**\n * Check the --frequency value. Throws a ValidationError for an unknown frequency.\n */\nexport function checkFrequency(frequency: string): void {\n if (!(BACKUP_FREQUENCIES as readonly string[]).includes(frequency)) {\n throw new ValidationError(\n `Invalid frequency \"${frequency}\": use ${BACKUP_FREQUENCIES.join(\", \")}`,\n \"frequency\",\n );\n }\n}\n\n/**\n * Parse the --retention value: an integer from 1 to 8760.\n */\nexport function parseRetention(value: unknown): number {\n const retention = Number(value);\n if (!Number.isInteger(retention) || retention < 1 || retention > 8760) {\n throw new ValidationError(\n `Invalid retention \"${String(value)}\": use a number of backups from 1 to 8760`,\n \"retention\",\n );\n }\n return retention;\n}\n\n/**\n * Resolve a storage provider ID or exact name to its numeric ID.\n */\nexport async function resolveStorageProviderId(\n value: string,\n execCtx: ExecutorContext,\n): Promise<number> {\n if (isId(value)) return Number(value);\n\n const { data } = await listStorageProviders({}, execCtx);\n const matches = data.filter((p) => p.name === value);\n\n if (matches.length === 0) {\n throw new ValidationError(`No storage provider named \"${value}\"`, \"storage-provider\", [\n \"List the storage providers with: forge storage-providers list\",\n ]);\n }\n if (matches.length > 1) {\n throw new ValidationError(\n `${matches.length} storage providers are named \"${value}\": use the ID (${matches.map((p) => p.id).join(\", \")})`,\n \"storage-provider\",\n );\n }\n return matches[0].id;\n}\n\n/**\n * Resolve database IDs or exact names to numeric IDs. Names are looked up on the server.\n */\nexport async function resolveDatabaseIds(\n values: string[],\n server_id: string,\n execCtx: ExecutorContext,\n): Promise<number[]> {\n if (values.every(isId)) return values.map(Number);\n\n const { data } = await listDatabases({ server_id }, execCtx);\n\n return values.map((value) => {\n if (isId(value)) return Number(value);\n const database = data.find((db) => db.name === value);\n if (!database) {\n throw new ValidationError(`No database named \"${value}\" on the server`, \"databases\", [\n `List the databases with: forge databases list --server ${server_id}`,\n ]);\n }\n return database.id;\n });\n}\n\n/**\n * Read the optional backup configuration fields that map one to one to the API.\n */\nexport function optionalBackupFields(\n options: CommandOptions,\n): Pick<\n CreateBackupConfigData,\n \"name\" | \"bucket\" | \"directory\" | \"day\" | \"time\" | \"cron\" | \"notification_email\"\n> {\n const fields: Record<string, string> = {};\n const map: Record<string, string> = {\n name: \"name\",\n bucket: \"bucket\",\n directory: \"directory\",\n day: \"day\",\n time: \"time\",\n cron: \"cron\",\n \"notification-email\": \"notification_email\",\n };\n for (const [option, field] of Object.entries(map)) {\n const value = options[option];\n if (typeof value === \"string\") fields[field] = value;\n }\n return fields;\n}\n","import {\n createBackupConfig,\n deleteBackupConfig,\n getBackupConfig,\n listBackupConfigs,\n updateBackupConfig,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\nimport {\n checkFrequency,\n listValues,\n optionalBackupFields,\n parseRetention,\n resolveDatabaseIds,\n resolveStorageProviderId,\n} from \"./options.ts\";\n\n/** Retention when --retention is not given: Forge requires a value. */\nconst DEFAULT_RETENTION = 5;\n\nexport async function backupsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge backups list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listBackupConfigs({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"schedule\", \"status\"],\n \"No backup configurations found.\",\n (b) => `${String(b.id).padEnd(8)} ${b.name.padEnd(20)} ${b.schedule.padEnd(12)} ${b.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function backupsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"backup_id\",\n \"forge backups get <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge backups get <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getBackupConfig({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"storage_provider_id\",\n \"provider\",\n \"bucket\",\n \"directory\",\n \"schedule\",\n \"displayable_schedule\",\n \"retention\",\n \"status\",\n \"next_run_time\",\n ]);\n }, ctx.formatter);\n}\n\nconst CREATE_USAGE =\n \"forge backups create --server <server> --storage-provider <id|name> --frequency <hourly|daily|weekly|custom> --databases <ids|names> [--retention <n>]\";\n\nexport async function backupsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const storageProvider = ctx.options[\"storage-provider\"];\n const frequency = ctx.options.frequency;\n const databases = listValues(ctx.options.databases);\n\n if (!server) {\n exitWithValidationError(\"server_id\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof storageProvider !== \"string\" || !storageProvider) {\n exitWithValidationError(\"storage-provider\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof frequency !== \"string\" || !frequency) {\n exitWithValidationError(\"frequency\", CREATE_USAGE, ctx.formatter);\n }\n\n if (databases.length === 0) {\n exitWithValidationError(\"databases\", CREATE_USAGE, ctx.formatter);\n }\n\n await runCommand(async () => {\n checkFrequency(frequency);\n const retention =\n ctx.options.retention === undefined\n ? DEFAULT_RETENTION\n : parseRetention(ctx.options.retention);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const storage_provider_id = await resolveStorageProviderId(storageProvider, execCtx);\n const database_ids = await resolveDatabaseIds(databases, server_id, execCtx);\n await createBackupConfig(\n {\n server_id,\n storage_provider_id,\n frequency,\n retention,\n database_ids,\n ...(ctx.options[\"include-new-databases\"] === true ? { include_new_databases: true } : {}),\n ...optionalBackupFields(ctx.options),\n },\n execCtx,\n );\n ctx.formatter.success(\"Backup configuration created.\");\n }, ctx.formatter);\n}\n\nconst UPDATE_USAGE =\n \"forge backups update <backup_id> --server <server> --storage-provider <id|name> --frequency <hourly|daily|weekly|custom> --retention <n> --databases <ids|names>\";\n\nexport async function backupsUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const storageProvider = ctx.options[\"storage-provider\"];\n const frequency = ctx.options.frequency;\n const databases = listValues(ctx.options.databases);\n\n if (!id) {\n exitWithValidationError(\"backup_id\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (!server) {\n exitWithValidationError(\"server_id\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (typeof storageProvider !== \"string\" || !storageProvider) {\n exitWithValidationError(\"storage-provider\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (typeof frequency !== \"string\" || !frequency) {\n exitWithValidationError(\"frequency\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (ctx.options.retention === undefined) {\n exitWithValidationError(\"retention\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (databases.length === 0) {\n exitWithValidationError(\"databases\", UPDATE_USAGE, ctx.formatter);\n }\n\n await runCommand(async () => {\n checkFrequency(frequency);\n const retention = parseRetention(ctx.options.retention);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const storage_provider_id = await resolveStorageProviderId(storageProvider, execCtx);\n const database_ids = await resolveDatabaseIds(databases, server_id, execCtx);\n await updateBackupConfig(\n {\n server_id,\n id,\n storage_provider_id,\n frequency,\n retention,\n database_ids,\n ...optionalBackupFields(ctx.options),\n },\n execCtx,\n );\n ctx.formatter.success(`Backup configuration ${id} updated.`);\n }, ctx.formatter);\n}\n\nexport async function backupsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"backup_id\",\n \"forge backups delete <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge backups delete <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteBackupConfig({ server_id, id }, execCtx);\n ctx.formatter.success(`Backup configuration ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n backupsCreate,\n backupsDelete,\n backupsGet,\n backupsList,\n backupsUpdate,\n} from \"./handlers.ts\";\n\nexport const handleBackupsCommand = createCommandRouter({\n resource: \"backups\",\n handlers: {\n list: backupsList,\n ls: backupsList,\n get: [backupsGet, \"args\"],\n create: backupsCreate,\n update: [backupsUpdate, \"args\"],\n delete: [backupsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showBackupsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge backups list\")} - List backup configurations on a server\n\n${colors.bold(\"USAGE:\")}\n forge backups list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge backups get\")} - Get backup configuration details\n\n${colors.bold(\"USAGE:\")}\n forge backups get <backup_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge backups create\")} - Create a database backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups create --server <server> --storage-provider <id|name> --frequency <frequency> --databases <ids|names> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id|name> Server ID or name (required)\n --storage-provider <id|name> Storage provider ID or exact name (required, see forge storage-providers list)\n --frequency <freq> hourly, daily, weekly or custom (required)\n --databases <ids|names> Database IDs or exact names, comma separated or repeated (required)\n --retention <n> Number of backups to keep, 1 to 8760 (default: 5)\n --time <HH:MM> Daily and weekly: time on the hour or half hour, e.g. 02:00\n --day <0-6> Weekly: day of week, 0 is Sunday\n --cron <expr> Custom: cron expression\n --bucket <bucket> Bucket (default: the storage provider bucket)\n --directory <dir> Directory in the bucket\n --name <name> Configuration name\n --notification-email <email> Email notified when a backup fails\n --include-new-databases Also back up databases created later\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLE:\")}\n forge backups create --server web-1 --storage-provider Backups --frequency daily \\\\\n --time 02:00 --retention 7 --directory web-1 --databases app,wordpress\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge backups update\")} - Update a database backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups update <backup_id> --server <server> --storage-provider <id|name> --frequency <frequency> --retention <n> --databases <ids|names> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id|name> Server ID or name (required)\n --storage-provider <id|name> Storage provider ID or exact name (required)\n --frequency <freq> hourly, daily, weekly or custom (required)\n --retention <n> Number of backups to keep, 1 to 8760 (required)\n --databases <ids|names> Database IDs or exact names, comma separated or repeated (required)\n --time <HH:MM> Daily and weekly: time on the hour or half hour\n --day <0-6> Weekly: day of week, 0 is Sunday\n --cron <expr> Custom: cron expression\n --bucket <bucket> Bucket\n --directory <dir> Directory in the bucket\n --name <name> Configuration name\n --notification-email <email> Email notified when a backup fails\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge backups delete\")} - Delete a backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups delete <backup_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge backups\")} - Manage backup configurations\n\n${colors.bold(\"USAGE:\")}\n forge backups <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List backup configurations\n get <id> Get backup configuration details\n create Create a new backup configuration\n update <id> Update a backup configuration\n delete <id> Delete a backup configuration\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge backups <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Shell completion installation command\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { colors } from \"../utils/colors.ts\";\n\nconst BASH_COMPLETION = `#!/usr/bin/env bash\n\n_forge_completions() {\n local cur prev commands subcommands options\n\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n prev=\"\\${COMP_WORDS[COMP_CWORD-1]}\"\n\n # Main commands\n commands=\"config servers s sites deployments d databases db database-users daemons env nginx certificates certs firewall-rules fw ssh ssh-keys backups storage-providers commands scheduled-jobs services php user monitors nginx-templates security-rules redirect-rules recipes completion help\"\n\n # Subcommands for each command\n local config_cmds=\"set get delete\"\n local servers_cmds=\"list ls get public-key create reboot\"\n local sites_cmds=\"list ls get apply\"\n local deployments_cmds=\"list ls deploy logs log script update-script\"\n local databases_cmds=\"list ls get\"\n local database_users_cmds=\"list ls get create delete\"\n local daemons_cmds=\"list ls get restart logs log\"\n local env_cmds=\"get update\"\n local nginx_cmds=\"get update\"\n local certificates_cmds=\"get activate\"\n local firewall_rules_cmds=\"list ls get\"\n local ssh_keys_cmds=\"list ls get sync\"\n local backups_cmds=\"list ls get create update delete\"\n local storage_providers_cmds=\"list ls get create delete\"\n local commands_cmds=\"list ls get create\"\n local scheduled_jobs_cmds=\"list ls get create delete\"\n local services_cmds=\"list ls restart\"\n local php_cmds=\"list ls config update-config max-upload-size set-max-upload-size max-execution-time set-max-execution-time opcache enable-opcache disable-opcache\"\n local user_cmds=\"get\"\n local monitors_cmds=\"list ls get create delete\"\n local nginx_templates_cmds=\"list ls get create update delete\"\n local security_rules_cmds=\"list ls get create delete\"\n local redirect_rules_cmds=\"list ls get create delete\"\n local recipes_cmds=\"list ls get run\"\n local completion_cmds=\"bash zsh fish\"\n\n # Global options\n options=\"--token --server --site --exact -f --format --no-color -h --help -v --version --name --command --content --from --to --provider --frequency --cron --type --operator --threshold --minutes --key --port --ip-address --user --private --dry-run --script --servers --domain --password --credential-id --region --size --project-type --directory --file --script-file --check --all-servers --prune --ubuntu-version --php-version --database --private-ip --ssh-port --tag --storage-provider --databases --retention --time --day --bucket --notification-email --include-new-databases --endpoint --access-key --secret-key-file --assume-role\"\n\n # Format options\n local formats=\"json human table\"\n\n # Completion logic\n case \"\\${COMP_CWORD}\" in\n 1)\n # Complete main commands\n COMPREPLY=( $(compgen -W \"\\${commands}\" -- \"\\${cur}\") )\n ;;\n 2)\n # Complete subcommands based on main command\n case \"\\${prev}\" in\n config)\n COMPREPLY=( $(compgen -W \"\\${config_cmds}\" -- \"\\${cur}\") )\n ;;\n servers|s)\n COMPREPLY=( $(compgen -W \"\\${servers_cmds}\" -- \"\\${cur}\") )\n ;;\n sites)\n COMPREPLY=( $(compgen -W \"\\${sites_cmds}\" -- \"\\${cur}\") )\n ;;\n deployments|d)\n COMPREPLY=( $(compgen -W \"\\${deployments_cmds}\" -- \"\\${cur}\") )\n ;;\n databases|db)\n COMPREPLY=( $(compgen -W \"\\${databases_cmds}\" -- \"\\${cur}\") )\n ;;\n database-users)\n COMPREPLY=( $(compgen -W \"\\${database_users_cmds}\" -- \"\\${cur}\") )\n ;;\n daemons)\n COMPREPLY=( $(compgen -W \"\\${daemons_cmds}\" -- \"\\${cur}\") )\n ;;\n env)\n COMPREPLY=( $(compgen -W \"\\${env_cmds}\" -- \"\\${cur}\") )\n ;;\n nginx)\n COMPREPLY=( $(compgen -W \"\\${nginx_cmds}\" -- \"\\${cur}\") )\n ;;\n certificates|certs)\n COMPREPLY=( $(compgen -W \"\\${certificates_cmds}\" -- \"\\${cur}\") )\n ;;\n firewall-rules|fw)\n COMPREPLY=( $(compgen -W \"\\${firewall_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n ssh-keys)\n COMPREPLY=( $(compgen -W \"\\${ssh_keys_cmds}\" -- \"\\${cur}\") )\n ;;\n backups)\n COMPREPLY=( $(compgen -W \"\\${backups_cmds}\" -- \"\\${cur}\") )\n ;;\n storage-providers)\n COMPREPLY=( $(compgen -W \"\\${storage_providers_cmds}\" -- \"\\${cur}\") )\n ;;\n commands)\n COMPREPLY=( $(compgen -W \"\\${commands_cmds}\" -- \"\\${cur}\") )\n ;;\n scheduled-jobs)\n COMPREPLY=( $(compgen -W \"\\${scheduled_jobs_cmds}\" -- \"\\${cur}\") )\n ;;\n services)\n COMPREPLY=( $(compgen -W \"\\${services_cmds}\" -- \"\\${cur}\") )\n ;;\n php)\n COMPREPLY=( $(compgen -W \"\\${php_cmds}\" -- \"\\${cur}\") )\n ;;\n user)\n COMPREPLY=( $(compgen -W \"\\${user_cmds}\" -- \"\\${cur}\") )\n ;;\n monitors)\n COMPREPLY=( $(compgen -W \"\\${monitors_cmds}\" -- \"\\${cur}\") )\n ;;\n nginx-templates)\n COMPREPLY=( $(compgen -W \"\\${nginx_templates_cmds}\" -- \"\\${cur}\") )\n ;;\n security-rules)\n COMPREPLY=( $(compgen -W \"\\${security_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n redirect-rules)\n COMPREPLY=( $(compgen -W \"\\${redirect_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n recipes)\n COMPREPLY=( $(compgen -W \"\\${recipes_cmds}\" -- \"\\${cur}\") )\n ;;\n completion)\n COMPREPLY=( $(compgen -W \"\\${completion_cmds}\" -- \"\\${cur}\") )\n ;;\n *)\n COMPREPLY=( $(compgen -W \"\\${options}\" -- \"\\${cur}\") )\n ;;\n esac\n ;;\n *)\n # Complete options and their values\n case \"\\${prev}\" in\n --format|-f)\n COMPREPLY=( $(compgen -W \"\\${formats}\" -- \"\\${cur}\") )\n ;;\n --file|--script-file)\n # Complete file paths\n COMPREPLY=( $(compgen -f -- \"\\${cur}\") )\n ;;\n --token|--server|--site|--version|--name|--command|--content|--from|--to|--provider|--frequency|--cron|--type|--operator|--threshold|--minutes|--key|--port|--ip-address|--user|--script|--servers|--domain|--password|--credential-id|--region|--size|--project-type|--directory|--ubuntu-version|--php-version|--database|--private-ip|--ssh-port|--tag|--storage-provider|--databases|--retention|--time|--day|--bucket|--notification-email|--endpoint|--access-key)\n # No completion for values requiring arguments\n COMPREPLY=()\n ;;\n *)\n COMPREPLY=( $(compgen -W \"\\${options}\" -- \"\\${cur}\") )\n ;;\n esac\n ;;\n esac\n\n return 0\n}\n\ncomplete -F _forge_completions forge\n`;\n\nconst ZSH_COMPLETION = `#compdef forge\n\n_forge() {\n local line state\n\n _arguments -C \\\\\n '1: :->command' \\\\\n '2: :->subcommand' \\\\\n '*: :->args'\n\n case $state in\n command)\n local -a commands\n commands=(\n 'config:Manage CLI configuration'\n 'servers:Manage servers'\n 's:Manage servers (alias)'\n 'sites:Manage sites'\n 'deployments:Manage deployments'\n 'd:Manage deployments (alias)'\n 'databases:Manage databases'\n 'db:Manage databases (alias)'\n 'database-users:Manage database users'\n 'daemons:Manage daemons'\n 'env:Manage environment variables'\n 'nginx:Manage nginx configuration'\n 'certificates:Manage SSL certificates'\n 'certs:Manage SSL certificates (alias)'\n 'firewall-rules:Manage firewall rules'\n 'fw:Manage firewall rules (alias)'\n 'ssh:Open an SSH session to a server'\n 'ssh-keys:Manage SSH keys'\n 'backups:Manage database backup configurations'\n 'storage-providers:Manage the storage providers of database backups'\n 'commands:Manage site commands'\n 'scheduled-jobs:Manage scheduled jobs'\n 'services:List and restart server services'\n 'php:Manage PHP versions, configuration, limits and OPcache'\n 'user:Display authenticated user profile'\n 'monitors:Manage server monitors'\n 'nginx-templates:Manage Nginx templates'\n 'security-rules:Manage site security rules'\n 'redirect-rules:Manage site redirect rules'\n 'recipes:Manage recipes'\n 'completion:Generate shell completion script'\n 'help:Show help'\n )\n _describe 'command' commands\n ;;\n subcommand)\n case $line[1] in\n config)\n local -a config_cmds\n config_cmds=(\n 'set:Save API token'\n 'get:Show current token'\n 'delete:Delete stored token'\n )\n _describe 'config command' config_cmds\n ;;\n servers|s)\n local -a servers_cmds\n servers_cmds=(\n 'list:List all servers'\n 'ls:List all servers (alias)'\n 'get:Get server details'\n 'public-key:Print the public key of the forge user'\n 'create:Create a server'\n 'reboot:Reboot a server'\n )\n _describe 'servers command' servers_cmds\n ;;\n sites)\n local -a sites_cmds\n sites_cmds=(\n 'list:List sites'\n 'ls:List sites (alias)'\n 'get:Get site details'\n 'apply:Make a site match a site file'\n )\n _describe 'sites command' sites_cmds\n ;;\n deployments|d)\n local -a deployments_cmds\n deployments_cmds=(\n 'list:List deployments'\n 'ls:List deployments (alias)'\n 'deploy:Trigger a deployment'\n 'logs:Show deployment output'\n 'log:Show deployment output (alias)'\n 'script:Show the deployment script'\n 'update-script:Update the deployment script'\n )\n _describe 'deployments command' deployments_cmds\n ;;\n databases|db)\n local -a databases_cmds\n databases_cmds=(\n 'list:List databases'\n 'ls:List databases (alias)'\n 'get:Get database details'\n )\n _describe 'databases command' databases_cmds\n ;;\n database-users)\n local -a database_users_cmds\n database_users_cmds=(\n 'list:List database users'\n 'ls:List database users (alias)'\n 'get:Get database user details'\n 'create:Create a database user'\n 'delete:Delete a database user'\n )\n _describe 'database-users command' database_users_cmds\n ;;\n daemons)\n local -a daemons_cmds\n daemons_cmds=(\n 'list:List daemons'\n 'ls:List daemons (alias)'\n 'get:Get daemon details'\n 'restart:Restart a daemon'\n 'logs:Show daemon log output'\n 'log:Show daemon log output (alias)'\n )\n _describe 'daemons command' daemons_cmds\n ;;\n env)\n local -a env_cmds\n env_cmds=(\n 'get:Get env variables'\n 'update:Update env variables'\n )\n _describe 'env command' env_cmds\n ;;\n nginx)\n local -a nginx_cmds\n nginx_cmds=(\n 'get:Get nginx config'\n 'update:Update nginx config'\n )\n _describe 'nginx command' nginx_cmds\n ;;\n certificates|certs)\n local -a certificates_cmds\n certificates_cmds=(\n 'get:Get certificate for a domain'\n 'activate:Activate a certificate'\n )\n _describe 'certificates command' certificates_cmds\n ;;\n firewall-rules|fw)\n local -a firewall_rules_cmds\n firewall_rules_cmds=(\n 'list:List firewall rules'\n 'ls:List firewall rules (alias)'\n 'get:Get firewall rule details'\n )\n _describe 'firewall-rules command' firewall_rules_cmds\n ;;\n ssh-keys)\n local -a ssh_keys_cmds\n ssh_keys_cmds=(\n 'list:List SSH keys'\n 'ls:List SSH keys (alias)'\n 'get:Get SSH key details'\n 'sync:Make server SSH keys match a file'\n )\n _describe 'ssh-keys command' ssh_keys_cmds\n ;;\n backups)\n local -a backups_cmds\n backups_cmds=(\n 'list:List backup configurations'\n 'ls:List backup configurations (alias)'\n 'get:Get backup configuration details'\n 'create:Create a backup configuration'\n 'update:Update a backup configuration'\n 'delete:Delete a backup configuration'\n )\n _describe 'backups command' backups_cmds\n ;;\n storage-providers)\n local -a storage_providers_cmds\n storage_providers_cmds=(\n 'list:List storage providers'\n 'ls:List storage providers (alias)'\n 'get:Get storage provider details'\n 'create:Create a storage provider'\n 'delete:Delete a storage provider'\n )\n _describe 'storage-providers command' storage_providers_cmds\n ;;\n commands)\n local -a commands_cmds\n commands_cmds=(\n 'list:List commands'\n 'ls:List commands (alias)'\n 'get:Get command details'\n 'create:Execute a command'\n )\n _describe 'commands command' commands_cmds\n ;;\n scheduled-jobs)\n local -a scheduled_jobs_cmds\n scheduled_jobs_cmds=(\n 'list:List scheduled jobs'\n 'ls:List scheduled jobs (alias)'\n 'get:Get scheduled job details'\n 'create:Create a scheduled job'\n 'delete:Delete a scheduled job'\n )\n _describe 'scheduled-jobs command' scheduled_jobs_cmds\n ;;\n services)\n local -a services_cmds\n services_cmds=(\n 'list:List services on a server'\n 'ls:List services on a server (alias)'\n 'restart:Restart a service'\n )\n _describe 'services command' services_cmds\n ;;\n php)\n local -a php_cmds\n php_cmds=(\n 'list:List installed PHP versions'\n 'ls:List installed PHP versions (alias)'\n 'config:Show a PHP configuration file'\n 'update-config:Replace a PHP configuration file'\n 'max-upload-size:Show the max upload size'\n 'set-max-upload-size:Set the max upload size'\n 'max-execution-time:Show the max execution time'\n 'set-max-execution-time:Set the max execution time'\n 'opcache:Show the OPcache status'\n 'enable-opcache:Enable OPcache'\n 'disable-opcache:Disable OPcache'\n )\n _describe 'php command' php_cmds\n ;;\n user)\n local -a user_cmds\n user_cmds=(\n 'get:Get the authenticated user profile'\n )\n _describe 'user command' user_cmds\n ;;\n monitors)\n local -a monitors_cmds\n monitors_cmds=(\n 'list:List monitors'\n 'ls:List monitors (alias)'\n 'get:Get monitor details'\n 'create:Create a monitor'\n 'delete:Delete a monitor'\n )\n _describe 'monitors command' monitors_cmds\n ;;\n nginx-templates)\n local -a nginx_templates_cmds\n nginx_templates_cmds=(\n 'list:List Nginx templates'\n 'ls:List Nginx templates (alias)'\n 'get:Get Nginx template details'\n 'create:Create a Nginx template'\n 'update:Update a Nginx template'\n 'delete:Delete a Nginx template'\n )\n _describe 'nginx-templates command' nginx_templates_cmds\n ;;\n security-rules)\n local -a security_rules_cmds\n security_rules_cmds=(\n 'list:List security rules'\n 'ls:List security rules (alias)'\n 'get:Get security rule details'\n 'create:Create a security rule'\n 'delete:Delete a security rule'\n )\n _describe 'security-rules command' security_rules_cmds\n ;;\n redirect-rules)\n local -a redirect_rules_cmds\n redirect_rules_cmds=(\n 'list:List redirect rules'\n 'ls:List redirect rules (alias)'\n 'get:Get redirect rule details'\n 'create:Create a redirect rule'\n 'delete:Delete a redirect rule'\n )\n _describe 'redirect-rules command' redirect_rules_cmds\n ;;\n recipes)\n local -a recipes_cmds\n recipes_cmds=(\n 'list:List all recipes'\n 'ls:List all recipes (alias)'\n 'get:Get recipe details'\n 'run:Run a recipe'\n )\n _describe 'recipes command' recipes_cmds\n ;;\n completion)\n local -a completion_cmds\n completion_cmds=(\n 'bash:Generate Bash completion script'\n 'zsh:Generate Zsh completion script'\n 'fish:Generate Fish completion script'\n )\n _describe 'completion shell' completion_cmds\n ;;\n esac\n ;;\n args)\n _arguments \\\\\n '--token[API token]:token:' \\\\\n '--server[Server ID]:server id:' \\\\\n '--site[Site ID]:site id:' \\\\\n '--exact[Match server and site names exactly]' \\\\\n '(-f --format)'{-f,--format}'[Output format]:format:(json human table)' \\\\\n '--no-color[Disable colored output]' \\\\\n '(-h --help)'{-h,--help}'[Show help]' \\\\\n '-v[Show version]' \\\\\n '--version[PHP version (php, services)]:version:' \\\\\n '--name[Name]:name:' \\\\\n '--command[Command]:command:' \\\\\n '--content[Content]:content:' \\\\\n '--from[From]:from:' \\\\\n '--to[To]:to:' \\\\\n '--provider[Provider]:provider:' \\\\\n '--frequency[Frequency]:frequency:' \\\\\n '--cron[Cron expression]:cron:' \\\\\n '--type[Type]:type:' \\\\\n '--operator[Operator]:operator:' \\\\\n '--threshold[Threshold]:threshold:' \\\\\n '--minutes[Minutes]:minutes:' \\\\\n '--key[Key]:key:' \\\\\n '--port[Port]:port:' \\\\\n '--ip-address[IP address]:ip address:' \\\\\n '--user[User]:user:' \\\\\n '--script[Script]:script:' \\\\\n '--servers[Servers]:servers:' \\\\\n '--domain[Domain]:domain:' \\\\\n '--password[Password]:password:' \\\\\n '--credential-id[Credential ID]:credential id:' \\\\\n '--region[Region]:region:' \\\\\n '--size[Size]:size:' \\\\\n '--project-type[Project type]:project type:' \\\\\n '--directory[Directory]:directory:' \\\\\n '--ubuntu-version[Ubuntu version]:ubuntu version:' \\\\\n '--php-version[PHP version]:php version:' \\\\\n '--database[Database type]:database type:' \\\\\n '--private-ip[Private IP address]:private ip address:' \\\\\n '--ssh-port[SSH port]:ssh port:' \\\\\n '--tag[Tag]:tag:' \\\\\n '--file[File path (- for stdin)]:file:_files' \\\\\n '--script-file[Deployment script file]:file:_files' \\\\\n '--all-servers[Target every server]' \\\\\n '--prune[Remove SSH keys that are not in the file]' \\\\\n '--dry-run[Print the plan and change nothing]' \\\\\n '--check[Compare with Forge, do not write]' \\\\\n '--storage-provider[Storage provider ID or name]:storage provider:' \\\\\n '--databases[Database IDs or names]:databases:' \\\\\n '--retention[Number of backups to keep]:retention:' \\\\\n '--time[Backup time (HH:MM)]:time:' \\\\\n '--day[Backup day of week (0-6)]:day:' \\\\\n '--cron[Cron expression]:cron:' \\\\\n '--bucket[Bucket]:bucket:' \\\\\n '--notification-email[Notification email]:email:' \\\\\n '--include-new-databases[Also back up new databases]' \\\\\n '--endpoint[S3 endpoint URL]:endpoint:' \\\\\n '--access-key[Access key ID]:access key:' \\\\\n '--secret-key-file[Secret key file (- for stdin)]:file:_files' \\\\\n '--assume-role[Use the EC2 instance role]'\n ;;\n esac\n}\n\n_forge \"$@\"\n`;\n\nconst FISH_COMPLETION = `# Completions for forge\n\n# Main commands\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"config\" -d \"Manage CLI configuration\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"servers\" -d \"Manage servers\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"s\" -d \"Manage servers (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"sites\" -d \"Manage sites\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"deployments\" -d \"Manage deployments\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"d\" -d \"Manage deployments (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"databases\" -d \"Manage databases\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"db\" -d \"Manage databases (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"database-users\" -d \"Manage database users\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"daemons\" -d \"Manage daemons\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"env\" -d \"Manage environment variables\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"nginx\" -d \"Manage nginx configuration\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"certificates\" -d \"Manage SSL certificates\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"certs\" -d \"Manage SSL certificates (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"firewall-rules\" -d \"Manage firewall rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"fw\" -d \"Manage firewall rules (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"ssh\" -d \"Open an SSH session to a server\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"ssh-keys\" -d \"Manage SSH keys\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"backups\" -d \"Manage database backup configurations\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"storage-providers\" -d \"Manage the storage providers of database backups\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"commands\" -d \"Manage site commands\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"scheduled-jobs\" -d \"Manage scheduled jobs\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"services\" -d \"List and restart server services\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"php\" -d \"Manage PHP versions, configuration, limits and OPcache\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"user\" -d \"Display authenticated user profile\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"monitors\" -d \"Manage server monitors\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"nginx-templates\" -d \"Manage Nginx templates\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"security-rules\" -d \"Manage site security rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"redirect-rules\" -d \"Manage site redirect rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"recipes\" -d \"Manage recipes\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"completion\" -d \"Generate shell completion script\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"help\" -d \"Show help\"\n\n# config subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"set\" -d \"Save API token\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"get\" -d \"Show current token\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"delete\" -d \"Delete stored token\"\n\n# servers subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"list\" -d \"List all servers\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"ls\" -d \"List all servers (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"get\" -d \"Get server details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"public-key\" -d \"Print the public key of the forge user\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"create\" -d \"Create a server\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"reboot\" -d \"Reboot a server\"\n\n# sites subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"list\" -d \"List sites\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"ls\" -d \"List sites (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"get\" -d \"Get site details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"apply\" -d \"Make a site match a site file\"\n\n# deployments subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"list\" -d \"List deployments\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"ls\" -d \"List deployments (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"deploy\" -d \"Trigger a deployment\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"logs\" -d \"Show deployment output\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"log\" -d \"Show deployment output (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"script\" -d \"Show the deployment script\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"update-script\" -d \"Update the deployment script\"\n\n# databases subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"list\" -d \"List databases\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"ls\" -d \"List databases (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"get\" -d \"Get database details\"\n\n# database-users subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"list\" -d \"List database users\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"ls\" -d \"List database users (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"get\" -d \"Get database user details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"create\" -d \"Create a database user\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"delete\" -d \"Delete a database user\"\n\n# daemons subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"list\" -d \"List daemons\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"ls\" -d \"List daemons (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"get\" -d \"Get daemon details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"restart\" -d \"Restart a daemon\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"logs\" -d \"Show daemon log output\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"log\" -d \"Show daemon log output (alias)\"\n\n# env subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from env\" -a \"get\" -d \"Get env variables\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from env\" -a \"update\" -d \"Update env variables\"\n\n# nginx subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx\" -a \"get\" -d \"Get nginx config\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx\" -a \"update\" -d \"Update nginx config\"\n\n# certificates subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"get\" -d \"Get certificate for a domain\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"get\" -d \"Get certificate details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"activate\" -d \"Activate a certificate\"\n\n# firewall-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"list\" -d \"List firewall rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"ls\" -d \"List firewall rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"get\" -d \"Get firewall rule details\"\n\n# ssh-keys subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"list\" -d \"List SSH keys\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"ls\" -d \"List SSH keys (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"get\" -d \"Get SSH key details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"sync\" -d \"Make server SSH keys match a file\"\n\n# backups subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"list\" -d \"List backup configurations\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"ls\" -d \"List backup configurations (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"get\" -d \"Get backup configuration details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"create\" -d \"Create a backup configuration\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"update\" -d \"Update a backup configuration\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"delete\" -d \"Delete a backup configuration\"\n\n# storage-providers subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"list\" -d \"List storage providers\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"ls\" -d \"List storage providers (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"get\" -d \"Get storage provider details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"create\" -d \"Create a storage provider\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"delete\" -d \"Delete a storage provider\"\n\n# commands subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"list\" -d \"List commands\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"ls\" -d \"List commands (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"get\" -d \"Get command details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"create\" -d \"Execute a command\"\n\n# scheduled-jobs subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"list\" -d \"List scheduled jobs\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"ls\" -d \"List scheduled jobs (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"get\" -d \"Get scheduled job details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"create\" -d \"Create a scheduled job\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"delete\" -d \"Delete a scheduled job\"\n\n# services subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"list\" -d \"List services on a server\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"ls\" -d \"List services on a server (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"restart\" -d \"Restart a service\"\n\n# php subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"list\" -d \"List installed PHP versions\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"ls\" -d \"List installed PHP versions (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"config\" -d \"Show a PHP configuration file\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"update-config\" -d \"Replace a PHP configuration file\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"max-upload-size\" -d \"Show the max upload size\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"set-max-upload-size\" -d \"Set the max upload size\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"max-execution-time\" -d \"Show the max execution time\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"set-max-execution-time\" -d \"Set the max execution time\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"opcache\" -d \"Show the OPcache status\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"enable-opcache\" -d \"Enable OPcache\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"disable-opcache\" -d \"Disable OPcache\"\n\n# user subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from user\" -a \"get\" -d \"Get the authenticated user profile\"\n\n# monitors subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"list\" -d \"List monitors\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"ls\" -d \"List monitors (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"get\" -d \"Get monitor details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"create\" -d \"Create a monitor\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"delete\" -d \"Delete a monitor\"\n\n# nginx-templates subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"list\" -d \"List Nginx templates\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"ls\" -d \"List Nginx templates (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"get\" -d \"Get Nginx template details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"create\" -d \"Create a Nginx template\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"update\" -d \"Update a Nginx template\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"delete\" -d \"Delete a Nginx template\"\n\n# security-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"list\" -d \"List security rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"ls\" -d \"List security rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"get\" -d \"Get security rule details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"create\" -d \"Create a security rule\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"delete\" -d \"Delete a security rule\"\n\n# redirect-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"list\" -d \"List redirect rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"ls\" -d \"List redirect rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"get\" -d \"Get redirect rule details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"create\" -d \"Create a redirect rule\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"delete\" -d \"Delete a redirect rule\"\n\n# recipes subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"list\" -d \"List all recipes\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"ls\" -d \"List all recipes (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"get\" -d \"Get recipe details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"run\" -d \"Run a recipe\"\n\n# completion subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"bash\" -d \"Install Bash completion\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"zsh\" -d \"Install Zsh completion\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"fish\" -d \"Install Fish completion\"\n\n# Global options\ncomplete -c forge -l token -d \"API token\" -r\ncomplete -c forge -l server -d \"Server ID\" -r\ncomplete -c forge -l site -d \"Site ID\" -r\ncomplete -c forge -l exact -d \"Match server and site names exactly\"\ncomplete -c forge -s f -l format -d \"Output format\" -xa \"json human table\"\ncomplete -c forge -l no-color -d \"Disable colored output\"\ncomplete -c forge -s h -l help -d \"Show help\"\ncomplete -c forge -s v -l version -d \"Show version\"\ncomplete -c forge -l name -d \"Name\" -r\ncomplete -c forge -l command -d \"Command\" -r\ncomplete -c forge -l content -d \"Content\" -r\ncomplete -c forge -l from -d \"From\" -r\ncomplete -c forge -l to -d \"To\" -r\ncomplete -c forge -l provider -d \"Provider\" -r\ncomplete -c forge -l frequency -d \"Frequency\" -r\ncomplete -c forge -l cron -d \"Cron expression\" -r\ncomplete -c forge -l type -d \"Type\" -r\ncomplete -c forge -l operator -d \"Operator\" -r\ncomplete -c forge -l threshold -d \"Threshold\" -r\ncomplete -c forge -l minutes -d \"Minutes\" -r\ncomplete -c forge -l key -d \"Key\" -r\ncomplete -c forge -l port -d \"Port\" -r\ncomplete -c forge -l ip-address -d \"IP address\" -r\ncomplete -c forge -l user -d \"User\" -r\ncomplete -c forge -l script -d \"Script\" -r\ncomplete -c forge -l servers -d \"Servers\" -r\ncomplete -c forge -l domain -d \"Domain\" -r\ncomplete -c forge -l password -d \"Password\" -r\ncomplete -c forge -l credential-id -d \"Credential ID\" -r\ncomplete -c forge -l region -d \"Region\" -r\ncomplete -c forge -l size -d \"Size\" -r\ncomplete -c forge -l project-type -d \"Project type\" -r\ncomplete -c forge -l directory -d \"Directory\" -r\ncomplete -c forge -l file -d \"File path (- for stdin)\" -r -F\ncomplete -c forge -l script-file -d \"Deployment script file\" -r -F\ncomplete -c forge -l all-servers -d \"Target every server\"\ncomplete -c forge -l prune -d \"Remove SSH keys that are not in the file\"\ncomplete -c forge -l ubuntu-version -d \"Ubuntu version\" -r\ncomplete -c forge -l php-version -d \"PHP version\" -r\ncomplete -c forge -l database -d \"Database type\" -r\ncomplete -c forge -l private-ip -d \"Private IP address\" -r\ncomplete -c forge -l ssh-port -d \"SSH port\" -r\ncomplete -c forge -l tag -d \"Tag\" -r\ncomplete -c forge -l dry-run -d \"Print the plan and change nothing\"\ncomplete -c forge -l check -d \"Compare with Forge, do not write\"\ncomplete -c forge -l storage-provider -d \"Storage provider ID or name\" -r\ncomplete -c forge -l databases -d \"Database IDs or names\" -r\ncomplete -c forge -l retention -d \"Number of backups to keep\" -r\ncomplete -c forge -l time -d \"Backup time (HH:MM)\" -r\ncomplete -c forge -l day -d \"Backup day of week (0-6)\" -r\ncomplete -c forge -l cron -d \"Cron expression\" -r\ncomplete -c forge -l bucket -d \"Bucket\" -r\ncomplete -c forge -l notification-email -d \"Notification email\" -r\ncomplete -c forge -l include-new-databases -d \"Also back up new databases\"\ncomplete -c forge -l endpoint -d \"S3 endpoint URL\" -r\ncomplete -c forge -l access-key -d \"Access key ID\" -r\ncomplete -c forge -l secret-key-file -d \"Secret key file (- for stdin)\" -r -F\ncomplete -c forge -l assume-role -d \"Use the EC2 instance role\"\n`;\n\n/**\n * Get the appropriate completion file path for the shell\n */\nfunction getCompletionPath(shell: string): string {\n const home = homedir();\n\n switch (shell) {\n case \"bash\":\n return join(home, \".local/share/bash-completion/completions/forge\");\n case \"zsh\":\n return join(home, \".zfunc/_forge\");\n case \"fish\": {\n const configHome = process.env[\"XDG_CONFIG_HOME\"] ?? join(home, \".config\");\n return join(configHome, \"fish/completions/forge.fish\");\n }\n default:\n throw new Error(`Unknown shell: ${shell}`);\n }\n}\n\nexport function showCompletionHelp(): void {\n console.log(`\n${colors.bold(\"forge completion\")} - Install shell completion\n\n${colors.bold(\"USAGE:\")}\n forge completion <shell> [--print]\n\n${colors.bold(\"SHELLS:\")}\n bash Install Bash completion\n zsh Install Zsh completion\n fish Install Fish completion\n\n${colors.bold(\"OPTIONS:\")}\n --print Print completion script instead of installing\n\n${colors.bold(\"INSTALLATION:\")}\n The completion script is automatically installed to the appropriate\n standard directory for your shell. After installation, restart your\n shell to activate completions.\n\n ${colors.bold(\"Bash:\")}\n forge completion bash\n # Installs to: ~/.local/share/bash-completion/completions/forge\n # Then run: exec bash\n\n ${colors.bold(\"Zsh:\")}\n forge completion zsh\n # Installs to: ~/.zfunc/_forge\n # Ensure fpath includes ~/.zfunc (add to ~/.zshrc before compinit):\n # fpath=(~/.zfunc $fpath)\n # Then run: exec zsh\n\n ${colors.bold(\"Fish:\")}\n forge completion fish\n # Installs to: ~/.config/fish/completions/forge.fish\n # Completions are loaded automatically\n\n${colors.bold(\"PRINT ONLY:\")}\n Use --print to output the script without installing:\n\n forge completion bash --print > my-completion.sh\n forge completion zsh --print | less\n`);\n}\n\nexport function handleCompletionCommand(\n shell: string,\n options: Record<string, string | boolean | string[]> = {},\n): void {\n const shouldPrint = options[\"print\"] !== undefined;\n\n const shellLower = shell.toLowerCase();\n\n // Get completion script\n let script: string;\n switch (shellLower) {\n case \"bash\":\n script = BASH_COMPLETION;\n break;\n case \"zsh\":\n script = ZSH_COMPLETION;\n break;\n case \"fish\":\n script = FISH_COMPLETION;\n break;\n default:\n console.error(\n `${colors.red(\"✗\")} Unknown shell: ${shell}. Supported shells: bash, zsh, fish`,\n );\n console.error(`Run ${colors.cyan(\"forge completion --help\")} for usage information.`);\n process.exit(1);\n return;\n }\n\n // If --print flag, just output the script\n if (shouldPrint) {\n process.stdout.write(script);\n return;\n }\n\n // Otherwise, install to appropriate directory\n const installPath = getCompletionPath(shellLower);\n const dir = installPath.substring(0, installPath.lastIndexOf(\"/\"));\n\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(installPath, script, \"utf8\");\n\n console.log(\n `${colors.green(\"✓\")} Installed ${shell} completion to ${colors.cyan(installPath)}`,\n );\n console.log();\n console.log(colors.bold(\"Next steps:\"));\n\n switch (shellLower) {\n case \"bash\":\n console.log(` 1. Restart your shell: ${colors.cyan(\"exec bash\")}`);\n console.log(` 2. Or source the file: ${colors.cyan(`source ${installPath}`)}`);\n break;\n case \"zsh\":\n console.log(\n ` 1. Ensure ${colors.cyan(\"~/.zfunc\")} is in your $fpath (add to ~/.zshrc before compinit):`,\n );\n console.log(` ${colors.cyan(\"fpath=(~/.zfunc $fpath)\")}`);\n console.log(` 2. Restart your shell: ${colors.cyan(\"exec zsh\")}`);\n break;\n case \"fish\":\n console.log(` Completions are loaded automatically. Restart fish if needed.`);\n break;\n }\n } catch (error) {\n console.error(\n `${colors.red(\"✗\")} Failed to install completion: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n}\n","import { getCertificate, activateCertificate } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerSiteDomainRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string; domain: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const domain = String(ctx.options.domain ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n if (!domain) {\n exitWithValidationError(\"domain_id\", usage, ctx.formatter);\n }\n\n return { server, site, domain };\n}\n\nexport async function certificatesGet(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge certificates get --server <server_id> --site <site_id> --domain <domain_id>\";\n\n const { server, site, domain } = requireServerSiteDomainRaw(ctx, usage);\n\n // Allow positional domain_id as first arg for convenience\n const domainId = args[0] || domain;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getCertificate({ server_id, site_id, domain_id: domainId }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"verification_method\",\n \"key_type\",\n \"status\",\n \"request_status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function certificatesActivate(args: string[], ctx: CommandContext): Promise<void> {\n const usage =\n \"forge certificates activate --server <server_id> --site <site_id> --domain <domain_id>\";\n\n const { server, site, domain } = requireServerSiteDomainRaw(ctx, usage);\n\n // Allow positional domain_id as first arg for convenience\n const domainId = args[0] || domain;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await activateCertificate({ server_id, site_id, domain_id: domainId }, execCtx);\n ctx.formatter.success(`Certificate for domain ${domainId} activated.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { certificatesGet, certificatesActivate } from \"./handlers.ts\";\n\nexport const handleCertificatesCommand = createCommandRouter({\n resource: \"certificates\",\n handlers: {\n get: [certificatesGet, \"args\"],\n activate: [certificatesActivate, \"args\"],\n },\n writeSubcommands: [\"activate\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showCertificatesHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge certificates get\")} - Get certificate for a domain\n\n${colors.bold(\"USAGE:\")}\n forge certificates get --server <server_id> --site <site_id> --domain <domain_id>\n`);\n } else if (subcommand === \"activate\") {\n console.log(`\n${colors.bold(\"forge certificates activate\")} - Activate a certificate\n\n${colors.bold(\"USAGE:\")}\n forge certificates activate --server <server_id> --site <site_id> --domain <domain_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge certificates\")} - Manage SSL certificates\n\n${colors.bold(\"USAGE:\")}\n forge certificates <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge certs\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get certificate for a domain\n activate Activate a certificate\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --domain <id> Domain record ID (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"NOTE:\")}\n In Forge v2, certificates are per-domain. Use domains to manage certificates.\n\nRun ${colors.cyan(\"forge certificates <subcommand> --help\")} for details.\n`);\n }\n}\n","import { createCommand, getCommand, listCommands } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function commandsList(ctx: CommandContext): Promise<void> {\n const usage = \"forge commands list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listCommands({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"status\", \"created_at\"],\n \"No commands found.\",\n (c) =>\n `${String(c.id).padEnd(8)} ${c.command.padEnd(50)} ${c.status.padEnd(12)} ${c.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function commandsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge commands get <command_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"command_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getCommand({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"status\",\n \"user_id\",\n \"duration\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function commandsCreate(ctx: CommandContext): Promise<void> {\n const usage = \"forge commands create --server <server_id> --site <site_id> --command <command>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const command = String(ctx.options.command ?? \"\");\n\n if (!command) {\n exitWithValidationError(\"command\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await createCommand({ server_id, site_id, command }, execCtx);\n ctx.formatter.success(\"Command queued for execution.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { commandsCreate, commandsGet, commandsList } from \"./handlers.ts\";\n\nexport const handleCommandsCommand = createCommandRouter({\n resource: \"commands\",\n handlers: {\n list: commandsList,\n ls: commandsList,\n get: [commandsGet, \"args\"],\n create: commandsCreate,\n },\n writeSubcommands: [\"create\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showCommandsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge commands list\")} - List commands executed on a site\n\n${colors.bold(\"USAGE:\")}\n forge commands list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge commands get\")} - Get command details\n\n${colors.bold(\"USAGE:\")}\n forge commands get <command_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge commands create\")} - Execute a command on a site\n\n${colors.bold(\"USAGE:\")}\n forge commands create --server <server_id> --site <site_id> --command <command> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --command <cmd> Command to execute (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge commands\")} - Manage site commands\n\n${colors.bold(\"USAGE:\")}\n forge commands <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List commands\n get <id> Get command details\n create Execute a command on a site\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge commands <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Config command — manage forge configuration\n */\n\nimport {\n createConfigStore,\n setToken,\n deleteToken,\n getToken,\n getOrganizationSlug,\n setOrganizationSlug,\n} from \"../config.ts\";\nimport { OutputFormatter } from \"../output.ts\";\nimport { type OutputFormat, isOutputFormat } from \"../types.ts\";\nimport { colors } from \"../utils/colors.ts\";\n\nexport function showConfigHelp(): void {\n console.log(`\n${colors.bold(\"forge config\")} - Manage CLI configuration\n\n${colors.bold(\"USAGE:\")}\n forge config <subcommand> [key] [value]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n set <key> <value> Save a config value\n get Show current configuration (masked)\n delete Delete all stored configuration\n\n${colors.bold(\"CONFIG KEYS:\")}\n apiToken Forge API token (scoped, from Forge dashboard)\n organizationSlug Default organization slug (e.g. 'studio-meta')\n\n${colors.bold(\"EXAMPLES:\")}\n forge config set apiToken YOUR_FORGE_TOKEN\n forge config set organizationSlug studio-meta\n forge config get\n forge config delete\n`);\n}\n\nexport function handleConfigCommand(\n subcommand: string,\n args: string[],\n options: Record<string, string | boolean | string[]>,\n): void {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const formatter = new OutputFormatter(format, options[\"no-color\"] === true);\n\n const store = createConfigStore();\n\n switch (subcommand) {\n case \"set\": {\n const [key, value] = args;\n if (!key || !value) {\n formatter.error(\"Usage: forge config set <key> <value>\");\n formatter.info(\"Keys: apiToken, organizationSlug\");\n process.exit(1);\n return;\n }\n\n switch (key) {\n case \"apiToken\":\n setToken(value, store);\n formatter.success(\"API token saved.\");\n break;\n case \"organizationSlug\":\n setOrganizationSlug(value, store);\n formatter.success(`Organization slug set to \"${value}\".`);\n break;\n default:\n formatter.error(`Unknown config key: ${key}`);\n formatter.info(\"Valid keys: apiToken, organizationSlug\");\n process.exit(1);\n }\n break;\n }\n\n case \"get\": {\n const token = getToken(store);\n const orgSlug = getOrganizationSlug(store);\n\n if (format === \"json\") {\n formatter.output({\n apiToken: token ? maskToken(token) : null,\n organizationSlug: orgSlug ?? null,\n });\n } else {\n if (token) {\n console.log(`apiToken: ${maskToken(token)}`);\n } else {\n formatter.warning(\"No API token configured.\");\n }\n if (orgSlug) {\n console.log(`organizationSlug: ${orgSlug}`);\n } else {\n formatter.warning(\"No organization slug configured.\");\n }\n\n if (!token || !orgSlug) {\n formatter.info(\"Run: forge config set <key> <value>\");\n }\n }\n break;\n }\n\n case \"delete\": {\n deleteToken(store);\n formatter.success(\"Configuration deleted.\");\n break;\n }\n\n default:\n showConfigHelp();\n break;\n }\n}\n\nfunction maskToken(token: string): string {\n return token.length > 8\n ? `${token.slice(0, 4)}${\"*\".repeat(token.length - 8)}${token.slice(-4)}`\n : \"****\";\n}\n","import {\n listDaemons,\n getDaemon,\n getDaemonLog,\n restartDaemon,\n updateDaemon,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function daemonsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge daemons list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDaemons({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"user\", \"status\"],\n \"No daemons found.\",\n (d) => `${String(d.id).padEnd(8)} ${d.command.padEnd(50)} ${d.user.padEnd(16)} ${d.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function daemonsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons get <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons get <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDaemon({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"directory\",\n \"processes\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function daemonsLogs(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons logs <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons logs <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDaemonLog({ server_id, id }, execCtx);\n if (result.data) {\n ctx.formatter.outputText(result.data);\n } else {\n ctx.formatter.info(\"No log output available.\");\n }\n }, ctx.formatter);\n}\n\nexport async function daemonsUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const options: Record<string, string> = { server_id, id, name };\n if (ctx.options.config) {\n options.config = String(ctx.options.config);\n }\n const result = await updateDaemon(options as never, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"directory\",\n \"processes\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function daemonsRestart(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons restart <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons restart <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await restartDaemon({ server_id, id }, execCtx);\n ctx.formatter.success(`Daemon ${id} restarted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { daemonsList, daemonsGet, daemonsLogs, daemonsRestart, daemonsUpdate } from \"./handlers.ts\";\n\nexport const handleDaemonsCommand = createCommandRouter({\n resource: \"daemons\",\n handlers: {\n list: daemonsList,\n ls: daemonsList,\n get: [daemonsGet, \"args\"],\n logs: [daemonsLogs, \"args\"],\n log: [daemonsLogs, \"args\"],\n restart: [daemonsRestart, \"args\"],\n update: [daemonsUpdate, \"args\"],\n },\n writeSubcommands: [\"restart\", \"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDaemonsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge daemons list\")} - List daemons on a server\n\n${colors.bold(\"USAGE:\")}\n forge daemons list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge daemons get\")} - Get daemon details\n\n${colors.bold(\"USAGE:\")}\n forge daemons get <daemon_id> --server <server_id>\n`);\n } else if (subcommand === \"logs\" || subcommand === \"log\") {\n console.log(`\n${colors.bold(\"forge daemons logs\")} - Show the log output of a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons logs <daemon_id> --server <server_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge daemons update\")} - Update a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons update <daemon_id> --server <server_id> --name <name> [--config <config>]\n`);\n } else if (subcommand === \"restart\") {\n console.log(`\n${colors.bold(\"forge daemons restart\")} - Restart a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons restart <daemon_id> --server <server_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge daemons\")} - Manage daemons\n\n${colors.bold(\"USAGE:\")}\n forge daemons <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List daemons\n get <id> Get daemon details\n logs <id> Show the log output of a daemon\n update <id> Update a daemon\n restart <id> Restart a daemon\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge daemons <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listDatabases, getDatabase } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function databasesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge databases list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDatabases({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No databases found.\",\n (db) => `${String(db.id).padEnd(8)} ${db.name.padEnd(30)} ${db.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function databasesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"database_id\",\n \"forge databases get <database_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge databases get <database_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDatabase({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { databasesList, databasesGet } from \"./handlers.ts\";\n\nexport const handleDatabasesCommand = createCommandRouter({\n resource: \"databases\",\n handlers: {\n list: databasesList,\n ls: databasesList,\n get: [databasesGet, \"args\"],\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDatabasesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge databases list\")} - List databases on a server\n\n${colors.bold(\"USAGE:\")}\n forge databases list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge databases get\")} - Get database details\n\n${colors.bold(\"USAGE:\")}\n forge databases get <database_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge databases\")} - Manage databases\n\n${colors.bold(\"USAGE:\")}\n forge databases <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge db\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List databases\n get <id> Get database details\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge databases <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createDatabaseUser,\n deleteDatabaseUser,\n getDatabaseUser,\n listDatabaseUsers,\n updateDatabaseUser,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function databaseUsersList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDatabaseUsers({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No database users found.\",\n (u) => `${String(u.id).padEnd(8)} ${u.name.padEnd(30)} ${u.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function databaseUsersGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users get <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users get <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDatabaseUser({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n const password = String(ctx.options.password ?? \"\");\n const databasesRaw = ctx.options.databases;\n const databases = Array.isArray(databasesRaw)\n ? databasesRaw.map(Number)\n : databasesRaw\n ? [Number(databasesRaw)]\n : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n if (!password) {\n exitWithValidationError(\n \"password\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createDatabaseUser(\n { server_id, name, password, ...(databases ? { databases } : {}) },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const password = ctx.options.password != null ? String(ctx.options.password) : undefined;\n const databaseIdsRaw = ctx.options[\"database-ids\"] ?? ctx.options.database_ids;\n const database_ids = Array.isArray(databaseIdsRaw)\n ? databaseIdsRaw.map(Number)\n : databaseIdsRaw\n ? [Number(databaseIdsRaw)]\n : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users update <user_id> --server <server_id> [--password <password>] [--database-ids <ids>]\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users update <user_id> --server <server_id> [--password <password>] [--database-ids <ids>]\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await updateDatabaseUser(\n {\n server_id,\n id,\n ...(password !== undefined ? { password } : {}),\n ...(database_ids ? { database_ids } : {}),\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users delete <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users delete <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteDatabaseUser({ server_id, id }, execCtx);\n ctx.formatter.success(`Database user ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n databaseUsersCreate,\n databaseUsersDelete,\n databaseUsersGet,\n databaseUsersList,\n databaseUsersUpdate,\n} from \"./handlers.ts\";\n\nexport const handleDatabaseUsersCommand = createCommandRouter({\n resource: \"database-users\",\n handlers: {\n list: databaseUsersList,\n ls: databaseUsersList,\n get: [databaseUsersGet, \"args\"],\n create: databaseUsersCreate,\n update: [databaseUsersUpdate, \"args\"],\n delete: [databaseUsersDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDatabaseUsersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge database-users list\")} - List database users on a server\n\n${colors.bold(\"USAGE:\")}\n forge database-users list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge database-users get\")} - Get database user details\n\n${colors.bold(\"USAGE:\")}\n forge database-users get <user_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge database-users create\")} - Create a new database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users create --server <server_id> --name <name> --password <password> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> Database user name (required)\n --password <pass> User password (required)\n --databases <ids> Comma-separated database IDs to grant access to (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge database-users update\")} - Update a database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users update <user_id> --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --password <pass> New password (optional)\n --database-ids <ids> Comma-separated database IDs (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge database-users delete\")} - Delete a database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users delete <user_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge database-users\")} - Manage database users\n\n${colors.bold(\"USAGE:\")}\n forge database-users <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List database users\n get <id> Get database user details\n create Create a new database user\n update <id> Update a database user\n delete <id> Delete a database user\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge database-users <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Read the content of an update command from a file, stdin or an inline option.\n */\n\nimport { readFileSync } from \"node:fs\";\n\nimport type { CommandOptions } from \"../context.ts\";\nimport type { OutputFormatter } from \"../output.ts\";\nimport type { OptionValue } from \"./args.ts\";\n\nimport { exitWithError } from \"../error-handler.ts\";\nimport { ValidationError } from \"../errors.ts\";\n\nexport interface ContentSource {\n /** What the content is, in lower case, e.g. \"deployment script\". */\n label: string;\n /** Usage line shown in validation errors. */\n usage: string;\n formatter: OutputFormatter;\n}\n\n/**\n * Exit when the content is empty, so Forge never gets a blank file.\n */\nfunction assertNotEmpty(content: string, field: string, source: ContentSource): void {\n if (!content.trim()) {\n const label = source.label.charAt(0).toUpperCase() + source.label.slice(1);\n exitWithError(new ValidationError(`${label} is empty`, field), source.formatter);\n }\n}\n\n/**\n * Read content from a file path, or from stdin when the path is \"-\".\n * Exits with a validation error when the path is missing, the file cannot be read or it is empty.\n */\nexport function readContentFile(\n path: OptionValue | undefined,\n field: string,\n source: ContentSource,\n): string {\n if (typeof path !== \"string\" || !path) {\n exitWithError(\n new ValidationError(`--${field} requires a path (use - for stdin)`, field, [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n let content: string;\n try {\n content = readFileSync(path === \"-\" ? 0 : path, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n exitWithError(\n new ValidationError(`Cannot read ${source.label} from ${path}: ${reason}`, field),\n source.formatter,\n );\n }\n\n assertNotEmpty(content, field, source);\n return content;\n}\n\n/**\n * Read content from exactly one of `--file <path|->` or `--content <string>`.\n * Exits with a validation error when both or none are given, or when the content is empty.\n */\nexport function readContentOption(options: CommandOptions, source: ContentSource): string {\n const { file, content } = options;\n\n if (file !== undefined && content !== undefined) {\n exitWithError(\n new ValidationError(\"Use either --file or --content, not both\", \"file\", [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n if (file !== undefined) {\n return readContentFile(file, \"file\", source);\n }\n\n if (content === undefined) {\n exitWithError(\n new ValidationError(`Missing ${source.label}: use --file or --content`, \"file\", [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n // `--content` without a value parses as `true`: treat it as empty content.\n const inline = typeof content === \"string\" ? content : \"\";\n assertNotEmpty(inline, \"content\", source);\n return inline;\n}\n","/**\n * Compare local content with the content on Forge for `--check`.\n */\n\nimport { diff } from \"node:util\";\n\nimport type { OutputFormatter } from \"../output.ts\";\n\nimport { ExitCode } from \"../error-handler.ts\";\n\n/**\n * Normalize CRLF to LF and drop a single trailing newline,\n * so editor and platform differences do not count as drift.\n */\nexport function normalizeContent(text: string): string {\n const lf = text.replaceAll(\"\\r\\n\", \"\\n\");\n return lf.endsWith(\"\\n\") ? lf.slice(0, -1) : lf;\n}\n\nfunction toLines(normalized: string): string[] {\n return normalized === \"\" ? [] : normalized.split(\"\\n\");\n}\n\ninterface DiffLine {\n op: \" \" | \"-\" | \"+\";\n text: string;\n /** Number of remote lines before this line. */\n remoteBefore: number;\n /** Number of local lines before this line. */\n localBefore: number;\n}\n\n/**\n * Build a unified-style line diff from `remote` to `local`, with `context`\n * unchanged lines around each change. Returns an empty string when both\n * are equal after normalization.\n */\nexport function unifiedDiff(remote: string, local: string, context = 3): string {\n const remoteText = normalizeContent(remote);\n const localText = normalizeContent(local);\n // Return early: util.diff also throws on two empty arrays (Node 24).\n if (remoteText === localText) {\n return \"\";\n }\n\n // util.diff marks lines only in its first argument with 1 and lines only in its second with -1.\n const entries = diff(toLines(remoteText), toLines(localText));\n\n let remoteCount = 0;\n let localCount = 0;\n const lines: DiffLine[] = entries.map(([op, text]) => {\n const line: DiffLine = {\n op: op === 0 ? \" \" : op === 1 ? \"-\" : \"+\",\n text,\n remoteBefore: remoteCount,\n localBefore: localCount,\n };\n if (op !== -1) remoteCount++;\n if (op !== 1) localCount++;\n return line;\n });\n\n // Group changes into hunks: a gap of more than 2 × context unchanged lines starts a new hunk.\n const changes = lines.flatMap((line, index) => (line.op === \" \" ? [] : [index]));\n const groups: number[][] = [];\n for (const index of changes) {\n const group = groups.at(-1);\n if (group && index - group[group.length - 1] - 1 <= 2 * context) {\n group.push(index);\n } else {\n groups.push([index]);\n }\n }\n\n const output = [\"--- remote\", \"+++ local\"];\n for (const group of groups) {\n const start = Math.max(0, group[0] - context);\n const end = Math.min(lines.length, group[group.length - 1] + context + 1);\n const hunk = lines.slice(start, end);\n const remoteLength = hunk.filter((line) => line.op !== \"+\").length;\n const localLength = hunk.filter((line) => line.op !== \"-\").length;\n // An empty side points at the line before the hunk, as in GNU diff.\n const remoteStart = hunk[0].remoteBefore + (remoteLength > 0 ? 1 : 0);\n const localStart = hunk[0].localBefore + (localLength > 0 ? 1 : 0);\n output.push(`@@ -${remoteStart},${remoteLength} +${localStart},${localLength} @@`);\n for (const line of hunk) {\n output.push(`${line.op}${line.text}`);\n }\n }\n\n return output.join(\"\\n\");\n}\n\n/**\n * A difference found by `--check`: `text` for human output, `json` for json output.\n */\nexport interface Drift {\n text: string;\n json: unknown;\n}\n\n/**\n * Print the result of a `--check` and set exit code 1 when the local content differs from Forge.\n * It sets `process.exitCode` and does not call `process.exit`, so a long diff\n * written to a pipe is not cut. JSON output is `{ inSync: true }` or `{ inSync: false, diff }`.\n */\nexport function reportDrift(label: string, drift: Drift | null, formatter: OutputFormatter): void {\n const name = label.charAt(0).toUpperCase() + label.slice(1);\n\n if (formatter.isJson()) {\n formatter.output(drift ? { inSync: false, diff: drift.json } : { inSync: true });\n } else if (drift) {\n console.log(drift.text);\n formatter.error(`${name} differs from Forge.`);\n } else {\n formatter.success(`${name} is in sync with Forge.`);\n }\n\n if (drift) {\n process.exitCode = ExitCode.GENERAL_ERROR;\n }\n}\n\n/**\n * Check `local` against `remote` as text and report a line diff.\n */\nexport function reportTextDrift(\n label: string,\n remote: string,\n local: string,\n formatter: OutputFormatter,\n): void {\n const text = unifiedDiff(remote, local);\n reportDrift(label, text ? { text, json: text } : null, formatter);\n}\n","/**\n * Print file content fetched from Forge, such as a configuration or a script.\n */\n\n/**\n * Write the content as it is, with a newline only when it does not end with one,\n * so `forge <command> get > file` round-trips with `--file file --check` without drift.\n */\nexport function printContent(content: string): void {\n process.stdout.write(content.endsWith(\"\\n\") ? content : `${content}\\n`);\n}\n","import {\n listDeployments,\n deploySiteAndWait,\n getDeploymentLog,\n getDeploymentScript,\n updateDeploymentScript,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ApiError } from \"../../errors.ts\";\nimport { readContentFile, readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function deploymentsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments list --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments list --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listDeployments({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"status\", \"commit\", \"started_at\"],\n \"No deployments found.\",\n (d) =>\n `${String(d.id).padEnd(8)} ${d.status.padEnd(12)} ${(d.commit.hash ?? \"—\").padEnd(10)} ${d.started_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function deploymentsLogs(args: string[], ctx: CommandContext): Promise<void> {\n const [deploymentId] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments logs [deployment_id] --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments logs [deployment_id] --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n\n let deployment_id = deploymentId;\n if (!deployment_id) {\n const deployments = await listDeployments({ server_id, site_id }, execCtx);\n if (deployments.data.length === 0) {\n ctx.formatter.info(\"No deployments found.\");\n return;\n }\n deployment_id = String(deployments.data[0].id);\n }\n\n const result = await getDeploymentLog({ server_id, site_id, deployment_id }, execCtx);\n if (result.data) {\n ctx.formatter.outputText(result.data);\n } else {\n ctx.formatter.info(\"No log output available.\");\n }\n }, ctx.formatter);\n}\n\nexport async function deploymentsScript(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments script --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments script --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getDeploymentScript({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function deploymentsUpdateScript(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge deployments update-script --server <server_id> --site <site_id> (--file <path|-> | --content <script>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const script = readContentOption(ctx.options, {\n label: \"deployment script\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getDeploymentScript({ server_id, site_id }, execCtx);\n reportTextDrift(\"deployment script\", remote.data, script, ctx.formatter);\n return;\n }\n\n await updateDeploymentScript({ server_id, site_id, content: script }, execCtx);\n ctx.formatter.success(\"Deployment script updated.\");\n }, ctx.formatter);\n}\n\nexport async function deploymentsDeploy(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge deployments deploy --server <server_id> --site <site_id> [--script-file <path>]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const streamLogs = Boolean(ctx.options.stream);\n const scriptFile = ctx.options[\"script-file\"];\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const script =\n scriptFile === undefined\n ? undefined\n : readContentFile(scriptFile, \"script-file\", {\n label: \"deployment script\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n\n // Upload the script first: a failure throws here, so the deploy never starts.\n if (script !== undefined) {\n await updateDeploymentScript({ server_id, site_id, content: script }, execCtx);\n process.stderr.write(\"Deployment script updated.\\n\");\n }\n\n const result = await deploySiteAndWait(\n {\n server_id,\n site_id,\n // Use either progress callback OR log streaming, not both\n onProgress: streamLogs\n ? undefined\n : ({ status, elapsed_ms }) => {\n process.stderr.write(`\\rDeploying… ${status} (${(elapsed_ms / 1000).toFixed(1)}s)`);\n },\n onLog: streamLogs\n ? (chunk) => {\n process.stdout.write(chunk);\n }\n : undefined,\n },\n execCtx,\n );\n\n // Separate the final status message from preceding output: in stream mode the\n // last log chunk has no trailing newline, otherwise clear the progress line.\n if (streamLogs) {\n process.stdout.write(\"\\n\");\n } else {\n process.stderr.write(\"\\n\");\n }\n\n const elapsedSec = (result.data.elapsed_ms / 1000).toFixed(1);\n\n // Output full log if we didn't stream it (needed for both success and failure).\n if (!streamLogs && result.data.log) {\n ctx.formatter.output(result.data.log);\n }\n\n if (result.data.status === \"success\") {\n ctx.formatter.success(`Deployment succeeded for site ${site_id} (${elapsedSec}s).`);\n } else {\n // Throw so the failure propagates to the exit code (non-zero) and the audit log\n // records status \"error\" instead of \"success\".\n throw new ApiError(`Deployment failed for site ${site_id} (${elapsedSec}s).`);\n }\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n deploymentsList,\n deploymentsDeploy,\n deploymentsLogs,\n deploymentsScript,\n deploymentsUpdateScript,\n} from \"./handlers.ts\";\n\nexport const handleDeploymentsCommand = createCommandRouter({\n resource: \"deployments\",\n handlers: {\n list: deploymentsList,\n ls: deploymentsList,\n deploy: deploymentsDeploy,\n logs: [deploymentsLogs, \"args\"],\n log: [deploymentsLogs, \"args\"],\n script: deploymentsScript,\n \"update-script\": deploymentsUpdateScript,\n },\n writeSubcommands: [\"deploy\", \"update-script\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDeploymentsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge deployments list\")} - List deployments for a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"logs\" || subcommand === \"log\") {\n console.log(`\n${colors.bold(\"forge deployments logs\")} - Show output of a deployment (latest if no id)\n\n${colors.bold(\"USAGE:\")}\n forge deployments logs [deployment_id] --server <server_id> --site <site_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"script\") {\n console.log(`\n${colors.bold(\"forge deployments script\")} - Show the deployment script of a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments script --server <server_id> --site <site_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json ({ content }), human (raw script)\n\n${colors.bold(\"EXAMPLES:\")}\n forge deployments script --server 123 --site 456 > deploy.sh\n`);\n } else if (subcommand === \"update-script\") {\n console.log(`\n${colors.bold(\"forge deployments update-script\")} - Update the deployment script of a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments update-script --server <server_id> --site <site_id> --file <path>\n forge deployments update-script --server <server_id> --site <site_id> --content <script>\n forge deployments update-script --server <server_id> --site <site_id> --file <path> --check\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the script from a file (use - for stdin)\n --content <str> Script content\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. An empty script is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge deployments update-script --server 123 --site 456 --file deploy.sh\n cat deploy.sh | forge deployments update-script --server 123 --site 456 --file -\n forge deployments update-script --server 123 --site 456 --file deploy.sh --check\n`);\n } else if (subcommand === \"deploy\") {\n console.log(`\n${colors.bold(\"forge deployments deploy\")} - Trigger a deployment\n\n${colors.bold(\"USAGE:\")}\n forge deployments deploy --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --script-file <path> Upload this deployment script before deploying (use - for stdin).\n If the upload fails, the deployment does not start.\n --stream Stream deployment logs in real-time (default: show progress)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge deployments\")} - Manage deployments\n\n${colors.bold(\"USAGE:\")}\n forge deployments <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge d\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List deployments for a site\n deploy Trigger a deployment\n logs Show output of a deployment (latest if no id)\n script Show the deployment script\n update-script Update the deployment script from a file, stdin or a string\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Script file, - for stdin (for update-script)\n --content <str> Script content (for update-script)\n --check Compare with Forge, do not write (for update-script)\n --script-file <path> Upload this script before deploying (for deploy)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge deployments <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Compare two .env files by variable name, without exposing any value.\n */\n\nimport type { Drift } from \"../../utils/drift.ts\";\n\nexport interface EnvDiff {\n /** Names only in the local file. */\n added: string[];\n /** Names only on Forge. */\n removed: string[];\n /** Names in both, with a different value. */\n changed: string[];\n}\n\nconst NAME = /^[A-Za-z_][A-Za-z0-9_.]*$/;\n\n/**\n * Find the closing quote of a quoted value. `\\` escapes a character in double quotes only.\n * Returns -1 when the value is not closed.\n */\nfunction closingQuote(value: string, quote: string): number {\n for (let index = 1; index < value.length; index++) {\n if (quote === '\"' && value[index] === \"\\\\\") {\n index++;\n } else if (value[index] === quote) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * Parse a .env file into a map of name to value, with the dotenv rules used by Laravel:\n * an optional `export ` prefix, quoted values that can span lines, and ` #` inline comments\n * after unquoted values. Blank lines, comments and lines without a valid name are ignored,\n * so a part of a value can never show as a name.\n */\nexport function parseEnv(content: string): Map<string, string> {\n const variables = new Map<string, string>();\n const lines = content.split(/\\r?\\n/);\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index].trim();\n const separator = line.indexOf(\"=\");\n const name = line\n .slice(0, Math.max(separator, 0))\n .trim()\n .replace(/^export\\s+/, \"\");\n if (!NAME.test(name)) {\n continue;\n }\n\n let value = line.slice(separator + 1).trim();\n const quote = value[0];\n if (quote === '\"' || quote === \"'\") {\n let end = closingQuote(value, quote);\n while (end === -1 && index + 1 < lines.length) {\n index++;\n value += `\\n${lines[index]}`;\n end = closingQuote(value, quote);\n }\n value = value.slice(1, end === -1 ? undefined : end);\n } else {\n value = value.replace(/\\s+#.*$/, \"\");\n }\n variables.set(name, value);\n }\n return variables;\n}\n\n/**\n * Compare the variables of two .env files. Returns only variable names.\n */\nexport function diffEnv(remote: string, local: string): EnvDiff {\n const remoteVars = parseEnv(remote);\n const localVars = parseEnv(local);\n const result: EnvDiff = { added: [], removed: [], changed: [] };\n\n for (const [name, value] of localVars) {\n if (!remoteVars.has(name)) {\n result.added.push(name);\n } else if (remoteVars.get(name) !== value) {\n result.changed.push(name);\n }\n }\n\n for (const name of remoteVars.keys()) {\n if (!localVars.has(name)) {\n result.removed.push(name);\n }\n }\n\n return result;\n}\n\n/**\n * Turn an env diff into a drift report, or null when the variables are the same.\n * The report holds variable names only, never values, because CI logs are often shared.\n */\nexport function envDrift(remote: string, local: string): Drift | null {\n const result = diffEnv(remote, local);\n const lines = [\n ...result.added.map((name) => `+ ${name} (added)`),\n ...result.removed.map((name) => `- ${name} (removed)`),\n ...result.changed.map((name) => `~ ${name} (changed)`),\n ];\n return lines.length > 0 ? { text: lines.join(\"\\n\"), json: result } : null;\n}\n","import { getEnv, updateEnv } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\nimport { envDrift } from \"./env-diff.ts\";\n\nexport async function envGet(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge env get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge env get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getEnv({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function envUpdate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge env update --server <server_id> --site <site_id> (--file <path|-> | --content <content>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const content = readContentOption(ctx.options, {\n label: \"environment file\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getEnv({ server_id, site_id }, execCtx);\n reportDrift(\"environment file\", envDrift(remote.data, content), ctx.formatter);\n return;\n }\n\n await updateEnv({ server_id, site_id, content }, execCtx);\n ctx.formatter.success(\"Environment variables updated.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { envGet, envUpdate } from \"./handlers.ts\";\n\nexport const handleEnvCommand = createCommandRouter({\n resource: \"env\",\n handlers: {\n get: envGet,\n update: envUpdate,\n },\n writeSubcommands: [\"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showEnvHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge env get\")} - Get environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env get --server <server_id> --site <site_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge env update\")} - Update environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env update --server <server_id> --site <site_id> --file <path>\n forge env update --server <server_id> --site <site_id> --file <path> --check\n forge env update --server <server_id> --site <site_id> --content <env_content>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New env content\n --check Compare with the .env on Forge and do not write.\n Exit 0 when in sync, 1 when different. Prints only variable\n names (added, removed, changed), never values.\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge env update --server 123 --site 456 --file .env\n cat .env | forge env update --server 123 --site 456 --file -\n forge env update --server 123 --site 456 --file .env --check\n`);\n } else {\n console.log(`\n${colors.bold(\"forge env\")} - Manage environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get environment variables\n update Update environment variables\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Content file, - for stdin (for update)\n --content <str> New env content (for update)\n --check Compare with Forge, do not write (for update)\n -f, --format <fmt> Output format: json, human\n\nRun ${colors.cyan(\"forge env <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listFirewallRules, getFirewallRule } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function firewallRulesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge firewall-rules list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listFirewallRules({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"port\", \"type\", \"ip_address\", \"status\"],\n \"No firewall rules found.\",\n (r) =>\n `${String(r.id).padEnd(8)} ${r.name.padEnd(20)} ${String(r.port).padEnd(8)} ${r.type.padEnd(8)} ${(r.ip_address ?? \"any\").padEnd(16)} ${r.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function firewallRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"firewall_rule_id\",\n \"forge firewall-rules get <rule_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge firewall-rules get <rule_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getFirewallRule({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"port\",\n \"type\",\n \"ip_address\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { firewallRulesList, firewallRulesGet } from \"./handlers.ts\";\n\nexport const handleFirewallRulesCommand = createCommandRouter({\n resource: \"firewall-rules\",\n handlers: {\n list: firewallRulesList,\n ls: firewallRulesList,\n get: [firewallRulesGet, \"args\"],\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showFirewallRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge firewall-rules list\")} - List firewall rules on a server\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge firewall-rules get\")} - Get firewall rule details\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules get <rule_id> --server <server_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge firewall-rules\")} - Manage firewall rules\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge fw\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List firewall rules\n get <id> Get firewall rule details\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge firewall-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","import { createMonitor, deleteMonitor, getMonitor, listMonitors } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function monitorsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge monitors list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listMonitors({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"type\", \"operator\", \"threshold\", \"state\"],\n \"No monitors found.\",\n (m) =>\n `${String(m.id).padEnd(8)} ${m.type.padEnd(20)} ${m.operator.padEnd(8)} ${String(m.threshold).padEnd(6)} ${m.state}`,\n );\n }, ctx.formatter);\n}\n\nexport async function monitorsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"monitor_id\",\n \"forge monitors get <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors get <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getMonitor({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"operator\",\n \"threshold\",\n \"minutes\",\n \"state\",\n \"state_changed_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function monitorsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const type = String(ctx.options.type ?? \"\");\n const operator = String(ctx.options.operator ?? \"\");\n const threshold = Number(ctx.options.threshold ?? 0);\n const notify = String(ctx.options.notify ?? \"\");\n const minutes = Number(ctx.options.minutes ?? 0);\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n if (!type) {\n exitWithValidationError(\n \"type\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n if (!operator) {\n exitWithValidationError(\n \"operator\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createMonitor(\n { server_id, type, operator, threshold, notify, minutes },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"operator\",\n \"threshold\",\n \"minutes\",\n \"state\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function monitorsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"monitor_id\",\n \"forge monitors delete <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors delete <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteMonitor({ server_id, id }, execCtx);\n ctx.formatter.success(`Monitor ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { monitorsCreate, monitorsDelete, monitorsGet, monitorsList } from \"./handlers.ts\";\n\nexport const handleMonitorsCommand = createCommandRouter({\n resource: \"monitors\",\n handlers: {\n list: monitorsList,\n ls: monitorsList,\n get: [monitorsGet, \"args\"],\n create: monitorsCreate,\n delete: [monitorsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showMonitorsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge monitors list\")} - List monitors on a server\n\n${colors.bold(\"USAGE:\")}\n forge monitors list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge monitors get\")} - Get monitor details\n\n${colors.bold(\"USAGE:\")}\n forge monitors get <monitor_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge monitors create\")} - Create a new monitor\n\n${colors.bold(\"USAGE:\")}\n forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --type <type> Monitor type (required)\n --operator <op> Comparison operator (required)\n --threshold <num> Alert threshold value (required)\n --minutes <num> Duration in minutes (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge monitors delete\")} - Delete a monitor\n\n${colors.bold(\"USAGE:\")}\n forge monitors delete <monitor_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge monitors\")} - Manage server monitors\n\n${colors.bold(\"USAGE:\")}\n forge monitors <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List monitors\n get <id> Get monitor details\n create Create a new monitor\n delete <id> Delete a monitor\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge monitors <subcommand> --help\")} for details.\n`);\n }\n}\n","import { getNginxConfig, updateNginxConfig } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function nginxGet(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge nginx get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getNginxConfig({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function nginxUpdate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge nginx update --server <server_id> --site <site_id> (--file <path|-> | --content <content>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const content = readContentOption(ctx.options, {\n label: \"nginx configuration\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getNginxConfig({ server_id, site_id }, execCtx);\n reportTextDrift(\"nginx configuration\", remote.data, content, ctx.formatter);\n return;\n }\n\n await updateNginxConfig({ server_id, site_id, content }, execCtx);\n ctx.formatter.success(\"Nginx configuration updated.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { nginxGet, nginxUpdate } from \"./handlers.ts\";\n\nexport const handleNginxCommand = createCommandRouter({\n resource: \"nginx\",\n handlers: {\n get: nginxGet,\n update: nginxUpdate,\n },\n writeSubcommands: [\"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showNginxHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge nginx get\")} - Get nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx get --server <server_id> --site <site_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge nginx update\")} - Update nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx update --server <server_id> --site <site_id> --file <path>\n forge nginx update --server <server_id> --site <site_id> --file <path> --check\n forge nginx update --server <server_id> --site <site_id> --content <nginx_config>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New nginx config\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge nginx update --server 123 --site 456 --file nginx.conf\n cat nginx.conf | forge nginx update --server 123 --site 456 --file -\n forge nginx update --server 123 --site 456 --file nginx.conf --check\n`);\n } else {\n console.log(`\n${colors.bold(\"forge nginx\")} - Manage nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get nginx configuration\n update Update nginx configuration\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Content file, - for stdin (for update)\n --content <str> New nginx config (for update)\n --check Compare with Forge, do not write (for update)\n\nRun ${colors.cyan(\"forge nginx <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createNginxTemplate,\n deleteNginxTemplate,\n getNginxTemplate,\n listNginxTemplates,\n updateNginxTemplate,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function nginxTemplatesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listNginxTemplates({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"created_at\"],\n \"No Nginx templates found.\",\n (t) => `${String(t.id).padEnd(8)} ${t.name.padEnd(40)} ${t.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates get <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates get <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getNginxTemplate({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\", \"content\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n const content = String(ctx.options.content ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n if (!content) {\n exitWithValidationError(\n \"content\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createNginxTemplate({ server_id, name, content }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates update <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates update <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const name = ctx.options.name ? String(ctx.options.name) : undefined;\n const content = ctx.options.content ? String(ctx.options.content) : undefined;\n const result = await updateNginxTemplate({ server_id, id, name, content }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates delete <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates delete <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteNginxTemplate({ server_id, id }, execCtx);\n ctx.formatter.success(`Nginx template ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n nginxTemplatesCreate,\n nginxTemplatesDelete,\n nginxTemplatesGet,\n nginxTemplatesList,\n nginxTemplatesUpdate,\n} from \"./handlers.ts\";\n\nexport const handleNginxTemplatesCommand = createCommandRouter({\n resource: \"nginx-templates\",\n handlers: {\n list: nginxTemplatesList,\n ls: nginxTemplatesList,\n get: [nginxTemplatesGet, \"args\"],\n create: nginxTemplatesCreate,\n update: [nginxTemplatesUpdate, \"args\"],\n delete: [nginxTemplatesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showNginxTemplatesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge nginx-templates list\")} - List Nginx templates on a server\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge nginx-templates get\")} - Get Nginx template details\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates get <template_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge nginx-templates create\")} - Create a new Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates create --server <server_id> --name <name> --content <content> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> Template name (required)\n --content <text> Template content (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge nginx-templates update\")} - Update an Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates update <template_id> --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> New template name (optional)\n --content <text> New template content (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge nginx-templates delete\")} - Delete an Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates delete <template_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge nginx-templates\")} - Manage Nginx templates\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List Nginx templates\n get <id> Get Nginx template details\n create Create a new Nginx template\n update <id> Update an Nginx template\n delete <id> Delete an Nginx template\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge nginx-templates <subcommand> --help\")} for details.\n`);\n }\n}\n","import type { ExecutorContext } from \"@studiometa/forge-core\";\nimport {\n disablePhpOpcache,\n enablePhpOpcache,\n getPhpConfig,\n getPhpMaxExecutionTime,\n getPhpMaxUploadSize,\n getPhpOpcache,\n listPhpVersions,\n PHP_CONFIG_TYPES,\n updatePhpConfig,\n updatePhpMaxExecutionTime,\n updatePhpMaxUploadSize,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\nimport { exitWithError, exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nconst CONFIG_USAGE =\n \"forge php config --server <server_id> --version <version> --type <cli|fpm|pool> [--user <user>]\";\nconst UPDATE_CONFIG_USAGE =\n \"forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> (--file <path|-> | --content <content>) [--user <user>] [--check]\";\n\n/**\n * Return the --server option, or exit with a validation error when it is missing.\n */\nfunction requireServer(ctx: CommandContext, usage: string): string {\n const server = String(ctx.options.server ?? \"\");\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n return server;\n}\n\n/**\n * Resolve the server and run `fn` with its ID, with the CLI error handling.\n */\nasync function withServer(\n ctx: CommandContext,\n server: string,\n fn: (server_id: string, execCtx: ExecutorContext) => Promise<void>,\n): Promise<void> {\n await runCommand(async () => {\n const execCtx = ctx.createExecutorContext(ctx.getToken());\n const server_id = await resolveServerId(server, execCtx);\n await fn(server_id, execCtx);\n }, ctx.formatter);\n}\n\ninterface ConfigTarget {\n version: string;\n type: string;\n user?: string;\n}\n\n/**\n * Read --version, --type and --user for the config commands.\n * Exits with a validation error when --version is missing, --type is not cli, fpm or pool,\n * or --user is given for a type other than pool.\n */\nfunction requireConfigTarget(ctx: CommandContext, usage: string): ConfigTarget {\n const { version, type, user } = ctx.options;\n\n if (typeof version !== \"string\" || !version) {\n exitWithValidationError(\"version\", usage, ctx.formatter);\n }\n\n if (typeof type !== \"string\" || !(PHP_CONFIG_TYPES as readonly string[]).includes(type)) {\n const message = typeof type === \"string\" ? `Invalid --type \"${type}\"` : \"type is required\";\n exitWithError(\n new ValidationError(message, \"type\", [\n `Valid types: ${PHP_CONFIG_TYPES.join(\", \")}`,\n `Usage: ${usage}`,\n ]),\n ctx.formatter,\n );\n }\n\n if (typeof user === \"string\" && user && type !== \"pool\") {\n exitWithError(\n new ValidationError(`--user applies to --type pool only, not \"${type}\"`, \"user\", [\n `Usage: ${usage}`,\n ]),\n ctx.formatter,\n );\n }\n\n return { version, type, user: typeof user === \"string\" ? user : undefined };\n}\n\n/**\n * Parse a whole number argument, or exit with a validation error.\n */\nfunction requireWholeNumber(\n value: string | undefined,\n field: string,\n usage: string,\n ctx: CommandContext,\n): number {\n if (value === undefined || !/^\\d+$/.test(value)) {\n const message =\n value === undefined ? `${field} is required` : `${field} must be a whole number: \"${value}\"`;\n exitWithError(new ValidationError(message, field, [`Usage: ${usage}`]), ctx.formatter);\n }\n return Number(value);\n}\n\n/**\n * List the PHP versions installed on a server.\n */\nexport async function phpList(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php list --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const result = await listPhpVersions({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"version\", \"binary_name\", \"status\"],\n \"No PHP versions installed.\",\n (v) =>\n `${String(v.id).padEnd(8)} ${v.version.padEnd(6)} ${v.binary_name.padEnd(10)} ${v.status}`,\n );\n });\n}\n\n/**\n * Print a PHP configuration file (cli, fpm or pool).\n */\nexport async function phpConfig(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, CONFIG_USAGE);\n const target = requireConfigTarget(ctx, CONFIG_USAGE);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const result = await getPhpConfig({ server_id, ...target }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n });\n}\n\n/**\n * Replace a PHP configuration file, or compare it with Forge when --check is set.\n */\nexport async function phpUpdateConfig(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, UPDATE_CONFIG_USAGE);\n const target = requireConfigTarget(ctx, UPDATE_CONFIG_USAGE);\n const label = `PHP ${target.type} configuration`;\n const content = readContentOption(ctx.options, {\n label,\n usage: UPDATE_CONFIG_USAGE,\n formatter: ctx.formatter,\n });\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n if (ctx.options.check) {\n const remote = await getPhpConfig({ server_id, ...target }, execCtx);\n reportTextDrift(label, remote.data, content, ctx.formatter);\n return;\n }\n\n await updatePhpConfig({ server_id, ...target, content }, execCtx);\n ctx.formatter.success(`${label} updated.`);\n });\n}\n\n/**\n * Print the PHP max upload size, in megabytes.\n */\nexport async function phpMaxUploadSize(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php max-upload-size --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpMaxUploadSize({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ max_upload_size: data });\n } else {\n console.log(`${data} MB`);\n }\n });\n}\n\n/**\n * Set the PHP max upload size, in megabytes.\n */\nexport async function phpSetMaxUploadSize(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge php set-max-upload-size <megabytes> --server <server_id>\";\n const size = requireWholeNumber(args[0], \"megabytes\", usage, ctx);\n const server = requireServer(ctx, usage);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await updatePhpMaxUploadSize({ server_id, size }, execCtx);\n ctx.formatter.success(`PHP max upload size set to ${size} MB.`);\n });\n}\n\n/**\n * Print the PHP max execution time, in seconds.\n */\nexport async function phpMaxExecutionTime(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php max-execution-time --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpMaxExecutionTime({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ max_execution_time: data });\n } else {\n console.log(`${data} seconds`);\n }\n });\n}\n\n/**\n * Set the PHP max execution time, in seconds.\n */\nexport async function phpSetMaxExecutionTime(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge php set-max-execution-time <seconds> --server <server_id>\";\n const seconds = requireWholeNumber(args[0], \"seconds\", usage, ctx);\n const server = requireServer(ctx, usage);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await updatePhpMaxExecutionTime({ server_id, seconds }, execCtx);\n ctx.formatter.success(`PHP max execution time set to ${seconds} seconds.`);\n });\n}\n\n/**\n * Print whether OPcache is enabled.\n */\nexport async function phpOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpOpcache({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ opcache_enabled: data });\n } else {\n console.log(`OPcache is ${data ? \"enabled\" : \"disabled\"}.`);\n }\n });\n}\n\n/**\n * Enable OPcache.\n */\nexport async function phpEnableOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php enable-opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await enablePhpOpcache({ server_id }, execCtx);\n ctx.formatter.success(\"OPcache enabled.\");\n });\n}\n\n/**\n * Disable OPcache.\n */\nexport async function phpDisableOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php disable-opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await disablePhpOpcache({ server_id }, execCtx);\n ctx.formatter.success(\"OPcache disabled.\");\n });\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n phpConfig,\n phpDisableOpcache,\n phpEnableOpcache,\n phpList,\n phpMaxExecutionTime,\n phpMaxUploadSize,\n phpOpcache,\n phpSetMaxExecutionTime,\n phpSetMaxUploadSize,\n phpUpdateConfig,\n} from \"./handlers.ts\";\n\nexport const handlePhpCommand = createCommandRouter({\n resource: \"php\",\n handlers: {\n list: phpList,\n ls: phpList,\n config: phpConfig,\n \"update-config\": phpUpdateConfig,\n \"max-upload-size\": phpMaxUploadSize,\n \"set-max-upload-size\": [phpSetMaxUploadSize, \"args\"],\n \"max-execution-time\": phpMaxExecutionTime,\n \"set-max-execution-time\": [phpSetMaxExecutionTime, \"args\"],\n opcache: phpOpcache,\n \"enable-opcache\": phpEnableOpcache,\n \"disable-opcache\": phpDisableOpcache,\n },\n writeSubcommands: [\n \"update-config\",\n \"set-max-upload-size\",\n \"set-max-execution-time\",\n \"enable-opcache\",\n \"disable-opcache\",\n ],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showPhpHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge php list\")} - List the PHP versions installed on a server\n\n${colors.bold(\"USAGE:\")}\n forge php list --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge php list --server 123\n`);\n } else if (subcommand === \"config\") {\n console.log(`\n${colors.bold(\"forge php config\")} - Print a PHP configuration file\n\n${colors.bold(\"USAGE:\")}\n forge php config --server <server_id> --version <version> --type <cli|fpm|pool>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID, or a version such as 8.3, php83 or php8.3 (required)\n --type <type> cli (CLI php.ini), fpm (FPM php.ini) or pool (FPM pool) (required)\n --user <name> FPM pool user (pool only)\n -f, --format <fmt> Output format: json ({ content }), human\n\n${colors.bold(\"EXAMPLES:\")}\n forge php config --server 123 --version 8.3 --type fpm\n forge php config --server 123 --version 8.3 --type pool > www.conf\n`);\n } else if (subcommand === \"update-config\") {\n console.log(`\n${colors.bold(\"forge php update-config\")} - Replace a PHP configuration file\n\n${colors.bold(\"USAGE:\")}\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --file <path>\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --file <path> --check\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --content <config>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID, or a version such as 8.3, php83 or php8.3 (required)\n --type <type> cli (CLI php.ini), fpm (FPM php.ini) or pool (FPM pool) (required)\n --user <name> FPM pool user (pool only)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New configuration file content\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n The content replaces the whole file.\n\n${colors.bold(\"EXAMPLES:\")}\n forge php update-config --server 123 --version 8.3 --type fpm --file php.ini\n cat php.ini | forge php update-config --server 123 --version 8.3 --type cli --file -\n forge php update-config --server 123 --version 8.3 --type fpm --file php.ini --check\n`);\n } else if (\n subcommand === \"max-upload-size\" ||\n subcommand === \"set-max-upload-size\" ||\n subcommand === \"max-execution-time\" ||\n subcommand === \"set-max-execution-time\"\n ) {\n console.log(`\n${colors.bold(\"forge php max-upload-size / max-execution-time\")} - Get or set PHP limits\n\n${colors.bold(\"USAGE:\")}\n forge php max-upload-size --server <server_id>\n forge php set-max-upload-size <megabytes> --server <server_id>\n forge php max-execution-time --server <server_id>\n forge php set-max-execution-time <seconds> --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"EXAMPLES:\")}\n forge php set-max-upload-size 128 --server 123\n forge php set-max-execution-time 120 --server 123\n`);\n } else if (\n subcommand === \"opcache\" ||\n subcommand === \"enable-opcache\" ||\n subcommand === \"disable-opcache\"\n ) {\n console.log(`\n${colors.bold(\"forge php opcache\")} - Get, enable or disable OPcache\n\n${colors.bold(\"USAGE:\")}\n forge php opcache --server <server_id>\n forge php enable-opcache --server <server_id>\n forge php disable-opcache --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human\n`);\n } else {\n console.log(`\n${colors.bold(\"forge php\")} - Manage PHP on a server\n\n${colors.bold(\"USAGE:\")}\n forge php <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List installed PHP versions\n config Print a configuration file (--version --type)\n update-config Replace a configuration file (--version --type --file|--content) [--check]\n max-upload-size Print the max upload size (MB)\n set-max-upload-size <mb> Set the max upload size (MB)\n max-execution-time Print the max execution time (seconds)\n set-max-execution-time <sec> Set the max execution time (seconds)\n opcache Print the OPcache status\n enable-opcache Enable OPcache\n disable-opcache Disable OPcache\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID or version (8.3, php83) (for config commands)\n --type <type> cli, fpm or pool (for config commands)\n --user <name> FPM pool user (for --type pool)\n --file <path> Content file, - for stdin (for update-config)\n --content <str> New content (for update-config)\n --check Compare with Forge, do not write (for update-config)\n\nRun ${colors.cyan(\"forge php <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listRecipes, getRecipe, runRecipe, updateRecipe } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\n\nexport async function recipesList(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listRecipes({}, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"user\", \"created_at\"],\n \"No recipes found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(40)} ${r.user.padEnd(16)} ${r.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function recipesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge recipes get <recipe_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getRecipe({ id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"user\", \"created_at\", \"script\"]);\n }, ctx.formatter);\n}\n\nexport async function recipesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\n \"id\",\n \"forge recipes update <recipe_id> [--name ...] [--user ...] [--script ...]\",\n ctx.formatter,\n );\n }\n\n const name = ctx.options.name as string | undefined;\n const user = ctx.options.user as string | undefined;\n const script = ctx.options.script as string | undefined;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await updateRecipe({ id, name, user, script }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"user\", \"created_at\", \"script\"]);\n }, ctx.formatter);\n}\n\nexport async function recipesRun(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const serversRaw = String(ctx.options.servers ?? \"\");\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge recipes run <recipe_id> --servers <ids>\", ctx.formatter);\n }\n\n if (!serversRaw) {\n exitWithValidationError(\n \"servers\",\n \"forge recipes run <recipe_id> --servers <server_id1,server_id2,...>\",\n ctx.formatter,\n );\n }\n\n const servers = serversRaw\n .split(\",\")\n .map((s) => Number(s.trim()))\n .filter((n) => !isNaN(n));\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n await runRecipe({ id, servers }, execCtx);\n ctx.formatter.success(`Recipe ${id} dispatched to ${servers.length} server(s).`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { recipesList, recipesGet, recipesRun, recipesUpdate } from \"./handlers.ts\";\n\nexport const handleRecipesCommand = createCommandRouter({\n resource: \"recipes\",\n handlers: {\n list: recipesList,\n ls: recipesList,\n get: [recipesGet, \"args\"],\n update: [recipesUpdate, \"args\"],\n run: [recipesRun, \"args\"],\n },\n writeSubcommands: [\"update\", \"run\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showRecipesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge recipes list\")} - List all recipes\n\n${colors.bold(\"USAGE:\")}\n forge recipes list [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge recipes get\")} - Get recipe details\n\n${colors.bold(\"USAGE:\")}\n forge recipes get <recipe_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge recipes update\")} - Update a recipe\n\n${colors.bold(\"USAGE:\")}\n forge recipes update <recipe_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> New recipe name\n --user <user> New recipe user\n --script <script> New recipe script\n`);\n } else if (subcommand === \"run\") {\n console.log(`\n${colors.bold(\"forge recipes run\")} - Run a recipe on servers\n\n${colors.bold(\"USAGE:\")}\n forge recipes run <recipe_id> --servers <server_id1,server_id2,...>\n\n${colors.bold(\"OPTIONS:\")}\n --servers <ids> Comma-separated server IDs to run recipe on\n`);\n } else {\n console.log(`\n${colors.bold(\"forge recipes\")} - Manage recipes\n\n${colors.bold(\"USAGE:\")}\n forge recipes <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List all recipes\n get <id> Get recipe details\n update <id> Update a recipe\n run <id> Run a recipe on servers\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge recipes <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createRedirectRule,\n deleteRedirectRule,\n getRedirectRule,\n listRedirectRules,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function redirectRulesList(ctx: CommandContext): Promise<void> {\n const usage = \"forge redirect-rules list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listRedirectRules({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"from\", \"to\", \"type\"],\n \"No redirect rules found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.from.padEnd(30)} ${r.to.padEnd(30)} ${r.type}`,\n );\n }, ctx.formatter);\n}\n\nexport async function redirectRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge redirect-rules get <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getRedirectRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"from\", \"to\", \"type\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function redirectRulesCreate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const from = String(ctx.options.from ?? \"\");\n const to = String(ctx.options.to ?? \"\");\n const type = String(ctx.options.type ?? \"redirect\");\n\n if (!from) {\n exitWithValidationError(\"from\", usage, ctx.formatter);\n }\n\n if (!to) {\n exitWithValidationError(\"to\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await createRedirectRule({ server_id, site_id, from, to, type }, execCtx);\n ctx.formatter.success(\"Redirect rule created.\");\n }, ctx.formatter);\n}\n\nexport async function redirectRulesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge redirect-rules delete <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await deleteRedirectRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.success(`Redirect rule ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n redirectRulesCreate,\n redirectRulesDelete,\n redirectRulesGet,\n redirectRulesList,\n} from \"./handlers.ts\";\n\nexport const handleRedirectRulesCommand = createCommandRouter({\n resource: \"redirect-rules\",\n handlers: {\n list: redirectRulesList,\n ls: redirectRulesList,\n get: [redirectRulesGet, \"args\"],\n create: redirectRulesCreate,\n delete: [redirectRulesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showRedirectRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge redirect-rules list\")} - List redirect rules for a site\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge redirect-rules get\")} - Get redirect rule details\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules get <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge redirect-rules create\")} - Create a new redirect rule\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --from <path> Source path to redirect from (required)\n --to <path> Destination path to redirect to (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge redirect-rules delete\")} - Delete a redirect rule\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules delete <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge redirect-rules\")} - Manage site redirect rules\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List redirect rules\n get <id> Get redirect rule details\n create Create a new redirect rule\n delete <id> Delete a redirect rule\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge redirect-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createScheduledJob,\n deleteScheduledJob,\n getScheduledJob,\n listScheduledJobs,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function scheduledJobsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await listScheduledJobs({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"frequency\", \"status\"],\n \"No scheduled jobs found.\",\n (j) =>\n `${String(j.id).padEnd(8)} ${j.command.padEnd(50)} ${j.frequency.padEnd(12)} ${j.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"job_id\",\n \"forge scheduled-jobs get <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs get <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await getScheduledJob({ server_id, id, site_id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"frequency\",\n \"cron\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n const command = String(ctx.options.command ?? \"\");\n const user = String(ctx.options.user ?? \"forge\");\n const frequency = String(ctx.options.frequency ?? \"custom\");\n const cron = ctx.options.cron ? String(ctx.options.cron) : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs create --server <server_id> --command <command> --user <user> --frequency <frequency>\",\n ctx.formatter,\n );\n }\n\n if (!command) {\n exitWithValidationError(\n \"command\",\n \"forge scheduled-jobs create --server <server_id> --command <command> --user <user> --frequency <frequency>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await createScheduledJob(\n { server_id, site_id, command, user, frequency, cron },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"frequency\",\n \"cron\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"job_id\",\n \"forge scheduled-jobs delete <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs delete <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n await deleteScheduledJob({ server_id, id, site_id }, execCtx);\n ctx.formatter.success(`Scheduled job ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n scheduledJobsCreate,\n scheduledJobsDelete,\n scheduledJobsGet,\n scheduledJobsList,\n} from \"./handlers.ts\";\n\nexport const handleScheduledJobsCommand = createCommandRouter({\n resource: \"scheduled-jobs\",\n handlers: {\n list: scheduledJobsList,\n ls: scheduledJobsList,\n get: [scheduledJobsGet, \"args\"],\n create: scheduledJobsCreate,\n delete: [scheduledJobsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showScheduledJobsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs list\")} - List scheduled jobs on a server\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs get\")} - Get scheduled job details\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs get <job_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs create\")} - Create a new scheduled job\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs create --server <server_id> --command <command> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --command <cmd> Command to run (required)\n --site <id> Site ID, to create the job on a site\n --user <user> User that runs the command (default: forge)\n --frequency <freq> minutely, hourly, nightly, weekly, monthly, reboot\n or custom (default: custom)\n --cron <expr> Cron expression, used when --frequency is custom\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge scheduled-jobs create --server web-1 --command \"php artisan schedule:run\" --frequency minutely\n forge scheduled-jobs create --server web-1 --command \"php artisan backup:run\" --cron \"0 3 * * *\"\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs delete\")} - Delete a scheduled job\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs delete <job_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge scheduled-jobs\")} - Manage scheduled jobs (cron)\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List scheduled jobs\n get <id> Get scheduled job details\n create Create a new scheduled job\n delete <id> Delete a scheduled job\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge scheduled-jobs <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createSecurityRule,\n deleteSecurityRule,\n getSecurityRule,\n listSecurityRules,\n updateSecurityRule,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function securityRulesList(ctx: CommandContext): Promise<void> {\n const usage = \"forge security-rules list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listSecurityRules({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"path\"],\n \"No security rules found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(30)} ${r.path ?? \"—\"}`,\n );\n }, ctx.formatter);\n}\n\nexport async function securityRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge security-rules get <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getSecurityRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesCreate(ctx: CommandContext): Promise<void> {\n const usage = \"forge security-rules create --server <server_id> --site <site_id> --name <name>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const name = String(ctx.options.name ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await createSecurityRule({ server_id, site_id, name, credentials: [] }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage =\n \"forge security-rules update <rule_id> --server <server_id> --site <site_id> --name <name>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const name = String(ctx.options.name ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await updateSecurityRule(\n { server_id, site_id, id, name, credentials: [] },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge security-rules delete <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await deleteSecurityRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.success(`Security rule ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n securityRulesCreate,\n securityRulesDelete,\n securityRulesGet,\n securityRulesList,\n securityRulesUpdate,\n} from \"./handlers.ts\";\n\nexport const handleSecurityRulesCommand = createCommandRouter({\n resource: \"security-rules\",\n handlers: {\n list: securityRulesList,\n ls: securityRulesList,\n get: [securityRulesGet, \"args\"],\n create: securityRulesCreate,\n update: [securityRulesUpdate, \"args\"],\n delete: [securityRulesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSecurityRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge security-rules list\")} - List security rules for a site\n\n${colors.bold(\"USAGE:\")}\n forge security-rules list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge security-rules get\")} - Get security rule details\n\n${colors.bold(\"USAGE:\")}\n forge security-rules get <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge security-rules create\")} - Create a new security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules create --server <server_id> --site <site_id> --name <name> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --name <name> Security rule name (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge security-rules update\")} - Update a security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules update <rule_id> --server <server_id> --site <site_id> --name <name> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --name <name> Security rule name (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge security-rules delete\")} - Delete a security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules delete <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge security-rules\")} - Manage site security rules\n\n${colors.bold(\"USAGE:\")}\n forge security-rules <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List security rules\n get <id> Get security rule details\n create Create a new security rule\n update <id> Update a security rule\n delete <id> Delete a security rule\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge security-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * CLI handlers for servers commands.\n * Delegates all HTTP logic to forge-core executors.\n */\n\nimport type { CreateServerOptions } from \"@studiometa/forge-core\";\nimport { listServers, getServer, createServer, rebootServer } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ApiError } from \"../../errors.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\n/**\n * List all servers.\n */\nexport async function serversList(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listServers({}, execCtx);\n\n const format = String(ctx.options.format ?? ctx.options.f ?? \"human\");\n\n if (format === \"table\" || format === \"json\") {\n ctx.formatter.output(result.data);\n } else {\n if (result.data.length === 0) {\n ctx.formatter.info(\"No servers found.\");\n return;\n }\n for (const server of result.data) {\n console.log(\n `${String(server.id).padEnd(8)} ${server.name.padEnd(30)} ${(server.ip_address ?? \"—\").padEnd(16)} ${server.is_ready ? \"ready\" : \"provisioning\"}`,\n );\n }\n }\n }, ctx.formatter);\n}\n\n/**\n * Get a single server by ID or name.\n */\nexport async function serversGet(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers get <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getServer({ server_id }, execCtx);\n ctx.formatter.output(result.data);\n }, ctx.formatter);\n}\n\n/**\n * Print the public key of the `forge` user of a server (`~/.ssh/id_rsa.pub`), the key that\n * Forge uses to clone repositories: add it to the git host before you create a site.\n */\nexport async function serversPublicKey(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers public-key <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getServer({ server_id }, execCtx);\n const key = result.data.local_public_key?.trim();\n if (!key) {\n throw new ApiError(`Server ${result.data.name} has no public key yet`, 404, [\n \"Wait until Forge provisions the server\",\n ]);\n }\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ public_key: key });\n } else {\n console.log(key);\n }\n }, ctx.formatter);\n}\n\nconst CREATE_USAGE = \"forge servers create --name <name> --ip-address <ip> [options]\";\n\n/**\n * Create a server. Defaults to a Custom VPS app server on Ubuntu 26.04.\n */\nexport async function serversCreate(ctx: CommandContext): Promise<void> {\n const name = String(ctx.options.name ?? \"\");\n const provider = String(ctx.options.provider ?? \"custom\");\n const ip_address = String(ctx.options[\"ip-address\"] ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", CREATE_USAGE, ctx.formatter);\n }\n\n if (provider === \"custom\" && !ip_address) {\n exitWithValidationError(\"ip-address\", CREATE_USAGE, ctx.formatter);\n }\n\n if (provider !== \"custom\") {\n for (const option of [\"credential-id\", \"region\", \"size\"]) {\n if (!ctx.options[option]) exitWithValidationError(option, CREATE_USAGE, ctx.formatter);\n }\n }\n\n const options: CreateServerOptions = {\n name,\n provider,\n type: String(ctx.options.type ?? \"app\"),\n ubuntu_version: String(ctx.options[\"ubuntu-version\"] ?? \"26.04\"),\n php_version: String(ctx.options[\"php-version\"] ?? \"php84\"),\n };\n\n if (ctx.options.database) options.database_type = String(ctx.options.database);\n if (ctx.options[\"credential-id\"]) options.credential_id = String(ctx.options[\"credential-id\"]);\n\n const tags = ctx.options.tag;\n if (tags) options.tags = (Array.isArray(tags) ? tags : [tags]).map(String);\n\n if (provider === \"custom\") {\n options.custom = { ip_address, ssh_port: String(ctx.options[\"ssh-port\"] ?? \"22\") };\n if (ctx.options[\"private-ip\"])\n options.custom.private_ip_address = String(ctx.options[\"private-ip\"]);\n } else {\n (options as Record<string, unknown>)[provider] = {\n region_id: String(ctx.options.region),\n size_id: String(ctx.options.size),\n };\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await createServer(options, execCtx);\n\n const format = String(ctx.options.format ?? ctx.options.f ?? \"human\");\n\n if (format === \"table\" || format === \"json\") {\n ctx.formatter.output(result.data);\n return;\n }\n\n ctx.formatter.success(`Server ${result.data.name} created (ID ${result.data.id}).`);\n if (provider === \"custom\") {\n ctx.formatter.info(\n `Run the provisioning command from the Forge server page as root on ${ip_address}.`,\n );\n }\n }, ctx.formatter);\n}\n\n/**\n * Reboot a server by ID or name.\n */\nexport async function serversReboot(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers reboot <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await rebootServer({ server_id }, execCtx);\n ctx.formatter.success(`Server ${server_id} reboot initiated.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n serversList,\n serversGet,\n serversCreate,\n serversReboot,\n serversPublicKey,\n} from \"./handlers.ts\";\n\nexport const handleServersCommand = createCommandRouter({\n resource: \"servers\",\n handlers: {\n list: serversList,\n ls: serversList,\n get: [serversGet, \"args\"],\n \"public-key\": [serversPublicKey, \"args\"],\n create: serversCreate,\n reboot: [serversReboot, \"args\"],\n },\n writeSubcommands: [\"create\", \"reboot\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showServersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge servers list\")} - List all servers\n\n${colors.bold(\"USAGE:\")}\n forge servers list [options]\n\n${colors.bold(\"OPTIONS:\")}\n --token <token> Forge API token\n -f, --format <fmt> Output format: json, human, table (default: human)\n --no-color Disable colored output\n -h, --help Show this help\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers list\n forge servers list --format json\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge servers get\")} - Get server details\n\n${colors.bold(\"USAGE:\")}\n forge servers get <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID (required)\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers get 123\n forge servers get 123 --format json\n`);\n } else if (subcommand === \"public-key\") {\n console.log(`\n${colors.bold(\"forge servers public-key\")} - Print the public key of the forge user\n\n${colors.bold(\"USAGE:\")}\n forge servers public-key <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID or name (required)\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json ({ \"public_key\": \"...\" }), human (the key only)\n\nForge clones repositories as the forge user, with this key (~/.ssh/id_rsa.pub).\nAdd it to the git host (e.g. as a deploy key) before you create a site with a\nrepository. It is not the key of GET /servers/{id}/key: that key lets Forge\nconnect to the server.\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers public-key 123\n forge servers public-key 123 > server.pub\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge servers create\")} - Create a server\n\n${colors.bold(\"USAGE:\")}\n forge servers create --name <name> --ip-address <ip> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> Server name (required, 30 characters max)\n --provider <provider> Server provider (default: custom)\n --ip-address <ip> Public IP address (required for custom)\n --private-ip <ip> Private IP address (custom only)\n --ssh-port <port> SSH port (custom only, default: 22)\n --region <id> Region ID (cloud providers)\n --size <id> Size ID (cloud providers)\n --credential-id <id> Server provider credential ID (cloud providers)\n --type <type> Server type: app, web, loadbalancer, database... (default: app)\n --ubuntu-version <ver> Ubuntu version (default: 26.04)\n --php-version <ver> PHP version (default: php84)\n --database <type> Database type, e.g. mariadb1011\n --tag <tag> Tag, repeatable\n -f, --format <fmt> Output format: json, human, table\n\nA Custom VPS must run a fresh Ubuntu with root SSH access. After the\ncommand, run the provisioning command from the Forge server page as root.\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers create --name web-1 --ip-address 203.0.113.10 --php-version php84 --database mariadb1011\n forge servers create --name worker-1 --provider hetzner --credential-id 42 --region fsn1 --size cpx31\n`);\n } else if (subcommand === \"reboot\") {\n console.log(`\n${colors.bold(\"forge servers reboot\")} - Reboot a server\n\n${colors.bold(\"USAGE:\")}\n forge servers reboot <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID (required)\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers reboot 123\n`);\n } else {\n console.log(`\n${colors.bold(\"forge servers\")} - Manage servers\n\n${colors.bold(\"USAGE:\")}\n forge servers <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge s\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List all servers\n get <id> Get server details\n public-key <id> Print the public key of the forge user\n create Create a server (requires --name, and --ip-address for custom)\n reboot <id> Reboot a server\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n -h, --help Show help for a subcommand\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers list\n forge servers get 123\n\nRun ${colors.cyan(\"forge servers <subcommand> --help\")} for subcommand details.\n`);\n }\n}\n","import {\n getServer,\n listServices,\n restartService,\n RESTARTABLE_SERVICES,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\n/**\n * List services on a server with a derived availability flag.\n */\nexport async function servicesList(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server\", \"forge services list <server>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listServices({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"service\", \"available\", \"detail\"],\n \"No services.\",\n (row) => {\n const status = row.available ? \"yes\" : \"no\";\n const detail = row.detail ? ` (${row.detail})` : \"\";\n return `${row.service.padEnd(12)}${status}${detail}`;\n },\n );\n }, ctx.formatter);\n}\n\n/**\n * Restart a service on a server.\n */\nexport async function servicesRestart(args: string[], ctx: CommandContext): Promise<void> {\n const [server, service] = args;\n\n if (!server) {\n exitWithValidationError(\"server\", \"forge services restart <server> <service>\", ctx.formatter);\n }\n\n if (!service) {\n exitWithValidationError(\"service\", \"forge services restart <server> <service>\", ctx.formatter);\n }\n\n const version =\n typeof ctx.options.version === \"string\" && ctx.options.version\n ? ctx.options.version\n : undefined;\n\n await runCommand(async () => {\n if (!(RESTARTABLE_SERVICES as readonly string[]).includes(service)) {\n throw new ValidationError(`Invalid service \"${service}\"`, \"service\", [\n `Valid services: ${RESTARTABLE_SERVICES.join(\", \")}`,\n ]);\n }\n\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n\n let resolvedVersion = version;\n if (service === \"php\" && !resolvedVersion) {\n const { data: srv } = await getServer({ server_id }, execCtx);\n if (!srv.php_version) {\n throw new ValidationError(\"The php service requires a version\", \"version\", [\n \"Pass --version <php_version> (e.g. --version php83)\",\n ]);\n }\n resolvedVersion = srv.php_version;\n }\n\n await restartService({ server_id, service, version: resolvedVersion }, execCtx);\n ctx.formatter.success(`${service} restart initiated on server ${server_id}.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { servicesList, servicesRestart } from \"./handlers.ts\";\n\nexport const handleServicesCommand = createCommandRouter({\n resource: \"services\",\n handlers: {\n list: [servicesList, \"args\"],\n ls: [servicesList, \"args\"],\n restart: [servicesRestart, \"args\"],\n },\n writeSubcommands: [\"restart\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showServicesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge services list\")} - List services on a server\n\n${colors.bold(\"USAGE:\")}\n forge services list <server> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n\n${colors.bold(\"NOTES:\")}\n Availability is a heuristic derived from the server object — the API has\n no services listing endpoint.\n\n${colors.bold(\"EXAMPLES:\")}\n forge services list 123\n forge services list my-server --format json\n`);\n } else if (subcommand === \"restart\") {\n console.log(`\n${colors.bold(\"forge services restart\")} - Restart a service on a server\n\n${colors.bold(\"USAGE:\")}\n forge services restart <server> <service> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n <service> One of: nginx, php, mysql, postgres, redis, supervisor\n\n${colors.bold(\"OPTIONS:\")}\n --version <ver> PHP version (e.g. php83) — required for the php service\n (defaults to the server's php_version when omitted)\n\n${colors.bold(\"EXAMPLES:\")}\n forge services restart 123 nginx\n forge services restart 123 php --version php83\n`);\n } else {\n console.log(`\n${colors.bold(\"forge services\")} - List and restart server services\n\n${colors.bold(\"USAGE:\")}\n forge services <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List services on a server\n restart <service> Restart a service (nginx, php, mysql, postgres, redis, supervisor)\n\n${colors.bold(\"OPTIONS:\")}\n --version <ver> PHP version (for the php service)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge services <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Path and command helpers of `forge sites apply`: normalize commands so that\n * equivalent spellings compare equal, and find which site owns a daemon or a scheduled job.\n *\n * Ownership is strict on purpose: `apply` deletes the workers and scheduled jobs of a site\n * that the site file does not declare, and a server often hosts many sites.\n */\n\nimport { posix } from \"node:path\";\n\n/** A site, as far as ownership is concerned. */\nexport interface SiteRoots {\n id: number;\n /** Absolute paths that belong to the site, e.g. `/home/forge/example.com`. */\n roots: string[];\n}\n\n/**\n * Normalize an absolute path: resolve `.` and `..`, collapse repeated slashes\n * and drop the trailing slash.\n */\nexport function normalizePath(path: string): string {\n const normalized = posix.normalize(path.trim());\n return normalized.length > 1 && normalized.endsWith(\"/\") ? normalized.slice(0, -1) : normalized;\n}\n\n/**\n * Whether `path` is `root` or inside it, compared on whole path segments:\n * `/home/forge/a.com` contains `/home/forge/a.com/current` but not `/home/forge/a.com-staging`.\n */\nexport function isPathInside(path: string, root: string): boolean {\n const child = normalizePath(path);\n const parent = normalizePath(root);\n if (parent === \"/\") return child.startsWith(\"/\");\n return child === parent || child.startsWith(`${parent}/`);\n}\n\n/**\n * Resolve `path` against `base` when it is relative.\n */\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith(\"/\") ? path : posix.join(base, path));\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`);\n}\n\n/**\n * Whether a shell command uses `root` as a whole path: `root` must start the command or follow\n * a space, a quote, `=` or a shell operator, and must end the command or be followed by `/`,\n * a space, a quote or a shell operator. `/home/forge/a.com` is not found in\n * `/home/forge/a.com-staging/artisan`, `/home/forge/a.com.old` or `/home/forge/*`.\n */\nexport function commandUsesPath(command: string, root: string): boolean {\n const path = normalizePath(root);\n if (path === \"/\") return false;\n const pattern = new RegExp(\n String.raw`(?:^|[\\s'\"=(;&|<>:])${escapeRegExp(path)}(?=$|[/\\s'\";&|)<>])`,\n );\n return pattern.test(command);\n}\n\n/**\n * Split a shell command into words, with the quoting rules of a POSIX shell:\n * single quotes keep everything, double quotes and a backslash escape one character.\n */\nexport function splitCommand(command: string): string[] {\n const words: string[] = [];\n let word = \"\";\n let inWord = false;\n let quote: \"'\" | '\"' | null = null;\n\n for (let index = 0; index < command.length; index++) {\n const char = command[index];\n if (quote === \"'\") {\n if (char === \"'\") quote = null;\n else word += char;\n } else if (quote === '\"') {\n if (char === '\"') quote = null;\n else if (\n char === \"\\\\\" &&\n index + 1 < command.length &&\n '\"\\\\$`'.includes(command[index + 1])\n ) {\n word += command[++index];\n } else word += char;\n } else if (char === \"'\" || char === '\"') {\n quote = char;\n inWord = true;\n } else if (char === \"\\\\\" && index + 1 < command.length) {\n word += command[++index];\n inWord = true;\n } else if (/\\s/.test(char)) {\n if (inWord) words.push(word);\n word = \"\";\n inWord = false;\n } else {\n word += char;\n inWord = true;\n }\n }\n\n if (inWord) words.push(word);\n return words;\n}\n\n/**\n * Quote a word for a POSIX shell when it needs quotes.\n */\nexport function quoteWord(word: string): string {\n if (word !== \"\" && /^[\\w@%+=:,./-]+$/.test(word)) return word;\n return `'${word.replaceAll(\"'\", String.raw`'\\''`)}'`;\n}\n\n/**\n * Write a command in one canonical form, so that equivalent spellings compare equal:\n * quotes only where needed, single spaces, and a relative `artisan` (or `./artisan`)\n * replaced by its absolute path in `directory`.\n *\n * `php artisan queue:work 'database' --queue=\"default\"` in `/home/forge/example.com/`\n * gives `php /home/forge/example.com/artisan queue:work database --queue=default`.\n */\nexport function canonicalCommand(command: string, directory: string | null): string {\n return splitCommand(command)\n .map((word) => {\n if (directory && (word === \"artisan\" || word === \"./artisan\")) {\n return `${normalizePath(directory)}/artisan`;\n }\n return word;\n })\n .map(quoteWord)\n .join(\" \");\n}\n\n/**\n * The site whose root holds `path`: the most specific root wins, so a site in\n * `/home/forge/a.com/admin` is not owned by `/home/forge/a.com`. Returns null when no site holds it.\n */\nexport function siteOfPath(path: string, sites: SiteRoots[]): number | null {\n let best: { id: number; length: number } | null = null;\n for (const site of sites) {\n for (const root of site.roots) {\n if (isPathInside(path, root)) {\n const length = normalizePath(root).length;\n if (!best || length > best.length) best = { id: site.id, length };\n }\n }\n }\n return best?.id ?? null;\n}\n\n/**\n * The sites whose roots a command uses as a path.\n */\nexport function sitesOfCommand(command: string, sites: SiteRoots[]): number[] {\n return sites\n .filter((site) => site.roots.some((root) => commandUsesPath(command, root)))\n .map((site) => site.id);\n}\n\n/**\n * Who owns a daemon or a scheduled job, from the point of view of one site:\n * - `site`: it belongs to the site; `apply` can match it, and delete it when it is not declared\n * - `ambiguous`: it may belong to the site; `apply` can match it but never deletes it\n * - `other`: it belongs to another site, to the server, or to nobody known; `apply` ignores it\n */\nexport type Ownership = \"site\" | \"ambiguous\" | \"other\";\n\n/**\n * Ownership of a daemon (a Forge background process).\n *\n * - With a directory: the site that holds the directory (see {@link siteOfPath}).\n * - Without a directory: `ambiguous` when the command uses the site root, `site` only when\n * the command uses no other site root and Forge also associates the daemon with the site.\n */\nexport function daemonOwnership(\n daemon: { directory: string | null; command: string },\n siteId: number,\n sites: SiteRoots[],\n associatedWithSite: boolean,\n): Ownership {\n if (daemon.directory && daemon.directory.trim()) {\n return siteOfPath(daemon.directory, sites) === siteId ? \"site\" : \"other\";\n }\n\n const owners = sitesOfCommand(daemon.command, sites);\n if (!owners.includes(siteId)) return \"other\";\n return owners.length === 1 && associatedWithSite ? \"site\" : \"ambiguous\";\n}\n\n/**\n * Ownership of a scheduled job. Forge lists the jobs of a site on a site route: those\n * belong to the site. A job of the server belongs to the site when its command uses the\n * site root and no other site root; when it uses several site roots, it is `ambiguous`.\n */\nexport function scheduledJobOwnership(\n job: { command: string },\n siteId: number,\n sites: SiteRoots[],\n listedOnSite: boolean,\n): Ownership {\n if (listedOnSite) return \"site\";\n const owners = sitesOfCommand(job.command, sites);\n if (!owners.includes(siteId)) return \"other\";\n return owners.length === 1 ? \"site\" : \"ambiguous\";\n}\n","/**\n * Compare a site file with the state of Forge and list the changes that `apply` makes.\n * Pure functions: no API call here.\n */\n\nimport type {\n BackgroundProcessAttributes,\n DatabaseAttributes,\n DatabaseUserAttributes,\n LoadBalancingNodeAttributes,\n ScheduledJobAttributes,\n SiteAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unifiedDiff } from \"../../../utils/drift.ts\";\nimport { parseEnv } from \"../../env/env-diff.ts\";\nimport type { SiteFile } from \"./site-file.ts\";\nimport {\n type Ownership,\n type SiteRoots,\n canonicalCommand,\n daemonOwnership,\n isPathInside,\n normalizePath,\n resolvePath,\n scheduledJobOwnership,\n} from \"./ownership.ts\";\n\nexport type Site = SiteAttributes & { id: number };\nexport type Daemon = BackgroundProcessAttributes & { id: number };\nexport type ScheduledJob = ScheduledJobAttributes & { id: number };\nexport type Database = DatabaseAttributes & { id: number };\nexport type DatabaseUser = DatabaseUserAttributes & { id: number };\nexport type LoadBalancingNode = LoadBalancingNodeAttributes & { id: number };\n\n/** Shown in place of a generated password. */\nexport const GENERATED = \"<generated>\";\n\n/** What `apply` reads from Forge. A list is undefined when the site file does not manage it. */\nexport interface RemoteState {\n /** All sites of the server. */\n sites: Site[];\n /** The site of the file, or null when it does not exist yet. */\n site: Site | null;\n databases?: Database[];\n databaseUsers?: DatabaseUser[];\n /** Content of the site .env; null when the site does not exist. */\n env?: string | null;\n /** All daemons of the server. */\n daemons?: Daemon[];\n /** IDs of the daemons that Forge associates with the site. */\n siteDaemonIds?: ReadonlySet<number>;\n /** All scheduled jobs of the server, with the jobs of the site. */\n jobs?: ScheduledJob[];\n /** IDs of the scheduled jobs that Forge lists on the site. */\n siteJobIds?: ReadonlySet<number>;\n /** Nginx configuration on Forge and the Nginx file rendered for the site; null when the site does not exist. */\n nginx?: { remote: string; rendered: string } | null;\n /** The site of the file on its load balancer, with its nodes; site is null when it does not exist. */\n loadBalancer?: {\n serverId: string;\n site: Site | null;\n nodes: LoadBalancingNode[];\n /** The server of the site file: the one node that the load balancer must send traffic to. */\n target: number;\n };\n}\n\nexport interface SiteSettings {\n type?: string;\n php_version?: string;\n web_directory?: string;\n source_control_provider?: string;\n repository?: string;\n branch?: string;\n}\n\nexport type Change =\n | { action: \"create-site\"; name: string; settings: SiteSettings }\n | { action: \"update-site\"; changes: Array<{ field: string; from: string | null; to: string }> }\n | { action: \"add-alias\"; name: string }\n | { action: \"create-database\"; name: string }\n | { action: \"create-database-user\"; name: string; database: string }\n | {\n action: \"add-env\";\n keys: string[];\n /** Keys that get the database name, user and password of a new database user. */\n generated: string[];\n /** The generated key that holds the password; its value never shows. */\n password?: string;\n }\n | { action: \"create-worker\"; command: string; directory: string; processes: number }\n | {\n action: \"delete-worker\";\n id: number;\n command: string;\n directory: string | null;\n processes: number;\n }\n | { action: \"create-job\"; command: string; frequency: string; cron?: string }\n | {\n action: \"update-load-balancer\";\n site: string;\n from: Array<{ server_id: number; port: number }>;\n to: { server_id: number; port: number };\n }\n /** `diff` is null for a site that does not exist yet: the file is rendered once it exists. */\n | { action: \"update-nginx\"; diff: string | null }\n | {\n action: \"delete-job\";\n id: number;\n command: string;\n frequency: string;\n cron: string;\n onSite: boolean;\n };\n\nexport interface Plan {\n changes: Change[];\n /** Differences that `apply` does not change, e.g. a different .env value. */\n warnings: string[];\n}\n\n/** The path of the site folder, e.g. `/home/forge/example.com`. */\nexport function siteHome(site: Pick<Site, \"user\" | \"name\">): string {\n return `/home/${site.user}/${site.name}`;\n}\n\n/** The directory that workers run in and relative `artisan` resolves against. */\nexport function siteWorkDirectory(site: Pick<Site, \"user\" | \"name\" | \"root_directory\">): string {\n return inSiteHome(site, site.root_directory || \"/\");\n}\n\n/**\n * Read a directory of a site, absolute (`/home/forge/example.com/public`) or relative to the\n * site folder (`/public`), as an absolute path inside the site folder. A relative `/` never\n * becomes the root of the server.\n */\nfunction inSiteHome(site: Pick<Site, \"user\" | \"name\">, directory: string): string {\n const home = siteHome(site);\n return isPathInside(directory, home)\n ? normalizePath(directory)\n : resolvePath(home, directory.replace(/^\\/+/, \"\"));\n}\n\n/** The paths that belong to each site, for ownership. */\nexport function siteRoots(sites: Site[]): SiteRoots[] {\n return sites.map((site) => ({\n id: site.id,\n roots: [...new Set([siteHome(site), siteWorkDirectory(site)].map(normalizePath))],\n }));\n}\n\n/** `PHP 8.3`, `php83` and `php8.3` all give `php83`. */\nexport function normalizePhp(version: string | null | undefined): string | null {\n return version ? version.toLowerCase().replaceAll(/[^a-z0-9]/g, \"\") : null;\n}\n\n/** Forge displays frequencies in title case, e.g. `Minutely`. */\nfunction normalizeFrequency(frequency: string): string {\n return frequency.trim().toLowerCase();\n}\n\n/** The path a declared site uses before it exists, from its domain. */\nfunction plannedWorkDirectory(file: SiteFile): string {\n return `/home/forge/${file.domain}`;\n}\n\nfunction sameName(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Pair declared items with existing ones that have the same key, each existing item once.\n * Returns the declared items without a match and the existing items without a match.\n */\nfunction matchByKey<D, E>(\n declared: D[],\n existing: E[],\n declaredKey: (item: D) => string,\n existingKey: (item: E) => string,\n): { missing: D[]; unmatched: E[] } {\n const pool = existing.map((item) => ({ item, key: existingKey(item), used: false }));\n const missing: D[] = [];\n for (const item of declared) {\n const key = declaredKey(item);\n const match = pool.find((entry) => !entry.used && entry.key === key);\n if (match) match.used = true;\n else missing.push(item);\n }\n return { missing, unmatched: pool.filter((entry) => !entry.used).map((entry) => entry.item) };\n}\n\nfunction planSite(file: SiteFile, site: Site | null, changes: Change[], warnings: string[]): void {\n if (!site) {\n changes.push({\n action: \"create-site\",\n name: file.domain,\n settings: {\n type: file.type,\n php_version: file.php,\n web_directory: file.webDirectory,\n source_control_provider: file.repository?.provider,\n repository: file.repository?.url,\n branch: file.repository?.branch,\n },\n });\n return;\n }\n\n const updates: Array<{ field: string; from: string | null; to: string }> = [];\n if (file.php && normalizePhp(site.php_version) !== normalizePhp(file.php)) {\n updates.push({ field: \"php_version\", from: site.php_version, to: file.php });\n }\n if (file.webDirectory) {\n const root = siteWorkDirectory(site);\n const expected = resolvePath(root, file.webDirectory.replace(/^\\/+/, \"\"));\n // Forge gives an absolute path; a relative one is read against the site root.\n const remote = isPathInside(site.web_directory, root)\n ? normalizePath(site.web_directory)\n : resolvePath(root, site.web_directory.replace(/^\\/+/, \"\"));\n if (remote !== expected) {\n updates.push({ field: \"web_directory\", from: site.web_directory, to: file.webDirectory });\n }\n }\n if (file.repository?.branch && site.repository?.branch !== file.repository.branch) {\n updates.push({\n field: \"branch\",\n from: site.repository?.branch ?? null,\n to: file.repository.branch,\n });\n }\n if (updates.length > 0) {\n changes.push({ action: \"update-site\", changes: updates });\n }\n\n const url = site.repository?.url;\n if (\n file.repository &&\n url &&\n url.replace(/\\.git$/, \"\") !== file.repository.url.replace(/\\.git$/, \"\")\n ) {\n warnings.push(\n `Repository differs on Forge (${url}): apply does not change the repository of a site.`,\n );\n }\n if (file.type && site.app_type && !sameName(site.app_type, file.type)) {\n warnings.push(\n `Site type differs on Forge (${site.app_type}): apply does not change the type of a site.`,\n );\n }\n}\n\nfunction planAliases(file: SiteFile, site: Site | null, changes: Change[]): void {\n const existing = site ? [site.name, ...(site.aliases ?? [])].map(String) : [];\n for (const alias of new Set(file.aliases ?? [])) {\n if (!existing.some((name) => sameName(name, alias))) {\n changes.push({ action: \"add-alias\", name: alias });\n }\n }\n}\n\n/** The .env keys of a new database user, from `database.env` or the Laravel names. */\nexport function databaseEnvKeys(database: NonNullable<SiteFile[\"database\"]>): {\n name: string;\n user: string;\n password: string;\n} {\n return {\n name: database.env?.name ?? \"DB_DATABASE\",\n user: database.env?.user ?? \"DB_USERNAME\",\n password: database.env?.password ?? \"DB_PASSWORD\",\n };\n}\n\n/**\n * Plan the database and its user. Returns the names of the .env keys that get generated values.\n */\nfunction planDatabase(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): string[] {\n if (!file.database) return [];\n const { name, user } = file.database;\n const databaseExists = (state.databases ?? []).some((db) => db.name === name);\n const userExists = (state.databaseUsers ?? []).some((u) => u.name === user);\n\n if (!databaseExists) {\n changes.push({ action: \"create-database\", name });\n }\n if (!userExists) {\n changes.push({ action: \"create-database-user\", name: user, database: name });\n const keys = databaseEnvKeys(file.database);\n return [keys.name, keys.user, keys.password];\n }\n if (!databaseExists) {\n warnings.push(\n `Database user ${user} exists: apply does not give it access to the new database ${name}.`,\n );\n }\n return [];\n}\n\nfunction planEnv(\n file: SiteFile,\n state: RemoteState,\n generated: string[],\n changes: Change[],\n warnings: string[],\n): void {\n const remote = parseEnv(state.env ?? \"\");\n const keys: string[] = [];\n for (const [key, value] of Object.entries(file.env ?? {})) {\n if (generated.includes(key)) continue;\n if (!remote.has(key)) keys.push(key);\n else if (remote.get(key) !== String(value)) {\n warnings.push(`.env key ${key} has another value on Forge: apply does not overwrite it.`);\n }\n }\n if (keys.length > 0 || generated.length > 0) {\n const password =\n file.database && generated.length > 0 ? databaseEnvKeys(file.database).password : undefined;\n changes.push({ action: \"add-env\", keys, generated, ...(password ? { password } : {}) });\n }\n}\n\nfunction planNginx(file: SiteFile, state: RemoteState, changes: Change[]): void {\n if (file.nginxTemplate === undefined) return;\n if (!state.nginx) {\n changes.push({ action: \"update-nginx\", diff: null });\n return;\n }\n const diff = unifiedDiff(state.nginx.remote, state.nginx.rendered);\n if (diff) changes.push({ action: \"update-nginx\", diff });\n}\n\nfunction describeOwnership(ownership: Ownership): string {\n return ownership === \"ambiguous\" ? \"its owner is not certain\" : \"it runs as root\";\n}\n\nfunction planWorkers(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): void {\n if (!file.workers) return;\n const site = state.site;\n const workDirectory = site ? siteWorkDirectory(site) : plannedWorkDirectory(file);\n\n const declared = file.workers.map((worker) => {\n const directory = worker.directory\n ? resolvePath(workDirectory, worker.directory)\n : workDirectory;\n return {\n command: worker.command,\n directory,\n processes: worker.processes,\n key: [canonicalCommand(worker.command, directory), directory, worker.processes, \"forge\"].join(\n \"\\n\",\n ),\n };\n });\n\n // A site that does not exist yet owns no daemon.\n const roots = siteRoots(state.sites);\n const candidates = site\n ? (state.daemons ?? []).flatMap((daemon) => {\n const ownership = daemonOwnership(\n daemon,\n site.id,\n roots,\n state.siteDaemonIds?.has(daemon.id) ?? false,\n );\n return ownership === \"other\" ? [] : [{ daemon, ownership }];\n })\n : [];\n\n const { missing, unmatched } = matchByKey(\n declared,\n candidates,\n (worker) => worker.key,\n ({ daemon }) => {\n // A daemon without a directory compares as one in the site root, but its relative\n // `artisan` stays relative: it does not run in the site root.\n const directory = daemon.directory?.trim() ? normalizePath(daemon.directory) : null;\n return [\n canonicalCommand(daemon.command, directory),\n directory ?? workDirectory,\n daemon.processes,\n daemon.user,\n ].join(\"\\n\");\n },\n );\n\n for (const worker of missing) {\n changes.push({\n action: \"create-worker\",\n command: worker.command,\n directory: worker.directory,\n processes: worker.processes,\n });\n }\n\n for (const { daemon, ownership } of unmatched) {\n // Never delete a daemon of root, or one whose owner is not certain.\n if (ownership === \"site\" && daemon.user !== \"root\") {\n changes.push({\n action: \"delete-worker\",\n id: daemon.id,\n command: daemon.command,\n directory: daemon.directory,\n processes: daemon.processes,\n });\n } else {\n warnings.push(\n `Kept daemon ${daemon.id} (${daemon.command}): not declared, but ${describeOwnership(ownership)}.`,\n );\n }\n }\n}\n\nfunction planSchedule(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): void {\n if (!file.schedule) return;\n const site = state.site;\n const workDirectory = site ? siteWorkDirectory(site) : plannedWorkDirectory(file);\n\n const declared = file.schedule.map((job) => {\n const command = canonicalCommand(job.command, workDirectory);\n const frequency = normalizeFrequency(job.frequency);\n return {\n command,\n frequency,\n cron: job.cron,\n key: [command, \"forge\", frequency, frequency === \"custom\" ? job.cron : \"\"].join(\"\\n\"),\n };\n });\n\n const roots = siteRoots(state.sites);\n const seen = new Set<number>();\n const candidates = site\n ? (state.jobs ?? []).flatMap((job) => {\n if (seen.has(job.id)) return [];\n seen.add(job.id);\n const onSite = state.siteJobIds?.has(job.id) ?? false;\n const ownership = scheduledJobOwnership(job, site.id, roots, onSite);\n return ownership === \"other\" ? [] : [{ job, ownership, onSite }];\n })\n : [];\n\n const { missing, unmatched } = matchByKey(\n declared,\n candidates,\n (job) => job.key,\n ({ job }) => {\n const frequency = normalizeFrequency(job.frequency);\n return [\n canonicalCommand(job.command, workDirectory),\n job.user,\n frequency,\n frequency === \"custom\" ? job.cron : \"\",\n ].join(\"\\n\");\n },\n );\n\n for (const job of missing) {\n changes.push({\n action: \"create-job\",\n command: job.command,\n frequency: job.frequency,\n ...(job.frequency === \"custom\" ? { cron: job.cron } : {}),\n });\n }\n\n for (const { job, ownership, onSite } of unmatched) {\n if (ownership === \"site\" && job.user !== \"root\") {\n changes.push({\n action: \"delete-job\",\n id: job.id,\n command: job.command,\n frequency: job.frequency,\n cron: job.cron,\n onSite,\n });\n } else {\n warnings.push(\n `Kept scheduled job ${job.id} (${job.command}): not declared, but ${describeOwnership(ownership)}.`,\n );\n }\n }\n}\n\n/**\n * Plan the nodes of the site on the load balancer: one node, the server of the site file, with\n * the default weight. Any other node is replaced.\n */\nfunction planLoadBalancer(file: SiteFile, state: RemoteState, changes: Change[]): void {\n const balancer = state.loadBalancer;\n if (!file.loadBalancer || !balancer?.site) return;\n const to = { server_id: balancer.target, port: file.loadBalancer.port };\n const [node, ...others] = balancer.nodes;\n const inSync =\n node !== undefined &&\n others.length === 0 &&\n node.server_id === to.server_id &&\n node.port === to.port &&\n node.weight === 1 &&\n !node.backup &&\n !node.down;\n if (inSync) return;\n changes.push({\n action: \"update-load-balancer\",\n site: balancer.site.name,\n from: balancer.nodes.map(({ server_id, port }) => ({ server_id, port })),\n to,\n });\n}\n\n/**\n * Compare the site file with the state of Forge. Keys that the file does not have are not\n * compared. The plan creates and updates what differs, and deletes only the workers and\n * scheduled jobs that surely belong to the site and that the file does not declare.\n */\nexport function buildPlan(file: SiteFile, state: RemoteState): Plan {\n const changes: Change[] = [];\n const warnings: string[] = [];\n\n planSite(file, state.site, changes, warnings);\n planAliases(file, state.site, changes);\n const generated = planDatabase(file, state, changes, warnings);\n if (file.env || generated.length > 0) {\n planEnv(file, state, generated, changes, warnings);\n }\n planNginx(file, state, changes);\n planWorkers(file, state, changes, warnings);\n planSchedule(file, state, changes, warnings);\n planLoadBalancer(file, state, changes);\n\n return { changes, warnings };\n}\n\nfunction quoted(value: string | null | undefined): string {\n return value ?? \"(none)\";\n}\n\n/**\n * One line per change, for human output. Values of .env keys never show.\n */\nexport function describeChange(change: Change): string {\n switch (change.action) {\n case \"create-site\": {\n const settings = Object.entries(change.settings)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}: ${value}`);\n return `+ create site ${change.name}${settings.length ? ` (${settings.join(\", \")})` : \"\"}`;\n }\n case \"update-site\":\n return `~ update site: ${change.changes\n .map((c) => `${c.field} ${quoted(c.from)} → ${c.to}`)\n .join(\", \")}`;\n case \"add-alias\":\n return `+ add alias ${change.name}`;\n case \"create-database\":\n return `+ create database ${change.name}`;\n case \"create-database-user\":\n return `+ create database user ${change.name} for ${change.database} (password: ${GENERATED})`;\n case \"add-env\":\n return `+ add .env keys: ${[\n ...change.keys,\n ...change.generated.map((key) => (key === change.password ? `${key}=${GENERATED}` : key)),\n ].join(\", \")}`;\n case \"update-nginx\":\n return change.diff === null\n ? \"~ write Nginx configuration (rendered once the site exists)\"\n : `~ update Nginx configuration:\\n${change.diff}`;\n case \"create-worker\":\n return `+ create worker: ${change.command} (directory: ${change.directory}, processes: ${change.processes})`;\n case \"delete-worker\":\n return `- delete worker ${change.id}: ${change.command} (directory: ${quoted(change.directory)}, processes: ${change.processes})`;\n case \"create-job\":\n return `+ create scheduled job: ${change.command} (${change.frequency}${change.cron ? ` ${change.cron}` : \"\"})`;\n case \"update-load-balancer\": {\n const node = ({ server_id, port }: { server_id: number; port: number }) =>\n `server ${server_id}:${port}`;\n const from = change.from.length > 0 ? change.from.map(node).join(\", \") : \"(none)\";\n return `~ update load balancer site ${change.site}: ${from} → ${node(change.to)}`;\n }\n case \"delete-job\":\n return `- delete scheduled job ${change.id}: ${change.command} (${change.frequency.toLowerCase()} ${change.cron})`;\n }\n}\n\n/**\n * The plan as text: one line per change, then the warnings.\n */\nexport function formatPlan(plan: Plan): string {\n return [\n ...plan.changes.map(describeChange),\n ...plan.warnings.map((warning) => `! ${warning}`),\n ].join(\"\\n\");\n}\n","/**\n * The Nginx file of a site file: an Nginx configuration with the template variables of Forge,\n * e.g. `{{ PROXY_PASS }}`, rendered locally with the values of the site.\n * See https://forge.laravel.com/docs/servers/nginx-templates\n */\n\nimport type { ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { ValidationError } from \"../../../errors.ts\";\nimport { isPathInside, normalizePath } from \"./ownership.ts\";\nimport { type Site, siteWorkDirectory } from \"./plan.ts\";\n\n/** The variables of Forge Nginx templates. Forge accepts spaces inside the braces. */\nexport const NGINX_VARIABLES = [\n \"DIRECTORY\",\n \"DOMAINS\",\n \"PATH\",\n \"PORT\",\n \"PORT_V6\",\n \"PROXY_PASS\",\n \"ROOT_PATH\",\n \"SERVER_PUBLIC_IP\",\n \"SERVER_PRIVATE_IP\",\n \"SITE\",\n \"SITE_ID\",\n \"USER\",\n] as const;\n\nexport type NginxVariable = (typeof NGINX_VARIABLES)[number];\n\n/** The variables that need the server, not only the site. */\nconst SERVER_VARIABLES: ReadonlySet<string> = new Set([\"SERVER_PUBLIC_IP\", \"SERVER_PRIVATE_IP\"]);\n\nconst VARIABLE = /\\{\\{\\s*([^{}]*?)\\s*\\}\\}/g;\n\n/** The names of the variables in a template, each once, in order. */\nexport function templateVariables(template: string): string[] {\n return [...new Set([...template.matchAll(VARIABLE)].map((match) => match[1]))];\n}\n\n/**\n * Exit with a validation error when the template has a variable that Forge does not define.\n */\nexport function assertNginxTemplate(template: string, source: string): void {\n const known: ReadonlySet<string> = new Set(NGINX_VARIABLES);\n const unknown = templateVariables(template).filter((name) => !known.has(name));\n if (unknown.length > 0) {\n throw new ValidationError(\n `Nginx file ${source} has unknown variables: ${unknown.map((name) => `{{${name}}}`).join(\", \")}`,\n \"nginx\",\n [`Supported variables: ${NGINX_VARIABLES.map((name) => `{{${name}}}`).join(\", \")}`],\n );\n }\n}\n\n/** True when rendering the template needs the attributes of the server. */\nexport function needsServer(template: string): boolean {\n return templateVariables(template).some((name) => SERVER_VARIABLES.has(name));\n}\n\n/** `PHP 8.3`, `php83` and `php8.3` all give `8.3`. */\nexport function phpSocketVersion(version: string): string {\n const digits = version.replaceAll(/\\D/g, \"\");\n if (digits.length < 2) {\n throw new ValidationError(`Cannot read the PHP version ${version} of the site`, \"nginx\");\n }\n return `${digits[0]}.${digits.slice(1)}`;\n}\n\nexport type NginxServer = Pick<ServerAttributes, \"ip_address\" | \"private_ip_address\">;\n\n/**\n * The value of each variable for a site, as Forge renders its templates.\n * A server is needed only for the `SERVER_*` variables.\n */\nexport function nginxValues(\n site: Site,\n server: NginxServer | null = null,\n): Record<NginxVariable, string> {\n const root = siteWorkDirectory(site);\n const path = isPathInside(site.web_directory, root)\n ? normalizePath(site.web_directory)\n : normalizePath(`${root}/${site.web_directory}`);\n const directory = path === root ? \"/\" : path.slice(root.length);\n const defaultServer = site.name === \"default\" ? \" default_server\" : \"\";\n const isolated = site.isolated ? `-${site.user}` : \"\";\n\n return {\n DIRECTORY: directory,\n DOMAINS: [site.name, ...(site.aliases ?? [])].join(\" \"),\n PATH: path,\n PORT: `80${defaultServer}`,\n PORT_V6: `[::]:80${defaultServer}`,\n get PROXY_PASS() {\n return `unix:/var/run/php/php${phpSocketVersion(site.php_version)}-fpm${isolated}.sock`;\n },\n ROOT_PATH: root,\n SERVER_PUBLIC_IP: server?.ip_address ?? \"\",\n SERVER_PRIVATE_IP: server?.private_ip_address ?? \"\",\n SITE: site.name,\n SITE_ID: String(site.id),\n USER: site.user,\n };\n}\n\n/**\n * Replace each variable of the template with its value for the site.\n */\nexport function renderNginx(\n template: string,\n site: Site,\n server: NginxServer | null = null,\n): string {\n const values = nginxValues(site, server);\n return template.replaceAll(VARIABLE, (match, name: string) =>\n name in values ? values[name as NginxVariable] : match,\n );\n}\n","/**\n * Read the state of Forge for a site file, and run a plan against Forge.\n */\n\nimport { randomBytes } from \"node:crypto\";\n\nimport {\n createDaemon,\n createDatabase,\n createDatabaseUser,\n createDomain,\n createScheduledJob,\n createSite,\n deleteDaemon,\n deleteScheduledJob,\n getEnv,\n getNginxConfig,\n getServer,\n getSite,\n listDaemons,\n listDatabaseUsers,\n listDatabases,\n listLoadBalancingNodes,\n listScheduledJobs,\n listServers,\n listSites,\n updateEnv,\n updateLoadBalancingNodes,\n updateNginxConfig,\n updateSite,\n} from \"@studiometa/forge-core\";\n\nimport type { CliExecutorContext } from \"../../../context.ts\";\nimport { CliError, ValidationError } from \"../../../errors.ts\";\nimport { unifiedDiff } from \"../../../utils/drift.ts\";\nimport { matchServerId } from \"../../../utils/resolve.ts\";\nimport { needsServer, renderNginx } from \"./nginx.ts\";\nimport {\n type Change,\n type Plan,\n type RemoteState,\n type Site,\n buildPlan,\n databaseEnvKeys,\n} from \"./plan.ts\";\nimport type { SiteFile } from \"./site-file.ts\";\n\n/** Error of `apply` that is not a validation error, e.g. a site that never gets installed. */\nexport class ApplyError extends CliError {\n readonly code = \"APPLY_ERROR\";\n readonly isRecoverable = false;\n}\n\n/**\n * Resolve the server of the site file, always with an exact name (never a partial match).\n */\nexport async function resolveApplyServer(\n server: string | number,\n ctx: CliExecutorContext,\n): Promise<string> {\n const value = String(server);\n if (/^\\d+$/.test(value)) return value;\n const servers = await listServers({}, ctx);\n return matchServerId(value, servers.data, true);\n}\n\n/**\n * The site named `domain` on the server, compared without case. A partial match never counts.\n */\nexport function findSite(sites: Site[], domain: string): Site | null {\n return sites.find((site) => site.name.toLowerCase() === domain.toLowerCase()) ?? null;\n}\n\n/**\n * The site of the load balancer named `domain` or one of the aliases, compared without case.\n * Its name can be any of them, e.g. the domain without `www`. Two matches are an error: a guess\n * could send the traffic of another site.\n */\nexport function findLoadBalancerSite(sites: Site[], names: string[]): Site | null {\n const wanted = new Set(names.map((name) => name.toLowerCase()));\n const matches = sites.filter((site) => wanted.has(site.name.toLowerCase()));\n if (matches.length > 1) {\n throw new ValidationError(\n `Several sites of the load balancer match the site file: ${matches.map((site) => site.name).join(\", \")}`,\n \"loadBalancer\",\n [\"Keep one site for the domain and its aliases on the load balancer\"],\n );\n }\n return matches[0] ?? null;\n}\n\n/**\n * Exit with a validation error when the load balancer has no site for the site file: the Forge\n * API cannot create a site on a load balancer.\n */\nexport function assertLoadBalancerSite(file: SiteFile, state: RemoteState): void {\n if (file.loadBalancer && !state.loadBalancer?.site) {\n throw new ValidationError(\n `The load balancer ${file.loadBalancer.server} has no site for ${file.domain}`,\n \"loadBalancer\",\n [\n `In Forge, create the site ${file.domain} on the load balancer (New site), then run apply again`,\n \"Check the domain, the aliases and the server of the load balancer\",\n ],\n );\n }\n}\n\n/**\n * Read from Forge what the site file manages, and nothing else.\n */\nexport async function readRemoteState(\n file: SiteFile,\n serverId: string,\n ctx: CliExecutorContext,\n): Promise<RemoteState> {\n const sites = (await listSites({ server_id: serverId }, ctx)).data;\n const site = findSite(sites, file.domain);\n const siteId = site ? String(site.id) : undefined;\n const state: RemoteState = { sites, site };\n\n if (file.database) {\n state.databases = (await listDatabases({ server_id: serverId }, ctx)).data;\n state.databaseUsers = (await listDatabaseUsers({ server_id: serverId }, ctx)).data;\n }\n\n if (file.env || file.database) {\n state.env = siteId ? (await getEnv({ server_id: serverId, site_id: siteId }, ctx)).data : null;\n }\n\n if (file.workers) {\n state.daemons = (await listDaemons({ server_id: serverId }, ctx)).data;\n state.siteDaemonIds = new Set(\n siteId\n ? (await listDaemons({ server_id: serverId, site_id: siteId }, ctx)).data.map((d) => d.id)\n : [],\n );\n }\n\n if (file.nginxTemplate !== undefined) {\n state.nginx = site ? await readNginx(file.nginxTemplate, serverId, site, ctx) : null;\n }\n\n if (file.schedule) {\n const siteJobs = siteId\n ? (await listScheduledJobs({ server_id: serverId, site_id: siteId }, ctx)).data\n : [];\n const serverJobs = (await listScheduledJobs({ server_id: serverId }, ctx)).data;\n state.jobs = [...siteJobs, ...serverJobs];\n state.siteJobIds = new Set(siteJobs.map((job) => job.id));\n }\n\n if (file.loadBalancer) {\n const balancerId = await resolveApplyServer(file.loadBalancer.server, ctx);\n const balancerSites = (await listSites({ server_id: balancerId }, ctx)).data;\n const balancerSite = findLoadBalancerSite(balancerSites, [\n file.domain,\n ...(file.aliases ?? []),\n ]);\n const nodes = balancerSite\n ? (\n await listLoadBalancingNodes(\n { server_id: balancerId, site_id: String(balancerSite.id) },\n ctx,\n )\n ).data\n : [];\n state.loadBalancer = {\n serverId: balancerId,\n site: balancerSite,\n nodes,\n target: Number(serverId),\n };\n }\n\n return state;\n}\n\n/**\n * Read the Nginx configuration of a site on Forge and render the Nginx file for the site.\n */\nexport async function readNginx(\n template: string,\n serverId: string,\n site: Site,\n ctx: CliExecutorContext,\n): Promise<{ remote: string; rendered: string }> {\n const remote = (await getNginxConfig({ server_id: serverId, site_id: String(site.id) }, ctx))\n .data;\n const server = needsServer(template)\n ? (await getServer({ server_id: serverId }, ctx)).data\n : null;\n return { remote, rendered: renderNginx(template, site, server) };\n}\n\n/**\n * Exit with a validation error when the site does not exist and the site file cannot create it.\n */\nexport function assertCanCreateSite(file: SiteFile, state: RemoteState): void {\n if (!state.site && !file.type) {\n throw new ValidationError(\n `Site ${file.domain} does not exist and the site file has no type to create it`,\n \"type\",\n ['Add \"type\" to the site file, e.g. \"type\": \"php\"', \"Check the domain and the server\"],\n );\n }\n}\n\n/** A random password for a database user: 32 characters, letters and digits only. */\nexport function generatePassword(): string {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n // 248 is the largest multiple of 62 below 256: drop higher bytes to keep the draw uniform.\n let password = \"\";\n while (password.length < 32) {\n for (const byte of randomBytes(64)) {\n if (byte < 248 && password.length < 32) password += alphabet[byte % 62];\n }\n }\n return password;\n}\n\n/** Write a value for a .env file, quoted when it needs quotes. */\nexport function formatEnvValue(value: string): string {\n if (/^[\\w.,:/@+-]*$/.test(value)) return value;\n if (!value.includes(\"'\") && !value.includes(\"\\n\")) return `'${value}'`;\n return `\"${value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"').replaceAll(\"\\n\", \"\\\\n\")}\"`;\n}\n\n/**\n * Set .env variables: replace the line of a variable that exists, append the others.\n */\nexport function setEnvValues(content: string, values: Map<string, string>): string {\n const lines = content === \"\" ? [] : content.replace(/\\n$/, \"\").split(\"\\n\");\n const pending = new Map(values);\n const result = lines.map((line) => {\n const match = /^\\s*(?:export\\s+)?([A-Za-z_][A-Za-z0-9_.]*)\\s*=/.exec(line);\n const name = match?.[1];\n if (name && pending.has(name)) {\n const value = pending.get(name)!;\n pending.delete(name);\n return `${name}=${formatEnvValue(value)}`;\n }\n return line;\n });\n for (const [name, value] of pending) {\n result.push(`${name}=${formatEnvValue(value)}`);\n }\n return `${result.join(\"\\n\")}\\n`;\n}\n\nexport interface ApplyOptions {\n /** Wait between two reads of a new site; injectable for tests. */\n sleep?: (ms: number) => Promise<void>;\n /** Time between two reads of a new site, in ms. */\n pollIntervalMs?: number;\n /** Time to wait for a new site to be installed, in ms. */\n timeoutMs?: number;\n /** Called before each change. */\n onChange?: (change: Change) => void;\n /** Generate a password; injectable for tests. */\n generatePassword?: () => string;\n}\n\n/** Forge clones the repository with the key of the server: the git host must accept it. */\nconst REPOSITORY_HINT = (serverId: string) =>\n `Check that the git host accepts the key of the server: forge servers public-key ${serverId}`;\n\nconst defaultSleep = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n\nasync function waitForSite(\n file: SiteFile,\n serverId: string,\n siteId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const sleep = options.sleep ?? defaultSleep;\n const interval = options.pollIntervalMs ?? 5000;\n const timeout = options.timeoutMs ?? 600_000;\n for (let waited = 0; ; waited += interval) {\n const site = (await getSite({ server_id: serverId, site_id: siteId }, ctx)).data;\n if (site.status === \"installed\") return;\n if (waited >= timeout) {\n throw new ApplyError(`Site ${site.name} is still ${site.status} on Forge`, [\n \"Run forge sites apply again once the site is installed\",\n ...(file.repository ? [REPOSITORY_HINT(serverId)] : []),\n ]);\n }\n await sleep(interval);\n }\n}\n\ninterface DatabaseIds {\n database_id?: number;\n database_user_id?: string;\n}\n\n/**\n * Create the database and its user. Returns their IDs and the .env values to write.\n */\nasync function applyDatabase(\n file: SiteFile,\n plan: Plan,\n state: RemoteState,\n serverId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<{ ids: DatabaseIds; env: Map<string, string> }> {\n const env = new Map<string, string>();\n const ids: DatabaseIds = {};\n if (!file.database) return { ids, env };\n\n let databaseId = state.databases?.find((db) => db.name === file.database!.name)?.id;\n for (const change of plan.changes) {\n if (change.action === \"create-database\") {\n options.onChange?.(change);\n databaseId = (await createDatabase({ server_id: serverId, name: change.name }, ctx)).data.id;\n } else if (change.action === \"create-database-user\") {\n options.onChange?.(change);\n const password = (options.generatePassword ?? generatePassword)();\n const user = await createDatabaseUser(\n {\n server_id: serverId,\n name: change.name,\n password,\n ...(databaseId === undefined ? {} : { database_ids: [databaseId] }),\n },\n ctx,\n );\n ids.database_user_id = String(user.data.id);\n const keys = databaseEnvKeys(file.database);\n env.set(keys.name, change.database);\n env.set(keys.user, change.name);\n env.set(keys.password, password);\n }\n }\n if (databaseId !== undefined) ids.database_id = databaseId;\n return { ids, env };\n}\n\n/**\n * Write the rendered Nginx file when it differs from Forge. After a change of the site or its\n * aliases, read the site again: the web directory and the domains are template variables.\n */\nasync function applyNginx(\n template: string,\n plan: Plan,\n serverId: string,\n site: Site,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const siteChanged = plan.changes.some(\n (change) => change.action === \"update-site\" || change.action === \"add-alias\",\n );\n const planned = plan.changes.some((change) => change.action === \"update-nginx\");\n if (!planned && !siteChanged) return;\n\n const params = { server_id: serverId, site_id: String(site.id) };\n const current = siteChanged ? (await getSite(params, ctx)).data : site;\n const { remote, rendered } = await readNginx(template, serverId, current, ctx);\n const diff = unifiedDiff(remote, rendered);\n if (!diff) return;\n options.onChange?.({ action: \"update-nginx\", diff });\n await updateNginxConfig({ ...params, content: rendered }, ctx);\n}\n\n/**\n * Run the changes of a plan for a site that exists.\n */\nasync function applyChanges(\n file: SiteFile,\n plan: Plan,\n state: RemoteState,\n serverId: string,\n site: Site,\n generatedEnv: Map<string, string>,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const params = { server_id: serverId, site_id: String(site.id) };\n const { env: databaseEnv } = await applyDatabase(file, plan, state, serverId, ctx, options);\n const env = new Map([...generatedEnv, ...databaseEnv]);\n const creations: Change[] = [];\n const deletions: Change[] = [];\n\n for (const change of plan.changes) {\n switch (change.action) {\n case \"update-site\": {\n options.onChange?.(change);\n const update: Record<string, string> = {};\n for (const { field, to } of change.changes) {\n if (field === \"php_version\") update.php_version = to;\n if (field === \"web_directory\") update.directory = to;\n if (field === \"branch\") update.repository_branch = to;\n }\n await updateSite({ ...params, ...update }, ctx);\n break;\n }\n case \"add-alias\":\n options.onChange?.(change);\n await createDomain(\n {\n ...params,\n name: change.name,\n allow_wildcard_subdomains: false,\n www_redirect_type: \"none\",\n },\n ctx,\n );\n break;\n case \"add-env\":\n for (const key of change.keys) env.set(key, String(file.env?.[key]));\n break;\n case \"create-worker\":\n case \"create-job\":\n creations.push(change);\n break;\n case \"delete-worker\":\n case \"delete-job\":\n deletions.push(change);\n break;\n default:\n break;\n }\n }\n\n if (env.size > 0) {\n const addEnv = plan.changes.find((change) => change.action === \"add-env\");\n if (addEnv) options.onChange?.(addEnv);\n const content = (await getEnv(params, ctx)).data;\n await updateEnv({ ...params, content: setEnvValues(content, env) }, ctx);\n }\n\n if (file.nginxTemplate !== undefined) {\n await applyNginx(file.nginxTemplate, plan, serverId, site, ctx, options);\n }\n\n // Create first, then delete: a changed worker runs again before the old one stops.\n for (const change of creations) {\n options.onChange?.(change);\n if (change.action === \"create-worker\") {\n await createDaemon(\n {\n server_id: serverId,\n site_id: site.id,\n name: change.command.slice(0, 255),\n command: change.command,\n user: \"forge\",\n directory: change.directory,\n processes: change.processes,\n },\n ctx,\n );\n } else if (change.action === \"create-job\") {\n await createScheduledJob(\n {\n ...params,\n command: change.command,\n user: \"forge\",\n frequency: change.frequency,\n ...(change.cron ? { cron: change.cron } : {}),\n },\n ctx,\n );\n }\n }\n\n // Last: the load balancer sends traffic to the server once the site is ready there.\n const balancer = state.loadBalancer;\n const balancing = plan.changes.find((change) => change.action === \"update-load-balancer\");\n if (balancing?.action === \"update-load-balancer\" && balancer?.site) {\n options.onChange?.(balancing);\n await updateLoadBalancingNodes(\n {\n server_id: balancer.serverId,\n site_id: String(balancer.site.id),\n balancer_method: \"round_robin\",\n balancing: [{ ...balancing.to, weight: 1 }],\n },\n ctx,\n );\n }\n\n for (const change of deletions) {\n options.onChange?.(change);\n if (change.action === \"delete-worker\") {\n await deleteDaemon({ server_id: serverId, id: String(change.id) }, ctx);\n } else if (change.action === \"delete-job\") {\n await deleteScheduledJob(\n {\n server_id: serverId,\n id: String(change.id),\n ...(change.onSite ? { site_id: params.site_id } : {}),\n },\n ctx,\n );\n }\n }\n}\n\n/**\n * Apply a site file: create the site when it does not exist and wait until Forge installs it,\n * then read the state again and run the other changes. Returns the plan that ran first.\n */\nexport async function applySiteFile(\n file: SiteFile,\n serverId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions = {},\n): Promise<Plan> {\n let state = await readRemoteState(file, serverId, ctx);\n assertLoadBalancerSite(file, state);\n const firstPlan = buildPlan(file, state);\n let plan = firstPlan;\n let generatedEnv = new Map<string, string>();\n\n const createSiteChange = plan.changes.find((change) => change.action === \"create-site\");\n if (createSiteChange && createSiteChange.action === \"create-site\") {\n assertCanCreateSite(file, state);\n const database = await applyDatabase(file, plan, state, serverId, ctx, options);\n generatedEnv = database.env;\n options.onChange?.(createSiteChange);\n const { settings } = createSiteChange;\n const created = await createSite(\n {\n server_id: serverId,\n type: file.type!,\n name: file.domain,\n ...(settings.php_version ? { php_version: settings.php_version } : {}),\n ...(settings.web_directory ? { web_directory: settings.web_directory } : {}),\n ...(settings.source_control_provider\n ? { source_control_provider: settings.source_control_provider }\n : {}),\n ...(settings.repository ? { repository: settings.repository } : {}),\n ...(settings.branch ? { branch: settings.branch } : {}),\n ...database.ids,\n },\n ctx,\n );\n await waitForSite(file, serverId, String(created.data.id), ctx, options);\n state = await readRemoteState(file, serverId, ctx);\n plan = buildPlan(file, state);\n }\n\n const site = state.site;\n if (!site) {\n throw new ApplyError(`Site ${file.domain} is not on server ${serverId} after its creation`);\n }\n await applyChanges(file, plan, state, serverId, site, generatedEnv, ctx, options);\n return firstPlan;\n}\n","/**\n * The site file of `forge sites apply`: a JSON file that declares one Forge site.\n * A key that is absent is not managed; only `server` and `domain` are required.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport * as v from \"valibot\";\n\nimport { ValidationError } from \"../../../errors.ts\";\nimport { assertNginxTemplate } from \"./nginx.ts\";\n\n/** URL of the JSON Schema of the site file, published with the package. */\nexport const SITE_FILE_SCHEMA_URL =\n \"https://unpkg.com/@studiometa/forge-cli/schemas/site.schema.json\";\n\nconst text = v.pipe(v.string(), v.trim(), v.nonEmpty());\n\n/** A server name (exact match) or ID. */\nconst serverRef = v.union([text, v.pipe(v.number(), v.integer(), v.minValue(1))]);\n\nexport const SITE_TYPES = [\n \"laravel\",\n \"symfony\",\n \"statamic\",\n \"wordpress\",\n \"phpmyadmin\",\n \"php\",\n \"nextjs\",\n \"nuxtjs\",\n \"static-html\",\n \"other\",\n \"custom\",\n] as const;\n\nexport const SOURCE_CONTROL_PROVIDERS = [\n \"github\",\n \"gitlab\",\n \"bitbucket\",\n \"gitlab-custom\",\n \"custom\",\n] as const;\n\nexport const SCHEDULE_FREQUENCIES = [\n \"minutely\",\n \"hourly\",\n \"nightly\",\n \"weekly\",\n \"monthly\",\n \"reboot\",\n \"custom\",\n] as const;\n\nexport const WorkerSchema = v.strictObject({\n command: text,\n processes: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1)), 1),\n directory: v.optional(text),\n});\n\nexport const ScheduledJobSchema = v.pipe(\n v.strictObject({\n command: text,\n frequency: v.picklist(SCHEDULE_FREQUENCIES),\n cron: v.optional(text),\n }),\n v.check(\n (job) => (job.frequency === \"custom\") === (job.cron !== undefined),\n \"cron is required with the custom frequency, and only with it\",\n ),\n);\n\nconst envName = v.pipe(\n v.string(),\n v.regex(/^[A-Za-z_][A-Za-z0-9_]*$/, \"invalid .env variable name\"),\n);\n\n/** The .env keys that a new database user gets. Default: the Laravel names. */\nexport const DatabaseEnvSchema = v.pipe(\n v.strictObject({\n name: v.optional(envName),\n user: v.optional(envName),\n password: v.optional(envName),\n }),\n v.check(\n (env) =>\n new Set([env.name ?? \"DB_DATABASE\", env.user ?? \"DB_USERNAME\", env.password ?? \"DB_PASSWORD\"])\n .size === 3,\n \"the .env keys of the database must be different\",\n ),\n);\n\n/** The load balancer that sends the traffic of the site to its server. */\nexport const LoadBalancerSchema = v.strictObject({\n server: serverRef,\n port: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 80),\n});\n\nexport const SiteFileSchema = v.strictObject({\n $schema: v.optional(v.string()),\n server: serverRef,\n domain: text,\n aliases: v.optional(v.array(text)),\n type: v.optional(v.picklist(SITE_TYPES)),\n php: v.optional(v.pipe(v.string(), v.regex(/^php\\d+$/, \"php must look like php83\"))),\n webDirectory: v.optional(text),\n repository: v.optional(\n v.strictObject({\n provider: v.picklist(SOURCE_CONTROL_PROVIDERS),\n url: text,\n branch: v.optional(text),\n }),\n ),\n database: v.optional(\n v.strictObject({ name: text, user: text, env: v.optional(DatabaseEnvSchema) }),\n ),\n env: v.optional(v.record(envName, v.union([v.string(), v.number(), v.boolean()]))),\n nginx: v.optional(text),\n workers: v.optional(v.array(WorkerSchema)),\n schedule: v.optional(v.array(ScheduledJobSchema)),\n loadBalancer: v.optional(LoadBalancerSchema),\n});\n\nexport type SiteFileData = v.InferOutput<typeof SiteFileSchema>;\n\n/** A site file with the content of its Nginx file, when it declares one. */\nexport type SiteFile = SiteFileData & { nginxTemplate?: string };\nexport type WorkerDeclaration = v.InferOutput<typeof WorkerSchema>;\nexport type ScheduledJobDeclaration = v.InferOutput<typeof ScheduledJobSchema>;\n\n/**\n * Validate parsed JSON as a site file. Throws a ValidationError that lists every issue.\n */\nexport function parseSiteFile(data: unknown, source = \"site file\"): SiteFileData {\n const result = v.safeParse(SiteFileSchema, data);\n if (!result.success) {\n const issues = result.issues.map((issue) => {\n const path = v.getDotPath(issue);\n return `${path ?? \"(root)\"}: ${issue.message}`;\n });\n throw new ValidationError(`Invalid ${source}`, \"file\", issues);\n }\n return result.output;\n}\n\n/**\n * Read and validate a site file from disk, with its Nginx file: a relative `nginx` path is\n * read against the folder of the site file.\n */\nexport function readSiteFile(path: string): SiteFile {\n let content: string;\n try {\n content = readFileSync(path, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Cannot read site file ${path}: ${reason}`, \"file\");\n }\n\n let data: unknown;\n try {\n data = JSON.parse(content);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Site file ${path} is not valid JSON: ${reason}`, \"file\");\n }\n\n const file: SiteFile = parseSiteFile(data, `site file ${path}`);\n if (file.nginx) {\n const nginxPath = resolve(dirname(path), file.nginx);\n try {\n file.nginxTemplate = readFileSync(nginxPath, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Cannot read Nginx file ${nginxPath}: ${reason}`, \"nginx\");\n }\n assertNginxTemplate(file.nginxTemplate, nginxPath);\n }\n return file;\n}\n","import type { CommandContext } from \"../../../context.ts\";\n\nimport { ExitCode, exitWithValidationError, runCommand } from \"../../../error-handler.ts\";\nimport {\n type ApplyOptions,\n applySiteFile,\n assertCanCreateSite,\n assertLoadBalancerSite,\n readRemoteState,\n resolveApplyServer,\n} from \"./apply.ts\";\nimport { buildPlan, describeChange } from \"./plan.ts\";\nimport { readSiteFile } from \"./site-file.ts\";\n\n/**\n * `forge sites apply --file site.json [--check]`: make a Forge site match a site file.\n * With `--check`, print the plan and exit 1 when Forge differs, without any change.\n */\nexport async function sitesApply(\n ctx: CommandContext,\n applyOptions: ApplyOptions = {},\n): Promise<void> {\n const usage = \"forge sites apply --file <site.json> [--check]\";\n const path = ctx.options.file;\n const check = Boolean(ctx.options.check);\n\n if (typeof path !== \"string\" || !path) {\n exitWithValidationError(\"file\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const file = readSiteFile(path);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveApplyServer(file.server, execCtx);\n\n if (check) {\n const state = await readRemoteState(file, server_id, execCtx);\n assertCanCreateSite(file, state);\n assertLoadBalancerSite(file, state);\n const plan = buildPlan(file, state);\n const inSync = plan.changes.length === 0;\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ inSync, changes: plan.changes, warnings: plan.warnings });\n } else {\n for (const change of plan.changes) console.log(describeChange(change));\n for (const warning of plan.warnings) ctx.formatter.warning(warning);\n if (inSync) ctx.formatter.success(`Site ${file.domain} is in sync with Forge.`);\n else ctx.formatter.error(`Site ${file.domain} differs from Forge.`);\n }\n if (!inSync) process.exitCode = ExitCode.GENERAL_ERROR;\n return;\n }\n\n const applied: string[] = [];\n const plan = await applySiteFile(file, server_id, execCtx, {\n ...applyOptions,\n onChange: (change) => {\n applied.push(change.action);\n if (!ctx.formatter.isJson()) console.log(describeChange(change));\n },\n });\n\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ changes: plan.changes, warnings: plan.warnings });\n } else {\n for (const warning of plan.warnings) ctx.formatter.warning(warning);\n ctx.formatter.success(\n applied.length === 0\n ? `Site ${file.domain} is in sync with Forge.`\n : `Site ${file.domain} applied: ${applied.length} change(s).`,\n );\n }\n }, ctx.formatter);\n}\n","import { listSites, getSite, updateSite } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function sitesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge sites list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listSites({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\", \"php_version\"],\n \"No sites found.\",\n (s) =>\n `${String(s.id).padEnd(8)} ${s.name.padEnd(40)} ${s.status.padEnd(12)} ${s.php_version}`,\n );\n }, ctx.formatter);\n}\n\nexport async function sitesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [siteArg] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!siteArg) {\n exitWithValidationError(\n \"site_id\",\n \"forge sites get <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge sites get <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(siteArg, server_id, execCtx);\n const result = await getSite({ server_id, site_id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"status\",\n \"php_version\",\n \"app_type\",\n \"repository\",\n \"quick_deploy\",\n \"deployment_status\",\n \"https\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function sitesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [siteArg] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!siteArg) {\n exitWithValidationError(\n \"site_id\",\n \"forge sites update <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge sites update <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(siteArg, server_id, execCtx);\n const result = await updateSite(\n {\n server_id,\n site_id,\n root_path: ctx.options.root_path as string | undefined,\n directory: ctx.options.directory as string | undefined,\n type: ctx.options.type as string | undefined,\n php_version: ctx.options.php_version as string | undefined,\n push_to_deploy:\n ctx.options.push_to_deploy !== undefined\n ? ctx.options.push_to_deploy === \"true\" || ctx.options.push_to_deploy === true\n : undefined,\n repository_branch: ctx.options.repository_branch as string | undefined,\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"status\",\n \"php_version\",\n \"app_type\",\n \"repository\",\n \"quick_deploy\",\n \"deployment_status\",\n \"https\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { sitesApply } from \"./apply/handler.ts\";\nimport { sitesList, sitesGet, sitesUpdate } from \"./handlers.ts\";\n\nexport const handleSitesCommand = createCommandRouter({\n resource: \"sites\",\n handlers: {\n list: sitesList,\n ls: sitesList,\n get: [sitesGet, \"args\"],\n update: [sitesUpdate, \"args\"],\n apply: (ctx) => sitesApply(ctx),\n },\n writeSubcommands: [\"apply\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSitesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge sites list\")} - List sites on a server\n\n${colors.bold(\"USAGE:\")}\n forge sites list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites list --server 123\n forge sites list --server 123 --format json\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge sites get\")} - Get site details\n\n${colors.bold(\"USAGE:\")}\n forge sites get <site_id> --server <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <site_id> Site ID (required)\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"apply\") {\n console.log(`\n${colors.bold(\"forge sites apply\")} - Make a site match a site file\n\n${colors.bold(\"USAGE:\")}\n forge sites apply --file <site.json> [--check] [options]\n\n${colors.bold(\"OPTIONS:\")}\n --file <path> Site file (required), e.g. config/forge/production/site.json\n --check Print the plan and change nothing: exit 0 when Forge matches,\n exit 1 when it differs, another code on error\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"SITE FILE:\")}\n Only \"server\" (exact name or ID) and \"domain\" (exact site name) are required.\n A key that is absent is not managed: apply does not read or change it.\n type, php, webDirectory, repository Create the site, or update php, web directory, branch\n aliases Add missing aliases, never remove one\n database { name, user, env } Create when missing; a new user gets a random\n password, written into the site .env only.\n env maps { name, user, password } to .env keys\n (default DB_DATABASE, DB_USERNAME, DB_PASSWORD)\n env Add missing keys, never overwrite a value\n nginx Nginx file, relative to the site file, with Forge\n template variables such as {{PATH}}, {{SITE_ID}},\n {{PROXY_PASS}}: rendered for the site, written\n when it differs (an unknown variable exits 3)\n workers, schedule Create missing ones, delete the ones of the site\n that the file does not declare ([] deletes all)\n\n A worker or scheduled job is deleted only when it surely belongs to the site:\n Forge lists it on the site, or its directory (or, without a directory, its command)\n uses the site path, compared on whole path segments. Jobs of root are never deleted.\n The plan never prints .env values.\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites apply --file config/forge/production/site.json --check\n forge sites apply --file config/forge/production/site.json\n`);\n } else {\n console.log(`\n${colors.bold(\"forge sites\")} - Manage sites\n\n${colors.bold(\"USAGE:\")}\n forge sites <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List sites on a server\n get <id> Get site details\n apply Make a site match a site file (--file, --check)\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required for most commands)\n -f, --format <fmt> Output format: json, human, table\n -h, --help Show help for a subcommand\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites list --server 123\n forge sites get 456 --server 123\n forge sites apply --file config/forge/production/site.json --check\n\nRun ${colors.cyan(\"forge sites <subcommand> --help\")} for subcommand details.\n`);\n }\n}\n","/**\n * Pure helpers for resolving SSH connection details from a Forge server.\n *\n * Kept free of side effects so the resolution logic is fully unit-testable\n * without spawning a real `ssh` process.\n */\n\nimport type { ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** Forge's conventional default provisioning user. */\nexport const DEFAULT_SSH_USER = \"forge\";\n\nexport interface SshTargetOptions {\n /** SSH user (defaults to {@link DEFAULT_SSH_USER}). */\n user?: string;\n /** Connect over the private network (`private_ip_address`) instead of the public IP. */\n private?: boolean;\n /** Override the server's `ssh_port` (string as parsed from the CLI). */\n port?: string;\n}\n\nexport interface SshTarget {\n user: string;\n host: string;\n port: number;\n}\n\n/**\n * Resolve the concrete user/host/port to connect to.\n *\n * @throws {ValidationError} when the selected IP is not available yet, or the port override is invalid.\n */\nexport function resolveSshTarget(\n server: ServerAttributes,\n options: SshTargetOptions = {},\n): SshTarget {\n const user = options.user?.trim() || DEFAULT_SSH_USER;\n\n const host = options.private ? server.private_ip_address : server.ip_address;\n if (!host) {\n const which = options.private ? \"private IP address\" : \"IP address\";\n const hints = [\n server.is_ready\n ? \"The server is ready but no address is available — check the Forge dashboard.\"\n : \"The server is still provisioning. Wait until it is ready, then try again.\",\n options.private ? undefined : \"Use --private to connect over the private network.\",\n ].filter((hint): hint is string => Boolean(hint));\n\n throw new ValidationError(`Server \"${server.name}\" has no ${which} available`, \"server\", hints);\n }\n\n let port = server.ssh_port;\n if (options.port !== undefined) {\n const parsed = Number(options.port);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {\n throw new ValidationError(`Invalid SSH port \"${options.port}\"`, \"port\", [\n \"Port must be an integer between 1 and 65535.\",\n ]);\n }\n port = parsed;\n }\n\n return { user, host, port };\n}\n\n/**\n * Build the argument list passed to the `ssh` binary.\n *\n * Any {@link remoteCommand} is appended after the connection flags, so\n * `forge ssh web uptime` runs `uptime` remotely and exits.\n */\nexport function buildSshArgs(target: SshTarget, remoteCommand: string[] = []): string[] {\n const args = [`${target.user}@${target.host}`, \"-p\", String(target.port)];\n if (remoteCommand.length > 0) {\n args.push(...remoteCommand);\n }\n return args;\n}\n","/**\n * CLI handler for `forge ssh` — open an interactive SSH session to a server.\n *\n * Resolves the server, reads its connection details from the API, then hands\n * off to the local `ssh` binary with an inherited stdio (interactive) session.\n */\n\nimport { spawnSync } from \"node:child_process\";\n\nimport { getServer } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { getCliAuditLogger } from \"../../audit.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\nimport { buildSshArgs, resolveSshTarget } from \"./ssh-target.ts\";\n\n/**\n * Connect to a server over SSH.\n *\n * @param server - Server ID or name (resolved via {@link resolveServerId}).\n * @param remote - Optional remote command to run instead of an interactive shell.\n * @param ctx - CLI command context.\n */\nexport async function sshConnect(\n server: string | undefined,\n remote: string[],\n ctx: CommandContext,\n): Promise<void> {\n if (!server) {\n exitWithValidationError(\"server\", \"forge ssh <server> [command...]\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const { data } = await getServer({ server_id }, execCtx);\n\n const target = resolveSshTarget(data, {\n user: typeof ctx.options.user === \"string\" ? ctx.options.user : undefined,\n private: ctx.options.private === true,\n port: typeof ctx.options.port === \"string\" ? ctx.options.port : undefined,\n });\n\n const sshArgs = buildSshArgs(target, remote);\n const printable = `ssh ${sshArgs.join(\" \")}`;\n\n // Script-safe modes: print the resolved command instead of opening a session.\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ command: printable, ...target, args: sshArgs });\n return;\n }\n if (ctx.options[\"dry-run\"] === true) {\n console.log(printable);\n return;\n }\n\n // Sanitized args for the audit log (never record the token).\n const auditArgs = {\n server: server_id,\n user: target.user,\n host: target.host,\n port: target.port,\n };\n\n try {\n const child = spawnSync(\"ssh\", sshArgs, { stdio: \"inherit\" });\n if (child.error) {\n throw child.error;\n }\n getCliAuditLogger().log({\n source: \"cli\",\n resource: \"ssh\",\n action: \"connect\",\n args: auditArgs,\n status: \"success\",\n });\n if (typeof child.status === \"number\" && child.status !== 0) {\n process.exit(child.status);\n }\n } catch (err) {\n getCliAuditLogger().log({\n source: \"cli\",\n resource: \"ssh\",\n action: \"connect\",\n args: auditArgs,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n }, ctx.formatter);\n}\n","import type { CommandOptions } from \"../../context.ts\";\n\nimport { createContext } from \"../../context.ts\";\nimport { sshConnect } from \"./handlers.ts\";\n\n/**\n * Route the top-level `forge ssh` command.\n *\n * Unlike resource commands there is no sub-action: the first positional is the\n * server, and any remaining positionals form an optional remote command.\n */\nexport async function handleSshCommand(\n server: string | undefined,\n remote: string[],\n options: CommandOptions,\n): Promise<void> {\n const ctx = createContext(options);\n await sshConnect(server, remote, ctx);\n}\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSshHelp(): void {\n console.log(`\n${colors.bold(\"forge ssh\")} - Open an SSH session to a server\n\n${colors.bold(\"USAGE:\")}\n forge ssh <server> [command...] [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n [command...] Optional remote command to run, then exit\n\n${colors.bold(\"OPTIONS:\")}\n --user <name> SSH user (default: forge)\n --private Connect over the private IP address\n --port <n> Override the server's SSH port\n --dry-run Print the ssh command instead of connecting\n -f, --format json Print the resolved connection details as JSON\n -h, --help Show this help\n\n${colors.bold(\"EXAMPLES:\")}\n # Interactive session (connects as forge@<ip>)\n forge ssh my-server\n\n # Connect as a custom user\n forge ssh my-server --user deploy\n\n # Use the private network\n forge ssh my-server --private\n\n # Run a one-off remote command\n forge ssh my-server uptime\n\n # Just show the command that would run\n forge ssh my-server --dry-run\n\n${colors.bold(\"NOTES:\")}\n Requires your local SSH key to be authorized on the server; this command\n launches ssh, it does not upload keys.\n`);\n}\n","import { listSshKeys, getSshKey } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function sshKeysList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge ssh-keys list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listSshKeys({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No SSH keys found.\",\n (k) => `${String(k.id).padEnd(8)} ${k.name.padEnd(30)} ${k.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function sshKeysGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"ssh_key_id\",\n \"forge ssh-keys get <key_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge ssh-keys get <key_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getSshKey({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n","/**\n * Pure logic for `forge ssh-keys sync`: parse an authorized_keys file, give each key\n * a stable managed name, and compare the file with the keys on a server.\n *\n * The Forge API does not return public keys, so keys are matched by name. The name\n * ends with a fingerprint of the key, so a changed key gets a new name.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** The Forge API documents no name limit: keep names short enough to read in a list. */\nconst MAX_SLUG_LENGTH = 40;\n\nconst KEY_TYPE = /^(ssh-|ecdsa-sha2-|sk-)[a-z0-9@.-]+$/;\nconst BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;\n\n/**\n * Check the base64 key data of a public key, as OpenSSH does: it must be canonical\n * base64, and the decoded key must start with its own type as a length-prefixed string.\n */\nexport function isValidKeyBlob(type: string, blob: string): boolean {\n if (!BASE64.test(blob) || blob.length % 4 !== 0) {\n return false;\n }\n const data = Buffer.from(blob, \"base64\");\n if (data.toString(\"base64\") !== blob || data.length < 4) {\n return false;\n }\n const typeLength = data.readUInt32BE(0);\n return 4 + typeLength <= data.length && data.toString(\"latin1\", 4, 4 + typeLength) === type;\n}\n\n/** A public key from the file, with the name it gets on Forge. */\nexport interface FileKey {\n name: string;\n /** Public key as sent to Forge: \"<type> <base64> [comment]\". */\n key: string;\n /** Line number in the file (1-based). */\n line: number;\n}\n\n/** A key that exists on a server. */\nexport interface ServerKey {\n id: number;\n name: string;\n user: string;\n}\n\nexport interface SyncPlan {\n /** File keys that are not on the server. */\n add: FileKey[];\n /** Keys of the user on the server that are not in the file. */\n remove: ServerKey[];\n /** File keys that are already on the server. */\n unchanged: FileKey[];\n}\n\n/**\n * Convert a key comment to a name prefix: lowercase, `[a-z0-9-]` only, \"key\" when empty.\n */\nexport function slugify(comment: string): string {\n const slug = comment\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/g, \"-\")\n .slice(0, MAX_SLUG_LENGTH)\n .replaceAll(/^-+|-+$/g, \"\");\n return slug || \"key\";\n}\n\n/**\n * Managed name of a key: \"<slug(comment)>-<first 8 hex chars of the SHA-256 of the key blob>\".\n * The blob is the decoded base64 field, as in an OpenSSH fingerprint.\n */\nexport function managedKeyName(comment: string, blob: string): string {\n const hash = createHash(\"sha256\").update(Buffer.from(blob, \"base64\")).digest(\"hex\");\n return `${slugify(comment)}-${hash.slice(0, 8)}`;\n}\n\n/**\n * Parse an authorized_keys file: one \"<type> <base64> [comment]\" per line.\n * Blank lines and \"#\" comments are ignored.\n *\n * @throws ValidationError for a malformed or duplicate key, with its line number.\n */\nexport function parseAuthorizedKeys(content: string): FileKey[] {\n const keys: FileKey[] = [];\n const seen = new Map<string, number>();\n\n for (const [index, raw] of content.split(/\\r?\\n/).entries()) {\n const line = index + 1;\n const text = raw.trim();\n if (!text || text.startsWith(\"#\")) {\n continue;\n }\n\n // The error never repeats the line: a wrong --file (a .env, a secret) must not leak to logs.\n const [type, blob = \"\", ...rest] = text.split(/\\s+/);\n const problem = !KEY_TYPE.test(type)\n ? \"unknown key type\"\n : !isValidKeyBlob(type, blob)\n ? \"missing or invalid base64 key data\"\n : undefined;\n if (problem) {\n throw new ValidationError(\n `Line ${line}: ${problem}, expected \"<type> <base64> [comment]\"`,\n \"file\",\n [\"Use one public key per line, as in ~/.ssh/authorized_keys (no options prefix)\"],\n );\n }\n\n const first = seen.get(blob);\n if (first !== undefined) {\n throw new ValidationError(`Line ${line}: duplicate of the key on line ${first}`, \"file\");\n }\n seen.set(blob, line);\n\n const comment = rest.join(\" \");\n keys.push({\n name: managedKeyName(comment, blob),\n key: [type, blob, comment].filter(Boolean).join(\" \"),\n line,\n });\n }\n\n return keys;\n}\n\n/**\n * Compare the file keys with the keys on a server, for one user.\n * Keys of other users are ignored.\n */\nexport function planSync(fileKeys: FileKey[], serverKeys: ServerKey[], user: string): SyncPlan {\n const userKeys = serverKeys.filter((k) => k.user === user);\n const serverNames = new Set(userKeys.map((k) => k.name));\n const fileNames = new Set(fileKeys.map((k) => k.name));\n\n return {\n add: fileKeys.filter((k) => !serverNames.has(k.name)),\n remove: userKeys.filter((k) => !fileNames.has(k.name)),\n unchanged: fileKeys.filter((k) => serverNames.has(k.name)),\n };\n}\n","import type { ExecutorContext } from \"@studiometa/forge-core\";\nimport { createSshKey, deleteSshKey, listServers, listSshKeys } from \"@studiometa/forge-core\";\n\nimport type { CliExecutorContext, CommandContext } from \"../../context.ts\";\nimport type { FileKey, SyncPlan } from \"./sync-plan.ts\";\n\nimport {\n ExitCode,\n exitWithError,\n exitWithValidationError,\n runCommand,\n} from \"../../error-handler.ts\";\nimport { ValidationError } from \"../../errors.ts\";\nimport { colors } from \"../../utils/colors.ts\";\nimport { readContentFile } from \"../../utils/content-source.ts\";\nimport { matchServerId } from \"../../utils/resolve.ts\";\nimport { parseAuthorizedKeys, planSync } from \"./sync-plan.ts\";\n\nconst USAGE =\n \"forge ssh-keys sync --file <path|-> (--server <id>... | --all-servers) [--user <name>] [--prune] [--dry-run]\";\n\n/** Sync state and outcome of one server. */\ninterface ServerSync {\n id: number;\n name: string;\n plan?: SyncPlan;\n added: string[];\n removed: string[];\n unchanged: string[];\n errors: string[];\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Read the --server values: repeated and/or comma separated.\n */\nfunction serverValues(value: unknown): string[] {\n return [value]\n .flat()\n .filter((v): v is string => typeof v === \"string\")\n .flatMap((v) => v.split(\",\"))\n .map((v) => v.trim())\n .filter(Boolean);\n}\n\n/**\n * Read and parse the --file option. Exits on a missing, unreadable, malformed or empty file.\n */\nfunction readFileKeys(ctx: CommandContext): FileKey[] {\n const { file } = ctx.options;\n const content = readContentFile(file, \"file\", {\n label: \"SSH keys file\",\n usage: USAGE,\n formatter: ctx.formatter,\n });\n\n let keys: FileKey[];\n try {\n keys = parseAuthorizedKeys(content);\n } catch (error) {\n // parseAuthorizedKeys only throws a ValidationError with the line number.\n exitWithError(error as ValidationError, ctx.formatter);\n }\n\n if (keys.length === 0) {\n exitWithError(\n new ValidationError(`No SSH keys found in ${String(file)}`, \"file\"),\n ctx.formatter,\n );\n }\n\n return keys;\n}\n\n/**\n * Resolve the target servers to ids and names, without duplicates.\n * Names are matched against one list of servers: one API call for all targets.\n */\nasync function resolveTargets(\n values: string[],\n allServers: boolean,\n execCtx: CliExecutorContext,\n): Promise<Array<{ id: number; name: string }>> {\n const servers = (await listServers({}, execCtx)).data;\n if (allServers) {\n return servers.map((s) => ({ id: s.id, name: s.name }));\n }\n\n const targets = new Map<number, string>();\n for (const value of values) {\n const id = Number(matchServerId(value, servers, execCtx.exactMatch));\n targets.set(id, servers.find((s) => s.id === id)?.name ?? String(id));\n }\n return [...targets].map(([id, name]) => ({ id, name }));\n}\n\nfunction printPlan(syncs: ServerSync[], user: string, prune: boolean): void {\n for (const sync of syncs) {\n console.log(colors.bold(`${sync.name} (${sync.id})`));\n for (const error of sync.errors) {\n console.log(colors.red(` ✗ ${error}`));\n }\n if (!sync.plan) continue;\n\n const { add, remove, unchanged } = sync.plan;\n for (const key of add) console.log(colors.green(` + ${key.name}`));\n if (prune) {\n for (const key of remove) console.log(colors.red(` - ${key.name}`));\n }\n for (const key of unchanged) console.log(colors.dim(` = ${key.name}`));\n if (!prune && remove.length > 0) {\n console.log(\n colors.yellow(\n ` ${remove.length} key(s) of user \"${user}\" not in the file are kept (use --prune to remove them)`,\n ),\n );\n }\n }\n}\n\nfunction printResult(syncs: ServerSync[]): void {\n for (const sync of syncs) {\n const summary = `${sync.name} (${sync.id}): ${sync.added.length} added, ${sync.removed.length} removed, ${sync.unchanged.length} unchanged`;\n if (sync.errors.length === 0) {\n console.log(colors.green(`✓ ${summary}`));\n continue;\n }\n console.log(colors.red(`✗ ${summary}, ${sync.errors.length} failed`));\n for (const error of sync.errors) {\n console.log(colors.red(` ${error}`));\n }\n }\n}\n\n/**\n * Apply a plan to one server. Each failed operation is recorded and the next one runs.\n * When an add fails, the removals are skipped: the user must not lose access to the server.\n */\nasync function applyPlan(\n sync: ServerSync,\n plan: SyncPlan,\n user: string,\n prune: boolean,\n execCtx: ExecutorContext,\n): Promise<void> {\n const server_id = String(sync.id);\n\n let addFailed = false;\n for (const key of plan.add) {\n try {\n await createSshKey({ server_id, name: key.name, key: key.key, user }, execCtx);\n sync.added.push(key.name);\n } catch (error) {\n addFailed = true;\n sync.errors.push(`add ${key.name}: ${errorMessage(error)}`);\n }\n }\n\n if (!prune) return;\n\n for (const key of plan.remove) {\n if (addFailed) {\n sync.errors.push(`remove ${key.name}: skipped because an add failed`);\n continue;\n }\n try {\n await deleteSshKey({ server_id, id: String(key.id) }, execCtx);\n sync.removed.push(key.name);\n } catch (error) {\n sync.errors.push(`remove ${key.name}: ${errorMessage(error)}`);\n }\n }\n}\n\n/**\n * Make the SSH keys of a user on one or more servers match an authorized_keys file.\n */\nexport async function sshKeysSync(ctx: CommandContext): Promise<void> {\n const { options, formatter } = ctx;\n const servers = serverValues(options.server);\n const allServers = options[\"all-servers\"] === true;\n const userOption = options.user;\n const prune = options.prune === true;\n const dryRun = options[\"dry-run\"] === true;\n\n if (options.file === undefined) {\n exitWithValidationError(\"file\", USAGE, formatter);\n }\n\n if (userOption !== undefined && (typeof userOption !== \"string\" || userOption === \"\")) {\n exitWithError(\n new ValidationError(\"--user requires a name\", \"user\", [`Usage: ${USAGE}`]),\n formatter,\n );\n }\n const user = typeof userOption === \"string\" ? userOption : \"forge\";\n\n if (allServers && options.server !== undefined) {\n exitWithError(\n new ValidationError(\"Use either --server or --all-servers, not both\", \"server\", [\n `Usage: ${USAGE}`,\n ]),\n formatter,\n );\n }\n\n if (!allServers && servers.length === 0) {\n exitWithError(\n new ValidationError(\"A target is required: --server <id> or --all-servers\", \"server\", [\n `Usage: ${USAGE}`,\n ]),\n formatter,\n );\n }\n\n const fileKeys = readFileKeys(ctx);\n\n const failed = await runCommand(async () => {\n const execCtx = ctx.createExecutorContext(ctx.getToken());\n const targets = await resolveTargets(servers, allServers, execCtx);\n\n // Servers run one after the other: the rate limiter allows 60 requests per minute.\n const syncs: ServerSync[] = [];\n for (const { id, name } of targets) {\n const sync: ServerSync = { id, name, added: [], removed: [], unchanged: [], errors: [] };\n try {\n const keys = await listSshKeys({ server_id: String(id), user }, execCtx);\n sync.plan = planSync(fileKeys, keys.data, user);\n sync.unchanged = sync.plan.unchanged.map((k) => k.name);\n } catch (error) {\n sync.errors.push(`list keys: ${errorMessage(error)}`);\n }\n syncs.push(sync);\n }\n\n const json = formatter.isJson();\n if (!json) {\n printPlan(syncs, user, prune);\n }\n\n if (dryRun) {\n for (const sync of syncs) {\n if (!sync.plan) continue;\n sync.added = sync.plan.add.map((k) => k.name);\n if (prune) sync.removed = sync.plan.remove.map((k) => k.name);\n }\n if (!json) console.log(colors.cyan(\"\\nDry run: no changes made.\"));\n } else {\n for (const sync of syncs) {\n if (sync.plan) {\n await applyPlan(sync, sync.plan, user, prune, execCtx);\n }\n }\n if (!json) {\n console.log(\"\");\n printResult(syncs);\n }\n }\n\n if (json) {\n console.log(\n JSON.stringify(\n {\n dry_run: dryRun,\n servers: syncs.map(({ id, name, added, removed, unchanged, errors }) => ({\n id,\n name,\n added,\n removed,\n unchanged,\n errors,\n })),\n },\n null,\n 2,\n ),\n );\n }\n\n return syncs.reduce((count, sync) => count + sync.errors.length, 0);\n }, formatter);\n\n // The errors are already in the output: exit without a second (JSON) error document.\n if (failed) {\n if (!formatter.isJson()) {\n formatter.error(`${failed} SSH key operation(s) failed`);\n }\n process.exit(ExitCode.GENERAL_ERROR);\n }\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { sshKeysList, sshKeysGet } from \"./handlers.ts\";\nimport { sshKeysSync } from \"./sync.ts\";\n\nexport const handleSshKeysCommand = createCommandRouter({\n resource: \"ssh-keys\",\n handlers: {\n list: sshKeysList,\n ls: sshKeysList,\n get: [sshKeysGet, \"args\"],\n sync: sshKeysSync,\n },\n writeSubcommands: [\"sync\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSshKeysHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge ssh-keys list\")} - List SSH keys on a server\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge ssh-keys get\")} - Get SSH key details\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys get <key_id> --server <server_id>\n`);\n } else if (subcommand === \"sync\") {\n console.log(`\n${colors.bold(\"forge ssh-keys sync\")} - Make the SSH keys of servers match a file\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys sync --file <path|-> --server <id> [--server <id>...] [options]\n forge ssh-keys sync --file <path|-> --all-servers [options]\n\n${colors.bold(\"OPTIONS:\")}\n --file <path> authorized_keys file: one \"<type> <base64> [comment]\" per line,\n blank lines and # comments ignored (use - for stdin)\n --server <id> Target server ID or name (repeatable or comma separated)\n --all-servers Target every server in the organization\n --user <name> Server user of the keys (default: forge)\n --prune Also remove the keys of the user that are not in the file\n --dry-run Print the plan and change nothing\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"HOW IT WORKS:\")}\n Each key gets the name \"<comment slug>-<first 8 hex chars of SHA-256 of the key>\".\n The Forge API does not return public keys, so keys are matched by name: a changed\n key gets a new name. The command lists the plan per server (+ add, - remove,\n = unchanged), applies it, then prints the result. Without --prune, keys are only\n added. Servers run one after the other; when an operation fails, the others still\n run and the command exits non-zero. When an add fails on a server, the removals on\n that server are skipped, so nobody loses access.\n\n${colors.bold(\"JSON OUTPUT:\")}\n { \"dry_run\": bool, \"servers\": [{ id, name, added, removed, unchanged, errors }] }\n With --dry-run, \"added\" and \"removed\" hold the planned changes, not applied ones.\n\n${colors.bold(\"EXAMPLES:\")}\n forge ssh-keys sync --file .forge/authorized_keys --server 123 --dry-run\n forge ssh-keys sync --file .forge/authorized_keys --all-servers --prune\n cat keys.pub | forge ssh-keys sync --file - --server web-1,web-2 --user deploy\n`);\n } else {\n console.log(`\n${colors.bold(\"forge ssh-keys\")} - Manage SSH keys\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List SSH keys\n get <id> Get SSH key details\n sync Make the SSH keys of servers match a file\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required, except for sync --all-servers)\n --file <path> authorized_keys file, - for stdin (for sync)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge ssh-keys <subcommand> --help\")} for details.\n`);\n }\n}\n","import type { StorageProviderAttributes } from \"@studiometa/forge-api\";\n\nimport { STORAGE_PROVIDER_TYPES } from \"@studiometa/forge-api\";\nimport {\n createStorageProvider,\n deleteStorageProvider,\n getStorageProvider,\n listStorageProviders,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithError, exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ValidationError } from \"../../errors.ts\";\nimport { readContentFile } from \"../../utils/content-source.ts\";\n\ntype StorageProvider = StorageProviderAttributes & { id: number };\n\nconst FIELDS: Array<keyof StorageProvider> = [\n \"id\",\n \"name\",\n \"provider\",\n \"provider_name\",\n \"endpoint\",\n \"region\",\n \"bucket\",\n \"directory\",\n \"in_use\",\n];\n\nconst CREATE_USAGE =\n \"forge storage-providers create --name <name> --provider <type> [--endpoint <url>] [--region <region>] [--bucket <bucket>] [--access-key <id>] [--secret-key-file <path|->]\";\n\nexport async function storageProvidersList(ctx: CommandContext): Promise<void> {\n const provider = typeof ctx.options.provider === \"string\" ? ctx.options.provider : undefined;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listStorageProviders(provider ? { provider } : {}, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"provider\", \"bucket\", \"in_use\"],\n \"No storage providers found.\",\n (p) =>\n `${String(p.id).padEnd(8)} ${p.name.padEnd(24)} ${p.provider.padEnd(10)} ${p.bucket ?? \"—\"}${p.in_use ? \" (in use)\" : \"\"}`,\n );\n }, ctx.formatter);\n}\n\nexport async function storageProvidersGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge storage-providers get <id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getStorageProvider({ id }, execCtx);\n ctx.formatter.outputOne(result.data, FIELDS);\n }, ctx.formatter);\n}\n\n/**\n * Read an optional string option. A flag given without a value is a validation error.\n */\nfunction stringOption(ctx: CommandContext, name: string): string | undefined {\n const value = ctx.options[name];\n if (value === undefined) return undefined;\n if (typeof value !== \"string\" || !value) {\n exitWithError(\n new ValidationError(`--${name} requires a value`, name, [`Usage: ${CREATE_USAGE}`]),\n ctx.formatter,\n );\n }\n return value;\n}\n\nexport async function storageProvidersCreate(ctx: CommandContext): Promise<void> {\n const name = ctx.options.name;\n const provider = ctx.options.provider;\n\n if (typeof name !== \"string\" || !name) {\n exitWithValidationError(\"name\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof provider !== \"string\" || !provider) {\n exitWithValidationError(\"provider\", CREATE_USAGE, ctx.formatter);\n }\n\n if (!(STORAGE_PROVIDER_TYPES as readonly string[]).includes(provider)) {\n exitWithError(\n new ValidationError(\n `Invalid provider \"${provider}\": use ${STORAGE_PROVIDER_TYPES.join(\", \")}`,\n \"provider\",\n ),\n ctx.formatter,\n );\n }\n\n const endpoint = stringOption(ctx, \"endpoint\");\n const region = stringOption(ctx, \"region\");\n const bucket = stringOption(ctx, \"bucket\");\n const directory = stringOption(ctx, \"directory\");\n const accessKey = stringOption(ctx, \"access-key\");\n\n // The secret key is read from a file or stdin, never from the command line,\n // so it does not show in the shell history or the process list. Only one\n // trailing newline is removed (as `echo` or an editor adds it): a secret is kept as is.\n const secretKey =\n ctx.options[\"secret-key-file\"] === undefined\n ? undefined\n : readContentFile(ctx.options[\"secret-key-file\"], \"secret-key-file\", {\n label: \"secret key\",\n usage: CREATE_USAGE,\n formatter: ctx.formatter,\n }).replace(/\\r?\\n$/, \"\");\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await createStorageProvider(\n {\n name,\n provider: provider as (typeof STORAGE_PROVIDER_TYPES)[number],\n ...(endpoint !== undefined ? { endpoint } : {}),\n ...(region !== undefined ? { region } : {}),\n ...(bucket !== undefined ? { bucket } : {}),\n ...(directory !== undefined ? { directory } : {}),\n ...(accessKey !== undefined ? { access_key: accessKey } : {}),\n ...(secretKey !== undefined ? { secret_key: secretKey } : {}),\n ...(ctx.options[\"assume-role\"] === true ? { assume_role: true } : {}),\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, FIELDS);\n }, ctx.formatter);\n}\n\nexport async function storageProvidersDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge storage-providers delete <id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n await deleteStorageProvider({ id }, execCtx);\n ctx.formatter.success(`Storage provider ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n storageProvidersCreate,\n storageProvidersDelete,\n storageProvidersGet,\n storageProvidersList,\n} from \"./handlers.ts\";\n\nexport const handleStorageProvidersCommand = createCommandRouter({\n resource: \"storage-providers\",\n handlers: {\n list: storageProvidersList,\n ls: storageProvidersList,\n get: [storageProvidersGet, \"args\"],\n create: storageProvidersCreate,\n delete: [storageProvidersDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showStorageProvidersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge storage-providers list\")} - List the organization's storage providers\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers list [options]\n\n${colors.bold(\"OPTIONS:\")}\n --provider <type> Only list one provider type (s3, spaces, hetzner, ovh, scaleway, custom)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge storage-providers get\")} - Get storage provider details\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers get <id> [options]\n\nForge never returns the access key or the secret key.\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge storage-providers create\")} - Create a storage provider for database backups\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers create --name <name> --provider <type> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> Provider name (required)\n --provider <type> s3, spaces, hetzner, ovh, scaleway or custom (S3 compatible) (required)\n --endpoint <url> S3 endpoint URL (custom providers)\n --region <region> Bucket region\n --bucket <bucket> Default bucket\n --directory <dir> Default directory in the bucket\n --access-key <id> Access key ID\n --secret-key-file <path> Read the secret key from a file, or from stdin with -\n --assume-role Use the EC2 instance role instead of keys (s3)\n -f, --format <fmt> Output format: json, human, table\n\nThe secret key is not accepted as an option value, so it does not show in the\nshell history or the process list. One trailing newline is removed.\n\n${colors.bold(\"EXAMPLE:\")}\n printf '%s' \"$S3_SECRET_KEY\" | forge storage-providers create --name Backups \\\\\n --provider custom --endpoint https://s3.example.com --region eu-west-1 \\\\\n --bucket my-bucket --access-key \"$S3_ACCESS_KEY\" --secret-key-file - --format json\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge storage-providers delete\")} - Delete a storage provider\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers delete <id> [options]\n\nForge refuses to delete a provider that a backup configuration uses.\n`);\n } else {\n console.log(`\n${colors.bold(\"forge storage-providers\")} - Manage the storage providers of database backups\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List storage providers\n get <id> Get storage provider details\n create Create a storage provider\n delete <id> Delete a storage provider\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge storage-providers <subcommand> --help\")} for details.\n`);\n }\n}\n","import { getUser } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { runCommand } from \"../../error-handler.ts\";\n\nexport async function userGet(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getUser({}, execCtx);\n ctx.formatter.output(result.data);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { userGet } from \"./handlers.ts\";\n\nexport const handleUserCommand = createCommandRouter({\n resource: \"user\",\n handlers: {\n get: userGet,\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showUserHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge user get\")} - Get the authenticated user profile\n\n${colors.bold(\"USAGE:\")}\n forge user get [options]\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge user\")} - Display authenticated user profile\n\n${colors.bold(\"USAGE:\")}\n forge user [subcommand] [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get the authenticated user profile\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge user <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Simple argument parser using native Node.js.\n * Parses process.argv into a structured format with no external deps.\n */\n\nexport type OptionValue = string | boolean | string[];\nexport type CommandOptions = Record<string, OptionValue>;\n\nexport interface ParsedArgs {\n command: string[];\n options: Record<string, OptionValue>;\n positional: string[];\n}\n\n/**\n * Whether an argument can be the value of the option before it.\n * A lone \"-\" is a value (it means stdin), other \"-\" prefixed arguments are options.\n */\nfunction isOptionValue(arg: string): boolean {\n return arg === \"-\" || !arg.startsWith(\"-\");\n}\n\n/**\n * Options that accept several values. Every other option keeps the last value.\n */\nconst REPEATABLE = new Set([\"server\", \"tag\", \"databases\"]);\n\n/**\n * Long options that never take a value, so the argument after them stays a command\n * or a positional argument (`forge --exact deployments deploy`).\n */\nconst FLAGS = new Set([\"exact\"]);\n\n/**\n * Set an option value. A repeatable option given more than once collects its string\n * values into an array (`--server 1 --server 2` → `[\"1\", \"2\"]`).\n */\nfunction setOption(\n options: Record<string, OptionValue>,\n key: string,\n value: string | boolean,\n): void {\n const previous = options[key];\n if (\n REPEATABLE.has(key) &&\n typeof value === \"string\" &&\n previous !== undefined &&\n typeof previous !== \"boolean\"\n ) {\n options[key] = [previous, value].flat();\n } else {\n options[key] = value;\n }\n}\n\nexport function parseArgs(argv: string[] = process.argv.slice(2)): ParsedArgs {\n const options: Record<string, OptionValue> = {};\n const positional: string[] = [];\n const command: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg.startsWith(\"--\")) {\n // Long option: --key=value or --key value or --flag\n const equalIndex = arg.indexOf(\"=\");\n if (equalIndex > -1) {\n const key = arg.slice(2, equalIndex);\n const value = arg.slice(equalIndex + 1);\n setOption(options, key, value);\n } else {\n const key = arg.slice(2);\n const nextArg = argv[i + 1];\n\n if (!FLAGS.has(key) && nextArg !== undefined && isOptionValue(nextArg)) {\n setOption(options, key, nextArg);\n i++;\n } else {\n setOption(options, key, true);\n }\n }\n } else if (arg.startsWith(\"-\") && arg.length > 1) {\n // Short option: -k value or -abc (multiple flags)\n if (arg.length === 2) {\n const key = arg[1];\n const nextArg = argv[i + 1];\n\n if (nextArg !== undefined && isOptionValue(nextArg)) {\n setOption(options, key, nextArg);\n i++;\n } else {\n setOption(options, key, true);\n }\n } else {\n // Multiple short flags: -abc -> -a -b -c\n for (let j = 1; j < arg.length; j++) {\n options[arg[j]] = true;\n }\n }\n } else {\n // Positional argument or command\n // First two non-option args are command and subcommand\n if (command.length < 2) {\n command.push(arg);\n } else {\n positional.push(arg);\n }\n }\n }\n\n return { command, options, positional };\n}\n\nexport function getOption(\n options: Record<string, OptionValue>,\n names: string[],\n defaultValue?: string,\n): string | undefined {\n for (const name of names) {\n if (name in options) {\n const value = options[name];\n return typeof value === \"string\" ? value : undefined;\n }\n }\n return defaultValue;\n}\n\nexport function hasFlag(options: Record<string, OptionValue>, names: string[]): boolean {\n return names.some((name) => options[name] === true);\n}\n\n/**\n * Whether the arguments ask for the CLI version: a bare `--version` or `-v`\n * with no command. Commands such as `php config` and `services restart` take\n * `--version <value>`, so a bare `--version` after a command is not a version request.\n */\nexport function isVersionRequest({ command, options }: ParsedArgs): boolean {\n return command.length === 0 && (options.version === true || options.v === true);\n}\n","#!/usr/bin/env node\n\nimport { handleBackupsCommand, showBackupsHelp } from \"./commands/backups/index.ts\";\nimport { handleCompletionCommand, showCompletionHelp } from \"./commands/completion.ts\";\nimport { handleCertificatesCommand, showCertificatesHelp } from \"./commands/certificates/index.ts\";\nimport { handleCommandsCommand, showCommandsHelp } from \"./commands/commands/index.ts\";\nimport { handleConfigCommand, showConfigHelp } from \"./commands/config.ts\";\nimport { handleDaemonsCommand, showDaemonsHelp } from \"./commands/daemons/index.ts\";\nimport { handleDatabasesCommand, showDatabasesHelp } from \"./commands/databases/index.ts\";\nimport {\n handleDatabaseUsersCommand,\n showDatabaseUsersHelp,\n} from \"./commands/database-users/index.ts\";\nimport { handleDeploymentsCommand, showDeploymentsHelp } from \"./commands/deployments/index.ts\";\nimport { handleEnvCommand, showEnvHelp } from \"./commands/env/index.ts\";\nimport {\n handleFirewallRulesCommand,\n showFirewallRulesHelp,\n} from \"./commands/firewall-rules/index.ts\";\nimport { handleMonitorsCommand, showMonitorsHelp } from \"./commands/monitors/index.ts\";\nimport { handleNginxCommand, showNginxHelp } from \"./commands/nginx/index.ts\";\nimport {\n handleNginxTemplatesCommand,\n showNginxTemplatesHelp,\n} from \"./commands/nginx-templates/index.ts\";\nimport { handlePhpCommand, showPhpHelp } from \"./commands/php/index.ts\";\nimport { handleRecipesCommand, showRecipesHelp } from \"./commands/recipes/index.ts\";\nimport {\n handleRedirectRulesCommand,\n showRedirectRulesHelp,\n} from \"./commands/redirect-rules/index.ts\";\nimport {\n handleScheduledJobsCommand,\n showScheduledJobsHelp,\n} from \"./commands/scheduled-jobs/index.ts\";\nimport {\n handleSecurityRulesCommand,\n showSecurityRulesHelp,\n} from \"./commands/security-rules/index.ts\";\nimport { handleServersCommand, showServersHelp } from \"./commands/servers/index.ts\";\nimport { handleServicesCommand, showServicesHelp } from \"./commands/services/index.ts\";\nimport { handleSitesCommand, showSitesHelp } from \"./commands/sites/index.ts\";\nimport { handleSshCommand, showSshHelp } from \"./commands/ssh/index.ts\";\nimport { handleSshKeysCommand, showSshKeysHelp } from \"./commands/ssh-keys/index.ts\";\nimport {\n handleStorageProvidersCommand,\n showStorageProvidersHelp,\n} from \"./commands/storage-providers/index.ts\";\nimport { handleUserCommand, showUserHelp } from \"./commands/user/index.ts\";\nimport { colors, setColorEnabled } from \"./utils/colors.ts\";\nimport { isVersionRequest, parseArgs } from \"./utils/args.ts\";\n\ndeclare const __VERSION__: string;\nconst VERSION = __VERSION__;\n\nfunction showHelp(): void {\n console.log(`\n${colors.bold(\"forge\")} v${VERSION}\n\n${colors.bold(\"USAGE:\")}\n forge <command> [subcommand] [options]\n\n${colors.bold(\"COMMANDS:\")}\n config Manage CLI configuration\n set <token> Save API token\n get Show current token (masked)\n delete Delete stored token\n\n servers, s Manage servers\n list, ls List all servers\n get <id> Get server details\n create Create a server (requires --name, and --ip-address for custom)\n reboot <id> Reboot a server\n\n sites Manage sites\n list, ls List sites (requires --server)\n get <id> Get site details (requires --server)\n apply Make a site match a site file (--file, --check)\n\n deployments, d Manage deployments\n list, ls List deployments (requires --server --site)\n deploy Trigger a deployment (requires --server --site)\n logs [id] Show deployment output (requires --server --site)\n script Show the deployment script (requires --server --site)\n update-script Update the deployment script (requires --server --site --file|--content) [--check]\n\n databases, db Manage databases\n list, ls List databases (requires --server)\n get <id> Get database details (requires --server)\n\n database-users Manage database users\n list, ls List database users (requires --server)\n get <id> Get database user details (requires --server)\n create Create a database user (requires --server --name --password)\n delete <id> Delete a database user (requires --server)\n\n daemons Manage daemons\n list, ls List daemons (requires --server)\n get <id> Get daemon details (requires --server)\n restart <id> Restart a daemon (requires --server)\n\n env Manage environment variables\n get Get env variables (requires --server --site)\n update Update env variables (requires --server --site --file|--content) [--check]\n\n nginx Manage nginx configuration\n get Get nginx config (requires --server --site)\n update Update nginx config (requires --server --site --file|--content) [--check]\n\n certificates, certs Manage SSL certificates (per-domain in v2)\n get Get certificate for a domain (requires --server --site --domain)\n get <id> Get certificate details (requires --server --site)\n activate <id> Activate a certificate (requires --server --site)\n\n firewall-rules, fw Manage firewall rules\n list, ls List firewall rules (requires --server)\n get <id> Get firewall rule details (requires --server)\n\n ssh <server> Open an SSH session to a server\n --user <name> (default: forge), --private, --port <n>\n\n ssh-keys Manage SSH keys\n list, ls List SSH keys (requires --server)\n get <id> Get SSH key details (requires --server)\n sync Make server SSH keys match a file (requires --file, --server|--all-servers)\n\n backups Manage database backup configurations\n list, ls List backup configurations (requires --server)\n get <id> Get backup configuration details (requires --server)\n create Create a backup configuration (requires --server --storage-provider --frequency --databases)\n update <id> Update a backup configuration (requires --server --storage-provider --frequency --retention --databases)\n delete <id> Delete a backup configuration (requires --server)\n\n storage-providers Manage the storage providers of database backups\n list, ls List storage providers\n get <id> Get storage provider details\n create Create a storage provider (requires --name --provider)\n delete <id> Delete a storage provider\n\n commands Manage site commands\n list, ls List commands (requires --server --site)\n get <id> Get command details (requires --server --site)\n create Execute a command (requires --server --site --command)\n\n scheduled-jobs Manage scheduled jobs (cron)\n list, ls List scheduled jobs (requires --server)\n get <id> Get scheduled job details (requires --server)\n create Create a scheduled job (requires --server --command)\n delete <id> Delete a scheduled job (requires --server)\n\n services List and restart server services\n list, ls List services on a server (forge services list <server>)\n restart <service> Restart a service (forge services restart <server> <service>)\n\n php Manage PHP versions, configuration, limits and OPcache\n list, ls List installed PHP versions (requires --server)\n config Show a configuration file (requires --server --version --type)\n update-config Replace a configuration file (requires --server --version --type --file|--content) [--check]\n max-upload-size Show the max upload size (requires --server)\n set-max-upload-size <mb>\n Set the max upload size (requires --server)\n max-execution-time Show the max execution time (requires --server)\n set-max-execution-time <seconds>\n Set the max execution time (requires --server)\n opcache Show the OPcache status (requires --server)\n enable-opcache Enable OPcache (requires --server)\n disable-opcache Disable OPcache (requires --server)\n\n user Display authenticated user profile\n get Get the authenticated user profile\n\n monitors Manage server monitors\n list, ls List monitors (requires --server)\n get <id> Get monitor details (requires --server)\n create Create a monitor (requires --server --type --operator --threshold --minutes)\n delete <id> Delete a monitor (requires --server)\n\n nginx-templates Manage Nginx templates\n list, ls List Nginx templates (requires --server)\n get <id> Get Nginx template details (requires --server)\n create Create a Nginx template (requires --server --name --content)\n update <id> Update a Nginx template (requires --server)\n delete <id> Delete a Nginx template (requires --server)\n\n security-rules Manage site security rules\n list, ls List security rules (requires --server --site)\n get <id> Get security rule details (requires --server --site)\n create Create a security rule (requires --server --site --name)\n delete <id> Delete a security rule (requires --server --site)\n\n redirect-rules Manage site redirect rules\n list, ls List redirect rules (requires --server --site)\n get <id> Get redirect rule details (requires --server --site)\n create Create a redirect rule (requires --server --site --from --to)\n delete <id> Delete a redirect rule (requires --server --site)\n\n recipes Manage recipes\n list, ls List all recipes\n get <id> Get recipe details\n run <id> Run a recipe (requires --servers)\n\n completion Generate shell completion script\n bash Install Bash completion\n zsh Install Zsh completion\n fish Install Fish completion\n\n${colors.bold(\"OPTIONS:\")}\n --token <token> Forge API token (overrides config and env)\n --org <slug> Organization slug (overrides config and FORGE_ORG)\n --server <id> Server ID (required for server-scoped commands)\n --site <id> Site ID (required for site-scoped commands)\n --exact Match --server and --site names exactly (no partial match)\n --domain <id> Domain record ID (for certificate commands)\n -f, --format <fmt> Output format: json, human, table (default: human)\n --no-color Disable colored output\n -h, --help Show help\n -v, --version Show version\n\n${colors.bold(\"EXAMPLES:\")}\n # Configure API token\n forge config set YOUR_TOKEN\n\n # Or pass token directly\n forge servers list --token YOUR_TOKEN\n\n # List all servers\n forge servers list\n\n # List sites on a server\n forge sites list --server 123\n\n # Deploy a site\n forge deployments deploy --server 123 --site 456\n\n # Get JSON output (for AI agents)\n forge servers list --format json\n\n${colors.bold(\"CREDENTIAL PRIORITY:\")}\n 1. CLI argument (--token)\n 2. Environment variable (FORGE_API_TOKEN)\n 3. Config file (~/.config/forge-tools/config.json)\n\n${colors.bold(\"ENVIRONMENT VARIABLES:\")}\n FORGE_API_TOKEN API token\n FORGE_ORG Organization slug (e.g. studio-meta)\n FORGE_EXACT_MATCH Set to 1 to match --server and --site names exactly (same as --exact)\n NO_COLOR Disable colors\n XDG_CONFIG_HOME Config directory (respects XDG spec)\n`);\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs();\n const { command, options, positional } = args;\n\n const [mainCommand, subcommand] = command;\n const wantsHelp = options.help !== undefined || options.h !== undefined;\n\n if (wantsHelp && !mainCommand) {\n showHelp();\n process.exit(0);\n }\n\n // Only a bare `--version`/`-v` with no command is the version request. After a\n // command, `--version` is a command option (e.g. `forge php config --version 8.3`),\n // and a missing value must reach the command to fail its validation.\n if (isVersionRequest(args)) {\n console.log(VERSION);\n process.exit(0);\n }\n\n if (options[\"no-color\"]) {\n setColorEnabled(false);\n }\n\n if (!mainCommand) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (mainCommand) {\n case \"config\":\n if (wantsHelp) {\n showConfigHelp();\n process.exit(0);\n }\n handleConfigCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"servers\":\n case \"s\":\n if (wantsHelp) {\n showServersHelp(subcommand);\n process.exit(0);\n }\n await handleServersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"sites\":\n if (wantsHelp) {\n showSitesHelp(subcommand);\n process.exit(0);\n }\n await handleSitesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"deployments\":\n case \"d\":\n if (wantsHelp) {\n showDeploymentsHelp(subcommand);\n process.exit(0);\n }\n await handleDeploymentsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"databases\":\n case \"db\":\n if (wantsHelp) {\n showDatabasesHelp(subcommand);\n process.exit(0);\n }\n await handleDatabasesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"database-users\":\n if (wantsHelp) {\n showDatabaseUsersHelp(subcommand);\n process.exit(0);\n }\n await handleDatabaseUsersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"daemons\":\n if (wantsHelp) {\n showDaemonsHelp(subcommand);\n process.exit(0);\n }\n await handleDaemonsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"env\":\n if (wantsHelp) {\n showEnvHelp(subcommand);\n process.exit(0);\n }\n await handleEnvCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"nginx\":\n if (wantsHelp) {\n showNginxHelp(subcommand);\n process.exit(0);\n }\n await handleNginxCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"certificates\":\n case \"certs\":\n if (wantsHelp) {\n showCertificatesHelp(subcommand);\n process.exit(0);\n }\n await handleCertificatesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"firewall-rules\":\n case \"fw\":\n if (wantsHelp) {\n showFirewallRulesHelp(subcommand);\n process.exit(0);\n }\n await handleFirewallRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"ssh\":\n if (wantsHelp) {\n showSshHelp();\n process.exit(0);\n }\n await handleSshCommand(subcommand, positional, options);\n break;\n\n case \"ssh-keys\":\n if (wantsHelp) {\n showSshKeysHelp(subcommand);\n process.exit(0);\n }\n await handleSshKeysCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"backups\":\n if (wantsHelp) {\n showBackupsHelp(subcommand);\n process.exit(0);\n }\n await handleBackupsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"storage-providers\":\n if (wantsHelp) {\n showStorageProvidersHelp(subcommand);\n process.exit(0);\n }\n await handleStorageProvidersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"commands\":\n if (wantsHelp) {\n showCommandsHelp(subcommand);\n process.exit(0);\n }\n await handleCommandsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"scheduled-jobs\":\n if (wantsHelp) {\n showScheduledJobsHelp(subcommand);\n process.exit(0);\n }\n await handleScheduledJobsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"services\":\n if (wantsHelp) {\n showServicesHelp(subcommand);\n process.exit(0);\n }\n await handleServicesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"php\":\n if (wantsHelp) {\n showPhpHelp(subcommand);\n process.exit(0);\n }\n await handlePhpCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"user\":\n if (wantsHelp) {\n showUserHelp(subcommand);\n process.exit(0);\n }\n await handleUserCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"monitors\":\n if (wantsHelp) {\n showMonitorsHelp(subcommand);\n process.exit(0);\n }\n await handleMonitorsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"nginx-templates\":\n if (wantsHelp) {\n showNginxTemplatesHelp(subcommand);\n process.exit(0);\n }\n await handleNginxTemplatesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"security-rules\":\n if (wantsHelp) {\n showSecurityRulesHelp(subcommand);\n process.exit(0);\n }\n await handleSecurityRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"redirect-rules\":\n if (wantsHelp) {\n showRedirectRulesHelp(subcommand);\n process.exit(0);\n }\n await handleRedirectRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"recipes\":\n if (wantsHelp) {\n showRecipesHelp(subcommand);\n process.exit(0);\n }\n await handleRecipesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"completion\":\n if (wantsHelp || !subcommand) {\n showCompletionHelp();\n process.exit(0);\n }\n handleCompletionCommand(subcommand, options);\n break;\n\n default:\n console.error(colors.red(`Unknown command: ${mainCommand}`));\n console.log(`Run ${colors.cyan(\"forge --help\")} for usage information`);\n process.exit(1);\n }\n } catch (error) {\n console.error(colors.red(\"Fatal error:\"), error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(colors.red(\"Unhandled error:\"), error);\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/audit.ts","../src/utils/command-router.ts","../src/utils/resolve.ts","../src/commands/backups/options.ts","../src/commands/backups/handlers.ts","../src/commands/backups/command.ts","../src/commands/backups/help.ts","../src/commands/completion.ts","../src/commands/certificates/handlers.ts","../src/commands/certificates/command.ts","../src/commands/certificates/help.ts","../src/commands/commands/handlers.ts","../src/commands/commands/command.ts","../src/commands/commands/help.ts","../src/commands/config.ts","../src/commands/daemons/handlers.ts","../src/commands/daemons/command.ts","../src/commands/daemons/help.ts","../src/commands/databases/handlers.ts","../src/commands/databases/command.ts","../src/commands/databases/help.ts","../src/commands/database-users/handlers.ts","../src/commands/database-users/command.ts","../src/commands/database-users/help.ts","../src/utils/content-source.ts","../src/utils/drift.ts","../src/utils/print-content.ts","../src/commands/deployments/handlers.ts","../src/commands/deployments/command.ts","../src/commands/deployments/help.ts","../src/commands/env/env-diff.ts","../src/commands/env/handlers.ts","../src/commands/env/command.ts","../src/commands/env/help.ts","../src/commands/firewall-rules/handlers.ts","../src/commands/firewall-rules/command.ts","../src/commands/firewall-rules/help.ts","../src/commands/monitors/handlers.ts","../src/commands/monitors/command.ts","../src/commands/monitors/help.ts","../src/commands/nginx/handlers.ts","../src/commands/nginx/command.ts","../src/commands/nginx/help.ts","../src/commands/nginx-templates/handlers.ts","../src/commands/nginx-templates/command.ts","../src/commands/nginx-templates/help.ts","../src/commands/php/handlers.ts","../src/commands/php/command.ts","../src/commands/php/help.ts","../src/commands/recipes/handlers.ts","../src/commands/recipes/command.ts","../src/commands/recipes/help.ts","../src/commands/redirect-rules/handlers.ts","../src/commands/redirect-rules/command.ts","../src/commands/redirect-rules/help.ts","../src/commands/scheduled-jobs/handlers.ts","../src/commands/scheduled-jobs/command.ts","../src/commands/scheduled-jobs/help.ts","../src/commands/security-rules/handlers.ts","../src/commands/security-rules/command.ts","../src/commands/security-rules/help.ts","../src/commands/servers/handlers.ts","../src/commands/servers/command.ts","../src/commands/servers/help.ts","../src/commands/services/handlers.ts","../src/commands/services/command.ts","../src/commands/services/help.ts","../src/commands/sites/apply/ownership.ts","../src/commands/sites/apply/plan.ts","../src/commands/sites/apply/nginx.ts","../src/commands/sites/apply/apply.ts","../src/commands/sites/apply/site-file.ts","../src/commands/sites/apply/handler.ts","../src/commands/sites/handlers.ts","../src/commands/sites/command.ts","../src/commands/sites/help.ts","../src/commands/ssh/ssh-target.ts","../src/commands/ssh/handlers.ts","../src/commands/ssh/command.ts","../src/commands/ssh/help.ts","../src/commands/ssh-keys/handlers.ts","../src/commands/ssh-keys/sync-plan.ts","../src/commands/ssh-keys/sync.ts","../src/commands/ssh-keys/command.ts","../src/commands/ssh-keys/help.ts","../src/commands/storage-providers/handlers.ts","../src/commands/storage-providers/command.ts","../src/commands/storage-providers/help.ts","../src/commands/user/handlers.ts","../src/commands/user/command.ts","../src/commands/user/help.ts","../src/utils/args.ts","../src/cli.ts"],"sourcesContent":["import { createAuditLogger } from \"@studiometa/forge-core\";\nimport type { AuditLogger } from \"@studiometa/forge-core\";\n\n/**\n * Shared audit logger for CLI write operations.\n * Lazily initialized on first use.\n */\nlet _auditLogger: AuditLogger | null = null;\n\nexport function getCliAuditLogger(): AuditLogger {\n if (!_auditLogger) _auditLogger = createAuditLogger(\"cli\");\n return _auditLogger;\n}\n","/**\n * Generic command router factory for CLI commands.\n *\n * Eliminates boilerplate switch/case pattern in command routing.\n *\n * @example\n * ```typescript\n * import { createCommandRouter } from '../../utils/command-router.ts';\n * import { serversList, serversGet } from './handlers.ts';\n *\n * export const handleServersCommand = createCommandRouter({\n * resource: 'servers',\n * handlers: {\n * list: serversList,\n * ls: serversList,\n * get: [serversGet, 'args'],\n * },\n * });\n * ```\n */\n\nimport type { CommandContext } from \"../context.ts\";\nimport { type OutputFormat, isOutputFormat } from \"../types.ts\";\n\nimport { createContext } from \"../context.ts\";\nimport { OutputFormatter } from \"../output.ts\";\nimport { getCliAuditLogger } from \"../audit.ts\";\n\n/**\n * Handler that only receives context (e.g., list commands)\n */\nexport type ListHandler = (ctx: CommandContext) => Promise<void>;\n\n/**\n * Handler that receives args and context (e.g., get/update commands)\n */\nexport type ArgsHandler = (args: string[], ctx: CommandContext) => Promise<void>;\n\n/**\n * Handler definition - either a ListHandler or an ArgsHandler marked with 'args'\n */\nexport type Handler = ListHandler | [ArgsHandler, \"args\"];\n\n/**\n * Configuration for the command router\n */\nexport interface CommandRouterConfig {\n /** Resource name for error messages (e.g., 'servers', 'sites') */\n resource: string;\n /** Map of subcommand names to handlers */\n handlers: Record<string, Handler>;\n /**\n * Set of subcommand names that are write operations.\n * These will be recorded in the audit log on success or failure.\n */\n writeSubcommands?: ReadonlyArray<string>;\n}\n\n/**\n * Creates a command router function that dispatches to the appropriate handler.\n */\nexport function createCommandRouter(config: CommandRouterConfig) {\n return async function (\n subcommand: string,\n args: string[],\n options: Record<string, string | boolean | string[]>,\n ): Promise<void> {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const formatter = new OutputFormatter(format, options[\"no-color\"] === true);\n\n const ctx = createContext(options);\n\n const handler = config.handlers[subcommand];\n if (!handler) {\n formatter.error(`Unknown ${config.resource} subcommand: ${subcommand}`);\n process.exit(1);\n return; // Unreachable in production, but needed for tests where process.exit is mocked\n }\n\n const isWrite = config.writeSubcommands?.includes(subcommand) ?? false;\n\n if (isWrite) {\n // Sanitized args for audit log (strip token)\n const { token: _token, ...safeOptions } = options;\n try {\n if (Array.isArray(handler)) {\n await handler[0](args, ctx);\n } else {\n await handler(ctx);\n }\n getCliAuditLogger().log({\n source: \"cli\",\n resource: config.resource,\n action: subcommand,\n args: safeOptions,\n status: \"success\",\n });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n getCliAuditLogger().log({\n source: \"cli\",\n resource: config.resource,\n action: subcommand,\n args: safeOptions,\n status: \"error\",\n error: errorMessage,\n });\n throw err;\n }\n } else {\n if (Array.isArray(handler)) {\n // ArgsHandler - receives args and context\n await handler[0](args, ctx);\n } else {\n // ListHandler - receives only context\n await handler(ctx);\n }\n }\n };\n}\n","/**\n * Smart resolution utilities for --server and --site options.\n *\n * Accepts numeric IDs (used as-is) or plain strings (resolved by name/partial match).\n * In exact mode (`--exact` or `FORGE_EXACT_MATCH=1`), a plain string must match a name exactly.\n */\n\nimport { listServers, listSites, matchByName } from \"@studiometa/forge-core\";\nimport type { CliExecutorContext } from \"../context.ts\";\nimport { ValidationError } from \"../errors.ts\";\n\ninterface NamedResource {\n id: number;\n name: string;\n}\n\nconst EXACT_MATCH_HINT =\n \"Pass the numeric ID or the exact name, or turn off exact matching: remove --exact and unset FORGE_EXACT_MATCH\";\n\nfunction formatResources(resources: NamedResource[]): string {\n return resources.map((r) => ` ${r.name} (${r.id})`).join(\"\\n\");\n}\n\n/**\n * Match a --server or --site value against a list of resources.\n *\n * - Numeric string → returned as-is\n * - Exact name (case-insensitive) → its ID\n * - Exact mode: no exact name → ValidationError listing the near (partial) matches\n * - Otherwise one partial match → its ID; 0 or 2+ partial matches → ValidationError\n */\nfunction matchResourceId(\n value: string,\n resources: NamedResource[],\n kind: \"server\" | \"site\",\n scope: string,\n exactMatch: boolean,\n): string {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const { exact, partial } = matchByName(resources, value, (r) => r.name);\n\n if (exact.length === 1) {\n return String(exact[0].id);\n }\n\n if (exactMatch && exact.length === 0) {\n const candidates =\n partial.length > 0\n ? `Near matches:\\n${formatResources(partial)}`\n : `Available ${kind}s:\\n${formatResources(resources)}`;\n throw new ValidationError(`No ${kind} named \"${value}\"${scope} (exact match required)`, kind, [\n candidates,\n EXACT_MATCH_HINT,\n ]);\n }\n\n if (partial.length === 0) {\n throw new ValidationError(`No ${kind} found matching \"${value}\"${scope}`, kind, [\n `Available ${kind}s:\\n${formatResources(resources)}`,\n ]);\n }\n\n if (partial.length > 1) {\n throw new ValidationError(\n `Ambiguous ${kind} name \"${value}\" — ${partial.length} matches found`,\n kind,\n [\n `Matching ${kind}s:\\n${formatResources(partial)}`,\n \"Use a more specific name or pass the numeric ID\",\n ],\n );\n }\n\n return String(partial[0].id);\n}\n\n/**\n * Resolve a --server value to a numeric server ID string.\n *\n * - Numeric string → returned as-is (no API call)\n * - Plain string → fetch all servers, then see {@link matchServerId}\n */\nexport async function resolveServerId(value: string, execCtx: CliExecutorContext): Promise<string> {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const result = await listServers({}, execCtx);\n return matchServerId(value, result.data, execCtx.exactMatch);\n}\n\n/**\n * Resolve a --server value to a numeric server ID string, against a list of servers\n * that is already loaded, with no API call.\n *\n * - Exact name match first, then a single partial match (unless `exactMatch`)\n * - 0 matches → ValidationError listing available servers (near matches in exact mode)\n * - 2+ matches → ValidationError listing ambiguous matches\n */\nexport function matchServerId(\n value: string,\n servers: NamedResource[],\n exactMatch: boolean,\n): string {\n return matchResourceId(value, servers, \"server\", \"\", exactMatch);\n}\n\n/**\n * Resolve a --site value to a numeric site ID string.\n *\n * - Numeric string → returned as-is (no API call)\n * - Plain string → fetch all sites for the server, exact domain match first, then a single\n * partial match (unless `execCtx.exactMatch`)\n * - 0 matches → ValidationError listing available sites (near matches in exact mode)\n * - 2+ matches → ValidationError listing ambiguous matches\n */\nexport async function resolveSiteId(\n value: string,\n serverId: string,\n execCtx: CliExecutorContext,\n): Promise<string> {\n if (/^\\d+$/.test(value)) {\n return value;\n }\n\n const result = await listSites({ server_id: serverId }, execCtx);\n return matchResourceId(value, result.data, \"site\", ` on server ${serverId}`, execCtx.exactMatch);\n}\n","/**\n * Read and resolve the options shared by `forge backups create` and `forge backups update`.\n */\n\nimport type { ExecutorContext } from \"@studiometa/forge-core\";\nimport type { CreateBackupConfigData } from \"@studiometa/forge-api\";\n\nimport { listDatabases, listStorageProviders } from \"@studiometa/forge-core\";\n\nimport type { CommandOptions } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** Backup frequencies accepted by Forge. */\nexport const BACKUP_FREQUENCIES = [\"hourly\", \"daily\", \"weekly\", \"custom\"] as const;\n\n/**\n * Read a list option: repeated and/or comma separated (`--databases 1,2 --databases app`).\n */\nexport function listValues(value: unknown): string[] {\n return [value]\n .flat()\n .filter((v): v is string => typeof v === \"string\")\n .flatMap((v) => v.split(\",\"))\n .map((v) => v.trim())\n .filter(Boolean);\n}\n\n/**\n * Whether a value is a numeric ID.\n */\nfunction isId(value: string): boolean {\n return /^\\d+$/.test(value);\n}\n\n/**\n * Check the --frequency value. Throws a ValidationError for an unknown frequency.\n */\nexport function checkFrequency(frequency: string): void {\n if (!(BACKUP_FREQUENCIES as readonly string[]).includes(frequency)) {\n throw new ValidationError(\n `Invalid frequency \"${frequency}\": use ${BACKUP_FREQUENCIES.join(\", \")}`,\n \"frequency\",\n );\n }\n}\n\n/**\n * Parse the --retention value: an integer from 1 to 8760.\n */\nexport function parseRetention(value: unknown): number {\n const retention = Number(value);\n if (!Number.isInteger(retention) || retention < 1 || retention > 8760) {\n throw new ValidationError(\n `Invalid retention \"${String(value)}\": use a number of backups from 1 to 8760`,\n \"retention\",\n );\n }\n return retention;\n}\n\n/**\n * Resolve a storage provider ID or exact name to its numeric ID.\n */\nexport async function resolveStorageProviderId(\n value: string,\n execCtx: ExecutorContext,\n): Promise<number> {\n if (isId(value)) return Number(value);\n\n const { data } = await listStorageProviders({}, execCtx);\n const matches = data.filter((p) => p.name === value);\n\n if (matches.length === 0) {\n throw new ValidationError(`No storage provider named \"${value}\"`, \"storage-provider\", [\n \"List the storage providers with: forge storage-providers list\",\n ]);\n }\n if (matches.length > 1) {\n throw new ValidationError(\n `${matches.length} storage providers are named \"${value}\": use the ID (${matches.map((p) => p.id).join(\", \")})`,\n \"storage-provider\",\n );\n }\n return matches[0].id;\n}\n\n/**\n * Resolve database IDs or exact names to numeric IDs. Names are looked up on the server.\n */\nexport async function resolveDatabaseIds(\n values: string[],\n server_id: string,\n execCtx: ExecutorContext,\n): Promise<number[]> {\n if (values.every(isId)) return values.map(Number);\n\n const { data } = await listDatabases({ server_id }, execCtx);\n\n return values.map((value) => {\n if (isId(value)) return Number(value);\n const database = data.find((db) => db.name === value);\n if (!database) {\n throw new ValidationError(`No database named \"${value}\" on the server`, \"databases\", [\n `List the databases with: forge databases list --server ${server_id}`,\n ]);\n }\n return database.id;\n });\n}\n\n/**\n * Read the optional backup configuration fields that map one to one to the API.\n */\nexport function optionalBackupFields(\n options: CommandOptions,\n): Pick<\n CreateBackupConfigData,\n \"name\" | \"bucket\" | \"directory\" | \"day\" | \"time\" | \"cron\" | \"notification_email\"\n> {\n const fields: Record<string, string> = {};\n const map: Record<string, string> = {\n name: \"name\",\n bucket: \"bucket\",\n directory: \"directory\",\n day: \"day\",\n time: \"time\",\n cron: \"cron\",\n \"notification-email\": \"notification_email\",\n };\n for (const [option, field] of Object.entries(map)) {\n const value = options[option];\n if (typeof value === \"string\") fields[field] = value;\n }\n return fields;\n}\n","import {\n createBackupConfig,\n deleteBackupConfig,\n getBackupConfig,\n listBackupConfigs,\n updateBackupConfig,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\nimport {\n checkFrequency,\n listValues,\n optionalBackupFields,\n parseRetention,\n resolveDatabaseIds,\n resolveStorageProviderId,\n} from \"./options.ts\";\n\n/** Retention when --retention is not given: Forge requires a value. */\nconst DEFAULT_RETENTION = 5;\n\nexport async function backupsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge backups list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listBackupConfigs({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"schedule\", \"status\"],\n \"No backup configurations found.\",\n (b) => `${String(b.id).padEnd(8)} ${b.name.padEnd(20)} ${b.schedule.padEnd(12)} ${b.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function backupsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"backup_id\",\n \"forge backups get <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge backups get <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getBackupConfig({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"storage_provider_id\",\n \"provider\",\n \"bucket\",\n \"directory\",\n \"schedule\",\n \"displayable_schedule\",\n \"retention\",\n \"status\",\n \"next_run_time\",\n ]);\n }, ctx.formatter);\n}\n\nconst CREATE_USAGE =\n \"forge backups create --server <server> --storage-provider <id|name> --frequency <hourly|daily|weekly|custom> --databases <ids|names> [--retention <n>]\";\n\nexport async function backupsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const storageProvider = ctx.options[\"storage-provider\"];\n const frequency = ctx.options.frequency;\n const databases = listValues(ctx.options.databases);\n\n if (!server) {\n exitWithValidationError(\"server_id\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof storageProvider !== \"string\" || !storageProvider) {\n exitWithValidationError(\"storage-provider\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof frequency !== \"string\" || !frequency) {\n exitWithValidationError(\"frequency\", CREATE_USAGE, ctx.formatter);\n }\n\n if (databases.length === 0) {\n exitWithValidationError(\"databases\", CREATE_USAGE, ctx.formatter);\n }\n\n await runCommand(async () => {\n checkFrequency(frequency);\n const retention =\n ctx.options.retention === undefined\n ? DEFAULT_RETENTION\n : parseRetention(ctx.options.retention);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const storage_provider_id = await resolveStorageProviderId(storageProvider, execCtx);\n const database_ids = await resolveDatabaseIds(databases, server_id, execCtx);\n await createBackupConfig(\n {\n server_id,\n storage_provider_id,\n frequency,\n retention,\n database_ids,\n ...(ctx.options[\"include-new-databases\"] === true ? { include_new_databases: true } : {}),\n ...optionalBackupFields(ctx.options),\n },\n execCtx,\n );\n ctx.formatter.success(\"Backup configuration created.\");\n }, ctx.formatter);\n}\n\nconst UPDATE_USAGE =\n \"forge backups update <backup_id> --server <server> --storage-provider <id|name> --frequency <hourly|daily|weekly|custom> --retention <n> --databases <ids|names>\";\n\nexport async function backupsUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const storageProvider = ctx.options[\"storage-provider\"];\n const frequency = ctx.options.frequency;\n const databases = listValues(ctx.options.databases);\n\n if (!id) {\n exitWithValidationError(\"backup_id\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (!server) {\n exitWithValidationError(\"server_id\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (typeof storageProvider !== \"string\" || !storageProvider) {\n exitWithValidationError(\"storage-provider\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (typeof frequency !== \"string\" || !frequency) {\n exitWithValidationError(\"frequency\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (ctx.options.retention === undefined) {\n exitWithValidationError(\"retention\", UPDATE_USAGE, ctx.formatter);\n }\n\n if (databases.length === 0) {\n exitWithValidationError(\"databases\", UPDATE_USAGE, ctx.formatter);\n }\n\n await runCommand(async () => {\n checkFrequency(frequency);\n const retention = parseRetention(ctx.options.retention);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const storage_provider_id = await resolveStorageProviderId(storageProvider, execCtx);\n const database_ids = await resolveDatabaseIds(databases, server_id, execCtx);\n await updateBackupConfig(\n {\n server_id,\n id,\n storage_provider_id,\n frequency,\n retention,\n database_ids,\n ...optionalBackupFields(ctx.options),\n },\n execCtx,\n );\n ctx.formatter.success(`Backup configuration ${id} updated.`);\n }, ctx.formatter);\n}\n\nexport async function backupsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"backup_id\",\n \"forge backups delete <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge backups delete <backup_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteBackupConfig({ server_id, id }, execCtx);\n ctx.formatter.success(`Backup configuration ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n backupsCreate,\n backupsDelete,\n backupsGet,\n backupsList,\n backupsUpdate,\n} from \"./handlers.ts\";\n\nexport const handleBackupsCommand = createCommandRouter({\n resource: \"backups\",\n handlers: {\n list: backupsList,\n ls: backupsList,\n get: [backupsGet, \"args\"],\n create: backupsCreate,\n update: [backupsUpdate, \"args\"],\n delete: [backupsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showBackupsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge backups list\")} - List backup configurations on a server\n\n${colors.bold(\"USAGE:\")}\n forge backups list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge backups get\")} - Get backup configuration details\n\n${colors.bold(\"USAGE:\")}\n forge backups get <backup_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge backups create\")} - Create a database backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups create --server <server> --storage-provider <id|name> --frequency <frequency> --databases <ids|names> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id|name> Server ID or name (required)\n --storage-provider <id|name> Storage provider ID or exact name (required, see forge storage-providers list)\n --frequency <freq> hourly, daily, weekly or custom (required)\n --databases <ids|names> Database IDs or exact names, comma separated or repeated (required)\n --retention <n> Number of backups to keep, 1 to 8760 (default: 5)\n --time <HH:MM> Daily and weekly: time on the hour or half hour, e.g. 02:00\n --day <0-6> Weekly: day of week, 0 is Sunday\n --cron <expr> Custom: cron expression\n --bucket <bucket> Bucket (default: the storage provider bucket)\n --directory <dir> Directory in the bucket\n --name <name> Configuration name\n --notification-email <email> Email notified when a backup fails\n --include-new-databases Also back up databases created later\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLE:\")}\n forge backups create --server web-1 --storage-provider Backups --frequency daily \\\\\n --time 02:00 --retention 7 --directory web-1 --databases app,wordpress\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge backups update\")} - Update a database backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups update <backup_id> --server <server> --storage-provider <id|name> --frequency <frequency> --retention <n> --databases <ids|names> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id|name> Server ID or name (required)\n --storage-provider <id|name> Storage provider ID or exact name (required)\n --frequency <freq> hourly, daily, weekly or custom (required)\n --retention <n> Number of backups to keep, 1 to 8760 (required)\n --databases <ids|names> Database IDs or exact names, comma separated or repeated (required)\n --time <HH:MM> Daily and weekly: time on the hour or half hour\n --day <0-6> Weekly: day of week, 0 is Sunday\n --cron <expr> Custom: cron expression\n --bucket <bucket> Bucket\n --directory <dir> Directory in the bucket\n --name <name> Configuration name\n --notification-email <email> Email notified when a backup fails\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge backups delete\")} - Delete a backup configuration\n\n${colors.bold(\"USAGE:\")}\n forge backups delete <backup_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge backups\")} - Manage backup configurations\n\n${colors.bold(\"USAGE:\")}\n forge backups <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List backup configurations\n get <id> Get backup configuration details\n create Create a new backup configuration\n update <id> Update a backup configuration\n delete <id> Delete a backup configuration\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge backups <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Shell completion installation command\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { colors } from \"../utils/colors.ts\";\n\nconst BASH_COMPLETION = `#!/usr/bin/env bash\n\n_forge_completions() {\n local cur prev commands subcommands options\n\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n prev=\"\\${COMP_WORDS[COMP_CWORD-1]}\"\n\n # Main commands\n commands=\"config servers s sites deployments d databases db database-users daemons env nginx certificates certs firewall-rules fw ssh ssh-keys backups storage-providers commands scheduled-jobs services php user monitors nginx-templates security-rules redirect-rules recipes completion help\"\n\n # Subcommands for each command\n local config_cmds=\"set get delete\"\n local servers_cmds=\"list ls get public-key create reboot\"\n local sites_cmds=\"list ls get apply\"\n local deployments_cmds=\"list ls deploy logs log script update-script\"\n local databases_cmds=\"list ls get\"\n local database_users_cmds=\"list ls get create delete\"\n local daemons_cmds=\"list ls get restart logs log\"\n local env_cmds=\"get update\"\n local nginx_cmds=\"get update\"\n local certificates_cmds=\"get activate\"\n local firewall_rules_cmds=\"list ls get\"\n local ssh_keys_cmds=\"list ls get sync\"\n local backups_cmds=\"list ls get create update delete\"\n local storage_providers_cmds=\"list ls get create delete\"\n local commands_cmds=\"list ls get create\"\n local scheduled_jobs_cmds=\"list ls get create delete\"\n local services_cmds=\"list ls restart\"\n local php_cmds=\"list ls config update-config max-upload-size set-max-upload-size max-execution-time set-max-execution-time opcache enable-opcache disable-opcache\"\n local user_cmds=\"get\"\n local monitors_cmds=\"list ls get create delete\"\n local nginx_templates_cmds=\"list ls get create update delete\"\n local security_rules_cmds=\"list ls get create delete\"\n local redirect_rules_cmds=\"list ls get create delete\"\n local recipes_cmds=\"list ls get run\"\n local completion_cmds=\"bash zsh fish\"\n\n # Global options\n options=\"--token --server --site --exact -f --format --no-color -h --help -v --version --name --command --content --from --to --provider --frequency --cron --type --operator --threshold --minutes --key --port --ip-address --user --private --dry-run --script --servers --domain --password --credential-id --region --size --project-type --directory --file --script-file --check --all-servers --prune --ubuntu-version --php-version --database --private-ip --ssh-port --tag --storage-provider --databases --retention --time --day --bucket --notification-email --include-new-databases --endpoint --access-key --secret-key-file --assume-role\"\n\n # Format options\n local formats=\"json human table\"\n\n # Completion logic\n case \"\\${COMP_CWORD}\" in\n 1)\n # Complete main commands\n COMPREPLY=( $(compgen -W \"\\${commands}\" -- \"\\${cur}\") )\n ;;\n 2)\n # Complete subcommands based on main command\n case \"\\${prev}\" in\n config)\n COMPREPLY=( $(compgen -W \"\\${config_cmds}\" -- \"\\${cur}\") )\n ;;\n servers|s)\n COMPREPLY=( $(compgen -W \"\\${servers_cmds}\" -- \"\\${cur}\") )\n ;;\n sites)\n COMPREPLY=( $(compgen -W \"\\${sites_cmds}\" -- \"\\${cur}\") )\n ;;\n deployments|d)\n COMPREPLY=( $(compgen -W \"\\${deployments_cmds}\" -- \"\\${cur}\") )\n ;;\n databases|db)\n COMPREPLY=( $(compgen -W \"\\${databases_cmds}\" -- \"\\${cur}\") )\n ;;\n database-users)\n COMPREPLY=( $(compgen -W \"\\${database_users_cmds}\" -- \"\\${cur}\") )\n ;;\n daemons)\n COMPREPLY=( $(compgen -W \"\\${daemons_cmds}\" -- \"\\${cur}\") )\n ;;\n env)\n COMPREPLY=( $(compgen -W \"\\${env_cmds}\" -- \"\\${cur}\") )\n ;;\n nginx)\n COMPREPLY=( $(compgen -W \"\\${nginx_cmds}\" -- \"\\${cur}\") )\n ;;\n certificates|certs)\n COMPREPLY=( $(compgen -W \"\\${certificates_cmds}\" -- \"\\${cur}\") )\n ;;\n firewall-rules|fw)\n COMPREPLY=( $(compgen -W \"\\${firewall_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n ssh-keys)\n COMPREPLY=( $(compgen -W \"\\${ssh_keys_cmds}\" -- \"\\${cur}\") )\n ;;\n backups)\n COMPREPLY=( $(compgen -W \"\\${backups_cmds}\" -- \"\\${cur}\") )\n ;;\n storage-providers)\n COMPREPLY=( $(compgen -W \"\\${storage_providers_cmds}\" -- \"\\${cur}\") )\n ;;\n commands)\n COMPREPLY=( $(compgen -W \"\\${commands_cmds}\" -- \"\\${cur}\") )\n ;;\n scheduled-jobs)\n COMPREPLY=( $(compgen -W \"\\${scheduled_jobs_cmds}\" -- \"\\${cur}\") )\n ;;\n services)\n COMPREPLY=( $(compgen -W \"\\${services_cmds}\" -- \"\\${cur}\") )\n ;;\n php)\n COMPREPLY=( $(compgen -W \"\\${php_cmds}\" -- \"\\${cur}\") )\n ;;\n user)\n COMPREPLY=( $(compgen -W \"\\${user_cmds}\" -- \"\\${cur}\") )\n ;;\n monitors)\n COMPREPLY=( $(compgen -W \"\\${monitors_cmds}\" -- \"\\${cur}\") )\n ;;\n nginx-templates)\n COMPREPLY=( $(compgen -W \"\\${nginx_templates_cmds}\" -- \"\\${cur}\") )\n ;;\n security-rules)\n COMPREPLY=( $(compgen -W \"\\${security_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n redirect-rules)\n COMPREPLY=( $(compgen -W \"\\${redirect_rules_cmds}\" -- \"\\${cur}\") )\n ;;\n recipes)\n COMPREPLY=( $(compgen -W \"\\${recipes_cmds}\" -- \"\\${cur}\") )\n ;;\n completion)\n COMPREPLY=( $(compgen -W \"\\${completion_cmds}\" -- \"\\${cur}\") )\n ;;\n *)\n COMPREPLY=( $(compgen -W \"\\${options}\" -- \"\\${cur}\") )\n ;;\n esac\n ;;\n *)\n # Complete options and their values\n case \"\\${prev}\" in\n --format|-f)\n COMPREPLY=( $(compgen -W \"\\${formats}\" -- \"\\${cur}\") )\n ;;\n --file|--script-file)\n # Complete file paths\n COMPREPLY=( $(compgen -f -- \"\\${cur}\") )\n ;;\n --token|--server|--site|--version|--name|--command|--content|--from|--to|--provider|--frequency|--cron|--type|--operator|--threshold|--minutes|--key|--port|--ip-address|--user|--script|--servers|--domain|--password|--credential-id|--region|--size|--project-type|--directory|--ubuntu-version|--php-version|--database|--private-ip|--ssh-port|--tag|--storage-provider|--databases|--retention|--time|--day|--bucket|--notification-email|--endpoint|--access-key)\n # No completion for values requiring arguments\n COMPREPLY=()\n ;;\n *)\n COMPREPLY=( $(compgen -W \"\\${options}\" -- \"\\${cur}\") )\n ;;\n esac\n ;;\n esac\n\n return 0\n}\n\ncomplete -F _forge_completions forge\n`;\n\nconst ZSH_COMPLETION = `#compdef forge\n\n_forge() {\n local line state\n\n _arguments -C \\\\\n '1: :->command' \\\\\n '2: :->subcommand' \\\\\n '*: :->args'\n\n case $state in\n command)\n local -a commands\n commands=(\n 'config:Manage CLI configuration'\n 'servers:Manage servers'\n 's:Manage servers (alias)'\n 'sites:Manage sites'\n 'deployments:Manage deployments'\n 'd:Manage deployments (alias)'\n 'databases:Manage databases'\n 'db:Manage databases (alias)'\n 'database-users:Manage database users'\n 'daemons:Manage daemons'\n 'env:Manage environment variables'\n 'nginx:Manage nginx configuration'\n 'certificates:Manage SSL certificates'\n 'certs:Manage SSL certificates (alias)'\n 'firewall-rules:Manage firewall rules'\n 'fw:Manage firewall rules (alias)'\n 'ssh:Open an SSH session to a server'\n 'ssh-keys:Manage SSH keys'\n 'backups:Manage database backup configurations'\n 'storage-providers:Manage the storage providers of database backups'\n 'commands:Manage site commands'\n 'scheduled-jobs:Manage scheduled jobs'\n 'services:List and restart server services'\n 'php:Manage PHP versions, configuration, limits and OPcache'\n 'user:Display authenticated user profile'\n 'monitors:Manage server monitors'\n 'nginx-templates:Manage Nginx templates'\n 'security-rules:Manage site security rules'\n 'redirect-rules:Manage site redirect rules'\n 'recipes:Manage recipes'\n 'completion:Generate shell completion script'\n 'help:Show help'\n )\n _describe 'command' commands\n ;;\n subcommand)\n case $line[1] in\n config)\n local -a config_cmds\n config_cmds=(\n 'set:Save API token'\n 'get:Show current token'\n 'delete:Delete stored token'\n )\n _describe 'config command' config_cmds\n ;;\n servers|s)\n local -a servers_cmds\n servers_cmds=(\n 'list:List all servers'\n 'ls:List all servers (alias)'\n 'get:Get server details'\n 'public-key:Print the public key of the forge user'\n 'create:Create a server'\n 'reboot:Reboot a server'\n )\n _describe 'servers command' servers_cmds\n ;;\n sites)\n local -a sites_cmds\n sites_cmds=(\n 'list:List sites'\n 'ls:List sites (alias)'\n 'get:Get site details'\n 'apply:Make a site match a site file'\n )\n _describe 'sites command' sites_cmds\n ;;\n deployments|d)\n local -a deployments_cmds\n deployments_cmds=(\n 'list:List deployments'\n 'ls:List deployments (alias)'\n 'deploy:Trigger a deployment'\n 'logs:Show deployment output'\n 'log:Show deployment output (alias)'\n 'script:Show the deployment script'\n 'update-script:Update the deployment script'\n )\n _describe 'deployments command' deployments_cmds\n ;;\n databases|db)\n local -a databases_cmds\n databases_cmds=(\n 'list:List databases'\n 'ls:List databases (alias)'\n 'get:Get database details'\n )\n _describe 'databases command' databases_cmds\n ;;\n database-users)\n local -a database_users_cmds\n database_users_cmds=(\n 'list:List database users'\n 'ls:List database users (alias)'\n 'get:Get database user details'\n 'create:Create a database user'\n 'delete:Delete a database user'\n )\n _describe 'database-users command' database_users_cmds\n ;;\n daemons)\n local -a daemons_cmds\n daemons_cmds=(\n 'list:List daemons'\n 'ls:List daemons (alias)'\n 'get:Get daemon details'\n 'restart:Restart a daemon'\n 'logs:Show daemon log output'\n 'log:Show daemon log output (alias)'\n )\n _describe 'daemons command' daemons_cmds\n ;;\n env)\n local -a env_cmds\n env_cmds=(\n 'get:Get env variables'\n 'update:Update env variables'\n )\n _describe 'env command' env_cmds\n ;;\n nginx)\n local -a nginx_cmds\n nginx_cmds=(\n 'get:Get nginx config'\n 'update:Update nginx config'\n )\n _describe 'nginx command' nginx_cmds\n ;;\n certificates|certs)\n local -a certificates_cmds\n certificates_cmds=(\n 'get:Get certificate for a domain'\n 'activate:Activate a certificate'\n )\n _describe 'certificates command' certificates_cmds\n ;;\n firewall-rules|fw)\n local -a firewall_rules_cmds\n firewall_rules_cmds=(\n 'list:List firewall rules'\n 'ls:List firewall rules (alias)'\n 'get:Get firewall rule details'\n )\n _describe 'firewall-rules command' firewall_rules_cmds\n ;;\n ssh-keys)\n local -a ssh_keys_cmds\n ssh_keys_cmds=(\n 'list:List SSH keys'\n 'ls:List SSH keys (alias)'\n 'get:Get SSH key details'\n 'sync:Make server SSH keys match a file'\n )\n _describe 'ssh-keys command' ssh_keys_cmds\n ;;\n backups)\n local -a backups_cmds\n backups_cmds=(\n 'list:List backup configurations'\n 'ls:List backup configurations (alias)'\n 'get:Get backup configuration details'\n 'create:Create a backup configuration'\n 'update:Update a backup configuration'\n 'delete:Delete a backup configuration'\n )\n _describe 'backups command' backups_cmds\n ;;\n storage-providers)\n local -a storage_providers_cmds\n storage_providers_cmds=(\n 'list:List storage providers'\n 'ls:List storage providers (alias)'\n 'get:Get storage provider details'\n 'create:Create a storage provider'\n 'delete:Delete a storage provider'\n )\n _describe 'storage-providers command' storage_providers_cmds\n ;;\n commands)\n local -a commands_cmds\n commands_cmds=(\n 'list:List commands'\n 'ls:List commands (alias)'\n 'get:Get command details'\n 'create:Execute a command'\n )\n _describe 'commands command' commands_cmds\n ;;\n scheduled-jobs)\n local -a scheduled_jobs_cmds\n scheduled_jobs_cmds=(\n 'list:List scheduled jobs'\n 'ls:List scheduled jobs (alias)'\n 'get:Get scheduled job details'\n 'create:Create a scheduled job'\n 'delete:Delete a scheduled job'\n )\n _describe 'scheduled-jobs command' scheduled_jobs_cmds\n ;;\n services)\n local -a services_cmds\n services_cmds=(\n 'list:List services on a server'\n 'ls:List services on a server (alias)'\n 'restart:Restart a service'\n )\n _describe 'services command' services_cmds\n ;;\n php)\n local -a php_cmds\n php_cmds=(\n 'list:List installed PHP versions'\n 'ls:List installed PHP versions (alias)'\n 'config:Show a PHP configuration file'\n 'update-config:Replace a PHP configuration file'\n 'max-upload-size:Show the max upload size'\n 'set-max-upload-size:Set the max upload size'\n 'max-execution-time:Show the max execution time'\n 'set-max-execution-time:Set the max execution time'\n 'opcache:Show the OPcache status'\n 'enable-opcache:Enable OPcache'\n 'disable-opcache:Disable OPcache'\n )\n _describe 'php command' php_cmds\n ;;\n user)\n local -a user_cmds\n user_cmds=(\n 'get:Get the authenticated user profile'\n )\n _describe 'user command' user_cmds\n ;;\n monitors)\n local -a monitors_cmds\n monitors_cmds=(\n 'list:List monitors'\n 'ls:List monitors (alias)'\n 'get:Get monitor details'\n 'create:Create a monitor'\n 'delete:Delete a monitor'\n )\n _describe 'monitors command' monitors_cmds\n ;;\n nginx-templates)\n local -a nginx_templates_cmds\n nginx_templates_cmds=(\n 'list:List Nginx templates'\n 'ls:List Nginx templates (alias)'\n 'get:Get Nginx template details'\n 'create:Create a Nginx template'\n 'update:Update a Nginx template'\n 'delete:Delete a Nginx template'\n )\n _describe 'nginx-templates command' nginx_templates_cmds\n ;;\n security-rules)\n local -a security_rules_cmds\n security_rules_cmds=(\n 'list:List security rules'\n 'ls:List security rules (alias)'\n 'get:Get security rule details'\n 'create:Create a security rule'\n 'delete:Delete a security rule'\n )\n _describe 'security-rules command' security_rules_cmds\n ;;\n redirect-rules)\n local -a redirect_rules_cmds\n redirect_rules_cmds=(\n 'list:List redirect rules'\n 'ls:List redirect rules (alias)'\n 'get:Get redirect rule details'\n 'create:Create a redirect rule'\n 'delete:Delete a redirect rule'\n )\n _describe 'redirect-rules command' redirect_rules_cmds\n ;;\n recipes)\n local -a recipes_cmds\n recipes_cmds=(\n 'list:List all recipes'\n 'ls:List all recipes (alias)'\n 'get:Get recipe details'\n 'run:Run a recipe'\n )\n _describe 'recipes command' recipes_cmds\n ;;\n completion)\n local -a completion_cmds\n completion_cmds=(\n 'bash:Generate Bash completion script'\n 'zsh:Generate Zsh completion script'\n 'fish:Generate Fish completion script'\n )\n _describe 'completion shell' completion_cmds\n ;;\n esac\n ;;\n args)\n _arguments \\\\\n '--token[API token]:token:' \\\\\n '--server[Server ID]:server id:' \\\\\n '--site[Site ID]:site id:' \\\\\n '--exact[Match server and site names exactly]' \\\\\n '(-f --format)'{-f,--format}'[Output format]:format:(json human table)' \\\\\n '--no-color[Disable colored output]' \\\\\n '(-h --help)'{-h,--help}'[Show help]' \\\\\n '-v[Show version]' \\\\\n '--version[PHP version (php, services)]:version:' \\\\\n '--name[Name]:name:' \\\\\n '--command[Command]:command:' \\\\\n '--content[Content]:content:' \\\\\n '--from[From]:from:' \\\\\n '--to[To]:to:' \\\\\n '--provider[Provider]:provider:' \\\\\n '--frequency[Frequency]:frequency:' \\\\\n '--cron[Cron expression]:cron:' \\\\\n '--type[Type]:type:' \\\\\n '--operator[Operator]:operator:' \\\\\n '--threshold[Threshold]:threshold:' \\\\\n '--minutes[Minutes]:minutes:' \\\\\n '--key[Key]:key:' \\\\\n '--port[Port]:port:' \\\\\n '--ip-address[IP address]:ip address:' \\\\\n '--user[User]:user:' \\\\\n '--script[Script]:script:' \\\\\n '--servers[Servers]:servers:' \\\\\n '--domain[Domain]:domain:' \\\\\n '--password[Password]:password:' \\\\\n '--credential-id[Credential ID]:credential id:' \\\\\n '--region[Region]:region:' \\\\\n '--size[Size]:size:' \\\\\n '--project-type[Project type]:project type:' \\\\\n '--directory[Directory]:directory:' \\\\\n '--ubuntu-version[Ubuntu version]:ubuntu version:' \\\\\n '--php-version[PHP version]:php version:' \\\\\n '--database[Database type]:database type:' \\\\\n '--private-ip[Private IP address]:private ip address:' \\\\\n '--ssh-port[SSH port]:ssh port:' \\\\\n '--tag[Tag]:tag:' \\\\\n '--file[File path (- for stdin)]:file:_files' \\\\\n '--script-file[Deployment script file]:file:_files' \\\\\n '--all-servers[Target every server]' \\\\\n '--prune[Remove SSH keys that are not in the file]' \\\\\n '--dry-run[Print the plan and change nothing]' \\\\\n '--check[Compare with Forge, do not write]' \\\\\n '--storage-provider[Storage provider ID or name]:storage provider:' \\\\\n '--databases[Database IDs or names]:databases:' \\\\\n '--retention[Number of backups to keep]:retention:' \\\\\n '--time[Backup time (HH:MM)]:time:' \\\\\n '--day[Backup day of week (0-6)]:day:' \\\\\n '--cron[Cron expression]:cron:' \\\\\n '--bucket[Bucket]:bucket:' \\\\\n '--notification-email[Notification email]:email:' \\\\\n '--include-new-databases[Also back up new databases]' \\\\\n '--endpoint[S3 endpoint URL]:endpoint:' \\\\\n '--access-key[Access key ID]:access key:' \\\\\n '--secret-key-file[Secret key file (- for stdin)]:file:_files' \\\\\n '--assume-role[Use the EC2 instance role]'\n ;;\n esac\n}\n\n_forge \"$@\"\n`;\n\nconst FISH_COMPLETION = `# Completions for forge\n\n# Main commands\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"config\" -d \"Manage CLI configuration\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"servers\" -d \"Manage servers\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"s\" -d \"Manage servers (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"sites\" -d \"Manage sites\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"deployments\" -d \"Manage deployments\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"d\" -d \"Manage deployments (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"databases\" -d \"Manage databases\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"db\" -d \"Manage databases (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"database-users\" -d \"Manage database users\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"daemons\" -d \"Manage daemons\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"env\" -d \"Manage environment variables\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"nginx\" -d \"Manage nginx configuration\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"certificates\" -d \"Manage SSL certificates\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"certs\" -d \"Manage SSL certificates (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"firewall-rules\" -d \"Manage firewall rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"fw\" -d \"Manage firewall rules (alias)\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"ssh\" -d \"Open an SSH session to a server\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"ssh-keys\" -d \"Manage SSH keys\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"backups\" -d \"Manage database backup configurations\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"storage-providers\" -d \"Manage the storage providers of database backups\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"commands\" -d \"Manage site commands\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"scheduled-jobs\" -d \"Manage scheduled jobs\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"services\" -d \"List and restart server services\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"php\" -d \"Manage PHP versions, configuration, limits and OPcache\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"user\" -d \"Display authenticated user profile\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"monitors\" -d \"Manage server monitors\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"nginx-templates\" -d \"Manage Nginx templates\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"security-rules\" -d \"Manage site security rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"redirect-rules\" -d \"Manage site redirect rules\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"recipes\" -d \"Manage recipes\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"completion\" -d \"Generate shell completion script\"\ncomplete -c forge -f -n \"__fish_use_subcommand\" -a \"help\" -d \"Show help\"\n\n# config subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"set\" -d \"Save API token\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"get\" -d \"Show current token\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from config\" -a \"delete\" -d \"Delete stored token\"\n\n# servers subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"list\" -d \"List all servers\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"ls\" -d \"List all servers (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"get\" -d \"Get server details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"public-key\" -d \"Print the public key of the forge user\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"create\" -d \"Create a server\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from servers s\" -a \"reboot\" -d \"Reboot a server\"\n\n# sites subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"list\" -d \"List sites\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"ls\" -d \"List sites (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"get\" -d \"Get site details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from sites\" -a \"apply\" -d \"Make a site match a site file\"\n\n# deployments subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"list\" -d \"List deployments\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"ls\" -d \"List deployments (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"deploy\" -d \"Trigger a deployment\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"logs\" -d \"Show deployment output\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"log\" -d \"Show deployment output (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"script\" -d \"Show the deployment script\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from deployments d\" -a \"update-script\" -d \"Update the deployment script\"\n\n# databases subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"list\" -d \"List databases\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"ls\" -d \"List databases (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from databases db\" -a \"get\" -d \"Get database details\"\n\n# database-users subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"list\" -d \"List database users\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"ls\" -d \"List database users (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"get\" -d \"Get database user details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"create\" -d \"Create a database user\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from database-users\" -a \"delete\" -d \"Delete a database user\"\n\n# daemons subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"list\" -d \"List daemons\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"ls\" -d \"List daemons (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"get\" -d \"Get daemon details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"restart\" -d \"Restart a daemon\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"logs\" -d \"Show daemon log output\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from daemons\" -a \"log\" -d \"Show daemon log output (alias)\"\n\n# env subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from env\" -a \"get\" -d \"Get env variables\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from env\" -a \"update\" -d \"Update env variables\"\n\n# nginx subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx\" -a \"get\" -d \"Get nginx config\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx\" -a \"update\" -d \"Update nginx config\"\n\n# certificates subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"get\" -d \"Get certificate for a domain\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"get\" -d \"Get certificate details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from certificates certs\" -a \"activate\" -d \"Activate a certificate\"\n\n# firewall-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"list\" -d \"List firewall rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"ls\" -d \"List firewall rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from firewall-rules fw\" -a \"get\" -d \"Get firewall rule details\"\n\n# ssh-keys subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"list\" -d \"List SSH keys\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"ls\" -d \"List SSH keys (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"get\" -d \"Get SSH key details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from ssh-keys\" -a \"sync\" -d \"Make server SSH keys match a file\"\n\n# backups subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"list\" -d \"List backup configurations\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"ls\" -d \"List backup configurations (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"get\" -d \"Get backup configuration details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"create\" -d \"Create a backup configuration\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"update\" -d \"Update a backup configuration\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from backups\" -a \"delete\" -d \"Delete a backup configuration\"\n\n# storage-providers subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"list\" -d \"List storage providers\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"ls\" -d \"List storage providers (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"get\" -d \"Get storage provider details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"create\" -d \"Create a storage provider\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from storage-providers\" -a \"delete\" -d \"Delete a storage provider\"\n\n# commands subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"list\" -d \"List commands\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"ls\" -d \"List commands (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"get\" -d \"Get command details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from commands\" -a \"create\" -d \"Execute a command\"\n\n# scheduled-jobs subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"list\" -d \"List scheduled jobs\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"ls\" -d \"List scheduled jobs (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"get\" -d \"Get scheduled job details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"create\" -d \"Create a scheduled job\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from scheduled-jobs\" -a \"delete\" -d \"Delete a scheduled job\"\n\n# services subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"list\" -d \"List services on a server\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"ls\" -d \"List services on a server (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from services\" -a \"restart\" -d \"Restart a service\"\n\n# php subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"list\" -d \"List installed PHP versions\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"ls\" -d \"List installed PHP versions (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"config\" -d \"Show a PHP configuration file\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"update-config\" -d \"Replace a PHP configuration file\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"max-upload-size\" -d \"Show the max upload size\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"set-max-upload-size\" -d \"Set the max upload size\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"max-execution-time\" -d \"Show the max execution time\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"set-max-execution-time\" -d \"Set the max execution time\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"opcache\" -d \"Show the OPcache status\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"enable-opcache\" -d \"Enable OPcache\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from php\" -a \"disable-opcache\" -d \"Disable OPcache\"\n\n# user subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from user\" -a \"get\" -d \"Get the authenticated user profile\"\n\n# monitors subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"list\" -d \"List monitors\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"ls\" -d \"List monitors (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"get\" -d \"Get monitor details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"create\" -d \"Create a monitor\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from monitors\" -a \"delete\" -d \"Delete a monitor\"\n\n# nginx-templates subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"list\" -d \"List Nginx templates\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"ls\" -d \"List Nginx templates (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"get\" -d \"Get Nginx template details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"create\" -d \"Create a Nginx template\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"update\" -d \"Update a Nginx template\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from nginx-templates\" -a \"delete\" -d \"Delete a Nginx template\"\n\n# security-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"list\" -d \"List security rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"ls\" -d \"List security rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"get\" -d \"Get security rule details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"create\" -d \"Create a security rule\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from security-rules\" -a \"delete\" -d \"Delete a security rule\"\n\n# redirect-rules subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"list\" -d \"List redirect rules\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"ls\" -d \"List redirect rules (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"get\" -d \"Get redirect rule details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"create\" -d \"Create a redirect rule\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from redirect-rules\" -a \"delete\" -d \"Delete a redirect rule\"\n\n# recipes subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"list\" -d \"List all recipes\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"ls\" -d \"List all recipes (alias)\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"get\" -d \"Get recipe details\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from recipes\" -a \"run\" -d \"Run a recipe\"\n\n# completion subcommands\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"bash\" -d \"Install Bash completion\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"zsh\" -d \"Install Zsh completion\"\ncomplete -c forge -f -n \"__fish_seen_subcommand_from completion\" -a \"fish\" -d \"Install Fish completion\"\n\n# Global options\ncomplete -c forge -l token -d \"API token\" -r\ncomplete -c forge -l server -d \"Server ID\" -r\ncomplete -c forge -l site -d \"Site ID\" -r\ncomplete -c forge -l exact -d \"Match server and site names exactly\"\ncomplete -c forge -s f -l format -d \"Output format\" -xa \"json human table\"\ncomplete -c forge -l no-color -d \"Disable colored output\"\ncomplete -c forge -s h -l help -d \"Show help\"\ncomplete -c forge -s v -l version -d \"Show version\"\ncomplete -c forge -l name -d \"Name\" -r\ncomplete -c forge -l command -d \"Command\" -r\ncomplete -c forge -l content -d \"Content\" -r\ncomplete -c forge -l from -d \"From\" -r\ncomplete -c forge -l to -d \"To\" -r\ncomplete -c forge -l provider -d \"Provider\" -r\ncomplete -c forge -l frequency -d \"Frequency\" -r\ncomplete -c forge -l cron -d \"Cron expression\" -r\ncomplete -c forge -l type -d \"Type\" -r\ncomplete -c forge -l operator -d \"Operator\" -r\ncomplete -c forge -l threshold -d \"Threshold\" -r\ncomplete -c forge -l minutes -d \"Minutes\" -r\ncomplete -c forge -l key -d \"Key\" -r\ncomplete -c forge -l port -d \"Port\" -r\ncomplete -c forge -l ip-address -d \"IP address\" -r\ncomplete -c forge -l user -d \"User\" -r\ncomplete -c forge -l script -d \"Script\" -r\ncomplete -c forge -l servers -d \"Servers\" -r\ncomplete -c forge -l domain -d \"Domain\" -r\ncomplete -c forge -l password -d \"Password\" -r\ncomplete -c forge -l credential-id -d \"Credential ID\" -r\ncomplete -c forge -l region -d \"Region\" -r\ncomplete -c forge -l size -d \"Size\" -r\ncomplete -c forge -l project-type -d \"Project type\" -r\ncomplete -c forge -l directory -d \"Directory\" -r\ncomplete -c forge -l file -d \"File path (- for stdin)\" -r -F\ncomplete -c forge -l script-file -d \"Deployment script file\" -r -F\ncomplete -c forge -l all-servers -d \"Target every server\"\ncomplete -c forge -l prune -d \"Remove SSH keys that are not in the file\"\ncomplete -c forge -l ubuntu-version -d \"Ubuntu version\" -r\ncomplete -c forge -l php-version -d \"PHP version\" -r\ncomplete -c forge -l database -d \"Database type\" -r\ncomplete -c forge -l private-ip -d \"Private IP address\" -r\ncomplete -c forge -l ssh-port -d \"SSH port\" -r\ncomplete -c forge -l tag -d \"Tag\" -r\ncomplete -c forge -l dry-run -d \"Print the plan and change nothing\"\ncomplete -c forge -l check -d \"Compare with Forge, do not write\"\ncomplete -c forge -l storage-provider -d \"Storage provider ID or name\" -r\ncomplete -c forge -l databases -d \"Database IDs or names\" -r\ncomplete -c forge -l retention -d \"Number of backups to keep\" -r\ncomplete -c forge -l time -d \"Backup time (HH:MM)\" -r\ncomplete -c forge -l day -d \"Backup day of week (0-6)\" -r\ncomplete -c forge -l cron -d \"Cron expression\" -r\ncomplete -c forge -l bucket -d \"Bucket\" -r\ncomplete -c forge -l notification-email -d \"Notification email\" -r\ncomplete -c forge -l include-new-databases -d \"Also back up new databases\"\ncomplete -c forge -l endpoint -d \"S3 endpoint URL\" -r\ncomplete -c forge -l access-key -d \"Access key ID\" -r\ncomplete -c forge -l secret-key-file -d \"Secret key file (- for stdin)\" -r -F\ncomplete -c forge -l assume-role -d \"Use the EC2 instance role\"\n`;\n\n/**\n * Get the appropriate completion file path for the shell\n */\nfunction getCompletionPath(shell: string): string {\n const home = homedir();\n\n switch (shell) {\n case \"bash\":\n return join(home, \".local/share/bash-completion/completions/forge\");\n case \"zsh\":\n return join(home, \".zfunc/_forge\");\n case \"fish\": {\n const configHome = process.env[\"XDG_CONFIG_HOME\"] ?? join(home, \".config\");\n return join(configHome, \"fish/completions/forge.fish\");\n }\n default:\n throw new Error(`Unknown shell: ${shell}`);\n }\n}\n\nexport function showCompletionHelp(): void {\n console.log(`\n${colors.bold(\"forge completion\")} - Install shell completion\n\n${colors.bold(\"USAGE:\")}\n forge completion <shell> [--print]\n\n${colors.bold(\"SHELLS:\")}\n bash Install Bash completion\n zsh Install Zsh completion\n fish Install Fish completion\n\n${colors.bold(\"OPTIONS:\")}\n --print Print completion script instead of installing\n\n${colors.bold(\"INSTALLATION:\")}\n The completion script is automatically installed to the appropriate\n standard directory for your shell. After installation, restart your\n shell to activate completions.\n\n ${colors.bold(\"Bash:\")}\n forge completion bash\n # Installs to: ~/.local/share/bash-completion/completions/forge\n # Then run: exec bash\n\n ${colors.bold(\"Zsh:\")}\n forge completion zsh\n # Installs to: ~/.zfunc/_forge\n # Ensure fpath includes ~/.zfunc (add to ~/.zshrc before compinit):\n # fpath=(~/.zfunc $fpath)\n # Then run: exec zsh\n\n ${colors.bold(\"Fish:\")}\n forge completion fish\n # Installs to: ~/.config/fish/completions/forge.fish\n # Completions are loaded automatically\n\n${colors.bold(\"PRINT ONLY:\")}\n Use --print to output the script without installing:\n\n forge completion bash --print > my-completion.sh\n forge completion zsh --print | less\n`);\n}\n\nexport function handleCompletionCommand(\n shell: string,\n options: Record<string, string | boolean | string[]> = {},\n): void {\n const shouldPrint = options[\"print\"] !== undefined;\n\n const shellLower = shell.toLowerCase();\n\n // Get completion script\n let script: string;\n switch (shellLower) {\n case \"bash\":\n script = BASH_COMPLETION;\n break;\n case \"zsh\":\n script = ZSH_COMPLETION;\n break;\n case \"fish\":\n script = FISH_COMPLETION;\n break;\n default:\n console.error(\n `${colors.red(\"✗\")} Unknown shell: ${shell}. Supported shells: bash, zsh, fish`,\n );\n console.error(`Run ${colors.cyan(\"forge completion --help\")} for usage information.`);\n process.exit(1);\n return;\n }\n\n // If --print flag, just output the script\n if (shouldPrint) {\n process.stdout.write(script);\n return;\n }\n\n // Otherwise, install to appropriate directory\n const installPath = getCompletionPath(shellLower);\n const dir = installPath.substring(0, installPath.lastIndexOf(\"/\"));\n\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(installPath, script, \"utf8\");\n\n console.log(\n `${colors.green(\"✓\")} Installed ${shell} completion to ${colors.cyan(installPath)}`,\n );\n console.log();\n console.log(colors.bold(\"Next steps:\"));\n\n switch (shellLower) {\n case \"bash\":\n console.log(` 1. Restart your shell: ${colors.cyan(\"exec bash\")}`);\n console.log(` 2. Or source the file: ${colors.cyan(`source ${installPath}`)}`);\n break;\n case \"zsh\":\n console.log(\n ` 1. Ensure ${colors.cyan(\"~/.zfunc\")} is in your $fpath (add to ~/.zshrc before compinit):`,\n );\n console.log(` ${colors.cyan(\"fpath=(~/.zfunc $fpath)\")}`);\n console.log(` 2. Restart your shell: ${colors.cyan(\"exec zsh\")}`);\n break;\n case \"fish\":\n console.log(` Completions are loaded automatically. Restart fish if needed.`);\n break;\n }\n } catch (error) {\n console.error(\n `${colors.red(\"✗\")} Failed to install completion: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n}\n","import { getCertificate, activateCertificate } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerSiteDomainRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string; domain: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const domain = String(ctx.options.domain ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n if (!domain) {\n exitWithValidationError(\"domain_id\", usage, ctx.formatter);\n }\n\n return { server, site, domain };\n}\n\nexport async function certificatesGet(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge certificates get --server <server_id> --site <site_id> --domain <domain_id>\";\n\n const { server, site, domain } = requireServerSiteDomainRaw(ctx, usage);\n\n // Allow positional domain_id as first arg for convenience\n const domainId = args[0] || domain;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getCertificate({ server_id, site_id, domain_id: domainId }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"verification_method\",\n \"key_type\",\n \"status\",\n \"request_status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function certificatesActivate(args: string[], ctx: CommandContext): Promise<void> {\n const usage =\n \"forge certificates activate --server <server_id> --site <site_id> --domain <domain_id>\";\n\n const { server, site, domain } = requireServerSiteDomainRaw(ctx, usage);\n\n // Allow positional domain_id as first arg for convenience\n const domainId = args[0] || domain;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await activateCertificate({ server_id, site_id, domain_id: domainId }, execCtx);\n ctx.formatter.success(`Certificate for domain ${domainId} activated.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { certificatesGet, certificatesActivate } from \"./handlers.ts\";\n\nexport const handleCertificatesCommand = createCommandRouter({\n resource: \"certificates\",\n handlers: {\n get: [certificatesGet, \"args\"],\n activate: [certificatesActivate, \"args\"],\n },\n writeSubcommands: [\"activate\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showCertificatesHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge certificates get\")} - Get certificate for a domain\n\n${colors.bold(\"USAGE:\")}\n forge certificates get --server <server_id> --site <site_id> --domain <domain_id>\n`);\n } else if (subcommand === \"activate\") {\n console.log(`\n${colors.bold(\"forge certificates activate\")} - Activate a certificate\n\n${colors.bold(\"USAGE:\")}\n forge certificates activate --server <server_id> --site <site_id> --domain <domain_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge certificates\")} - Manage SSL certificates\n\n${colors.bold(\"USAGE:\")}\n forge certificates <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge certs\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get certificate for a domain\n activate Activate a certificate\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --domain <id> Domain record ID (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"NOTE:\")}\n In Forge v2, certificates are per-domain. Use domains to manage certificates.\n\nRun ${colors.cyan(\"forge certificates <subcommand> --help\")} for details.\n`);\n }\n}\n","import { createCommand, getCommand, listCommands } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function commandsList(ctx: CommandContext): Promise<void> {\n const usage = \"forge commands list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listCommands({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"status\", \"created_at\"],\n \"No commands found.\",\n (c) =>\n `${String(c.id).padEnd(8)} ${c.command.padEnd(50)} ${c.status.padEnd(12)} ${c.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function commandsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge commands get <command_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"command_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getCommand({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"status\",\n \"user_id\",\n \"duration\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function commandsCreate(ctx: CommandContext): Promise<void> {\n const usage = \"forge commands create --server <server_id> --site <site_id> --command <command>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const command = String(ctx.options.command ?? \"\");\n\n if (!command) {\n exitWithValidationError(\"command\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await createCommand({ server_id, site_id, command }, execCtx);\n ctx.formatter.success(\"Command queued for execution.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { commandsCreate, commandsGet, commandsList } from \"./handlers.ts\";\n\nexport const handleCommandsCommand = createCommandRouter({\n resource: \"commands\",\n handlers: {\n list: commandsList,\n ls: commandsList,\n get: [commandsGet, \"args\"],\n create: commandsCreate,\n },\n writeSubcommands: [\"create\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showCommandsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge commands list\")} - List commands executed on a site\n\n${colors.bold(\"USAGE:\")}\n forge commands list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge commands get\")} - Get command details\n\n${colors.bold(\"USAGE:\")}\n forge commands get <command_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge commands create\")} - Execute a command on a site\n\n${colors.bold(\"USAGE:\")}\n forge commands create --server <server_id> --site <site_id> --command <command> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --command <cmd> Command to execute (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge commands\")} - Manage site commands\n\n${colors.bold(\"USAGE:\")}\n forge commands <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List commands\n get <id> Get command details\n create Execute a command on a site\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge commands <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Config command — manage forge configuration\n */\n\nimport {\n createConfigStore,\n setToken,\n deleteToken,\n getToken,\n getOrganizationSlug,\n setOrganizationSlug,\n} from \"../config.ts\";\nimport { OutputFormatter } from \"../output.ts\";\nimport { type OutputFormat, isOutputFormat } from \"../types.ts\";\nimport { colors } from \"../utils/colors.ts\";\n\nexport function showConfigHelp(): void {\n console.log(`\n${colors.bold(\"forge config\")} - Manage CLI configuration\n\n${colors.bold(\"USAGE:\")}\n forge config <subcommand> [key] [value]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n set <key> <value> Save a config value\n get Show current configuration (masked)\n delete Delete all stored configuration\n\n${colors.bold(\"CONFIG KEYS:\")}\n apiToken Forge API token (scoped, from Forge dashboard)\n organizationSlug Default organization slug (e.g. 'studio-meta')\n\n${colors.bold(\"EXAMPLES:\")}\n forge config set apiToken YOUR_FORGE_TOKEN\n forge config set organizationSlug studio-meta\n forge config get\n forge config delete\n`);\n}\n\nexport function handleConfigCommand(\n subcommand: string,\n args: string[],\n options: Record<string, string | boolean | string[]>,\n): void {\n const rawFormat = options.format ?? options.f ?? \"human\";\n const format: OutputFormat = isOutputFormat(rawFormat) ? rawFormat : \"human\";\n const formatter = new OutputFormatter(format, options[\"no-color\"] === true);\n\n const store = createConfigStore();\n\n switch (subcommand) {\n case \"set\": {\n const [key, value] = args;\n if (!key || !value) {\n formatter.error(\"Usage: forge config set <key> <value>\");\n formatter.info(\"Keys: apiToken, organizationSlug\");\n process.exit(1);\n return;\n }\n\n switch (key) {\n case \"apiToken\":\n setToken(value, store);\n formatter.success(\"API token saved.\");\n break;\n case \"organizationSlug\":\n setOrganizationSlug(value, store);\n formatter.success(`Organization slug set to \"${value}\".`);\n break;\n default:\n formatter.error(`Unknown config key: ${key}`);\n formatter.info(\"Valid keys: apiToken, organizationSlug\");\n process.exit(1);\n }\n break;\n }\n\n case \"get\": {\n const token = getToken(store);\n const orgSlug = getOrganizationSlug(store);\n\n if (format === \"json\") {\n formatter.output({\n apiToken: token ? maskToken(token) : null,\n organizationSlug: orgSlug ?? null,\n });\n } else {\n if (token) {\n console.log(`apiToken: ${maskToken(token)}`);\n } else {\n formatter.warning(\"No API token configured.\");\n }\n if (orgSlug) {\n console.log(`organizationSlug: ${orgSlug}`);\n } else {\n formatter.warning(\"No organization slug configured.\");\n }\n\n if (!token || !orgSlug) {\n formatter.info(\"Run: forge config set <key> <value>\");\n }\n }\n break;\n }\n\n case \"delete\": {\n deleteToken(store);\n formatter.success(\"Configuration deleted.\");\n break;\n }\n\n default:\n showConfigHelp();\n break;\n }\n}\n\nfunction maskToken(token: string): string {\n return token.length > 8\n ? `${token.slice(0, 4)}${\"*\".repeat(token.length - 8)}${token.slice(-4)}`\n : \"****\";\n}\n","import {\n listDaemons,\n getDaemon,\n getDaemonLog,\n restartDaemon,\n updateDaemon,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function daemonsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge daemons list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDaemons({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"user\", \"status\"],\n \"No daemons found.\",\n (d) => `${String(d.id).padEnd(8)} ${d.command.padEnd(50)} ${d.user.padEnd(16)} ${d.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function daemonsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons get <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons get <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDaemon({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"directory\",\n \"processes\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function daemonsLogs(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons logs <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons logs <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDaemonLog({ server_id, id }, execCtx);\n if (result.data) {\n ctx.formatter.outputText(result.data);\n } else {\n ctx.formatter.info(\"No log output available.\");\n }\n }, ctx.formatter);\n}\n\nexport async function daemonsUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge daemons update <daemon_id> --server <server_id> --name <name>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const options: Record<string, string> = { server_id, id, name };\n if (ctx.options.config) {\n options.config = String(ctx.options.config);\n }\n const result = await updateDaemon(options as never, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"directory\",\n \"processes\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function daemonsRestart(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"daemon_id\",\n \"forge daemons restart <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge daemons restart <daemon_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await restartDaemon({ server_id, id }, execCtx);\n ctx.formatter.success(`Daemon ${id} restarted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { daemonsList, daemonsGet, daemonsLogs, daemonsRestart, daemonsUpdate } from \"./handlers.ts\";\n\nexport const handleDaemonsCommand = createCommandRouter({\n resource: \"daemons\",\n handlers: {\n list: daemonsList,\n ls: daemonsList,\n get: [daemonsGet, \"args\"],\n logs: [daemonsLogs, \"args\"],\n log: [daemonsLogs, \"args\"],\n restart: [daemonsRestart, \"args\"],\n update: [daemonsUpdate, \"args\"],\n },\n writeSubcommands: [\"restart\", \"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDaemonsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge daemons list\")} - List daemons on a server\n\n${colors.bold(\"USAGE:\")}\n forge daemons list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge daemons get\")} - Get daemon details\n\n${colors.bold(\"USAGE:\")}\n forge daemons get <daemon_id> --server <server_id>\n`);\n } else if (subcommand === \"logs\" || subcommand === \"log\") {\n console.log(`\n${colors.bold(\"forge daemons logs\")} - Show the log output of a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons logs <daemon_id> --server <server_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge daemons update\")} - Update a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons update <daemon_id> --server <server_id> --name <name> [--config <config>]\n`);\n } else if (subcommand === \"restart\") {\n console.log(`\n${colors.bold(\"forge daemons restart\")} - Restart a daemon\n\n${colors.bold(\"USAGE:\")}\n forge daemons restart <daemon_id> --server <server_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge daemons\")} - Manage daemons\n\n${colors.bold(\"USAGE:\")}\n forge daemons <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List daemons\n get <id> Get daemon details\n logs <id> Show the log output of a daemon\n update <id> Update a daemon\n restart <id> Restart a daemon\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge daemons <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listDatabases, getDatabase } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function databasesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge databases list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDatabases({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No databases found.\",\n (db) => `${String(db.id).padEnd(8)} ${db.name.padEnd(30)} ${db.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function databasesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"database_id\",\n \"forge databases get <database_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge databases get <database_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDatabase({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { databasesList, databasesGet } from \"./handlers.ts\";\n\nexport const handleDatabasesCommand = createCommandRouter({\n resource: \"databases\",\n handlers: {\n list: databasesList,\n ls: databasesList,\n get: [databasesGet, \"args\"],\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDatabasesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge databases list\")} - List databases on a server\n\n${colors.bold(\"USAGE:\")}\n forge databases list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge databases get\")} - Get database details\n\n${colors.bold(\"USAGE:\")}\n forge databases get <database_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge databases\")} - Manage databases\n\n${colors.bold(\"USAGE:\")}\n forge databases <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge db\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List databases\n get <id> Get database details\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge databases <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createDatabaseUser,\n deleteDatabaseUser,\n getDatabaseUser,\n listDatabaseUsers,\n updateDatabaseUser,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function databaseUsersList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listDatabaseUsers({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No database users found.\",\n (u) => `${String(u.id).padEnd(8)} ${u.name.padEnd(30)} ${u.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function databaseUsersGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users get <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users get <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getDatabaseUser({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n const password = String(ctx.options.password ?? \"\");\n const databasesRaw = ctx.options.databases;\n const databases = Array.isArray(databasesRaw)\n ? databasesRaw.map(Number)\n : databasesRaw\n ? [Number(databasesRaw)]\n : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n if (!password) {\n exitWithValidationError(\n \"password\",\n \"forge database-users create --server <server_id> --name <name> --password <password>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createDatabaseUser(\n { server_id, name, password, ...(databases ? { databases } : {}) },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const password = ctx.options.password != null ? String(ctx.options.password) : undefined;\n const databaseIdsRaw = ctx.options[\"database-ids\"] ?? ctx.options.database_ids;\n const database_ids = Array.isArray(databaseIdsRaw)\n ? databaseIdsRaw.map(Number)\n : databaseIdsRaw\n ? [Number(databaseIdsRaw)]\n : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users update <user_id> --server <server_id> [--password <password>] [--database-ids <ids>]\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users update <user_id> --server <server_id> [--password <password>] [--database-ids <ids>]\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await updateDatabaseUser(\n {\n server_id,\n id,\n ...(password !== undefined ? { password } : {}),\n ...(database_ids ? { database_ids } : {}),\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function databaseUsersDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"user_id\",\n \"forge database-users delete <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge database-users delete <user_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteDatabaseUser({ server_id, id }, execCtx);\n ctx.formatter.success(`Database user ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n databaseUsersCreate,\n databaseUsersDelete,\n databaseUsersGet,\n databaseUsersList,\n databaseUsersUpdate,\n} from \"./handlers.ts\";\n\nexport const handleDatabaseUsersCommand = createCommandRouter({\n resource: \"database-users\",\n handlers: {\n list: databaseUsersList,\n ls: databaseUsersList,\n get: [databaseUsersGet, \"args\"],\n create: databaseUsersCreate,\n update: [databaseUsersUpdate, \"args\"],\n delete: [databaseUsersDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDatabaseUsersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge database-users list\")} - List database users on a server\n\n${colors.bold(\"USAGE:\")}\n forge database-users list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge database-users get\")} - Get database user details\n\n${colors.bold(\"USAGE:\")}\n forge database-users get <user_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge database-users create\")} - Create a new database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users create --server <server_id> --name <name> --password <password> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> Database user name (required)\n --password <pass> User password (required)\n --databases <ids> Comma-separated database IDs to grant access to (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge database-users update\")} - Update a database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users update <user_id> --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --password <pass> New password (optional)\n --database-ids <ids> Comma-separated database IDs (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge database-users delete\")} - Delete a database user\n\n${colors.bold(\"USAGE:\")}\n forge database-users delete <user_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge database-users\")} - Manage database users\n\n${colors.bold(\"USAGE:\")}\n forge database-users <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List database users\n get <id> Get database user details\n create Create a new database user\n update <id> Update a database user\n delete <id> Delete a database user\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge database-users <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Read the content of an update command from a file, stdin or an inline option.\n */\n\nimport { readFileSync } from \"node:fs\";\n\nimport type { CommandOptions } from \"../context.ts\";\nimport type { OutputFormatter } from \"../output.ts\";\nimport type { OptionValue } from \"./args.ts\";\n\nimport { exitWithError } from \"../error-handler.ts\";\nimport { ValidationError } from \"../errors.ts\";\n\nexport interface ContentSource {\n /** What the content is, in lower case, e.g. \"deployment script\". */\n label: string;\n /** Usage line shown in validation errors. */\n usage: string;\n formatter: OutputFormatter;\n}\n\n/**\n * Exit when the content is empty, so Forge never gets a blank file.\n */\nfunction assertNotEmpty(content: string, field: string, source: ContentSource): void {\n if (!content.trim()) {\n const label = source.label.charAt(0).toUpperCase() + source.label.slice(1);\n exitWithError(new ValidationError(`${label} is empty`, field), source.formatter);\n }\n}\n\n/**\n * Read content from a file path, or from stdin when the path is \"-\".\n * Exits with a validation error when the path is missing, the file cannot be read or it is empty.\n */\nexport function readContentFile(\n path: OptionValue | undefined,\n field: string,\n source: ContentSource,\n): string {\n if (typeof path !== \"string\" || !path) {\n exitWithError(\n new ValidationError(`--${field} requires a path (use - for stdin)`, field, [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n let content: string;\n try {\n content = readFileSync(path === \"-\" ? 0 : path, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n exitWithError(\n new ValidationError(`Cannot read ${source.label} from ${path}: ${reason}`, field),\n source.formatter,\n );\n }\n\n assertNotEmpty(content, field, source);\n return content;\n}\n\n/**\n * Read content from exactly one of `--file <path|->` or `--content <string>`.\n * Exits with a validation error when both or none are given, or when the content is empty.\n */\nexport function readContentOption(options: CommandOptions, source: ContentSource): string {\n const { file, content } = options;\n\n if (file !== undefined && content !== undefined) {\n exitWithError(\n new ValidationError(\"Use either --file or --content, not both\", \"file\", [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n if (file !== undefined) {\n return readContentFile(file, \"file\", source);\n }\n\n if (content === undefined) {\n exitWithError(\n new ValidationError(`Missing ${source.label}: use --file or --content`, \"file\", [\n `Usage: ${source.usage}`,\n ]),\n source.formatter,\n );\n }\n\n // `--content` without a value parses as `true`: treat it as empty content.\n const inline = typeof content === \"string\" ? content : \"\";\n assertNotEmpty(inline, \"content\", source);\n return inline;\n}\n","/**\n * Compare local content with the content on Forge for `--check`.\n */\n\nimport { diff } from \"node:util\";\n\nimport type { OutputFormatter } from \"../output.ts\";\n\nimport { ExitCode } from \"../error-handler.ts\";\n\n/**\n * Normalize CRLF to LF and drop a single trailing newline,\n * so editor and platform differences do not count as drift.\n */\nexport function normalizeContent(text: string): string {\n const lf = text.replaceAll(\"\\r\\n\", \"\\n\");\n return lf.endsWith(\"\\n\") ? lf.slice(0, -1) : lf;\n}\n\nfunction toLines(normalized: string): string[] {\n return normalized === \"\" ? [] : normalized.split(\"\\n\");\n}\n\ninterface DiffLine {\n op: \" \" | \"-\" | \"+\";\n text: string;\n /** Number of remote lines before this line. */\n remoteBefore: number;\n /** Number of local lines before this line. */\n localBefore: number;\n}\n\n/**\n * Build a unified-style line diff from `remote` to `local`, with `context`\n * unchanged lines around each change. Returns an empty string when both\n * are equal after normalization.\n */\nexport function unifiedDiff(remote: string, local: string, context = 3): string {\n const remoteText = normalizeContent(remote);\n const localText = normalizeContent(local);\n // Return early: util.diff also throws on two empty arrays (Node 24).\n if (remoteText === localText) {\n return \"\";\n }\n\n // util.diff marks lines only in its first argument with 1 and lines only in its second with -1.\n const entries = diff(toLines(remoteText), toLines(localText));\n\n let remoteCount = 0;\n let localCount = 0;\n const lines: DiffLine[] = entries.map(([op, text]) => {\n const line: DiffLine = {\n op: op === 0 ? \" \" : op === 1 ? \"-\" : \"+\",\n text,\n remoteBefore: remoteCount,\n localBefore: localCount,\n };\n if (op !== -1) remoteCount++;\n if (op !== 1) localCount++;\n return line;\n });\n\n // Group changes into hunks: a gap of more than 2 × context unchanged lines starts a new hunk.\n const changes = lines.flatMap((line, index) => (line.op === \" \" ? [] : [index]));\n const groups: number[][] = [];\n for (const index of changes) {\n const group = groups.at(-1);\n if (group && index - group[group.length - 1] - 1 <= 2 * context) {\n group.push(index);\n } else {\n groups.push([index]);\n }\n }\n\n const output = [\"--- remote\", \"+++ local\"];\n for (const group of groups) {\n const start = Math.max(0, group[0] - context);\n const end = Math.min(lines.length, group[group.length - 1] + context + 1);\n const hunk = lines.slice(start, end);\n const remoteLength = hunk.filter((line) => line.op !== \"+\").length;\n const localLength = hunk.filter((line) => line.op !== \"-\").length;\n // An empty side points at the line before the hunk, as in GNU diff.\n const remoteStart = hunk[0].remoteBefore + (remoteLength > 0 ? 1 : 0);\n const localStart = hunk[0].localBefore + (localLength > 0 ? 1 : 0);\n output.push(`@@ -${remoteStart},${remoteLength} +${localStart},${localLength} @@`);\n for (const line of hunk) {\n output.push(`${line.op}${line.text}`);\n }\n }\n\n return output.join(\"\\n\");\n}\n\n/**\n * A difference found by `--check`: `text` for human output, `json` for json output.\n */\nexport interface Drift {\n text: string;\n json: unknown;\n}\n\n/**\n * Print the result of a `--check` and set exit code 1 when the local content differs from Forge.\n * It sets `process.exitCode` and does not call `process.exit`, so a long diff\n * written to a pipe is not cut. JSON output is `{ inSync: true }` or `{ inSync: false, diff }`.\n */\nexport function reportDrift(label: string, drift: Drift | null, formatter: OutputFormatter): void {\n const name = label.charAt(0).toUpperCase() + label.slice(1);\n\n if (formatter.isJson()) {\n formatter.output(drift ? { inSync: false, diff: drift.json } : { inSync: true });\n } else if (drift) {\n console.log(drift.text);\n formatter.error(`${name} differs from Forge.`);\n } else {\n formatter.success(`${name} is in sync with Forge.`);\n }\n\n if (drift) {\n process.exitCode = ExitCode.GENERAL_ERROR;\n }\n}\n\n/**\n * Check `local` against `remote` as text and report a line diff.\n */\nexport function reportTextDrift(\n label: string,\n remote: string,\n local: string,\n formatter: OutputFormatter,\n): void {\n const text = unifiedDiff(remote, local);\n reportDrift(label, text ? { text, json: text } : null, formatter);\n}\n","/**\n * Print file content fetched from Forge, such as a configuration or a script.\n */\n\n/**\n * Write the content as it is, with a newline only when it does not end with one,\n * so `forge <command> get > file` round-trips with `--file file --check` without drift.\n */\nexport function printContent(content: string): void {\n process.stdout.write(content.endsWith(\"\\n\") ? content : `${content}\\n`);\n}\n","import {\n listDeployments,\n deploySiteAndWait,\n getDeploymentLog,\n getDeploymentScript,\n updateDeploymentScript,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ApiError } from \"../../errors.ts\";\nimport { readContentFile, readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function deploymentsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments list --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments list --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listDeployments({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"status\", \"commit\", \"started_at\"],\n \"No deployments found.\",\n (d) =>\n `${String(d.id).padEnd(8)} ${d.status.padEnd(12)} ${(d.commit.hash ?? \"—\").padEnd(10)} ${d.started_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function deploymentsLogs(args: string[], ctx: CommandContext): Promise<void> {\n const [deploymentId] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments logs [deployment_id] --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments logs [deployment_id] --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n\n let deployment_id = deploymentId;\n if (!deployment_id) {\n const deployments = await listDeployments({ server_id, site_id }, execCtx);\n if (deployments.data.length === 0) {\n ctx.formatter.info(\"No deployments found.\");\n return;\n }\n deployment_id = String(deployments.data[0].id);\n }\n\n const result = await getDeploymentLog({ server_id, site_id, deployment_id }, execCtx);\n if (result.data) {\n ctx.formatter.outputText(result.data);\n } else {\n ctx.formatter.info(\"No log output available.\");\n }\n }, ctx.formatter);\n}\n\nexport async function deploymentsScript(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge deployments script --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge deployments script --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getDeploymentScript({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function deploymentsUpdateScript(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge deployments update-script --server <server_id> --site <site_id> (--file <path|-> | --content <script>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const script = readContentOption(ctx.options, {\n label: \"deployment script\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getDeploymentScript({ server_id, site_id }, execCtx);\n reportTextDrift(\"deployment script\", remote.data, script, ctx.formatter);\n return;\n }\n\n await updateDeploymentScript({ server_id, site_id, content: script }, execCtx);\n ctx.formatter.success(\"Deployment script updated.\");\n }, ctx.formatter);\n}\n\nexport async function deploymentsDeploy(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge deployments deploy --server <server_id> --site <site_id> [--script-file <path>]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const streamLogs = Boolean(ctx.options.stream);\n const scriptFile = ctx.options[\"script-file\"];\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const script =\n scriptFile === undefined\n ? undefined\n : readContentFile(scriptFile, \"script-file\", {\n label: \"deployment script\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n\n // Upload the script first: a failure throws here, so the deploy never starts.\n if (script !== undefined) {\n await updateDeploymentScript({ server_id, site_id, content: script }, execCtx);\n process.stderr.write(\"Deployment script updated.\\n\");\n }\n\n const result = await deploySiteAndWait(\n {\n server_id,\n site_id,\n // Use either progress callback OR log streaming, not both\n onProgress: streamLogs\n ? undefined\n : ({ status, elapsed_ms }) => {\n process.stderr.write(`\\rDeploying… ${status} (${(elapsed_ms / 1000).toFixed(1)}s)`);\n },\n onLog: streamLogs\n ? (chunk) => {\n process.stdout.write(chunk);\n }\n : undefined,\n },\n execCtx,\n );\n\n // Separate the final status message from preceding output: in stream mode the\n // last log chunk has no trailing newline, otherwise clear the progress line.\n if (streamLogs) {\n process.stdout.write(\"\\n\");\n } else {\n process.stderr.write(\"\\n\");\n }\n\n const elapsedSec = (result.data.elapsed_ms / 1000).toFixed(1);\n\n // Output full log if we didn't stream it (needed for both success and failure).\n if (!streamLogs && result.data.log) {\n ctx.formatter.output(result.data.log);\n }\n\n if (result.data.status === \"success\") {\n ctx.formatter.success(`Deployment succeeded for site ${site_id} (${elapsedSec}s).`);\n } else {\n // Throw so the failure propagates to the exit code (non-zero) and the audit log\n // records status \"error\" instead of \"success\".\n throw new ApiError(`Deployment failed for site ${site_id} (${elapsedSec}s).`);\n }\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n deploymentsList,\n deploymentsDeploy,\n deploymentsLogs,\n deploymentsScript,\n deploymentsUpdateScript,\n} from \"./handlers.ts\";\n\nexport const handleDeploymentsCommand = createCommandRouter({\n resource: \"deployments\",\n handlers: {\n list: deploymentsList,\n ls: deploymentsList,\n deploy: deploymentsDeploy,\n logs: [deploymentsLogs, \"args\"],\n log: [deploymentsLogs, \"args\"],\n script: deploymentsScript,\n \"update-script\": deploymentsUpdateScript,\n },\n writeSubcommands: [\"deploy\", \"update-script\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showDeploymentsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge deployments list\")} - List deployments for a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"logs\" || subcommand === \"log\") {\n console.log(`\n${colors.bold(\"forge deployments logs\")} - Show output of a deployment (latest if no id)\n\n${colors.bold(\"USAGE:\")}\n forge deployments logs [deployment_id] --server <server_id> --site <site_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"script\") {\n console.log(`\n${colors.bold(\"forge deployments script\")} - Show the deployment script of a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments script --server <server_id> --site <site_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json ({ content }), human (raw script)\n\n${colors.bold(\"EXAMPLES:\")}\n forge deployments script --server 123 --site 456 > deploy.sh\n`);\n } else if (subcommand === \"update-script\") {\n console.log(`\n${colors.bold(\"forge deployments update-script\")} - Update the deployment script of a site\n\n${colors.bold(\"USAGE:\")}\n forge deployments update-script --server <server_id> --site <site_id> --file <path>\n forge deployments update-script --server <server_id> --site <site_id> --content <script>\n forge deployments update-script --server <server_id> --site <site_id> --file <path> --check\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the script from a file (use - for stdin)\n --content <str> Script content\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. An empty script is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge deployments update-script --server 123 --site 456 --file deploy.sh\n cat deploy.sh | forge deployments update-script --server 123 --site 456 --file -\n forge deployments update-script --server 123 --site 456 --file deploy.sh --check\n`);\n } else if (subcommand === \"deploy\") {\n console.log(`\n${colors.bold(\"forge deployments deploy\")} - Trigger a deployment\n\n${colors.bold(\"USAGE:\")}\n forge deployments deploy --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --script-file <path> Upload this deployment script before deploying (use - for stdin).\n If the upload fails, the deployment does not start.\n --stream Stream deployment logs in real-time (default: show progress)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge deployments\")} - Manage deployments\n\n${colors.bold(\"USAGE:\")}\n forge deployments <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge d\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List deployments for a site\n deploy Trigger a deployment\n logs Show output of a deployment (latest if no id)\n script Show the deployment script\n update-script Update the deployment script from a file, stdin or a string\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Script file, - for stdin (for update-script)\n --content <str> Script content (for update-script)\n --check Compare with Forge, do not write (for update-script)\n --script-file <path> Upload this script before deploying (for deploy)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge deployments <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Compare two .env files by variable name, without exposing any value.\n */\n\nimport type { Drift } from \"../../utils/drift.ts\";\n\nexport interface EnvDiff {\n /** Names only in the local file. */\n added: string[];\n /** Names only on Forge. */\n removed: string[];\n /** Names in both, with a different value. */\n changed: string[];\n}\n\nconst NAME = /^[A-Za-z_][A-Za-z0-9_.]*$/;\n\n/**\n * Find the closing quote of a quoted value. `\\` escapes a character in double quotes only.\n * Returns -1 when the value is not closed.\n */\nfunction closingQuote(value: string, quote: string): number {\n for (let index = 1; index < value.length; index++) {\n if (quote === '\"' && value[index] === \"\\\\\") {\n index++;\n } else if (value[index] === quote) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * Parse a .env file into a map of name to value, with the dotenv rules used by Laravel:\n * an optional `export ` prefix, quoted values that can span lines, and ` #` inline comments\n * after unquoted values. Blank lines, comments and lines without a valid name are ignored,\n * so a part of a value can never show as a name.\n */\nexport function parseEnv(content: string): Map<string, string> {\n const variables = new Map<string, string>();\n const lines = content.split(/\\r?\\n/);\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index].trim();\n const separator = line.indexOf(\"=\");\n const name = line\n .slice(0, Math.max(separator, 0))\n .trim()\n .replace(/^export\\s+/, \"\");\n if (!NAME.test(name)) {\n continue;\n }\n\n let value = line.slice(separator + 1).trim();\n const quote = value[0];\n if (quote === '\"' || quote === \"'\") {\n let end = closingQuote(value, quote);\n while (end === -1 && index + 1 < lines.length) {\n index++;\n value += `\\n${lines[index]}`;\n end = closingQuote(value, quote);\n }\n value = value.slice(1, end === -1 ? undefined : end);\n } else {\n value = value.replace(/\\s+#.*$/, \"\");\n }\n variables.set(name, value);\n }\n return variables;\n}\n\n/**\n * Compare the variables of two .env files. Returns only variable names.\n */\nexport function diffEnv(remote: string, local: string): EnvDiff {\n const remoteVars = parseEnv(remote);\n const localVars = parseEnv(local);\n const result: EnvDiff = { added: [], removed: [], changed: [] };\n\n for (const [name, value] of localVars) {\n if (!remoteVars.has(name)) {\n result.added.push(name);\n } else if (remoteVars.get(name) !== value) {\n result.changed.push(name);\n }\n }\n\n for (const name of remoteVars.keys()) {\n if (!localVars.has(name)) {\n result.removed.push(name);\n }\n }\n\n return result;\n}\n\n/**\n * Turn an env diff into a drift report, or null when the variables are the same.\n * The report holds variable names only, never values, because CI logs are often shared.\n */\nexport function envDrift(remote: string, local: string): Drift | null {\n const result = diffEnv(remote, local);\n const lines = [\n ...result.added.map((name) => `+ ${name} (added)`),\n ...result.removed.map((name) => `- ${name} (removed)`),\n ...result.changed.map((name) => `~ ${name} (changed)`),\n ];\n return lines.length > 0 ? { text: lines.join(\"\\n\"), json: result } : null;\n}\n","import { getEnv, updateEnv } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\nimport { envDrift } from \"./env-diff.ts\";\n\nexport async function envGet(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge env get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge env get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getEnv({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function envUpdate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge env update --server <server_id> --site <site_id> (--file <path|-> | --content <content>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const content = readContentOption(ctx.options, {\n label: \"environment file\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getEnv({ server_id, site_id }, execCtx);\n reportDrift(\"environment file\", envDrift(remote.data, content), ctx.formatter);\n return;\n }\n\n await updateEnv({ server_id, site_id, content }, execCtx);\n ctx.formatter.success(\"Environment variables updated.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { envGet, envUpdate } from \"./handlers.ts\";\n\nexport const handleEnvCommand = createCommandRouter({\n resource: \"env\",\n handlers: {\n get: envGet,\n update: envUpdate,\n },\n writeSubcommands: [\"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showEnvHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge env get\")} - Get environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env get --server <server_id> --site <site_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge env update\")} - Update environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env update --server <server_id> --site <site_id> --file <path>\n forge env update --server <server_id> --site <site_id> --file <path> --check\n forge env update --server <server_id> --site <site_id> --content <env_content>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New env content\n --check Compare with the .env on Forge and do not write.\n Exit 0 when in sync, 1 when different. Prints only variable\n names (added, removed, changed), never values.\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge env update --server 123 --site 456 --file .env\n cat .env | forge env update --server 123 --site 456 --file -\n forge env update --server 123 --site 456 --file .env --check\n`);\n } else {\n console.log(`\n${colors.bold(\"forge env\")} - Manage environment variables\n\n${colors.bold(\"USAGE:\")}\n forge env <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get environment variables\n update Update environment variables\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Content file, - for stdin (for update)\n --content <str> New env content (for update)\n --check Compare with Forge, do not write (for update)\n -f, --format <fmt> Output format: json, human\n\nRun ${colors.cyan(\"forge env <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listFirewallRules, getFirewallRule } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function firewallRulesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge firewall-rules list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listFirewallRules({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"port\", \"type\", \"ip_address\", \"status\"],\n \"No firewall rules found.\",\n (r) =>\n `${String(r.id).padEnd(8)} ${r.name.padEnd(20)} ${String(r.port).padEnd(8)} ${r.type.padEnd(8)} ${(r.ip_address ?? \"any\").padEnd(16)} ${r.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function firewallRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"firewall_rule_id\",\n \"forge firewall-rules get <rule_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge firewall-rules get <rule_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getFirewallRule({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"port\",\n \"type\",\n \"ip_address\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { firewallRulesList, firewallRulesGet } from \"./handlers.ts\";\n\nexport const handleFirewallRulesCommand = createCommandRouter({\n resource: \"firewall-rules\",\n handlers: {\n list: firewallRulesList,\n ls: firewallRulesList,\n get: [firewallRulesGet, \"args\"],\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showFirewallRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge firewall-rules list\")} - List firewall rules on a server\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge firewall-rules get\")} - Get firewall rule details\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules get <rule_id> --server <server_id>\n`);\n } else {\n console.log(`\n${colors.bold(\"forge firewall-rules\")} - Manage firewall rules\n\n${colors.bold(\"USAGE:\")}\n forge firewall-rules <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge fw\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List firewall rules\n get <id> Get firewall rule details\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge firewall-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","import { createMonitor, deleteMonitor, getMonitor, listMonitors } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function monitorsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge monitors list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listMonitors({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"type\", \"operator\", \"threshold\", \"state\"],\n \"No monitors found.\",\n (m) =>\n `${String(m.id).padEnd(8)} ${m.type.padEnd(20)} ${m.operator.padEnd(8)} ${String(m.threshold).padEnd(6)} ${m.state}`,\n );\n }, ctx.formatter);\n}\n\nexport async function monitorsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"monitor_id\",\n \"forge monitors get <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors get <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getMonitor({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"operator\",\n \"threshold\",\n \"minutes\",\n \"state\",\n \"state_changed_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function monitorsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const type = String(ctx.options.type ?? \"\");\n const operator = String(ctx.options.operator ?? \"\");\n const threshold = Number(ctx.options.threshold ?? 0);\n const notify = String(ctx.options.notify ?? \"\");\n const minutes = Number(ctx.options.minutes ?? 0);\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n if (!type) {\n exitWithValidationError(\n \"type\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n if (!operator) {\n exitWithValidationError(\n \"operator\",\n \"forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createMonitor(\n { server_id, type, operator, threshold, notify, minutes },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"type\",\n \"operator\",\n \"threshold\",\n \"minutes\",\n \"state\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function monitorsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"monitor_id\",\n \"forge monitors delete <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge monitors delete <monitor_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteMonitor({ server_id, id }, execCtx);\n ctx.formatter.success(`Monitor ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { monitorsCreate, monitorsDelete, monitorsGet, monitorsList } from \"./handlers.ts\";\n\nexport const handleMonitorsCommand = createCommandRouter({\n resource: \"monitors\",\n handlers: {\n list: monitorsList,\n ls: monitorsList,\n get: [monitorsGet, \"args\"],\n create: monitorsCreate,\n delete: [monitorsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showMonitorsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge monitors list\")} - List monitors on a server\n\n${colors.bold(\"USAGE:\")}\n forge monitors list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge monitors get\")} - Get monitor details\n\n${colors.bold(\"USAGE:\")}\n forge monitors get <monitor_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge monitors create\")} - Create a new monitor\n\n${colors.bold(\"USAGE:\")}\n forge monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --type <type> Monitor type (required)\n --operator <op> Comparison operator (required)\n --threshold <num> Alert threshold value (required)\n --minutes <num> Duration in minutes (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge monitors delete\")} - Delete a monitor\n\n${colors.bold(\"USAGE:\")}\n forge monitors delete <monitor_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge monitors\")} - Manage server monitors\n\n${colors.bold(\"USAGE:\")}\n forge monitors <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List monitors\n get <id> Get monitor details\n create Create a new monitor\n delete <id> Delete a monitor\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge monitors <subcommand> --help\")} for details.\n`);\n }\n}\n","import { getNginxConfig, updateNginxConfig } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function nginxGet(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n if (!site) {\n exitWithValidationError(\n \"site_id\",\n \"forge nginx get --server <server_id> --site <site_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getNginxConfig({ server_id, site_id }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n }, ctx.formatter);\n}\n\nexport async function nginxUpdate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge nginx update --server <server_id> --site <site_id> (--file <path|-> | --content <content>) [--check]\";\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n const check = Boolean(ctx.options.check);\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n const content = readContentOption(ctx.options, {\n label: \"nginx configuration\",\n usage,\n formatter: ctx.formatter,\n });\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n if (check) {\n const remote = await getNginxConfig({ server_id, site_id }, execCtx);\n reportTextDrift(\"nginx configuration\", remote.data, content, ctx.formatter);\n return;\n }\n\n await updateNginxConfig({ server_id, site_id, content }, execCtx);\n ctx.formatter.success(\"Nginx configuration updated.\");\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { nginxGet, nginxUpdate } from \"./handlers.ts\";\n\nexport const handleNginxCommand = createCommandRouter({\n resource: \"nginx\",\n handlers: {\n get: nginxGet,\n update: nginxUpdate,\n },\n writeSubcommands: [\"update\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showNginxHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge nginx get\")} - Get nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx get --server <server_id> --site <site_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge nginx update\")} - Update nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx update --server <server_id> --site <site_id> --file <path>\n forge nginx update --server <server_id> --site <site_id> --file <path> --check\n forge nginx update --server <server_id> --site <site_id> --content <nginx_config>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New nginx config\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n\n${colors.bold(\"EXAMPLES:\")}\n forge nginx update --server 123 --site 456 --file nginx.conf\n cat nginx.conf | forge nginx update --server 123 --site 456 --file -\n forge nginx update --server 123 --site 456 --file nginx.conf --check\n`);\n } else {\n console.log(`\n${colors.bold(\"forge nginx\")} - Manage nginx configuration\n\n${colors.bold(\"USAGE:\")}\n forge nginx <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get nginx configuration\n update Update nginx configuration\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --file <path> Content file, - for stdin (for update)\n --content <str> New nginx config (for update)\n --check Compare with Forge, do not write (for update)\n\nRun ${colors.cyan(\"forge nginx <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createNginxTemplate,\n deleteNginxTemplate,\n getNginxTemplate,\n listNginxTemplates,\n updateNginxTemplate,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function nginxTemplatesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listNginxTemplates({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"created_at\"],\n \"No Nginx templates found.\",\n (t) => `${String(t.id).padEnd(8)} ${t.name.padEnd(40)} ${t.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates get <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates get <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getNginxTemplate({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\", \"content\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const name = String(ctx.options.name ?? \"\");\n const content = String(ctx.options.content ?? \"\");\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n if (!name) {\n exitWithValidationError(\n \"name\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n if (!content) {\n exitWithValidationError(\n \"content\",\n \"forge nginx-templates create --server <server_id> --name <name> --content <content>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await createNginxTemplate({ server_id, name, content }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates update <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates update <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const name = ctx.options.name ? String(ctx.options.name) : undefined;\n const content = ctx.options.content ? String(ctx.options.content) : undefined;\n const result = await updateNginxTemplate({ server_id, id, name, content }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function nginxTemplatesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"template_id\",\n \"forge nginx-templates delete <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge nginx-templates delete <template_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await deleteNginxTemplate({ server_id, id }, execCtx);\n ctx.formatter.success(`Nginx template ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n nginxTemplatesCreate,\n nginxTemplatesDelete,\n nginxTemplatesGet,\n nginxTemplatesList,\n nginxTemplatesUpdate,\n} from \"./handlers.ts\";\n\nexport const handleNginxTemplatesCommand = createCommandRouter({\n resource: \"nginx-templates\",\n handlers: {\n list: nginxTemplatesList,\n ls: nginxTemplatesList,\n get: [nginxTemplatesGet, \"args\"],\n create: nginxTemplatesCreate,\n update: [nginxTemplatesUpdate, \"args\"],\n delete: [nginxTemplatesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showNginxTemplatesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge nginx-templates list\")} - List Nginx templates on a server\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge nginx-templates get\")} - Get Nginx template details\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates get <template_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge nginx-templates create\")} - Create a new Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates create --server <server_id> --name <name> --content <content> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> Template name (required)\n --content <text> Template content (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge nginx-templates update\")} - Update an Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates update <template_id> --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --name <name> New template name (optional)\n --content <text> New template content (optional)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge nginx-templates delete\")} - Delete an Nginx template\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates delete <template_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge nginx-templates\")} - Manage Nginx templates\n\n${colors.bold(\"USAGE:\")}\n forge nginx-templates <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List Nginx templates\n get <id> Get Nginx template details\n create Create a new Nginx template\n update <id> Update an Nginx template\n delete <id> Delete an Nginx template\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge nginx-templates <subcommand> --help\")} for details.\n`);\n }\n}\n","import type { ExecutorContext } from \"@studiometa/forge-core\";\nimport {\n disablePhpOpcache,\n enablePhpOpcache,\n getPhpConfig,\n getPhpMaxExecutionTime,\n getPhpMaxUploadSize,\n getPhpOpcache,\n listPhpVersions,\n PHP_CONFIG_TYPES,\n updatePhpConfig,\n updatePhpMaxExecutionTime,\n updatePhpMaxUploadSize,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\nimport { exitWithError, exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { readContentOption } from \"../../utils/content-source.ts\";\nimport { reportTextDrift } from \"../../utils/drift.ts\";\nimport { printContent } from \"../../utils/print-content.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nconst CONFIG_USAGE =\n \"forge php config --server <server_id> --version <version> --type <cli|fpm|pool> [--user <user>]\";\nconst UPDATE_CONFIG_USAGE =\n \"forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> (--file <path|-> | --content <content>) [--user <user>] [--check]\";\n\n/**\n * Return the --server option, or exit with a validation error when it is missing.\n */\nfunction requireServer(ctx: CommandContext, usage: string): string {\n const server = String(ctx.options.server ?? \"\");\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n return server;\n}\n\n/**\n * Resolve the server and run `fn` with its ID, with the CLI error handling.\n */\nasync function withServer(\n ctx: CommandContext,\n server: string,\n fn: (server_id: string, execCtx: ExecutorContext) => Promise<void>,\n): Promise<void> {\n await runCommand(async () => {\n const execCtx = ctx.createExecutorContext(ctx.getToken());\n const server_id = await resolveServerId(server, execCtx);\n await fn(server_id, execCtx);\n }, ctx.formatter);\n}\n\ninterface ConfigTarget {\n version: string;\n type: string;\n user?: string;\n}\n\n/**\n * Read --version, --type and --user for the config commands.\n * Exits with a validation error when --version is missing, --type is not cli, fpm or pool,\n * or --user is given for a type other than pool.\n */\nfunction requireConfigTarget(ctx: CommandContext, usage: string): ConfigTarget {\n const { version, type, user } = ctx.options;\n\n if (typeof version !== \"string\" || !version) {\n exitWithValidationError(\"version\", usage, ctx.formatter);\n }\n\n if (typeof type !== \"string\" || !(PHP_CONFIG_TYPES as readonly string[]).includes(type)) {\n const message = typeof type === \"string\" ? `Invalid --type \"${type}\"` : \"type is required\";\n exitWithError(\n new ValidationError(message, \"type\", [\n `Valid types: ${PHP_CONFIG_TYPES.join(\", \")}`,\n `Usage: ${usage}`,\n ]),\n ctx.formatter,\n );\n }\n\n if (typeof user === \"string\" && user && type !== \"pool\") {\n exitWithError(\n new ValidationError(`--user applies to --type pool only, not \"${type}\"`, \"user\", [\n `Usage: ${usage}`,\n ]),\n ctx.formatter,\n );\n }\n\n return { version, type, user: typeof user === \"string\" ? user : undefined };\n}\n\n/**\n * Parse a whole number argument, or exit with a validation error.\n */\nfunction requireWholeNumber(\n value: string | undefined,\n field: string,\n usage: string,\n ctx: CommandContext,\n): number {\n if (value === undefined || !/^\\d+$/.test(value)) {\n const message =\n value === undefined ? `${field} is required` : `${field} must be a whole number: \"${value}\"`;\n exitWithError(new ValidationError(message, field, [`Usage: ${usage}`]), ctx.formatter);\n }\n return Number(value);\n}\n\n/**\n * List the PHP versions installed on a server.\n */\nexport async function phpList(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php list --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const result = await listPhpVersions({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"version\", \"binary_name\", \"status\"],\n \"No PHP versions installed.\",\n (v) =>\n `${String(v.id).padEnd(8)} ${v.version.padEnd(6)} ${v.binary_name.padEnd(10)} ${v.status}`,\n );\n });\n}\n\n/**\n * Print a PHP configuration file (cli, fpm or pool).\n */\nexport async function phpConfig(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, CONFIG_USAGE);\n const target = requireConfigTarget(ctx, CONFIG_USAGE);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const result = await getPhpConfig({ server_id, ...target }, execCtx);\n if (ctx.formatter.isJson()) {\n console.log(JSON.stringify({ content: result.data }));\n } else {\n printContent(result.data);\n }\n });\n}\n\n/**\n * Replace a PHP configuration file, or compare it with Forge when --check is set.\n */\nexport async function phpUpdateConfig(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, UPDATE_CONFIG_USAGE);\n const target = requireConfigTarget(ctx, UPDATE_CONFIG_USAGE);\n const label = `PHP ${target.type} configuration`;\n const content = readContentOption(ctx.options, {\n label,\n usage: UPDATE_CONFIG_USAGE,\n formatter: ctx.formatter,\n });\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n if (ctx.options.check) {\n const remote = await getPhpConfig({ server_id, ...target }, execCtx);\n reportTextDrift(label, remote.data, content, ctx.formatter);\n return;\n }\n\n await updatePhpConfig({ server_id, ...target, content }, execCtx);\n ctx.formatter.success(`${label} updated.`);\n });\n}\n\n/**\n * Print the PHP max upload size, in megabytes.\n */\nexport async function phpMaxUploadSize(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php max-upload-size --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpMaxUploadSize({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ max_upload_size: data });\n } else {\n console.log(`${data} MB`);\n }\n });\n}\n\n/**\n * Set the PHP max upload size, in megabytes.\n */\nexport async function phpSetMaxUploadSize(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge php set-max-upload-size <megabytes> --server <server_id>\";\n const size = requireWholeNumber(args[0], \"megabytes\", usage, ctx);\n const server = requireServer(ctx, usage);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await updatePhpMaxUploadSize({ server_id, size }, execCtx);\n ctx.formatter.success(`PHP max upload size set to ${size} MB.`);\n });\n}\n\n/**\n * Print the PHP max execution time, in seconds.\n */\nexport async function phpMaxExecutionTime(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php max-execution-time --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpMaxExecutionTime({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ max_execution_time: data });\n } else {\n console.log(`${data} seconds`);\n }\n });\n}\n\n/**\n * Set the PHP max execution time, in seconds.\n */\nexport async function phpSetMaxExecutionTime(args: string[], ctx: CommandContext): Promise<void> {\n const usage = \"forge php set-max-execution-time <seconds> --server <server_id>\";\n const seconds = requireWholeNumber(args[0], \"seconds\", usage, ctx);\n const server = requireServer(ctx, usage);\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await updatePhpMaxExecutionTime({ server_id, seconds }, execCtx);\n ctx.formatter.success(`PHP max execution time set to ${seconds} seconds.`);\n });\n}\n\n/**\n * Print whether OPcache is enabled.\n */\nexport async function phpOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n const { data } = await getPhpOpcache({ server_id }, execCtx);\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ opcache_enabled: data });\n } else {\n console.log(`OPcache is ${data ? \"enabled\" : \"disabled\"}.`);\n }\n });\n}\n\n/**\n * Enable OPcache.\n */\nexport async function phpEnableOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php enable-opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await enablePhpOpcache({ server_id }, execCtx);\n ctx.formatter.success(\"OPcache enabled.\");\n });\n}\n\n/**\n * Disable OPcache.\n */\nexport async function phpDisableOpcache(ctx: CommandContext): Promise<void> {\n const server = requireServer(ctx, \"forge php disable-opcache --server <server_id>\");\n\n await withServer(ctx, server, async (server_id, execCtx) => {\n await disablePhpOpcache({ server_id }, execCtx);\n ctx.formatter.success(\"OPcache disabled.\");\n });\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n phpConfig,\n phpDisableOpcache,\n phpEnableOpcache,\n phpList,\n phpMaxExecutionTime,\n phpMaxUploadSize,\n phpOpcache,\n phpSetMaxExecutionTime,\n phpSetMaxUploadSize,\n phpUpdateConfig,\n} from \"./handlers.ts\";\n\nexport const handlePhpCommand = createCommandRouter({\n resource: \"php\",\n handlers: {\n list: phpList,\n ls: phpList,\n config: phpConfig,\n \"update-config\": phpUpdateConfig,\n \"max-upload-size\": phpMaxUploadSize,\n \"set-max-upload-size\": [phpSetMaxUploadSize, \"args\"],\n \"max-execution-time\": phpMaxExecutionTime,\n \"set-max-execution-time\": [phpSetMaxExecutionTime, \"args\"],\n opcache: phpOpcache,\n \"enable-opcache\": phpEnableOpcache,\n \"disable-opcache\": phpDisableOpcache,\n },\n writeSubcommands: [\n \"update-config\",\n \"set-max-upload-size\",\n \"set-max-execution-time\",\n \"enable-opcache\",\n \"disable-opcache\",\n ],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showPhpHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge php list\")} - List the PHP versions installed on a server\n\n${colors.bold(\"USAGE:\")}\n forge php list --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge php list --server 123\n`);\n } else if (subcommand === \"config\") {\n console.log(`\n${colors.bold(\"forge php config\")} - Print a PHP configuration file\n\n${colors.bold(\"USAGE:\")}\n forge php config --server <server_id> --version <version> --type <cli|fpm|pool>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID, or a version such as 8.3, php83 or php8.3 (required)\n --type <type> cli (CLI php.ini), fpm (FPM php.ini) or pool (FPM pool) (required)\n --user <name> FPM pool user (pool only)\n -f, --format <fmt> Output format: json ({ content }), human\n\n${colors.bold(\"EXAMPLES:\")}\n forge php config --server 123 --version 8.3 --type fpm\n forge php config --server 123 --version 8.3 --type pool > www.conf\n`);\n } else if (subcommand === \"update-config\") {\n console.log(`\n${colors.bold(\"forge php update-config\")} - Replace a PHP configuration file\n\n${colors.bold(\"USAGE:\")}\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --file <path>\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --file <path> --check\n forge php update-config --server <server_id> --version <version> --type <cli|fpm|pool> --content <config>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID, or a version such as 8.3, php83 or php8.3 (required)\n --type <type> cli (CLI php.ini), fpm (FPM php.ini) or pool (FPM pool) (required)\n --user <name> FPM pool user (pool only)\n --file <path> Read the content from a file (use - for stdin)\n --content <str> New configuration file content\n --check Compare with the content on Forge and do not write.\n Exit 0 when in sync, 1 with a line diff (- remote, + local).\n -f, --format <fmt> Output format: json ({ inSync, diff? } with --check), human\n\n Give exactly one of --file or --content. Empty content is rejected.\n The content replaces the whole file.\n\n${colors.bold(\"EXAMPLES:\")}\n forge php update-config --server 123 --version 8.3 --type fpm --file php.ini\n cat php.ini | forge php update-config --server 123 --version 8.3 --type cli --file -\n forge php update-config --server 123 --version 8.3 --type fpm --file php.ini --check\n`);\n } else if (\n subcommand === \"max-upload-size\" ||\n subcommand === \"set-max-upload-size\" ||\n subcommand === \"max-execution-time\" ||\n subcommand === \"set-max-execution-time\"\n ) {\n console.log(`\n${colors.bold(\"forge php max-upload-size / max-execution-time\")} - Get or set PHP limits\n\n${colors.bold(\"USAGE:\")}\n forge php max-upload-size --server <server_id>\n forge php set-max-upload-size <megabytes> --server <server_id>\n forge php max-execution-time --server <server_id>\n forge php set-max-execution-time <seconds> --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"EXAMPLES:\")}\n forge php set-max-upload-size 128 --server 123\n forge php set-max-execution-time 120 --server 123\n`);\n } else if (\n subcommand === \"opcache\" ||\n subcommand === \"enable-opcache\" ||\n subcommand === \"disable-opcache\"\n ) {\n console.log(`\n${colors.bold(\"forge php opcache\")} - Get, enable or disable OPcache\n\n${colors.bold(\"USAGE:\")}\n forge php opcache --server <server_id>\n forge php enable-opcache --server <server_id>\n forge php disable-opcache --server <server_id>\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n -f, --format <fmt> Output format: json, human\n`);\n } else {\n console.log(`\n${colors.bold(\"forge php\")} - Manage PHP on a server\n\n${colors.bold(\"USAGE:\")}\n forge php <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List installed PHP versions\n config Print a configuration file (--version --type)\n update-config Replace a configuration file (--version --type --file|--content) [--check]\n max-upload-size Print the max upload size (MB)\n set-max-upload-size <mb> Set the max upload size (MB)\n max-execution-time Print the max execution time (seconds)\n set-max-execution-time <sec> Set the max execution time (seconds)\n opcache Print the OPcache status\n enable-opcache Enable OPcache\n disable-opcache Disable OPcache\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required)\n --version <ver> PHP version ID or version (8.3, php83) (for config commands)\n --type <type> cli, fpm or pool (for config commands)\n --user <name> FPM pool user (for --type pool)\n --file <path> Content file, - for stdin (for update-config)\n --content <str> New content (for update-config)\n --check Compare with Forge, do not write (for update-config)\n\nRun ${colors.cyan(\"forge php <subcommand> --help\")} for details.\n`);\n }\n}\n","import { listRecipes, getRecipe, runRecipe, updateRecipe } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\n\nexport async function recipesList(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listRecipes({}, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"user\", \"created_at\"],\n \"No recipes found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(40)} ${r.user.padEnd(16)} ${r.created_at}`,\n );\n }, ctx.formatter);\n}\n\nexport async function recipesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge recipes get <recipe_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getRecipe({ id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"user\", \"created_at\", \"script\"]);\n }, ctx.formatter);\n}\n\nexport async function recipesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\n \"id\",\n \"forge recipes update <recipe_id> [--name ...] [--user ...] [--script ...]\",\n ctx.formatter,\n );\n }\n\n const name = ctx.options.name as string | undefined;\n const user = ctx.options.user as string | undefined;\n const script = ctx.options.script as string | undefined;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await updateRecipe({ id, name, user, script }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"user\", \"created_at\", \"script\"]);\n }, ctx.formatter);\n}\n\nexport async function recipesRun(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const serversRaw = String(ctx.options.servers ?? \"\");\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge recipes run <recipe_id> --servers <ids>\", ctx.formatter);\n }\n\n if (!serversRaw) {\n exitWithValidationError(\n \"servers\",\n \"forge recipes run <recipe_id> --servers <server_id1,server_id2,...>\",\n ctx.formatter,\n );\n }\n\n const servers = serversRaw\n .split(\",\")\n .map((s) => Number(s.trim()))\n .filter((n) => !isNaN(n));\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n await runRecipe({ id, servers }, execCtx);\n ctx.formatter.success(`Recipe ${id} dispatched to ${servers.length} server(s).`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { recipesList, recipesGet, recipesRun, recipesUpdate } from \"./handlers.ts\";\n\nexport const handleRecipesCommand = createCommandRouter({\n resource: \"recipes\",\n handlers: {\n list: recipesList,\n ls: recipesList,\n get: [recipesGet, \"args\"],\n update: [recipesUpdate, \"args\"],\n run: [recipesRun, \"args\"],\n },\n writeSubcommands: [\"update\", \"run\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showRecipesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge recipes list\")} - List all recipes\n\n${colors.bold(\"USAGE:\")}\n forge recipes list [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge recipes get\")} - Get recipe details\n\n${colors.bold(\"USAGE:\")}\n forge recipes get <recipe_id>\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge recipes update\")} - Update a recipe\n\n${colors.bold(\"USAGE:\")}\n forge recipes update <recipe_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> New recipe name\n --user <user> New recipe user\n --script <script> New recipe script\n`);\n } else if (subcommand === \"run\") {\n console.log(`\n${colors.bold(\"forge recipes run\")} - Run a recipe on servers\n\n${colors.bold(\"USAGE:\")}\n forge recipes run <recipe_id> --servers <server_id1,server_id2,...>\n\n${colors.bold(\"OPTIONS:\")}\n --servers <ids> Comma-separated server IDs to run recipe on\n`);\n } else {\n console.log(`\n${colors.bold(\"forge recipes\")} - Manage recipes\n\n${colors.bold(\"USAGE:\")}\n forge recipes <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List all recipes\n get <id> Get recipe details\n update <id> Update a recipe\n run <id> Run a recipe on servers\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge recipes <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createRedirectRule,\n deleteRedirectRule,\n getRedirectRule,\n listRedirectRules,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function redirectRulesList(ctx: CommandContext): Promise<void> {\n const usage = \"forge redirect-rules list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listRedirectRules({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"from\", \"to\", \"type\"],\n \"No redirect rules found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.from.padEnd(30)} ${r.to.padEnd(30)} ${r.type}`,\n );\n }, ctx.formatter);\n}\n\nexport async function redirectRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge redirect-rules get <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getRedirectRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"from\", \"to\", \"type\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function redirectRulesCreate(ctx: CommandContext): Promise<void> {\n const usage =\n \"forge redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const from = String(ctx.options.from ?? \"\");\n const to = String(ctx.options.to ?? \"\");\n const type = String(ctx.options.type ?? \"redirect\");\n\n if (!from) {\n exitWithValidationError(\"from\", usage, ctx.formatter);\n }\n\n if (!to) {\n exitWithValidationError(\"to\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await createRedirectRule({ server_id, site_id, from, to, type }, execCtx);\n ctx.formatter.success(\"Redirect rule created.\");\n }, ctx.formatter);\n}\n\nexport async function redirectRulesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge redirect-rules delete <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await deleteRedirectRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.success(`Redirect rule ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n redirectRulesCreate,\n redirectRulesDelete,\n redirectRulesGet,\n redirectRulesList,\n} from \"./handlers.ts\";\n\nexport const handleRedirectRulesCommand = createCommandRouter({\n resource: \"redirect-rules\",\n handlers: {\n list: redirectRulesList,\n ls: redirectRulesList,\n get: [redirectRulesGet, \"args\"],\n create: redirectRulesCreate,\n delete: [redirectRulesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showRedirectRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge redirect-rules list\")} - List redirect rules for a site\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge redirect-rules get\")} - Get redirect rule details\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules get <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge redirect-rules create\")} - Create a new redirect rule\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --from <path> Source path to redirect from (required)\n --to <path> Destination path to redirect to (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge redirect-rules delete\")} - Delete a redirect rule\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules delete <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge redirect-rules\")} - Manage site redirect rules\n\n${colors.bold(\"USAGE:\")}\n forge redirect-rules <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List redirect rules\n get <id> Get redirect rule details\n create Create a new redirect rule\n delete <id> Delete a redirect rule\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge redirect-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createScheduledJob,\n deleteScheduledJob,\n getScheduledJob,\n listScheduledJobs,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function scheduledJobsList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs list --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await listScheduledJobs({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"command\", \"frequency\", \"status\"],\n \"No scheduled jobs found.\",\n (j) =>\n `${String(j.id).padEnd(8)} ${j.command.padEnd(50)} ${j.frequency.padEnd(12)} ${j.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"job_id\",\n \"forge scheduled-jobs get <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs get <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await getScheduledJob({ server_id, id, site_id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"frequency\",\n \"cron\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsCreate(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n const command = String(ctx.options.command ?? \"\");\n const user = String(ctx.options.user ?? \"forge\");\n const frequency = String(ctx.options.frequency ?? \"custom\");\n const cron = ctx.options.cron ? String(ctx.options.cron) : undefined;\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs create --server <server_id> --command <command> --user <user> --frequency <frequency>\",\n ctx.formatter,\n );\n }\n\n if (!command) {\n exitWithValidationError(\n \"command\",\n \"forge scheduled-jobs create --server <server_id> --command <command> --user <user> --frequency <frequency>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n const result = await createScheduledJob(\n { server_id, site_id, command, user, frequency, cron },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"command\",\n \"user\",\n \"frequency\",\n \"cron\",\n \"status\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function scheduledJobsDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n const site = ctx.options.site ? String(ctx.options.site) : undefined;\n\n if (!id) {\n exitWithValidationError(\n \"job_id\",\n \"forge scheduled-jobs delete <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge scheduled-jobs delete <job_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = site ? await resolveSiteId(site, server_id, execCtx) : undefined;\n await deleteScheduledJob({ server_id, id, site_id }, execCtx);\n ctx.formatter.success(`Scheduled job ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n scheduledJobsCreate,\n scheduledJobsDelete,\n scheduledJobsGet,\n scheduledJobsList,\n} from \"./handlers.ts\";\n\nexport const handleScheduledJobsCommand = createCommandRouter({\n resource: \"scheduled-jobs\",\n handlers: {\n list: scheduledJobsList,\n ls: scheduledJobsList,\n get: [scheduledJobsGet, \"args\"],\n create: scheduledJobsCreate,\n delete: [scheduledJobsDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showScheduledJobsHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs list\")} - List scheduled jobs on a server\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs get\")} - Get scheduled job details\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs get <job_id> --server <server_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs create\")} - Create a new scheduled job\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs create --server <server_id> --command <command> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --command <cmd> Command to run (required)\n --site <id> Site ID, to create the job on a site\n --user <user> User that runs the command (default: forge)\n --frequency <freq> minutely, hourly, nightly, weekly, monthly, reboot\n or custom (default: custom)\n --cron <expr> Cron expression, used when --frequency is custom\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge scheduled-jobs create --server web-1 --command \"php artisan schedule:run\" --frequency minutely\n forge scheduled-jobs create --server web-1 --command \"php artisan backup:run\" --cron \"0 3 * * *\"\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge scheduled-jobs delete\")} - Delete a scheduled job\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs delete <job_id> --server <server_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge scheduled-jobs\")} - Manage scheduled jobs (cron)\n\n${colors.bold(\"USAGE:\")}\n forge scheduled-jobs <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List scheduled jobs\n get <id> Get scheduled job details\n create Create a new scheduled job\n delete <id> Delete a scheduled job\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge scheduled-jobs <subcommand> --help\")} for details.\n`);\n }\n}\n","import {\n createSecurityRule,\n deleteSecurityRule,\n getSecurityRule,\n listSecurityRules,\n updateSecurityRule,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nfunction requireServerAndSiteRaw(\n ctx: CommandContext,\n usage: string,\n): { server: string; site: string } {\n const server = String(ctx.options.server ?? \"\");\n const site = String(ctx.options.site ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", usage, ctx.formatter);\n }\n if (!site) {\n exitWithValidationError(\"site_id\", usage, ctx.formatter);\n }\n\n return { server, site };\n}\n\nexport async function securityRulesList(ctx: CommandContext): Promise<void> {\n const usage = \"forge security-rules list --server <server_id> --site <site_id>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await listSecurityRules({ server_id, site_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"path\"],\n \"No security rules found.\",\n (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(30)} ${r.path ?? \"—\"}`,\n );\n }, ctx.formatter);\n}\n\nexport async function securityRulesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge security-rules get <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await getSecurityRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesCreate(ctx: CommandContext): Promise<void> {\n const usage = \"forge security-rules create --server <server_id> --site <site_id> --name <name>\";\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const name = String(ctx.options.name ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await createSecurityRule({ server_id, site_id, name, credentials: [] }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage =\n \"forge security-rules update <rule_id> --server <server_id> --site <site_id> --name <name>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n const name = String(ctx.options.name ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n const result = await updateSecurityRule(\n { server_id, site_id, id, name, credentials: [] },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"path\", \"created_at\"]);\n }, ctx.formatter);\n}\n\nexport async function securityRulesDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const usage = \"forge security-rules delete <rule_id> --server <server_id> --site <site_id>\";\n\n if (!id) {\n exitWithValidationError(\"rule_id\", usage, ctx.formatter);\n }\n\n const { server, site } = requireServerAndSiteRaw(ctx, usage);\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(site, server_id, execCtx);\n await deleteSecurityRule({ server_id, site_id, id }, execCtx);\n ctx.formatter.success(`Security rule ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n securityRulesCreate,\n securityRulesDelete,\n securityRulesGet,\n securityRulesList,\n securityRulesUpdate,\n} from \"./handlers.ts\";\n\nexport const handleSecurityRulesCommand = createCommandRouter({\n resource: \"security-rules\",\n handlers: {\n list: securityRulesList,\n ls: securityRulesList,\n get: [securityRulesGet, \"args\"],\n create: securityRulesCreate,\n update: [securityRulesUpdate, \"args\"],\n delete: [securityRulesDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"update\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSecurityRulesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge security-rules list\")} - List security rules for a site\n\n${colors.bold(\"USAGE:\")}\n forge security-rules list --server <server_id> --site <site_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge security-rules get\")} - Get security rule details\n\n${colors.bold(\"USAGE:\")}\n forge security-rules get <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge security-rules create\")} - Create a new security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules create --server <server_id> --site <site_id> --name <name> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --name <name> Security rule name (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"update\") {\n console.log(`\n${colors.bold(\"forge security-rules update\")} - Update a security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules update <rule_id> --server <server_id> --site <site_id> --name <name> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n --name <name> Security rule name (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge security-rules delete\")} - Delete a security rule\n\n${colors.bold(\"USAGE:\")}\n forge security-rules delete <rule_id> --server <server_id> --site <site_id> [options]\n`);\n } else {\n console.log(`\n${colors.bold(\"forge security-rules\")} - Manage site security rules\n\n${colors.bold(\"USAGE:\")}\n forge security-rules <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List security rules\n get <id> Get security rule details\n create Create a new security rule\n update <id> Update a security rule\n delete <id> Delete a security rule\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n --site <id> Site ID (required)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge security-rules <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * CLI handlers for servers commands.\n * Delegates all HTTP logic to forge-core executors.\n */\n\nimport type { CreateServerOptions } from \"@studiometa/forge-core\";\nimport { listServers, getServer, createServer, rebootServer } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ApiError } from \"../../errors.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\n/**\n * List all servers.\n */\nexport async function serversList(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listServers({}, execCtx);\n\n const format = String(ctx.options.format ?? ctx.options.f ?? \"human\");\n\n if (format === \"table\" || format === \"json\") {\n ctx.formatter.output(result.data);\n } else {\n if (result.data.length === 0) {\n ctx.formatter.info(\"No servers found.\");\n return;\n }\n for (const server of result.data) {\n console.log(\n `${String(server.id).padEnd(8)} ${server.name.padEnd(30)} ${(server.ip_address ?? \"—\").padEnd(16)} ${server.is_ready ? \"ready\" : \"provisioning\"}`,\n );\n }\n }\n }, ctx.formatter);\n}\n\n/**\n * Get a single server by ID or name.\n */\nexport async function serversGet(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers get <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getServer({ server_id }, execCtx);\n ctx.formatter.output(result.data);\n }, ctx.formatter);\n}\n\n/**\n * Print the public key of the `forge` user of a server (`~/.ssh/id_rsa.pub`), the key that\n * Forge uses to clone repositories: add it to the git host before you create a site.\n */\nexport async function serversPublicKey(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers public-key <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getServer({ server_id }, execCtx);\n const key = result.data.local_public_key?.trim();\n if (!key) {\n throw new ApiError(`Server ${result.data.name} has no public key yet`, 404, [\n \"Wait until Forge provisions the server\",\n ]);\n }\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ public_key: key });\n } else {\n console.log(key);\n }\n }, ctx.formatter);\n}\n\nconst CREATE_USAGE = \"forge servers create --name <name> --ip-address <ip> [options]\";\n\n/**\n * Create a server. Defaults to a Custom VPS app server on Ubuntu 26.04.\n */\nexport async function serversCreate(ctx: CommandContext): Promise<void> {\n const name = String(ctx.options.name ?? \"\");\n const provider = String(ctx.options.provider ?? \"custom\");\n const ip_address = String(ctx.options[\"ip-address\"] ?? \"\");\n\n if (!name) {\n exitWithValidationError(\"name\", CREATE_USAGE, ctx.formatter);\n }\n\n if (provider === \"custom\" && !ip_address) {\n exitWithValidationError(\"ip-address\", CREATE_USAGE, ctx.formatter);\n }\n\n if (provider !== \"custom\") {\n for (const option of [\"credential-id\", \"region\", \"size\"]) {\n if (!ctx.options[option]) exitWithValidationError(option, CREATE_USAGE, ctx.formatter);\n }\n }\n\n const options: CreateServerOptions = {\n name,\n provider,\n type: String(ctx.options.type ?? \"app\"),\n ubuntu_version: String(ctx.options[\"ubuntu-version\"] ?? \"26.04\"),\n php_version: String(ctx.options[\"php-version\"] ?? \"php84\"),\n };\n\n if (ctx.options.database) options.database_type = String(ctx.options.database);\n if (ctx.options[\"credential-id\"]) options.credential_id = String(ctx.options[\"credential-id\"]);\n\n const tags = ctx.options.tag;\n if (tags) options.tags = (Array.isArray(tags) ? tags : [tags]).map(String);\n\n if (provider === \"custom\") {\n options.custom = { ip_address, ssh_port: String(ctx.options[\"ssh-port\"] ?? \"22\") };\n if (ctx.options[\"private-ip\"])\n options.custom.private_ip_address = String(ctx.options[\"private-ip\"]);\n } else {\n (options as Record<string, unknown>)[provider] = {\n region_id: String(ctx.options.region),\n size_id: String(ctx.options.size),\n };\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await createServer(options, execCtx);\n\n const format = String(ctx.options.format ?? ctx.options.f ?? \"human\");\n\n if (format === \"table\" || format === \"json\") {\n ctx.formatter.output(result.data);\n return;\n }\n\n ctx.formatter.success(`Server ${result.data.name} created (ID ${result.data.id}).`);\n if (provider === \"custom\") {\n ctx.formatter.info(\n `Run the provisioning command from the Forge server page as root on ${ip_address}.`,\n );\n }\n }, ctx.formatter);\n}\n\n/**\n * Reboot a server by ID or name.\n */\nexport async function serversReboot(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge servers reboot <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n await rebootServer({ server_id }, execCtx);\n ctx.formatter.success(`Server ${server_id} reboot initiated.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n serversList,\n serversGet,\n serversCreate,\n serversReboot,\n serversPublicKey,\n} from \"./handlers.ts\";\n\nexport const handleServersCommand = createCommandRouter({\n resource: \"servers\",\n handlers: {\n list: serversList,\n ls: serversList,\n get: [serversGet, \"args\"],\n \"public-key\": [serversPublicKey, \"args\"],\n create: serversCreate,\n reboot: [serversReboot, \"args\"],\n },\n writeSubcommands: [\"create\", \"reboot\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showServersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge servers list\")} - List all servers\n\n${colors.bold(\"USAGE:\")}\n forge servers list [options]\n\n${colors.bold(\"OPTIONS:\")}\n --token <token> Forge API token\n -f, --format <fmt> Output format: json, human, table (default: human)\n --no-color Disable colored output\n -h, --help Show this help\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers list\n forge servers list --format json\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge servers get\")} - Get server details\n\n${colors.bold(\"USAGE:\")}\n forge servers get <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID (required)\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers get 123\n forge servers get 123 --format json\n`);\n } else if (subcommand === \"public-key\") {\n console.log(`\n${colors.bold(\"forge servers public-key\")} - Print the public key of the forge user\n\n${colors.bold(\"USAGE:\")}\n forge servers public-key <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID or name (required)\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json ({ \"public_key\": \"...\" }), human (the key only)\n\nForge clones repositories as the forge user, with this key (~/.ssh/id_rsa.pub).\nAdd it to the git host (e.g. as a deploy key) before you create a site with a\nrepository. It is not the key of GET /servers/{id}/key: that key lets Forge\nconnect to the server.\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers public-key 123\n forge servers public-key 123 > server.pub\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge servers create\")} - Create a server\n\n${colors.bold(\"USAGE:\")}\n forge servers create --name <name> --ip-address <ip> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> Server name (required, 30 characters max)\n --provider <provider> Server provider (default: custom)\n --ip-address <ip> Public IP address (required for custom)\n --private-ip <ip> Private IP address (custom only)\n --ssh-port <port> SSH port (custom only, default: 22)\n --region <id> Region ID (cloud providers)\n --size <id> Size ID (cloud providers)\n --credential-id <id> Server provider credential ID (cloud providers)\n --type <type> Server type: app, web, loadbalancer, database... (default: app)\n --ubuntu-version <ver> Ubuntu version (default: 26.04)\n --php-version <ver> PHP version (default: php84)\n --database <type> Database type, e.g. mariadb1011\n --tag <tag> Tag, repeatable\n -f, --format <fmt> Output format: json, human, table\n\nA Custom VPS must run a fresh Ubuntu with root SSH access. After the\ncommand, run the provisioning command from the Forge server page as root.\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers create --name web-1 --ip-address 203.0.113.10 --php-version php84 --database mariadb1011\n forge servers create --name worker-1 --provider hetzner --credential-id 42 --region fsn1 --size cpx31\n`);\n } else if (subcommand === \"reboot\") {\n console.log(`\n${colors.bold(\"forge servers reboot\")} - Reboot a server\n\n${colors.bold(\"USAGE:\")}\n forge servers reboot <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server_id> Server ID (required)\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers reboot 123\n`);\n } else {\n console.log(`\n${colors.bold(\"forge servers\")} - Manage servers\n\n${colors.bold(\"USAGE:\")}\n forge servers <subcommand> [options]\n\n${colors.bold(\"ALIASES:\")}\n forge s\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List all servers\n get <id> Get server details\n public-key <id> Print the public key of the forge user\n create Create a server (requires --name, and --ip-address for custom)\n reboot <id> Reboot a server\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n -h, --help Show help for a subcommand\n\n${colors.bold(\"EXAMPLES:\")}\n forge servers list\n forge servers get 123\n\nRun ${colors.cyan(\"forge servers <subcommand> --help\")} for subcommand details.\n`);\n }\n}\n","import {\n getServer,\n listServices,\n restartService,\n RESTARTABLE_SERVICES,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { ValidationError } from \"../../errors.ts\";\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\n/**\n * List services on a server with a derived availability flag.\n */\nexport async function servicesList(args: string[], ctx: CommandContext): Promise<void> {\n const [server] = args;\n\n if (!server) {\n exitWithValidationError(\"server\", \"forge services list <server>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listServices({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"service\", \"available\", \"detail\"],\n \"No services.\",\n (row) => {\n const status = row.available ? \"yes\" : \"no\";\n const detail = row.detail ? ` (${row.detail})` : \"\";\n return `${row.service.padEnd(12)}${status}${detail}`;\n },\n );\n }, ctx.formatter);\n}\n\n/**\n * Restart a service on a server.\n */\nexport async function servicesRestart(args: string[], ctx: CommandContext): Promise<void> {\n const [server, service] = args;\n\n if (!server) {\n exitWithValidationError(\"server\", \"forge services restart <server> <service>\", ctx.formatter);\n }\n\n if (!service) {\n exitWithValidationError(\"service\", \"forge services restart <server> <service>\", ctx.formatter);\n }\n\n const version =\n typeof ctx.options.version === \"string\" && ctx.options.version\n ? ctx.options.version\n : undefined;\n\n await runCommand(async () => {\n if (!(RESTARTABLE_SERVICES as readonly string[]).includes(service)) {\n throw new ValidationError(`Invalid service \"${service}\"`, \"service\", [\n `Valid services: ${RESTARTABLE_SERVICES.join(\", \")}`,\n ]);\n }\n\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n\n let resolvedVersion = version;\n if (service === \"php\" && !resolvedVersion) {\n const { data: srv } = await getServer({ server_id }, execCtx);\n if (!srv.php_version) {\n throw new ValidationError(\"The php service requires a version\", \"version\", [\n \"Pass --version <php_version> (e.g. --version php83)\",\n ]);\n }\n resolvedVersion = srv.php_version;\n }\n\n await restartService({ server_id, service, version: resolvedVersion }, execCtx);\n ctx.formatter.success(`${service} restart initiated on server ${server_id}.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { servicesList, servicesRestart } from \"./handlers.ts\";\n\nexport const handleServicesCommand = createCommandRouter({\n resource: \"services\",\n handlers: {\n list: [servicesList, \"args\"],\n ls: [servicesList, \"args\"],\n restart: [servicesRestart, \"args\"],\n },\n writeSubcommands: [\"restart\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showServicesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge services list\")} - List services on a server\n\n${colors.bold(\"USAGE:\")}\n forge services list <server> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n\n${colors.bold(\"NOTES:\")}\n Availability is a heuristic derived from the server object — the API has\n no services listing endpoint.\n\n${colors.bold(\"EXAMPLES:\")}\n forge services list 123\n forge services list my-server --format json\n`);\n } else if (subcommand === \"restart\") {\n console.log(`\n${colors.bold(\"forge services restart\")} - Restart a service on a server\n\n${colors.bold(\"USAGE:\")}\n forge services restart <server> <service> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n <service> One of: nginx, php, mysql, postgres, redis, supervisor\n\n${colors.bold(\"OPTIONS:\")}\n --version <ver> PHP version (e.g. php83) — required for the php service\n (defaults to the server's php_version when omitted)\n\n${colors.bold(\"EXAMPLES:\")}\n forge services restart 123 nginx\n forge services restart 123 php --version php83\n`);\n } else {\n console.log(`\n${colors.bold(\"forge services\")} - List and restart server services\n\n${colors.bold(\"USAGE:\")}\n forge services <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List services on a server\n restart <service> Restart a service (nginx, php, mysql, postgres, redis, supervisor)\n\n${colors.bold(\"OPTIONS:\")}\n --version <ver> PHP version (for the php service)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge services <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Path and command helpers of `forge sites apply`: normalize commands so that\n * equivalent spellings compare equal, and find which site owns a daemon or a scheduled job.\n *\n * Ownership is strict on purpose: `apply` deletes the workers and scheduled jobs of a site\n * that the site file does not declare, and a server often hosts many sites.\n */\n\nimport { posix } from \"node:path\";\n\n/** A site, as far as ownership is concerned. */\nexport interface SiteRoots {\n id: number;\n /** Absolute paths that belong to the site, e.g. `/home/forge/example.com`. */\n roots: string[];\n}\n\n/**\n * Normalize an absolute path: resolve `.` and `..`, collapse repeated slashes\n * and drop the trailing slash.\n */\nexport function normalizePath(path: string): string {\n const normalized = posix.normalize(path.trim());\n return normalized.length > 1 && normalized.endsWith(\"/\") ? normalized.slice(0, -1) : normalized;\n}\n\n/**\n * Whether `path` is `root` or inside it, compared on whole path segments:\n * `/home/forge/a.com` contains `/home/forge/a.com/current` but not `/home/forge/a.com-staging`.\n */\nexport function isPathInside(path: string, root: string): boolean {\n const child = normalizePath(path);\n const parent = normalizePath(root);\n if (parent === \"/\") return child.startsWith(\"/\");\n return child === parent || child.startsWith(`${parent}/`);\n}\n\n/**\n * Resolve `path` against `base` when it is relative.\n */\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith(\"/\") ? path : posix.join(base, path));\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`);\n}\n\n/**\n * Whether a shell command uses `root` as a whole path: `root` must start the command or follow\n * a space, a quote, `=` or a shell operator, and must end the command or be followed by `/`,\n * a space, a quote or a shell operator. `/home/forge/a.com` is not found in\n * `/home/forge/a.com-staging/artisan`, `/home/forge/a.com.old` or `/home/forge/*`.\n */\nexport function commandUsesPath(command: string, root: string): boolean {\n const path = normalizePath(root);\n if (path === \"/\") return false;\n const pattern = new RegExp(\n String.raw`(?:^|[\\s'\"=(;&|<>:])${escapeRegExp(path)}(?=$|[/\\s'\";&|)<>])`,\n );\n return pattern.test(command);\n}\n\n/**\n * Split a shell command into words, with the quoting rules of a POSIX shell:\n * single quotes keep everything, double quotes and a backslash escape one character.\n */\nexport function splitCommand(command: string): string[] {\n const words: string[] = [];\n let word = \"\";\n let inWord = false;\n let quote: \"'\" | '\"' | null = null;\n\n for (let index = 0; index < command.length; index++) {\n const char = command[index];\n if (quote === \"'\") {\n if (char === \"'\") quote = null;\n else word += char;\n } else if (quote === '\"') {\n if (char === '\"') quote = null;\n else if (\n char === \"\\\\\" &&\n index + 1 < command.length &&\n '\"\\\\$`'.includes(command[index + 1])\n ) {\n word += command[++index];\n } else word += char;\n } else if (char === \"'\" || char === '\"') {\n quote = char;\n inWord = true;\n } else if (char === \"\\\\\" && index + 1 < command.length) {\n word += command[++index];\n inWord = true;\n } else if (/\\s/.test(char)) {\n if (inWord) words.push(word);\n word = \"\";\n inWord = false;\n } else {\n word += char;\n inWord = true;\n }\n }\n\n if (inWord) words.push(word);\n return words;\n}\n\n/**\n * Quote a word for a POSIX shell when it needs quotes.\n */\nexport function quoteWord(word: string): string {\n if (word !== \"\" && /^[\\w@%+=:,./-]+$/.test(word)) return word;\n return `'${word.replaceAll(\"'\", String.raw`'\\''`)}'`;\n}\n\n/**\n * Write a command in one canonical form, so that equivalent spellings compare equal:\n * quotes only where needed, single spaces, and a relative `artisan` (or `./artisan`)\n * replaced by its absolute path in `directory`.\n *\n * `php artisan queue:work 'database' --queue=\"default\"` in `/home/forge/example.com/`\n * gives `php /home/forge/example.com/artisan queue:work database --queue=default`.\n */\nexport function canonicalCommand(command: string, directory: string | null): string {\n return splitCommand(command)\n .map((word) => {\n if (directory && (word === \"artisan\" || word === \"./artisan\")) {\n return `${normalizePath(directory)}/artisan`;\n }\n return word;\n })\n .map(quoteWord)\n .join(\" \");\n}\n\n/**\n * The site whose root holds `path`: the most specific root wins, so a site in\n * `/home/forge/a.com/admin` is not owned by `/home/forge/a.com`. Returns null when no site holds it.\n */\nexport function siteOfPath(path: string, sites: SiteRoots[]): number | null {\n let best: { id: number; length: number } | null = null;\n for (const site of sites) {\n for (const root of site.roots) {\n if (isPathInside(path, root)) {\n const length = normalizePath(root).length;\n if (!best || length > best.length) best = { id: site.id, length };\n }\n }\n }\n return best?.id ?? null;\n}\n\n/**\n * The sites whose roots a command uses as a path.\n */\nexport function sitesOfCommand(command: string, sites: SiteRoots[]): number[] {\n return sites\n .filter((site) => site.roots.some((root) => commandUsesPath(command, root)))\n .map((site) => site.id);\n}\n\n/**\n * Who owns a daemon or a scheduled job, from the point of view of one site:\n * - `site`: it belongs to the site; `apply` can match it, and delete it when it is not declared\n * - `ambiguous`: it may belong to the site; `apply` can match it but never deletes it\n * - `other`: it belongs to another site, to the server, or to nobody known; `apply` ignores it\n */\nexport type Ownership = \"site\" | \"ambiguous\" | \"other\";\n\n/**\n * Ownership of a daemon (a Forge background process).\n *\n * - With a directory: the site that holds the directory (see {@link siteOfPath}).\n * - Without a directory: `ambiguous` when the command uses the site root, `site` only when\n * the command uses no other site root and Forge also associates the daemon with the site.\n */\nexport function daemonOwnership(\n daemon: { directory: string | null; command: string },\n siteId: number,\n sites: SiteRoots[],\n associatedWithSite: boolean,\n): Ownership {\n if (daemon.directory && daemon.directory.trim()) {\n return siteOfPath(daemon.directory, sites) === siteId ? \"site\" : \"other\";\n }\n\n const owners = sitesOfCommand(daemon.command, sites);\n if (!owners.includes(siteId)) return \"other\";\n return owners.length === 1 && associatedWithSite ? \"site\" : \"ambiguous\";\n}\n\n/**\n * Ownership of a scheduled job. Forge lists the jobs of a site on a site route: those\n * belong to the site. A job of the server belongs to the site when its command uses the\n * site root and no other site root; when it uses several site roots, it is `ambiguous`.\n */\nexport function scheduledJobOwnership(\n job: { command: string },\n siteId: number,\n sites: SiteRoots[],\n listedOnSite: boolean,\n): Ownership {\n if (listedOnSite) return \"site\";\n const owners = sitesOfCommand(job.command, sites);\n if (!owners.includes(siteId)) return \"other\";\n return owners.length === 1 ? \"site\" : \"ambiguous\";\n}\n","/**\n * Compare a site file with the state of Forge and list the changes that `apply` makes.\n * Pure functions: no API call here.\n */\n\nimport type {\n BackgroundProcessAttributes,\n DatabaseAttributes,\n DatabaseUserAttributes,\n LoadBalancingNodeAttributes,\n ScheduledJobAttributes,\n SiteAttributes,\n} from \"@studiometa/forge-api\";\n\nimport { unifiedDiff } from \"../../../utils/drift.ts\";\nimport { parseEnv } from \"../../env/env-diff.ts\";\nimport type { SiteFile } from \"./site-file.ts\";\nimport {\n type Ownership,\n type SiteRoots,\n canonicalCommand,\n daemonOwnership,\n isPathInside,\n normalizePath,\n resolvePath,\n scheduledJobOwnership,\n} from \"./ownership.ts\";\n\nexport type Site = SiteAttributes & { id: number };\nexport type Daemon = BackgroundProcessAttributes & { id: number };\nexport type ScheduledJob = ScheduledJobAttributes & { id: number };\nexport type Database = DatabaseAttributes & { id: number };\nexport type DatabaseUser = DatabaseUserAttributes & { id: number };\nexport type LoadBalancingNode = LoadBalancingNodeAttributes & { id: number };\n\n/** Shown in place of a generated password. */\nexport const GENERATED = \"<generated>\";\n\n/** What `apply` reads from Forge. A list is undefined when the site file does not manage it. */\nexport interface RemoteState {\n /** All sites of the server. */\n sites: Site[];\n /** The site of the file, or null when it does not exist yet. */\n site: Site | null;\n databases?: Database[];\n databaseUsers?: DatabaseUser[];\n /** Content of the site .env; null when the site does not exist. */\n env?: string | null;\n /** All daemons of the server. */\n daemons?: Daemon[];\n /** IDs of the daemons that Forge associates with the site. */\n siteDaemonIds?: ReadonlySet<number>;\n /** All scheduled jobs of the server, with the jobs of the site. */\n jobs?: ScheduledJob[];\n /** IDs of the scheduled jobs that Forge lists on the site. */\n siteJobIds?: ReadonlySet<number>;\n /** Nginx configuration on Forge and the Nginx file rendered for the site; null when the site does not exist. */\n nginx?: { remote: string; rendered: string } | null;\n /** The site of the file on its load balancer, with its nodes; site is null when it does not exist. */\n loadBalancer?: {\n serverId: string;\n site: Site | null;\n nodes: LoadBalancingNode[];\n /** The server of the site file: the one node that the load balancer must send traffic to. */\n target: number;\n };\n}\n\nexport interface SiteSettings {\n type?: string;\n php_version?: string;\n web_directory?: string;\n source_control_provider?: string;\n repository?: string;\n branch?: string;\n}\n\nexport type Change =\n | { action: \"create-site\"; name: string; settings: SiteSettings }\n | { action: \"update-site\"; changes: Array<{ field: string; from: string | null; to: string }> }\n | { action: \"add-alias\"; name: string }\n | { action: \"create-database\"; name: string }\n | { action: \"create-database-user\"; name: string; database: string }\n | {\n action: \"add-env\";\n keys: string[];\n /** Keys that get the database name, user and password of a new database user. */\n generated: string[];\n /** The generated key that holds the password; its value never shows. */\n password?: string;\n }\n | { action: \"create-worker\"; command: string; directory: string; processes: number }\n | {\n action: \"delete-worker\";\n id: number;\n command: string;\n directory: string | null;\n processes: number;\n }\n | { action: \"create-job\"; command: string; frequency: string; cron?: string }\n | {\n action: \"update-load-balancer\";\n site: string;\n from: Array<{ server_id: number; port: number }>;\n to: { server_id: number; port: number };\n }\n /** `diff` is null for a site that does not exist yet: the file is rendered once it exists. */\n | { action: \"update-nginx\"; diff: string | null }\n | {\n action: \"delete-job\";\n id: number;\n command: string;\n frequency: string;\n cron: string;\n onSite: boolean;\n };\n\nexport interface Plan {\n changes: Change[];\n /** Differences that `apply` does not change, e.g. a different .env value. */\n warnings: string[];\n}\n\n/** The path of the site folder, e.g. `/home/forge/example.com`. */\nexport function siteHome(site: Pick<Site, \"user\" | \"name\">): string {\n return `/home/${site.user}/${site.name}`;\n}\n\n/** The directory that workers run in and relative `artisan` resolves against. */\nexport function siteWorkDirectory(site: Pick<Site, \"user\" | \"name\" | \"root_directory\">): string {\n return inSiteHome(site, site.root_directory || \"/\");\n}\n\n/**\n * Read a directory of a site, absolute (`/home/forge/example.com/public`) or relative to the\n * site folder (`/public`), as an absolute path inside the site folder. A relative `/` never\n * becomes the root of the server.\n */\nfunction inSiteHome(site: Pick<Site, \"user\" | \"name\">, directory: string): string {\n const home = siteHome(site);\n return isPathInside(directory, home)\n ? normalizePath(directory)\n : resolvePath(home, directory.replace(/^\\/+/, \"\"));\n}\n\n/** The paths that belong to each site, for ownership. */\nexport function siteRoots(sites: Site[]): SiteRoots[] {\n return sites.map((site) => ({\n id: site.id,\n roots: [...new Set([siteHome(site), siteWorkDirectory(site)].map(normalizePath))],\n }));\n}\n\n/** `PHP 8.3`, `php83` and `php8.3` all give `php83`. */\nexport function normalizePhp(version: string | null | undefined): string | null {\n return version ? version.toLowerCase().replaceAll(/[^a-z0-9]/g, \"\") : null;\n}\n\n/** Forge displays frequencies in title case, e.g. `Minutely`. */\nfunction normalizeFrequency(frequency: string): string {\n return frequency.trim().toLowerCase();\n}\n\n/** The path a declared site uses before it exists, from its domain. */\nfunction plannedWorkDirectory(file: SiteFile): string {\n return `/home/forge/${file.domain}`;\n}\n\nfunction sameName(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Pair declared items with existing ones that have the same key, each existing item once.\n * Returns the declared items without a match and the existing items without a match.\n */\nfunction matchByKey<D, E>(\n declared: D[],\n existing: E[],\n declaredKey: (item: D) => string,\n existingKey: (item: E) => string,\n): { missing: D[]; unmatched: E[] } {\n const pool = existing.map((item) => ({ item, key: existingKey(item), used: false }));\n const missing: D[] = [];\n for (const item of declared) {\n const key = declaredKey(item);\n const match = pool.find((entry) => !entry.used && entry.key === key);\n if (match) match.used = true;\n else missing.push(item);\n }\n return { missing, unmatched: pool.filter((entry) => !entry.used).map((entry) => entry.item) };\n}\n\nfunction planSite(file: SiteFile, site: Site | null, changes: Change[], warnings: string[]): void {\n if (!site) {\n changes.push({\n action: \"create-site\",\n name: file.domain,\n settings: {\n type: file.type,\n php_version: file.php,\n web_directory: file.webDirectory,\n source_control_provider: file.repository?.provider,\n repository: file.repository?.url,\n branch: file.repository?.branch,\n },\n });\n return;\n }\n\n const updates: Array<{ field: string; from: string | null; to: string }> = [];\n if (file.php && normalizePhp(site.php_version) !== normalizePhp(file.php)) {\n updates.push({ field: \"php_version\", from: site.php_version, to: file.php });\n }\n if (file.webDirectory) {\n const root = siteWorkDirectory(site);\n const expected = resolvePath(root, file.webDirectory.replace(/^\\/+/, \"\"));\n // Forge gives an absolute path; a relative one is read against the site root.\n const remote = isPathInside(site.web_directory, root)\n ? normalizePath(site.web_directory)\n : resolvePath(root, site.web_directory.replace(/^\\/+/, \"\"));\n if (remote !== expected) {\n updates.push({ field: \"web_directory\", from: site.web_directory, to: file.webDirectory });\n }\n }\n if (file.repository?.branch && site.repository?.branch !== file.repository.branch) {\n updates.push({\n field: \"branch\",\n from: site.repository?.branch ?? null,\n to: file.repository.branch,\n });\n }\n if (updates.length > 0) {\n changes.push({ action: \"update-site\", changes: updates });\n }\n\n const url = site.repository?.url;\n if (\n file.repository &&\n url &&\n url.replace(/\\.git$/, \"\") !== file.repository.url.replace(/\\.git$/, \"\")\n ) {\n warnings.push(\n `Repository differs on Forge (${url}): apply does not change the repository of a site.`,\n );\n }\n if (file.type && site.app_type && !sameName(site.app_type, file.type)) {\n warnings.push(\n `Site type differs on Forge (${site.app_type}): apply does not change the type of a site.`,\n );\n }\n}\n\nfunction planAliases(file: SiteFile, site: Site | null, changes: Change[]): void {\n const existing = site ? [site.name, ...(site.aliases ?? [])].map(String) : [];\n for (const alias of new Set(file.aliases ?? [])) {\n if (!existing.some((name) => sameName(name, alias))) {\n changes.push({ action: \"add-alias\", name: alias });\n }\n }\n}\n\n/** The .env keys of a new database user, from `database.env` or the Laravel names. */\nexport function databaseEnvKeys(database: NonNullable<SiteFile[\"database\"]>): {\n name: string;\n user: string;\n password: string;\n} {\n return {\n name: database.env?.name ?? \"DB_DATABASE\",\n user: database.env?.user ?? \"DB_USERNAME\",\n password: database.env?.password ?? \"DB_PASSWORD\",\n };\n}\n\n/**\n * Plan the database and its user. Returns the names of the .env keys that get generated values.\n */\nfunction planDatabase(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): string[] {\n if (!file.database) return [];\n const { name, user } = file.database;\n const databaseExists = (state.databases ?? []).some((db) => db.name === name);\n const userExists = (state.databaseUsers ?? []).some((u) => u.name === user);\n\n if (!databaseExists) {\n changes.push({ action: \"create-database\", name });\n }\n if (!userExists) {\n changes.push({ action: \"create-database-user\", name: user, database: name });\n const keys = databaseEnvKeys(file.database);\n return [keys.name, keys.user, keys.password];\n }\n if (!databaseExists) {\n warnings.push(\n `Database user ${user} exists: apply does not give it access to the new database ${name}.`,\n );\n }\n return [];\n}\n\nfunction planEnv(\n file: SiteFile,\n state: RemoteState,\n generated: string[],\n changes: Change[],\n warnings: string[],\n): void {\n const remote = parseEnv(state.env ?? \"\");\n const keys: string[] = [];\n for (const [key, value] of Object.entries(file.env ?? {})) {\n if (generated.includes(key)) continue;\n if (!remote.has(key)) keys.push(key);\n else if (remote.get(key) !== String(value)) {\n warnings.push(`.env key ${key} has another value on Forge: apply does not overwrite it.`);\n }\n }\n if (keys.length > 0 || generated.length > 0) {\n const password =\n file.database && generated.length > 0 ? databaseEnvKeys(file.database).password : undefined;\n changes.push({ action: \"add-env\", keys, generated, ...(password ? { password } : {}) });\n }\n}\n\nfunction planNginx(file: SiteFile, state: RemoteState, changes: Change[]): void {\n if (file.nginxTemplate === undefined) return;\n if (!state.nginx) {\n changes.push({ action: \"update-nginx\", diff: null });\n return;\n }\n const diff = unifiedDiff(state.nginx.remote, state.nginx.rendered);\n if (diff) changes.push({ action: \"update-nginx\", diff });\n}\n\nfunction describeOwnership(ownership: Ownership): string {\n return ownership === \"ambiguous\" ? \"its owner is not certain\" : \"it runs as root\";\n}\n\nfunction planWorkers(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): void {\n if (!file.workers) return;\n const site = state.site;\n const workDirectory = site ? siteWorkDirectory(site) : plannedWorkDirectory(file);\n\n const declared = file.workers.map((worker) => {\n const directory = worker.directory\n ? resolvePath(workDirectory, worker.directory)\n : workDirectory;\n return {\n command: worker.command,\n directory,\n processes: worker.processes,\n key: [canonicalCommand(worker.command, directory), directory, worker.processes, \"forge\"].join(\n \"\\n\",\n ),\n };\n });\n\n // A site that does not exist yet owns no daemon.\n const roots = siteRoots(state.sites);\n const candidates = site\n ? (state.daemons ?? []).flatMap((daemon) => {\n const ownership = daemonOwnership(\n daemon,\n site.id,\n roots,\n state.siteDaemonIds?.has(daemon.id) ?? false,\n );\n return ownership === \"other\" ? [] : [{ daemon, ownership }];\n })\n : [];\n\n const { missing, unmatched } = matchByKey(\n declared,\n candidates,\n (worker) => worker.key,\n ({ daemon }) => {\n // A daemon without a directory compares as one in the site root, but its relative\n // `artisan` stays relative: it does not run in the site root.\n const directory = daemon.directory?.trim() ? normalizePath(daemon.directory) : null;\n return [\n canonicalCommand(daemon.command, directory),\n directory ?? workDirectory,\n daemon.processes,\n daemon.user,\n ].join(\"\\n\");\n },\n );\n\n for (const worker of missing) {\n changes.push({\n action: \"create-worker\",\n command: worker.command,\n directory: worker.directory,\n processes: worker.processes,\n });\n }\n\n for (const { daemon, ownership } of unmatched) {\n // Never delete a daemon of root, or one whose owner is not certain.\n if (ownership === \"site\" && daemon.user !== \"root\") {\n changes.push({\n action: \"delete-worker\",\n id: daemon.id,\n command: daemon.command,\n directory: daemon.directory,\n processes: daemon.processes,\n });\n } else {\n warnings.push(\n `Kept daemon ${daemon.id} (${daemon.command}): not declared, but ${describeOwnership(ownership)}.`,\n );\n }\n }\n}\n\nfunction planSchedule(\n file: SiteFile,\n state: RemoteState,\n changes: Change[],\n warnings: string[],\n): void {\n if (!file.schedule) return;\n const site = state.site;\n const workDirectory = site ? siteWorkDirectory(site) : plannedWorkDirectory(file);\n\n const declared = file.schedule.map((job) => {\n const command = canonicalCommand(job.command, workDirectory);\n const frequency = normalizeFrequency(job.frequency);\n return {\n command,\n frequency,\n cron: job.cron,\n key: [command, \"forge\", frequency, frequency === \"custom\" ? job.cron : \"\"].join(\"\\n\"),\n };\n });\n\n const roots = siteRoots(state.sites);\n const seen = new Set<number>();\n const candidates = site\n ? (state.jobs ?? []).flatMap((job) => {\n if (seen.has(job.id)) return [];\n seen.add(job.id);\n const onSite = state.siteJobIds?.has(job.id) ?? false;\n const ownership = scheduledJobOwnership(job, site.id, roots, onSite);\n return ownership === \"other\" ? [] : [{ job, ownership, onSite }];\n })\n : [];\n\n const { missing, unmatched } = matchByKey(\n declared,\n candidates,\n (job) => job.key,\n ({ job }) => {\n const frequency = normalizeFrequency(job.frequency);\n return [\n canonicalCommand(job.command, workDirectory),\n job.user,\n frequency,\n frequency === \"custom\" ? job.cron : \"\",\n ].join(\"\\n\");\n },\n );\n\n for (const job of missing) {\n changes.push({\n action: \"create-job\",\n command: job.command,\n frequency: job.frequency,\n ...(job.frequency === \"custom\" ? { cron: job.cron } : {}),\n });\n }\n\n for (const { job, ownership, onSite } of unmatched) {\n if (ownership === \"site\" && job.user !== \"root\") {\n changes.push({\n action: \"delete-job\",\n id: job.id,\n command: job.command,\n frequency: job.frequency,\n cron: job.cron,\n onSite,\n });\n } else {\n warnings.push(\n `Kept scheduled job ${job.id} (${job.command}): not declared, but ${describeOwnership(ownership)}.`,\n );\n }\n }\n}\n\n/**\n * Plan the nodes of the site on the load balancer: one node, the server of the site file, with\n * the default weight. Any other node is replaced.\n */\nfunction planLoadBalancer(file: SiteFile, state: RemoteState, changes: Change[]): void {\n const balancer = state.loadBalancer;\n if (!file.loadBalancer || !balancer?.site) return;\n const to = { server_id: balancer.target, port: file.loadBalancer.port };\n const [node, ...others] = balancer.nodes;\n const inSync =\n node !== undefined &&\n others.length === 0 &&\n node.server_id === to.server_id &&\n node.port === to.port &&\n node.weight === 1 &&\n !node.backup &&\n !node.down;\n if (inSync) return;\n changes.push({\n action: \"update-load-balancer\",\n site: balancer.site.name,\n from: balancer.nodes.map(({ server_id, port }) => ({ server_id, port })),\n to,\n });\n}\n\n/**\n * Compare the site file with the state of Forge. Keys that the file does not have are not\n * compared. The plan creates and updates what differs, and deletes only the workers and\n * scheduled jobs that surely belong to the site and that the file does not declare.\n */\nexport function buildPlan(file: SiteFile, state: RemoteState): Plan {\n const changes: Change[] = [];\n const warnings: string[] = [];\n\n planSite(file, state.site, changes, warnings);\n planAliases(file, state.site, changes);\n const generated = planDatabase(file, state, changes, warnings);\n if (file.env || generated.length > 0) {\n planEnv(file, state, generated, changes, warnings);\n }\n planNginx(file, state, changes);\n planWorkers(file, state, changes, warnings);\n planSchedule(file, state, changes, warnings);\n planLoadBalancer(file, state, changes);\n\n return { changes, warnings };\n}\n\nfunction quoted(value: string | null | undefined): string {\n return value ?? \"(none)\";\n}\n\n/**\n * One line per change, for human output. Values of .env keys never show.\n */\nexport function describeChange(change: Change): string {\n switch (change.action) {\n case \"create-site\": {\n const settings = Object.entries(change.settings)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}: ${value}`);\n return `+ create site ${change.name}${settings.length ? ` (${settings.join(\", \")})` : \"\"}`;\n }\n case \"update-site\":\n return `~ update site: ${change.changes\n .map((c) => `${c.field} ${quoted(c.from)} → ${c.to}`)\n .join(\", \")}`;\n case \"add-alias\":\n return `+ add alias ${change.name}`;\n case \"create-database\":\n return `+ create database ${change.name}`;\n case \"create-database-user\":\n return `+ create database user ${change.name} for ${change.database} (password: ${GENERATED})`;\n case \"add-env\":\n return `+ add .env keys: ${[\n ...change.keys,\n ...change.generated.map((key) => (key === change.password ? `${key}=${GENERATED}` : key)),\n ].join(\", \")}`;\n case \"update-nginx\":\n return change.diff === null\n ? \"~ write Nginx configuration (rendered once the site exists)\"\n : `~ update Nginx configuration:\\n${change.diff}`;\n case \"create-worker\":\n return `+ create worker: ${change.command} (directory: ${change.directory}, processes: ${change.processes})`;\n case \"delete-worker\":\n return `- delete worker ${change.id}: ${change.command} (directory: ${quoted(change.directory)}, processes: ${change.processes})`;\n case \"create-job\":\n return `+ create scheduled job: ${change.command} (${change.frequency}${change.cron ? ` ${change.cron}` : \"\"})`;\n case \"update-load-balancer\": {\n const node = ({ server_id, port }: { server_id: number; port: number }) =>\n `server ${server_id}:${port}`;\n const from = change.from.length > 0 ? change.from.map(node).join(\", \") : \"(none)\";\n return `~ update load balancer site ${change.site}: ${from} → ${node(change.to)}`;\n }\n case \"delete-job\":\n return `- delete scheduled job ${change.id}: ${change.command} (${change.frequency.toLowerCase()} ${change.cron})`;\n }\n}\n\n/**\n * The plan as text: one line per change, then the warnings.\n */\nexport function formatPlan(plan: Plan): string {\n return [\n ...plan.changes.map(describeChange),\n ...plan.warnings.map((warning) => `! ${warning}`),\n ].join(\"\\n\");\n}\n","/**\n * The Nginx file of a site file: an Nginx configuration with the template variables of Forge,\n * e.g. `{{ PROXY_PASS }}`, rendered locally with the values of the site.\n * See https://forge.laravel.com/docs/servers/nginx-templates\n */\n\nimport type { ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { ValidationError } from \"../../../errors.ts\";\nimport { isPathInside, normalizePath } from \"./ownership.ts\";\nimport { type Site, siteWorkDirectory } from \"./plan.ts\";\n\n/** The variables of Forge Nginx templates. Forge accepts spaces inside the braces. */\nexport const NGINX_VARIABLES = [\n \"DIRECTORY\",\n \"DOMAINS\",\n \"PATH\",\n \"PORT\",\n \"PORT_V6\",\n \"PROXY_PASS\",\n \"ROOT_PATH\",\n \"SERVER_PUBLIC_IP\",\n \"SERVER_PRIVATE_IP\",\n \"SITE\",\n \"SITE_ID\",\n \"USER\",\n] as const;\n\nexport type NginxVariable = (typeof NGINX_VARIABLES)[number];\n\n/** The variables that need the server, not only the site. */\nconst SERVER_VARIABLES: ReadonlySet<string> = new Set([\"SERVER_PUBLIC_IP\", \"SERVER_PRIVATE_IP\"]);\n\nconst VARIABLE = /\\{\\{\\s*([^{}]*?)\\s*\\}\\}/g;\n\n/** The names of the variables in a template, each once, in order. */\nexport function templateVariables(template: string): string[] {\n return [...new Set([...template.matchAll(VARIABLE)].map((match) => match[1]))];\n}\n\n/**\n * Exit with a validation error when the template has a variable that Forge does not define.\n */\nexport function assertNginxTemplate(template: string, source: string): void {\n const known: ReadonlySet<string> = new Set(NGINX_VARIABLES);\n const unknown = templateVariables(template).filter((name) => !known.has(name));\n if (unknown.length > 0) {\n throw new ValidationError(\n `Nginx file ${source} has unknown variables: ${unknown.map((name) => `{{${name}}}`).join(\", \")}`,\n \"nginx\",\n [`Supported variables: ${NGINX_VARIABLES.map((name) => `{{${name}}}`).join(\", \")}`],\n );\n }\n}\n\n/** True when rendering the template needs the attributes of the server. */\nexport function needsServer(template: string): boolean {\n return templateVariables(template).some((name) => SERVER_VARIABLES.has(name));\n}\n\n/** `PHP 8.3`, `php83` and `php8.3` all give `8.3`. */\nexport function phpSocketVersion(version: string): string {\n const digits = version.replaceAll(/\\D/g, \"\");\n if (digits.length < 2) {\n throw new ValidationError(`Cannot read the PHP version ${version} of the site`, \"nginx\");\n }\n return `${digits[0]}.${digits.slice(1)}`;\n}\n\nexport type NginxServer = Pick<ServerAttributes, \"ip_address\" | \"private_ip_address\">;\n\n/**\n * The value of each variable for a site, as Forge renders its templates.\n * A server is needed only for the `SERVER_*` variables.\n */\nexport function nginxValues(\n site: Site,\n server: NginxServer | null = null,\n): Record<NginxVariable, string> {\n const root = siteWorkDirectory(site);\n const path = isPathInside(site.web_directory, root)\n ? normalizePath(site.web_directory)\n : normalizePath(`${root}/${site.web_directory}`);\n const directory = path === root ? \"/\" : path.slice(root.length);\n const defaultServer = site.name === \"default\" ? \" default_server\" : \"\";\n const isolated = site.isolated ? `-${site.user}` : \"\";\n\n return {\n DIRECTORY: directory,\n DOMAINS: [site.name, ...(site.aliases ?? [])].join(\" \"),\n PATH: path,\n PORT: `80${defaultServer}`,\n PORT_V6: `[::]:80${defaultServer}`,\n get PROXY_PASS() {\n return `unix:/var/run/php/php${phpSocketVersion(site.php_version)}-fpm${isolated}.sock`;\n },\n ROOT_PATH: root,\n SERVER_PUBLIC_IP: server?.ip_address ?? \"\",\n SERVER_PRIVATE_IP: server?.private_ip_address ?? \"\",\n SITE: site.name,\n SITE_ID: String(site.id),\n USER: site.user,\n };\n}\n\n/**\n * Replace each variable of the template with its value for the site.\n */\nexport function renderNginx(\n template: string,\n site: Site,\n server: NginxServer | null = null,\n): string {\n const values = nginxValues(site, server);\n return template.replaceAll(VARIABLE, (match, name: string) =>\n name in values ? values[name as NginxVariable] : match,\n );\n}\n","/**\n * Read the state of Forge for a site file, and run a plan against Forge.\n */\n\nimport { randomBytes } from \"node:crypto\";\n\nimport {\n createDaemon,\n createDatabase,\n createDatabaseUser,\n createDomain,\n createScheduledJob,\n createSite,\n deleteDaemon,\n deleteScheduledJob,\n getEnv,\n getNginxConfig,\n getServer,\n getSite,\n listDaemons,\n listDatabaseUsers,\n listDatabases,\n listLoadBalancingNodes,\n listScheduledJobs,\n listServers,\n listSites,\n updateEnv,\n updateLoadBalancingNodes,\n updateNginxConfig,\n updateSite,\n} from \"@studiometa/forge-core\";\n\nimport type { CliExecutorContext } from \"../../../context.ts\";\nimport { CliError, ValidationError } from \"../../../errors.ts\";\nimport { unifiedDiff } from \"../../../utils/drift.ts\";\nimport { matchServerId } from \"../../../utils/resolve.ts\";\nimport { needsServer, renderNginx } from \"./nginx.ts\";\nimport {\n type Change,\n type Plan,\n type RemoteState,\n type Site,\n buildPlan,\n databaseEnvKeys,\n} from \"./plan.ts\";\nimport type { SiteFile } from \"./site-file.ts\";\n\n/** Error of `apply` that is not a validation error, e.g. a site that never gets installed. */\nexport class ApplyError extends CliError {\n readonly code = \"APPLY_ERROR\";\n readonly isRecoverable = false;\n}\n\n/**\n * Resolve the server of the site file, always with an exact name (never a partial match).\n */\nexport async function resolveApplyServer(\n server: string | number,\n ctx: CliExecutorContext,\n): Promise<string> {\n const value = String(server);\n if (/^\\d+$/.test(value)) return value;\n const servers = await listServers({}, ctx);\n return matchServerId(value, servers.data, true);\n}\n\n/**\n * The site named `domain` on the server, compared without case. A partial match never counts.\n */\nexport function findSite(sites: Site[], domain: string): Site | null {\n return sites.find((site) => site.name.toLowerCase() === domain.toLowerCase()) ?? null;\n}\n\n/**\n * The site of the load balancer named `domain` or one of the aliases, compared without case.\n * Its name can be any of them, e.g. the domain without `www`. Two matches are an error: a guess\n * could send the traffic of another site.\n */\nexport function findLoadBalancerSite(sites: Site[], names: string[]): Site | null {\n const wanted = new Set(names.map((name) => name.toLowerCase()));\n const matches = sites.filter((site) => wanted.has(site.name.toLowerCase()));\n if (matches.length > 1) {\n throw new ValidationError(\n `Several sites of the load balancer match the site file: ${matches.map((site) => site.name).join(\", \")}`,\n \"loadBalancer\",\n [\"Keep one site for the domain and its aliases on the load balancer\"],\n );\n }\n return matches[0] ?? null;\n}\n\n/**\n * Exit with a validation error when the load balancer has no site for the site file: the Forge\n * API cannot create a site on a load balancer.\n */\nexport function assertLoadBalancerSite(file: SiteFile, state: RemoteState): void {\n if (file.loadBalancer && !state.loadBalancer?.site) {\n throw new ValidationError(\n `The load balancer ${file.loadBalancer.server} has no site for ${file.domain}`,\n \"loadBalancer\",\n [\n `In Forge, create the site ${file.domain} on the load balancer (New site), then run apply again`,\n \"Check the domain, the aliases and the server of the load balancer\",\n ],\n );\n }\n}\n\n/**\n * Read from Forge what the site file manages, and nothing else.\n */\nexport async function readRemoteState(\n file: SiteFile,\n serverId: string,\n ctx: CliExecutorContext,\n): Promise<RemoteState> {\n const sites = (await listSites({ server_id: serverId }, ctx)).data;\n const site = findSite(sites, file.domain);\n const siteId = site ? String(site.id) : undefined;\n const state: RemoteState = { sites, site };\n\n if (file.database) {\n state.databases = (await listDatabases({ server_id: serverId }, ctx)).data;\n state.databaseUsers = (await listDatabaseUsers({ server_id: serverId }, ctx)).data;\n }\n\n if (file.env || file.database) {\n state.env = siteId ? (await getEnv({ server_id: serverId, site_id: siteId }, ctx)).data : null;\n }\n\n if (file.workers) {\n state.daemons = (await listDaemons({ server_id: serverId }, ctx)).data;\n state.siteDaemonIds = new Set(\n siteId\n ? (await listDaemons({ server_id: serverId, site_id: siteId }, ctx)).data.map((d) => d.id)\n : [],\n );\n }\n\n if (file.nginxTemplate !== undefined) {\n state.nginx = site ? await readNginx(file.nginxTemplate, serverId, site, ctx) : null;\n }\n\n if (file.schedule) {\n const siteJobs = siteId\n ? (await listScheduledJobs({ server_id: serverId, site_id: siteId }, ctx)).data\n : [];\n const serverJobs = (await listScheduledJobs({ server_id: serverId }, ctx)).data;\n state.jobs = [...siteJobs, ...serverJobs];\n state.siteJobIds = new Set(siteJobs.map((job) => job.id));\n }\n\n if (file.loadBalancer) {\n const balancerId = await resolveApplyServer(file.loadBalancer.server, ctx);\n const balancerSites = (await listSites({ server_id: balancerId }, ctx)).data;\n const balancerSite = findLoadBalancerSite(balancerSites, [\n file.domain,\n ...(file.aliases ?? []),\n ]);\n const nodes = balancerSite\n ? (\n await listLoadBalancingNodes(\n { server_id: balancerId, site_id: String(balancerSite.id) },\n ctx,\n )\n ).data\n : [];\n state.loadBalancer = {\n serverId: balancerId,\n site: balancerSite,\n nodes,\n target: Number(serverId),\n };\n }\n\n return state;\n}\n\n/**\n * Read the Nginx configuration of a site on Forge and render the Nginx file for the site.\n */\nexport async function readNginx(\n template: string,\n serverId: string,\n site: Site,\n ctx: CliExecutorContext,\n): Promise<{ remote: string; rendered: string }> {\n const remote = (await getNginxConfig({ server_id: serverId, site_id: String(site.id) }, ctx))\n .data;\n const server = needsServer(template)\n ? (await getServer({ server_id: serverId }, ctx)).data\n : null;\n return { remote, rendered: renderNginx(template, site, server) };\n}\n\n/**\n * Exit with a validation error when the site does not exist and the site file cannot create it.\n */\nexport function assertCanCreateSite(file: SiteFile, state: RemoteState): void {\n if (!state.site && !file.type) {\n throw new ValidationError(\n `Site ${file.domain} does not exist and the site file has no type to create it`,\n \"type\",\n ['Add \"type\" to the site file, e.g. \"type\": \"php\"', \"Check the domain and the server\"],\n );\n }\n}\n\n/** A random password for a database user: 32 characters, letters and digits only. */\nexport function generatePassword(): string {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n // 248 is the largest multiple of 62 below 256: drop higher bytes to keep the draw uniform.\n let password = \"\";\n while (password.length < 32) {\n for (const byte of randomBytes(64)) {\n if (byte < 248 && password.length < 32) password += alphabet[byte % 62];\n }\n }\n return password;\n}\n\n/** Write a value for a .env file, quoted when it needs quotes. */\nexport function formatEnvValue(value: string): string {\n if (/^[\\w.,:/@+-]*$/.test(value)) return value;\n if (!value.includes(\"'\") && !value.includes(\"\\n\")) return `'${value}'`;\n return `\"${value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"').replaceAll(\"\\n\", \"\\\\n\")}\"`;\n}\n\n/**\n * Set .env variables: replace the line of a variable that exists, append the others.\n */\nexport function setEnvValues(content: string, values: Map<string, string>): string {\n const lines = content === \"\" ? [] : content.replace(/\\n$/, \"\").split(\"\\n\");\n const pending = new Map(values);\n const result = lines.map((line) => {\n const match = /^\\s*(?:export\\s+)?([A-Za-z_][A-Za-z0-9_.]*)\\s*=/.exec(line);\n const name = match?.[1];\n if (name && pending.has(name)) {\n const value = pending.get(name)!;\n pending.delete(name);\n return `${name}=${formatEnvValue(value)}`;\n }\n return line;\n });\n for (const [name, value] of pending) {\n result.push(`${name}=${formatEnvValue(value)}`);\n }\n return `${result.join(\"\\n\")}\\n`;\n}\n\nexport interface ApplyOptions {\n /** Wait between two reads of a new site; injectable for tests. */\n sleep?: (ms: number) => Promise<void>;\n /** Time between two reads of a new site, in ms. */\n pollIntervalMs?: number;\n /** Time to wait for a new site to be installed, in ms. */\n timeoutMs?: number;\n /** Called before each change. */\n onChange?: (change: Change) => void;\n /** Generate a password; injectable for tests. */\n generatePassword?: () => string;\n}\n\n/** Forge clones the repository with the key of the server: the git host must accept it. */\nconst REPOSITORY_HINT = (serverId: string) =>\n `Check that the git host accepts the key of the server: forge servers public-key ${serverId}`;\n\nconst defaultSleep = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n\nasync function waitForSite(\n file: SiteFile,\n serverId: string,\n siteId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const sleep = options.sleep ?? defaultSleep;\n const interval = options.pollIntervalMs ?? 5000;\n const timeout = options.timeoutMs ?? 600_000;\n for (let waited = 0; ; waited += interval) {\n const site = (await getSite({ server_id: serverId, site_id: siteId }, ctx)).data;\n if (site.status === \"installed\") return;\n if (waited >= timeout) {\n throw new ApplyError(`Site ${site.name} is still ${site.status} on Forge`, [\n \"Run forge sites apply again once the site is installed\",\n ...(file.repository ? [REPOSITORY_HINT(serverId)] : []),\n ]);\n }\n await sleep(interval);\n }\n}\n\ninterface DatabaseIds {\n database_id?: number;\n database_user_id?: string;\n}\n\n/**\n * Create the database and its user. Returns their IDs and the .env values to write.\n */\nasync function applyDatabase(\n file: SiteFile,\n plan: Plan,\n state: RemoteState,\n serverId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<{ ids: DatabaseIds; env: Map<string, string> }> {\n const env = new Map<string, string>();\n const ids: DatabaseIds = {};\n if (!file.database) return { ids, env };\n\n let databaseId = state.databases?.find((db) => db.name === file.database!.name)?.id;\n for (const change of plan.changes) {\n if (change.action === \"create-database\") {\n options.onChange?.(change);\n databaseId = (await createDatabase({ server_id: serverId, name: change.name }, ctx)).data.id;\n } else if (change.action === \"create-database-user\") {\n options.onChange?.(change);\n const password = (options.generatePassword ?? generatePassword)();\n const user = await createDatabaseUser(\n {\n server_id: serverId,\n name: change.name,\n password,\n ...(databaseId === undefined ? {} : { database_ids: [databaseId] }),\n },\n ctx,\n );\n ids.database_user_id = String(user.data.id);\n const keys = databaseEnvKeys(file.database);\n env.set(keys.name, change.database);\n env.set(keys.user, change.name);\n env.set(keys.password, password);\n }\n }\n if (databaseId !== undefined) ids.database_id = databaseId;\n return { ids, env };\n}\n\n/**\n * Write the rendered Nginx file when it differs from Forge. After a change of the site or its\n * aliases, read the site again: the web directory and the domains are template variables.\n */\nasync function applyNginx(\n template: string,\n plan: Plan,\n serverId: string,\n site: Site,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const siteChanged = plan.changes.some(\n (change) => change.action === \"update-site\" || change.action === \"add-alias\",\n );\n const planned = plan.changes.some((change) => change.action === \"update-nginx\");\n if (!planned && !siteChanged) return;\n\n const params = { server_id: serverId, site_id: String(site.id) };\n const current = siteChanged ? (await getSite(params, ctx)).data : site;\n const { remote, rendered } = await readNginx(template, serverId, current, ctx);\n const diff = unifiedDiff(remote, rendered);\n if (!diff) return;\n options.onChange?.({ action: \"update-nginx\", diff });\n await updateNginxConfig({ ...params, content: rendered }, ctx);\n}\n\n/**\n * Run the changes of a plan for a site that exists.\n */\nasync function applyChanges(\n file: SiteFile,\n plan: Plan,\n state: RemoteState,\n serverId: string,\n site: Site,\n generatedEnv: Map<string, string>,\n ctx: CliExecutorContext,\n options: ApplyOptions,\n): Promise<void> {\n const params = { server_id: serverId, site_id: String(site.id) };\n const { env: databaseEnv } = await applyDatabase(file, plan, state, serverId, ctx, options);\n const env = new Map([...generatedEnv, ...databaseEnv]);\n const creations: Change[] = [];\n const deletions: Change[] = [];\n\n for (const change of plan.changes) {\n switch (change.action) {\n case \"update-site\": {\n options.onChange?.(change);\n const update: Record<string, string> = {};\n for (const { field, to } of change.changes) {\n if (field === \"php_version\") update.php_version = to;\n if (field === \"web_directory\") update.directory = to;\n if (field === \"branch\") update.repository_branch = to;\n }\n await updateSite({ ...params, ...update }, ctx);\n break;\n }\n case \"add-alias\":\n options.onChange?.(change);\n await createDomain(\n {\n ...params,\n name: change.name,\n allow_wildcard_subdomains: false,\n www_redirect_type: \"none\",\n },\n ctx,\n );\n break;\n case \"add-env\":\n for (const key of change.keys) env.set(key, String(file.env?.[key]));\n break;\n case \"create-worker\":\n case \"create-job\":\n creations.push(change);\n break;\n case \"delete-worker\":\n case \"delete-job\":\n deletions.push(change);\n break;\n default:\n break;\n }\n }\n\n if (env.size > 0) {\n const addEnv = plan.changes.find((change) => change.action === \"add-env\");\n if (addEnv) options.onChange?.(addEnv);\n const content = (await getEnv(params, ctx)).data;\n await updateEnv({ ...params, content: setEnvValues(content, env) }, ctx);\n }\n\n if (file.nginxTemplate !== undefined) {\n await applyNginx(file.nginxTemplate, plan, serverId, site, ctx, options);\n }\n\n // Create first, then delete: a changed worker runs again before the old one stops.\n for (const change of creations) {\n options.onChange?.(change);\n if (change.action === \"create-worker\") {\n await createDaemon(\n {\n server_id: serverId,\n site_id: site.id,\n name: change.command.slice(0, 255),\n command: change.command,\n user: \"forge\",\n directory: change.directory,\n processes: change.processes,\n },\n ctx,\n );\n } else if (change.action === \"create-job\") {\n await createScheduledJob(\n {\n ...params,\n command: change.command,\n user: \"forge\",\n frequency: change.frequency,\n ...(change.cron ? { cron: change.cron } : {}),\n },\n ctx,\n );\n }\n }\n\n // Last: the load balancer sends traffic to the server once the site is ready there.\n const balancer = state.loadBalancer;\n const balancing = plan.changes.find((change) => change.action === \"update-load-balancer\");\n if (balancing?.action === \"update-load-balancer\" && balancer?.site) {\n options.onChange?.(balancing);\n await updateLoadBalancingNodes(\n {\n server_id: balancer.serverId,\n site_id: String(balancer.site.id),\n balancer_method: \"round_robin\",\n balancing: [{ ...balancing.to, weight: 1 }],\n },\n ctx,\n );\n }\n\n for (const change of deletions) {\n options.onChange?.(change);\n if (change.action === \"delete-worker\") {\n await deleteDaemon({ server_id: serverId, id: String(change.id) }, ctx);\n } else if (change.action === \"delete-job\") {\n await deleteScheduledJob(\n {\n server_id: serverId,\n id: String(change.id),\n ...(change.onSite ? { site_id: params.site_id } : {}),\n },\n ctx,\n );\n }\n }\n}\n\n/**\n * Apply a site file: create the site when it does not exist and wait until Forge installs it,\n * then read the state again and run the other changes. Returns the plan that ran first.\n */\nexport async function applySiteFile(\n file: SiteFile,\n serverId: string,\n ctx: CliExecutorContext,\n options: ApplyOptions = {},\n): Promise<Plan> {\n let state = await readRemoteState(file, serverId, ctx);\n assertLoadBalancerSite(file, state);\n const firstPlan = buildPlan(file, state);\n let plan = firstPlan;\n let generatedEnv = new Map<string, string>();\n\n const createSiteChange = plan.changes.find((change) => change.action === \"create-site\");\n if (createSiteChange && createSiteChange.action === \"create-site\") {\n assertCanCreateSite(file, state);\n const database = await applyDatabase(file, plan, state, serverId, ctx, options);\n generatedEnv = database.env;\n options.onChange?.(createSiteChange);\n const { settings } = createSiteChange;\n const created = await createSite(\n {\n server_id: serverId,\n type: file.type!,\n name: file.domain,\n domain_mode: \"custom\",\n www_redirect_type: \"none\",\n allow_wildcard_subdomains: false,\n ...(settings.php_version ? { php_version: settings.php_version } : {}),\n ...(settings.web_directory ? { web_directory: settings.web_directory } : {}),\n ...(settings.source_control_provider\n ? { source_control_provider: settings.source_control_provider }\n : {}),\n ...(settings.repository ? { repository: settings.repository } : {}),\n ...(settings.branch ? { branch: settings.branch } : {}),\n ...database.ids,\n },\n ctx,\n );\n await waitForSite(file, serverId, String(created.data.id), ctx, options);\n state = await readRemoteState(file, serverId, ctx);\n plan = buildPlan(file, state);\n }\n\n const site = state.site;\n if (!site) {\n throw new ApplyError(`Site ${file.domain} is not on server ${serverId} after its creation`);\n }\n await applyChanges(file, plan, state, serverId, site, generatedEnv, ctx, options);\n return firstPlan;\n}\n","/**\n * The site file of `forge sites apply`: a JSON file that declares one Forge site.\n * A key that is absent is not managed; only `server` and `domain` are required.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport * as v from \"valibot\";\n\nimport { ValidationError } from \"../../../errors.ts\";\nimport { assertNginxTemplate } from \"./nginx.ts\";\n\n/** URL of the JSON Schema of the site file, published with the package. */\nexport const SITE_FILE_SCHEMA_URL =\n \"https://unpkg.com/@studiometa/forge-cli/schemas/site.schema.json\";\n\nconst text = v.pipe(v.string(), v.trim(), v.nonEmpty());\n\n/** A server name (exact match) or ID. */\nconst serverRef = v.union([text, v.pipe(v.number(), v.integer(), v.minValue(1))]);\n\nexport const SITE_TYPES = [\n \"laravel\",\n \"symfony\",\n \"statamic\",\n \"wordpress\",\n \"phpmyadmin\",\n \"php\",\n \"nextjs\",\n \"nuxtjs\",\n \"static-html\",\n \"other\",\n \"custom\",\n] as const;\n\nexport const SOURCE_CONTROL_PROVIDERS = [\n \"github\",\n \"gitlab\",\n \"bitbucket\",\n \"gitlab-custom\",\n \"custom\",\n] as const;\n\nexport const SCHEDULE_FREQUENCIES = [\n \"minutely\",\n \"hourly\",\n \"nightly\",\n \"weekly\",\n \"monthly\",\n \"reboot\",\n \"custom\",\n] as const;\n\nexport const WorkerSchema = v.strictObject({\n command: text,\n processes: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1)), 1),\n directory: v.optional(text),\n});\n\nexport const ScheduledJobSchema = v.pipe(\n v.strictObject({\n command: text,\n frequency: v.picklist(SCHEDULE_FREQUENCIES),\n cron: v.optional(text),\n }),\n v.check(\n (job) => (job.frequency === \"custom\") === (job.cron !== undefined),\n \"cron is required with the custom frequency, and only with it\",\n ),\n);\n\nconst envName = v.pipe(\n v.string(),\n v.regex(/^[A-Za-z_][A-Za-z0-9_]*$/, \"invalid .env variable name\"),\n);\n\n/** The .env keys that a new database user gets. Default: the Laravel names. */\nexport const DatabaseEnvSchema = v.pipe(\n v.strictObject({\n name: v.optional(envName),\n user: v.optional(envName),\n password: v.optional(envName),\n }),\n v.check(\n (env) =>\n new Set([env.name ?? \"DB_DATABASE\", env.user ?? \"DB_USERNAME\", env.password ?? \"DB_PASSWORD\"])\n .size === 3,\n \"the .env keys of the database must be different\",\n ),\n);\n\n/** The load balancer that sends the traffic of the site to its server. */\nexport const LoadBalancerSchema = v.strictObject({\n server: serverRef,\n port: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(65535)), 80),\n});\n\nexport const SiteFileSchema = v.strictObject({\n $schema: v.optional(v.string()),\n server: serverRef,\n domain: text,\n aliases: v.optional(v.array(text)),\n type: v.optional(v.picklist(SITE_TYPES)),\n php: v.optional(v.pipe(v.string(), v.regex(/^php\\d+$/, \"php must look like php83\"))),\n webDirectory: v.optional(text),\n repository: v.optional(\n v.strictObject({\n provider: v.picklist(SOURCE_CONTROL_PROVIDERS),\n url: text,\n branch: v.optional(text),\n }),\n ),\n database: v.optional(\n v.strictObject({ name: text, user: text, env: v.optional(DatabaseEnvSchema) }),\n ),\n env: v.optional(v.record(envName, v.union([v.string(), v.number(), v.boolean()]))),\n nginx: v.optional(text),\n workers: v.optional(v.array(WorkerSchema)),\n schedule: v.optional(v.array(ScheduledJobSchema)),\n loadBalancer: v.optional(LoadBalancerSchema),\n});\n\nexport type SiteFileData = v.InferOutput<typeof SiteFileSchema>;\n\n/** A site file with the content of its Nginx file, when it declares one. */\nexport type SiteFile = SiteFileData & { nginxTemplate?: string };\nexport type WorkerDeclaration = v.InferOutput<typeof WorkerSchema>;\nexport type ScheduledJobDeclaration = v.InferOutput<typeof ScheduledJobSchema>;\n\n/**\n * Validate parsed JSON as a site file. Throws a ValidationError that lists every issue.\n */\nexport function parseSiteFile(data: unknown, source = \"site file\"): SiteFileData {\n const result = v.safeParse(SiteFileSchema, data);\n if (!result.success) {\n const issues = result.issues.map((issue) => {\n const path = v.getDotPath(issue);\n return `${path ?? \"(root)\"}: ${issue.message}`;\n });\n throw new ValidationError(`Invalid ${source}`, \"file\", issues);\n }\n return result.output;\n}\n\n/**\n * Read and validate a site file from disk, with its Nginx file: a relative `nginx` path is\n * read against the folder of the site file.\n */\nexport function readSiteFile(path: string): SiteFile {\n let content: string;\n try {\n content = readFileSync(path, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Cannot read site file ${path}: ${reason}`, \"file\");\n }\n\n let data: unknown;\n try {\n data = JSON.parse(content);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Site file ${path} is not valid JSON: ${reason}`, \"file\");\n }\n\n const file: SiteFile = parseSiteFile(data, `site file ${path}`);\n if (file.nginx) {\n const nginxPath = resolve(dirname(path), file.nginx);\n try {\n file.nginxTemplate = readFileSync(nginxPath, \"utf8\");\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new ValidationError(`Cannot read Nginx file ${nginxPath}: ${reason}`, \"nginx\");\n }\n assertNginxTemplate(file.nginxTemplate, nginxPath);\n }\n return file;\n}\n","import type { CommandContext } from \"../../../context.ts\";\n\nimport { ExitCode, exitWithValidationError, runCommand } from \"../../../error-handler.ts\";\nimport {\n type ApplyOptions,\n applySiteFile,\n assertCanCreateSite,\n assertLoadBalancerSite,\n readRemoteState,\n resolveApplyServer,\n} from \"./apply.ts\";\nimport { buildPlan, describeChange } from \"./plan.ts\";\nimport { readSiteFile } from \"./site-file.ts\";\n\n/**\n * `forge sites apply --file site.json [--check]`: make a Forge site match a site file.\n * With `--check`, print the plan and exit 1 when Forge differs, without any change.\n */\nexport async function sitesApply(\n ctx: CommandContext,\n applyOptions: ApplyOptions = {},\n): Promise<void> {\n const usage = \"forge sites apply --file <site.json> [--check]\";\n const path = ctx.options.file;\n const check = Boolean(ctx.options.check);\n\n if (typeof path !== \"string\" || !path) {\n exitWithValidationError(\"file\", usage, ctx.formatter);\n }\n\n await runCommand(async () => {\n const file = readSiteFile(path);\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveApplyServer(file.server, execCtx);\n\n if (check) {\n const state = await readRemoteState(file, server_id, execCtx);\n assertCanCreateSite(file, state);\n assertLoadBalancerSite(file, state);\n const plan = buildPlan(file, state);\n const inSync = plan.changes.length === 0;\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ inSync, changes: plan.changes, warnings: plan.warnings });\n } else {\n for (const change of plan.changes) console.log(describeChange(change));\n for (const warning of plan.warnings) ctx.formatter.warning(warning);\n if (inSync) ctx.formatter.success(`Site ${file.domain} is in sync with Forge.`);\n else ctx.formatter.error(`Site ${file.domain} differs from Forge.`);\n }\n if (!inSync) process.exitCode = ExitCode.GENERAL_ERROR;\n return;\n }\n\n const applied: string[] = [];\n const plan = await applySiteFile(file, server_id, execCtx, {\n ...applyOptions,\n onChange: (change) => {\n applied.push(change.action);\n if (!ctx.formatter.isJson()) console.log(describeChange(change));\n },\n });\n\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ changes: plan.changes, warnings: plan.warnings });\n } else {\n for (const warning of plan.warnings) ctx.formatter.warning(warning);\n ctx.formatter.success(\n applied.length === 0\n ? `Site ${file.domain} is in sync with Forge.`\n : `Site ${file.domain} applied: ${applied.length} change(s).`,\n );\n }\n }, ctx.formatter);\n}\n","import { listSites, getSite, updateSite } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId, resolveSiteId } from \"../../utils/resolve.ts\";\n\nexport async function sitesList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge sites list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listSites({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\", \"php_version\"],\n \"No sites found.\",\n (s) =>\n `${String(s.id).padEnd(8)} ${s.name.padEnd(40)} ${s.status.padEnd(12)} ${s.php_version}`,\n );\n }, ctx.formatter);\n}\n\nexport async function sitesGet(args: string[], ctx: CommandContext): Promise<void> {\n const [siteArg] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!siteArg) {\n exitWithValidationError(\n \"site_id\",\n \"forge sites get <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge sites get <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(siteArg, server_id, execCtx);\n const result = await getSite({ server_id, site_id }, execCtx);\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"status\",\n \"php_version\",\n \"app_type\",\n \"repository\",\n \"quick_deploy\",\n \"deployment_status\",\n \"https\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n\nexport async function sitesUpdate(args: string[], ctx: CommandContext): Promise<void> {\n const [siteArg] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!siteArg) {\n exitWithValidationError(\n \"site_id\",\n \"forge sites update <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge sites update <site_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const site_id = await resolveSiteId(siteArg, server_id, execCtx);\n const result = await updateSite(\n {\n server_id,\n site_id,\n root_path: ctx.options.root_path as string | undefined,\n directory: ctx.options.directory as string | undefined,\n type: ctx.options.type as string | undefined,\n php_version: ctx.options.php_version as string | undefined,\n push_to_deploy:\n ctx.options.push_to_deploy !== undefined\n ? ctx.options.push_to_deploy === \"true\" || ctx.options.push_to_deploy === true\n : undefined,\n repository_branch: ctx.options.repository_branch as string | undefined,\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, [\n \"id\",\n \"name\",\n \"status\",\n \"php_version\",\n \"app_type\",\n \"repository\",\n \"quick_deploy\",\n \"deployment_status\",\n \"https\",\n \"created_at\",\n ]);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { sitesApply } from \"./apply/handler.ts\";\nimport { sitesList, sitesGet, sitesUpdate } from \"./handlers.ts\";\n\nexport const handleSitesCommand = createCommandRouter({\n resource: \"sites\",\n handlers: {\n list: sitesList,\n ls: sitesList,\n get: [sitesGet, \"args\"],\n update: [sitesUpdate, \"args\"],\n apply: (ctx) => sitesApply(ctx),\n },\n writeSubcommands: [\"apply\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSitesHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge sites list\")} - List sites on a server\n\n${colors.bold(\"USAGE:\")}\n forge sites list --server <server_id> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites list --server 123\n forge sites list --server 123 --format json\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge sites get\")} - Get site details\n\n${colors.bold(\"USAGE:\")}\n forge sites get <site_id> --server <server_id> [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <site_id> Site ID (required)\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"apply\") {\n console.log(`\n${colors.bold(\"forge sites apply\")} - Make a site match a site file\n\n${colors.bold(\"USAGE:\")}\n forge sites apply --file <site.json> [--check] [options]\n\n${colors.bold(\"OPTIONS:\")}\n --file <path> Site file (required), e.g. config/forge/production/site.json\n --check Print the plan and change nothing: exit 0 when Forge matches,\n exit 1 when it differs, another code on error\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"SITE FILE:\")}\n Only \"server\" (exact name or ID) and \"domain\" (exact site name) are required.\n A key that is absent is not managed: apply does not read or change it.\n type, php, webDirectory, repository Create the site, or update php, web directory, branch\n aliases Add missing aliases, never remove one\n database { name, user, env } Create when missing; a new user gets a random\n password, written into the site .env only.\n env maps { name, user, password } to .env keys\n (default DB_DATABASE, DB_USERNAME, DB_PASSWORD)\n env Add missing keys, never overwrite a value\n nginx Nginx file, relative to the site file, with Forge\n template variables such as {{PATH}}, {{SITE_ID}},\n {{PROXY_PASS}}: rendered for the site, written\n when it differs (an unknown variable exits 3)\n workers, schedule Create missing ones, delete the ones of the site\n that the file does not declare ([] deletes all)\n\n A worker or scheduled job is deleted only when it surely belongs to the site:\n Forge lists it on the site, or its directory (or, without a directory, its command)\n uses the site path, compared on whole path segments. Jobs of root are never deleted.\n The plan never prints .env values.\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites apply --file config/forge/production/site.json --check\n forge sites apply --file config/forge/production/site.json\n`);\n } else {\n console.log(`\n${colors.bold(\"forge sites\")} - Manage sites\n\n${colors.bold(\"USAGE:\")}\n forge sites <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List sites on a server\n get <id> Get site details\n apply Make a site match a site file (--file, --check)\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID (required for most commands)\n -f, --format <fmt> Output format: json, human, table\n -h, --help Show help for a subcommand\n\n${colors.bold(\"EXAMPLES:\")}\n forge sites list --server 123\n forge sites get 456 --server 123\n forge sites apply --file config/forge/production/site.json --check\n\nRun ${colors.cyan(\"forge sites <subcommand> --help\")} for subcommand details.\n`);\n }\n}\n","/**\n * Pure helpers for resolving SSH connection details from a Forge server.\n *\n * Kept free of side effects so the resolution logic is fully unit-testable\n * without spawning a real `ssh` process.\n */\n\nimport type { ServerAttributes } from \"@studiometa/forge-api\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** Forge's conventional default provisioning user. */\nexport const DEFAULT_SSH_USER = \"forge\";\n\nexport interface SshTargetOptions {\n /** SSH user (defaults to {@link DEFAULT_SSH_USER}). */\n user?: string;\n /** Connect over the private network (`private_ip_address`) instead of the public IP. */\n private?: boolean;\n /** Override the server's `ssh_port` (string as parsed from the CLI). */\n port?: string;\n}\n\nexport interface SshTarget {\n user: string;\n host: string;\n port: number;\n}\n\n/**\n * Resolve the concrete user/host/port to connect to.\n *\n * @throws {ValidationError} when the selected IP is not available yet, or the port override is invalid.\n */\nexport function resolveSshTarget(\n server: ServerAttributes,\n options: SshTargetOptions = {},\n): SshTarget {\n const user = options.user?.trim() || DEFAULT_SSH_USER;\n\n const host = options.private ? server.private_ip_address : server.ip_address;\n if (!host) {\n const which = options.private ? \"private IP address\" : \"IP address\";\n const hints = [\n server.is_ready\n ? \"The server is ready but no address is available — check the Forge dashboard.\"\n : \"The server is still provisioning. Wait until it is ready, then try again.\",\n options.private ? undefined : \"Use --private to connect over the private network.\",\n ].filter((hint): hint is string => Boolean(hint));\n\n throw new ValidationError(`Server \"${server.name}\" has no ${which} available`, \"server\", hints);\n }\n\n let port = server.ssh_port;\n if (options.port !== undefined) {\n const parsed = Number(options.port);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {\n throw new ValidationError(`Invalid SSH port \"${options.port}\"`, \"port\", [\n \"Port must be an integer between 1 and 65535.\",\n ]);\n }\n port = parsed;\n }\n\n return { user, host, port };\n}\n\n/**\n * Build the argument list passed to the `ssh` binary.\n *\n * Any {@link remoteCommand} is appended after the connection flags, so\n * `forge ssh web uptime` runs `uptime` remotely and exits.\n */\nexport function buildSshArgs(target: SshTarget, remoteCommand: string[] = []): string[] {\n const args = [`${target.user}@${target.host}`, \"-p\", String(target.port)];\n if (remoteCommand.length > 0) {\n args.push(...remoteCommand);\n }\n return args;\n}\n","/**\n * CLI handler for `forge ssh` — open an interactive SSH session to a server.\n *\n * Resolves the server, reads its connection details from the API, then hands\n * off to the local `ssh` binary with an inherited stdio (interactive) session.\n */\n\nimport { spawnSync } from \"node:child_process\";\n\nimport { getServer } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { getCliAuditLogger } from \"../../audit.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\nimport { buildSshArgs, resolveSshTarget } from \"./ssh-target.ts\";\n\n/**\n * Connect to a server over SSH.\n *\n * @param server - Server ID or name (resolved via {@link resolveServerId}).\n * @param remote - Optional remote command to run instead of an interactive shell.\n * @param ctx - CLI command context.\n */\nexport async function sshConnect(\n server: string | undefined,\n remote: string[],\n ctx: CommandContext,\n): Promise<void> {\n if (!server) {\n exitWithValidationError(\"server\", \"forge ssh <server> [command...]\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const { data } = await getServer({ server_id }, execCtx);\n\n const target = resolveSshTarget(data, {\n user: typeof ctx.options.user === \"string\" ? ctx.options.user : undefined,\n private: ctx.options.private === true,\n port: typeof ctx.options.port === \"string\" ? ctx.options.port : undefined,\n });\n\n const sshArgs = buildSshArgs(target, remote);\n const printable = `ssh ${sshArgs.join(\" \")}`;\n\n // Script-safe modes: print the resolved command instead of opening a session.\n if (ctx.formatter.isJson()) {\n ctx.formatter.output({ command: printable, ...target, args: sshArgs });\n return;\n }\n if (ctx.options[\"dry-run\"] === true) {\n console.log(printable);\n return;\n }\n\n // Sanitized args for the audit log (never record the token).\n const auditArgs = {\n server: server_id,\n user: target.user,\n host: target.host,\n port: target.port,\n };\n\n try {\n const child = spawnSync(\"ssh\", sshArgs, { stdio: \"inherit\" });\n if (child.error) {\n throw child.error;\n }\n getCliAuditLogger().log({\n source: \"cli\",\n resource: \"ssh\",\n action: \"connect\",\n args: auditArgs,\n status: \"success\",\n });\n if (typeof child.status === \"number\" && child.status !== 0) {\n process.exit(child.status);\n }\n } catch (err) {\n getCliAuditLogger().log({\n source: \"cli\",\n resource: \"ssh\",\n action: \"connect\",\n args: auditArgs,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n }, ctx.formatter);\n}\n","import type { CommandOptions } from \"../../context.ts\";\n\nimport { createContext } from \"../../context.ts\";\nimport { sshConnect } from \"./handlers.ts\";\n\n/**\n * Route the top-level `forge ssh` command.\n *\n * Unlike resource commands there is no sub-action: the first positional is the\n * server, and any remaining positionals form an optional remote command.\n */\nexport async function handleSshCommand(\n server: string | undefined,\n remote: string[],\n options: CommandOptions,\n): Promise<void> {\n const ctx = createContext(options);\n await sshConnect(server, remote, ctx);\n}\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSshHelp(): void {\n console.log(`\n${colors.bold(\"forge ssh\")} - Open an SSH session to a server\n\n${colors.bold(\"USAGE:\")}\n forge ssh <server> [command...] [options]\n\n${colors.bold(\"ARGUMENTS:\")}\n <server> Server ID or name (required)\n [command...] Optional remote command to run, then exit\n\n${colors.bold(\"OPTIONS:\")}\n --user <name> SSH user (default: forge)\n --private Connect over the private IP address\n --port <n> Override the server's SSH port\n --dry-run Print the ssh command instead of connecting\n -f, --format json Print the resolved connection details as JSON\n -h, --help Show this help\n\n${colors.bold(\"EXAMPLES:\")}\n # Interactive session (connects as forge@<ip>)\n forge ssh my-server\n\n # Connect as a custom user\n forge ssh my-server --user deploy\n\n # Use the private network\n forge ssh my-server --private\n\n # Run a one-off remote command\n forge ssh my-server uptime\n\n # Just show the command that would run\n forge ssh my-server --dry-run\n\n${colors.bold(\"NOTES:\")}\n Requires your local SSH key to be authorized on the server; this command\n launches ssh, it does not upload keys.\n`);\n}\n","import { listSshKeys, getSshKey } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { resolveServerId } from \"../../utils/resolve.ts\";\n\nexport async function sshKeysList(ctx: CommandContext): Promise<void> {\n const server = String(ctx.options.server ?? \"\");\n\n if (!server) {\n exitWithValidationError(\"server_id\", \"forge ssh-keys list --server <server_id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await listSshKeys({ server_id }, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"status\"],\n \"No SSH keys found.\",\n (k) => `${String(k.id).padEnd(8)} ${k.name.padEnd(30)} ${k.status}`,\n );\n }, ctx.formatter);\n}\n\nexport async function sshKeysGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n const server = String(ctx.options.server ?? \"\");\n\n if (!id) {\n exitWithValidationError(\n \"ssh_key_id\",\n \"forge ssh-keys get <key_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n if (!server) {\n exitWithValidationError(\n \"server_id\",\n \"forge ssh-keys get <key_id> --server <server_id>\",\n ctx.formatter,\n );\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const server_id = await resolveServerId(server, execCtx);\n const result = await getSshKey({ server_id, id }, execCtx);\n ctx.formatter.outputOne(result.data, [\"id\", \"name\", \"status\", \"created_at\"]);\n }, ctx.formatter);\n}\n","/**\n * Pure logic for `forge ssh-keys sync`: parse an authorized_keys file, give each key\n * a stable managed name, and compare the file with the keys on a server.\n *\n * The Forge API does not return public keys, so keys are matched by name. The name\n * ends with a fingerprint of the key, so a changed key gets a new name.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport { ValidationError } from \"../../errors.ts\";\n\n/** The Forge API documents no name limit: keep names short enough to read in a list. */\nconst MAX_SLUG_LENGTH = 40;\n\nconst KEY_TYPE = /^(ssh-|ecdsa-sha2-|sk-)[a-z0-9@.-]+$/;\nconst BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;\n\n/**\n * Check the base64 key data of a public key, as OpenSSH does: it must be canonical\n * base64, and the decoded key must start with its own type as a length-prefixed string.\n */\nexport function isValidKeyBlob(type: string, blob: string): boolean {\n if (!BASE64.test(blob) || blob.length % 4 !== 0) {\n return false;\n }\n const data = Buffer.from(blob, \"base64\");\n if (data.toString(\"base64\") !== blob || data.length < 4) {\n return false;\n }\n const typeLength = data.readUInt32BE(0);\n return 4 + typeLength <= data.length && data.toString(\"latin1\", 4, 4 + typeLength) === type;\n}\n\n/** A public key from the file, with the name it gets on Forge. */\nexport interface FileKey {\n name: string;\n /** Public key as sent to Forge: \"<type> <base64> [comment]\". */\n key: string;\n /** Line number in the file (1-based). */\n line: number;\n}\n\n/** A key that exists on a server. */\nexport interface ServerKey {\n id: number;\n name: string;\n user: string;\n}\n\nexport interface SyncPlan {\n /** File keys that are not on the server. */\n add: FileKey[];\n /** Keys of the user on the server that are not in the file. */\n remove: ServerKey[];\n /** File keys that are already on the server. */\n unchanged: FileKey[];\n}\n\n/**\n * Convert a key comment to a name prefix: lowercase, `[a-z0-9-]` only, \"key\" when empty.\n */\nexport function slugify(comment: string): string {\n const slug = comment\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/g, \"-\")\n .slice(0, MAX_SLUG_LENGTH)\n .replaceAll(/^-+|-+$/g, \"\");\n return slug || \"key\";\n}\n\n/**\n * Managed name of a key: \"<slug(comment)>-<first 8 hex chars of the SHA-256 of the key blob>\".\n * The blob is the decoded base64 field, as in an OpenSSH fingerprint.\n */\nexport function managedKeyName(comment: string, blob: string): string {\n const hash = createHash(\"sha256\").update(Buffer.from(blob, \"base64\")).digest(\"hex\");\n return `${slugify(comment)}-${hash.slice(0, 8)}`;\n}\n\n/**\n * Parse an authorized_keys file: one \"<type> <base64> [comment]\" per line.\n * Blank lines and \"#\" comments are ignored.\n *\n * @throws ValidationError for a malformed or duplicate key, with its line number.\n */\nexport function parseAuthorizedKeys(content: string): FileKey[] {\n const keys: FileKey[] = [];\n const seen = new Map<string, number>();\n\n for (const [index, raw] of content.split(/\\r?\\n/).entries()) {\n const line = index + 1;\n const text = raw.trim();\n if (!text || text.startsWith(\"#\")) {\n continue;\n }\n\n // The error never repeats the line: a wrong --file (a .env, a secret) must not leak to logs.\n const [type, blob = \"\", ...rest] = text.split(/\\s+/);\n const problem = !KEY_TYPE.test(type)\n ? \"unknown key type\"\n : !isValidKeyBlob(type, blob)\n ? \"missing or invalid base64 key data\"\n : undefined;\n if (problem) {\n throw new ValidationError(\n `Line ${line}: ${problem}, expected \"<type> <base64> [comment]\"`,\n \"file\",\n [\"Use one public key per line, as in ~/.ssh/authorized_keys (no options prefix)\"],\n );\n }\n\n const first = seen.get(blob);\n if (first !== undefined) {\n throw new ValidationError(`Line ${line}: duplicate of the key on line ${first}`, \"file\");\n }\n seen.set(blob, line);\n\n const comment = rest.join(\" \");\n keys.push({\n name: managedKeyName(comment, blob),\n key: [type, blob, comment].filter(Boolean).join(\" \"),\n line,\n });\n }\n\n return keys;\n}\n\n/**\n * Compare the file keys with the keys on a server, for one user.\n * Keys of other users are ignored.\n */\nexport function planSync(fileKeys: FileKey[], serverKeys: ServerKey[], user: string): SyncPlan {\n const userKeys = serverKeys.filter((k) => k.user === user);\n const serverNames = new Set(userKeys.map((k) => k.name));\n const fileNames = new Set(fileKeys.map((k) => k.name));\n\n return {\n add: fileKeys.filter((k) => !serverNames.has(k.name)),\n remove: userKeys.filter((k) => !fileNames.has(k.name)),\n unchanged: fileKeys.filter((k) => serverNames.has(k.name)),\n };\n}\n","import type { ExecutorContext } from \"@studiometa/forge-core\";\nimport { createSshKey, deleteSshKey, listServers, listSshKeys } from \"@studiometa/forge-core\";\n\nimport type { CliExecutorContext, CommandContext } from \"../../context.ts\";\nimport type { FileKey, SyncPlan } from \"./sync-plan.ts\";\n\nimport {\n ExitCode,\n exitWithError,\n exitWithValidationError,\n runCommand,\n} from \"../../error-handler.ts\";\nimport { ValidationError } from \"../../errors.ts\";\nimport { colors } from \"../../utils/colors.ts\";\nimport { readContentFile } from \"../../utils/content-source.ts\";\nimport { matchServerId } from \"../../utils/resolve.ts\";\nimport { parseAuthorizedKeys, planSync } from \"./sync-plan.ts\";\n\nconst USAGE =\n \"forge ssh-keys sync --file <path|-> (--server <id>... | --all-servers) [--user <name>] [--prune] [--dry-run]\";\n\n/** Sync state and outcome of one server. */\ninterface ServerSync {\n id: number;\n name: string;\n plan?: SyncPlan;\n added: string[];\n removed: string[];\n unchanged: string[];\n errors: string[];\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Read the --server values: repeated and/or comma separated.\n */\nfunction serverValues(value: unknown): string[] {\n return [value]\n .flat()\n .filter((v): v is string => typeof v === \"string\")\n .flatMap((v) => v.split(\",\"))\n .map((v) => v.trim())\n .filter(Boolean);\n}\n\n/**\n * Read and parse the --file option. Exits on a missing, unreadable, malformed or empty file.\n */\nfunction readFileKeys(ctx: CommandContext): FileKey[] {\n const { file } = ctx.options;\n const content = readContentFile(file, \"file\", {\n label: \"SSH keys file\",\n usage: USAGE,\n formatter: ctx.formatter,\n });\n\n let keys: FileKey[];\n try {\n keys = parseAuthorizedKeys(content);\n } catch (error) {\n // parseAuthorizedKeys only throws a ValidationError with the line number.\n exitWithError(error as ValidationError, ctx.formatter);\n }\n\n if (keys.length === 0) {\n exitWithError(\n new ValidationError(`No SSH keys found in ${String(file)}`, \"file\"),\n ctx.formatter,\n );\n }\n\n return keys;\n}\n\n/**\n * Resolve the target servers to ids and names, without duplicates.\n * Names are matched against one list of servers: one API call for all targets.\n */\nasync function resolveTargets(\n values: string[],\n allServers: boolean,\n execCtx: CliExecutorContext,\n): Promise<Array<{ id: number; name: string }>> {\n const servers = (await listServers({}, execCtx)).data;\n if (allServers) {\n return servers.map((s) => ({ id: s.id, name: s.name }));\n }\n\n const targets = new Map<number, string>();\n for (const value of values) {\n const id = Number(matchServerId(value, servers, execCtx.exactMatch));\n targets.set(id, servers.find((s) => s.id === id)?.name ?? String(id));\n }\n return [...targets].map(([id, name]) => ({ id, name }));\n}\n\nfunction printPlan(syncs: ServerSync[], user: string, prune: boolean): void {\n for (const sync of syncs) {\n console.log(colors.bold(`${sync.name} (${sync.id})`));\n for (const error of sync.errors) {\n console.log(colors.red(` ✗ ${error}`));\n }\n if (!sync.plan) continue;\n\n const { add, remove, unchanged } = sync.plan;\n for (const key of add) console.log(colors.green(` + ${key.name}`));\n if (prune) {\n for (const key of remove) console.log(colors.red(` - ${key.name}`));\n }\n for (const key of unchanged) console.log(colors.dim(` = ${key.name}`));\n if (!prune && remove.length > 0) {\n console.log(\n colors.yellow(\n ` ${remove.length} key(s) of user \"${user}\" not in the file are kept (use --prune to remove them)`,\n ),\n );\n }\n }\n}\n\nfunction printResult(syncs: ServerSync[]): void {\n for (const sync of syncs) {\n const summary = `${sync.name} (${sync.id}): ${sync.added.length} added, ${sync.removed.length} removed, ${sync.unchanged.length} unchanged`;\n if (sync.errors.length === 0) {\n console.log(colors.green(`✓ ${summary}`));\n continue;\n }\n console.log(colors.red(`✗ ${summary}, ${sync.errors.length} failed`));\n for (const error of sync.errors) {\n console.log(colors.red(` ${error}`));\n }\n }\n}\n\n/**\n * Apply a plan to one server. Each failed operation is recorded and the next one runs.\n * When an add fails, the removals are skipped: the user must not lose access to the server.\n */\nasync function applyPlan(\n sync: ServerSync,\n plan: SyncPlan,\n user: string,\n prune: boolean,\n execCtx: ExecutorContext,\n): Promise<void> {\n const server_id = String(sync.id);\n\n let addFailed = false;\n for (const key of plan.add) {\n try {\n await createSshKey({ server_id, name: key.name, key: key.key, user }, execCtx);\n sync.added.push(key.name);\n } catch (error) {\n addFailed = true;\n sync.errors.push(`add ${key.name}: ${errorMessage(error)}`);\n }\n }\n\n if (!prune) return;\n\n for (const key of plan.remove) {\n if (addFailed) {\n sync.errors.push(`remove ${key.name}: skipped because an add failed`);\n continue;\n }\n try {\n await deleteSshKey({ server_id, id: String(key.id) }, execCtx);\n sync.removed.push(key.name);\n } catch (error) {\n sync.errors.push(`remove ${key.name}: ${errorMessage(error)}`);\n }\n }\n}\n\n/**\n * Make the SSH keys of a user on one or more servers match an authorized_keys file.\n */\nexport async function sshKeysSync(ctx: CommandContext): Promise<void> {\n const { options, formatter } = ctx;\n const servers = serverValues(options.server);\n const allServers = options[\"all-servers\"] === true;\n const userOption = options.user;\n const prune = options.prune === true;\n const dryRun = options[\"dry-run\"] === true;\n\n if (options.file === undefined) {\n exitWithValidationError(\"file\", USAGE, formatter);\n }\n\n if (userOption !== undefined && (typeof userOption !== \"string\" || userOption === \"\")) {\n exitWithError(\n new ValidationError(\"--user requires a name\", \"user\", [`Usage: ${USAGE}`]),\n formatter,\n );\n }\n const user = typeof userOption === \"string\" ? userOption : \"forge\";\n\n if (allServers && options.server !== undefined) {\n exitWithError(\n new ValidationError(\"Use either --server or --all-servers, not both\", \"server\", [\n `Usage: ${USAGE}`,\n ]),\n formatter,\n );\n }\n\n if (!allServers && servers.length === 0) {\n exitWithError(\n new ValidationError(\"A target is required: --server <id> or --all-servers\", \"server\", [\n `Usage: ${USAGE}`,\n ]),\n formatter,\n );\n }\n\n const fileKeys = readFileKeys(ctx);\n\n const failed = await runCommand(async () => {\n const execCtx = ctx.createExecutorContext(ctx.getToken());\n const targets = await resolveTargets(servers, allServers, execCtx);\n\n // Servers run one after the other: the rate limiter allows 60 requests per minute.\n const syncs: ServerSync[] = [];\n for (const { id, name } of targets) {\n const sync: ServerSync = { id, name, added: [], removed: [], unchanged: [], errors: [] };\n try {\n const keys = await listSshKeys({ server_id: String(id), user }, execCtx);\n sync.plan = planSync(fileKeys, keys.data, user);\n sync.unchanged = sync.plan.unchanged.map((k) => k.name);\n } catch (error) {\n sync.errors.push(`list keys: ${errorMessage(error)}`);\n }\n syncs.push(sync);\n }\n\n const json = formatter.isJson();\n if (!json) {\n printPlan(syncs, user, prune);\n }\n\n if (dryRun) {\n for (const sync of syncs) {\n if (!sync.plan) continue;\n sync.added = sync.plan.add.map((k) => k.name);\n if (prune) sync.removed = sync.plan.remove.map((k) => k.name);\n }\n if (!json) console.log(colors.cyan(\"\\nDry run: no changes made.\"));\n } else {\n for (const sync of syncs) {\n if (sync.plan) {\n await applyPlan(sync, sync.plan, user, prune, execCtx);\n }\n }\n if (!json) {\n console.log(\"\");\n printResult(syncs);\n }\n }\n\n if (json) {\n console.log(\n JSON.stringify(\n {\n dry_run: dryRun,\n servers: syncs.map(({ id, name, added, removed, unchanged, errors }) => ({\n id,\n name,\n added,\n removed,\n unchanged,\n errors,\n })),\n },\n null,\n 2,\n ),\n );\n }\n\n return syncs.reduce((count, sync) => count + sync.errors.length, 0);\n }, formatter);\n\n // The errors are already in the output: exit without a second (JSON) error document.\n if (failed) {\n if (!formatter.isJson()) {\n formatter.error(`${failed} SSH key operation(s) failed`);\n }\n process.exit(ExitCode.GENERAL_ERROR);\n }\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { sshKeysList, sshKeysGet } from \"./handlers.ts\";\nimport { sshKeysSync } from \"./sync.ts\";\n\nexport const handleSshKeysCommand = createCommandRouter({\n resource: \"ssh-keys\",\n handlers: {\n list: sshKeysList,\n ls: sshKeysList,\n get: [sshKeysGet, \"args\"],\n sync: sshKeysSync,\n },\n writeSubcommands: [\"sync\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showSshKeysHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge ssh-keys list\")} - List SSH keys on a server\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys list --server <server_id> [options]\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge ssh-keys get\")} - Get SSH key details\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys get <key_id> --server <server_id>\n`);\n } else if (subcommand === \"sync\") {\n console.log(`\n${colors.bold(\"forge ssh-keys sync\")} - Make the SSH keys of servers match a file\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys sync --file <path|-> --server <id> [--server <id>...] [options]\n forge ssh-keys sync --file <path|-> --all-servers [options]\n\n${colors.bold(\"OPTIONS:\")}\n --file <path> authorized_keys file: one \"<type> <base64> [comment]\" per line,\n blank lines and # comments ignored (use - for stdin)\n --server <id> Target server ID or name (repeatable or comma separated)\n --all-servers Target every server in the organization\n --user <name> Server user of the keys (default: forge)\n --prune Also remove the keys of the user that are not in the file\n --dry-run Print the plan and change nothing\n -f, --format <fmt> Output format: json, human\n\n${colors.bold(\"HOW IT WORKS:\")}\n Each key gets the name \"<comment slug>-<first 8 hex chars of SHA-256 of the key>\".\n The Forge API does not return public keys, so keys are matched by name: a changed\n key gets a new name. The command lists the plan per server (+ add, - remove,\n = unchanged), applies it, then prints the result. Without --prune, keys are only\n added. Servers run one after the other; when an operation fails, the others still\n run and the command exits non-zero. When an add fails on a server, the removals on\n that server are skipped, so nobody loses access.\n\n${colors.bold(\"JSON OUTPUT:\")}\n { \"dry_run\": bool, \"servers\": [{ id, name, added, removed, unchanged, errors }] }\n With --dry-run, \"added\" and \"removed\" hold the planned changes, not applied ones.\n\n${colors.bold(\"EXAMPLES:\")}\n forge ssh-keys sync --file .forge/authorized_keys --server 123 --dry-run\n forge ssh-keys sync --file .forge/authorized_keys --all-servers --prune\n cat keys.pub | forge ssh-keys sync --file - --server web-1,web-2 --user deploy\n`);\n } else {\n console.log(`\n${colors.bold(\"forge ssh-keys\")} - Manage SSH keys\n\n${colors.bold(\"USAGE:\")}\n forge ssh-keys <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List SSH keys\n get <id> Get SSH key details\n sync Make the SSH keys of servers match a file\n\n${colors.bold(\"OPTIONS:\")}\n --server <id> Server ID or name (required, except for sync --all-servers)\n --file <path> authorized_keys file, - for stdin (for sync)\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge ssh-keys <subcommand> --help\")} for details.\n`);\n }\n}\n","import type { StorageProviderAttributes } from \"@studiometa/forge-api\";\n\nimport { STORAGE_PROVIDER_TYPES } from \"@studiometa/forge-api\";\nimport {\n createStorageProvider,\n deleteStorageProvider,\n getStorageProvider,\n listStorageProviders,\n} from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { exitWithError, exitWithValidationError, runCommand } from \"../../error-handler.ts\";\nimport { ValidationError } from \"../../errors.ts\";\nimport { readContentFile } from \"../../utils/content-source.ts\";\n\ntype StorageProvider = StorageProviderAttributes & { id: number };\n\nconst FIELDS: Array<keyof StorageProvider> = [\n \"id\",\n \"name\",\n \"provider\",\n \"provider_name\",\n \"endpoint\",\n \"region\",\n \"bucket\",\n \"directory\",\n \"in_use\",\n];\n\nconst CREATE_USAGE =\n \"forge storage-providers create --name <name> --provider <type> [--endpoint <url>] [--region <region>] [--bucket <bucket>] [--access-key <id>] [--secret-key-file <path|->]\";\n\nexport async function storageProvidersList(ctx: CommandContext): Promise<void> {\n const provider = typeof ctx.options.provider === \"string\" ? ctx.options.provider : undefined;\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await listStorageProviders(provider ? { provider } : {}, execCtx);\n ctx.formatter.outputList(\n result.data,\n [\"id\", \"name\", \"provider\", \"bucket\", \"in_use\"],\n \"No storage providers found.\",\n (p) =>\n `${String(p.id).padEnd(8)} ${p.name.padEnd(24)} ${p.provider.padEnd(10)} ${p.bucket ?? \"—\"}${p.in_use ? \" (in use)\" : \"\"}`,\n );\n }, ctx.formatter);\n}\n\nexport async function storageProvidersGet(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge storage-providers get <id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getStorageProvider({ id }, execCtx);\n ctx.formatter.outputOne(result.data, FIELDS);\n }, ctx.formatter);\n}\n\n/**\n * Read an optional string option. A flag given without a value is a validation error.\n */\nfunction stringOption(ctx: CommandContext, name: string): string | undefined {\n const value = ctx.options[name];\n if (value === undefined) return undefined;\n if (typeof value !== \"string\" || !value) {\n exitWithError(\n new ValidationError(`--${name} requires a value`, name, [`Usage: ${CREATE_USAGE}`]),\n ctx.formatter,\n );\n }\n return value;\n}\n\nexport async function storageProvidersCreate(ctx: CommandContext): Promise<void> {\n const name = ctx.options.name;\n const provider = ctx.options.provider;\n\n if (typeof name !== \"string\" || !name) {\n exitWithValidationError(\"name\", CREATE_USAGE, ctx.formatter);\n }\n\n if (typeof provider !== \"string\" || !provider) {\n exitWithValidationError(\"provider\", CREATE_USAGE, ctx.formatter);\n }\n\n if (!(STORAGE_PROVIDER_TYPES as readonly string[]).includes(provider)) {\n exitWithError(\n new ValidationError(\n `Invalid provider \"${provider}\": use ${STORAGE_PROVIDER_TYPES.join(\", \")}`,\n \"provider\",\n ),\n ctx.formatter,\n );\n }\n\n const endpoint = stringOption(ctx, \"endpoint\");\n const region = stringOption(ctx, \"region\");\n const bucket = stringOption(ctx, \"bucket\");\n const directory = stringOption(ctx, \"directory\");\n const accessKey = stringOption(ctx, \"access-key\");\n\n // The secret key is read from a file or stdin, never from the command line,\n // so it does not show in the shell history or the process list. Only one\n // trailing newline is removed (as `echo` or an editor adds it): a secret is kept as is.\n const secretKey =\n ctx.options[\"secret-key-file\"] === undefined\n ? undefined\n : readContentFile(ctx.options[\"secret-key-file\"], \"secret-key-file\", {\n label: \"secret key\",\n usage: CREATE_USAGE,\n formatter: ctx.formatter,\n }).replace(/\\r?\\n$/, \"\");\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await createStorageProvider(\n {\n name,\n provider: provider as (typeof STORAGE_PROVIDER_TYPES)[number],\n ...(endpoint !== undefined ? { endpoint } : {}),\n ...(region !== undefined ? { region } : {}),\n ...(bucket !== undefined ? { bucket } : {}),\n ...(directory !== undefined ? { directory } : {}),\n ...(accessKey !== undefined ? { access_key: accessKey } : {}),\n ...(secretKey !== undefined ? { secret_key: secretKey } : {}),\n ...(ctx.options[\"assume-role\"] === true ? { assume_role: true } : {}),\n },\n execCtx,\n );\n ctx.formatter.outputOne(result.data, FIELDS);\n }, ctx.formatter);\n}\n\nexport async function storageProvidersDelete(args: string[], ctx: CommandContext): Promise<void> {\n const [id] = args;\n\n if (!id) {\n exitWithValidationError(\"id\", \"forge storage-providers delete <id>\", ctx.formatter);\n }\n\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n await deleteStorageProvider({ id }, execCtx);\n ctx.formatter.success(`Storage provider ${id} deleted.`);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport {\n storageProvidersCreate,\n storageProvidersDelete,\n storageProvidersGet,\n storageProvidersList,\n} from \"./handlers.ts\";\n\nexport const handleStorageProvidersCommand = createCommandRouter({\n resource: \"storage-providers\",\n handlers: {\n list: storageProvidersList,\n ls: storageProvidersList,\n get: [storageProvidersGet, \"args\"],\n create: storageProvidersCreate,\n delete: [storageProvidersDelete, \"args\"],\n },\n writeSubcommands: [\"create\", \"delete\"],\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showStorageProvidersHelp(subcommand?: string): void {\n if (subcommand === \"list\" || subcommand === \"ls\") {\n console.log(`\n${colors.bold(\"forge storage-providers list\")} - List the organization's storage providers\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers list [options]\n\n${colors.bold(\"OPTIONS:\")}\n --provider <type> Only list one provider type (s3, spaces, hetzner, ovh, scaleway, custom)\n -f, --format <fmt> Output format: json, human, table\n`);\n } else if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge storage-providers get\")} - Get storage provider details\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers get <id> [options]\n\nForge never returns the access key or the secret key.\n`);\n } else if (subcommand === \"create\") {\n console.log(`\n${colors.bold(\"forge storage-providers create\")} - Create a storage provider for database backups\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers create --name <name> --provider <type> [options]\n\n${colors.bold(\"OPTIONS:\")}\n --name <name> Provider name (required)\n --provider <type> s3, spaces, hetzner, ovh, scaleway or custom (S3 compatible) (required)\n --endpoint <url> S3 endpoint URL (custom providers)\n --region <region> Bucket region\n --bucket <bucket> Default bucket\n --directory <dir> Default directory in the bucket\n --access-key <id> Access key ID\n --secret-key-file <path> Read the secret key from a file, or from stdin with -\n --assume-role Use the EC2 instance role instead of keys (s3)\n -f, --format <fmt> Output format: json, human, table\n\nThe secret key is not accepted as an option value, so it does not show in the\nshell history or the process list. One trailing newline is removed.\n\n${colors.bold(\"EXAMPLE:\")}\n printf '%s' \"$S3_SECRET_KEY\" | forge storage-providers create --name Backups \\\\\n --provider custom --endpoint https://s3.example.com --region eu-west-1 \\\\\n --bucket my-bucket --access-key \"$S3_ACCESS_KEY\" --secret-key-file - --format json\n`);\n } else if (subcommand === \"delete\") {\n console.log(`\n${colors.bold(\"forge storage-providers delete\")} - Delete a storage provider\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers delete <id> [options]\n\nForge refuses to delete a provider that a backup configuration uses.\n`);\n } else {\n console.log(`\n${colors.bold(\"forge storage-providers\")} - Manage the storage providers of database backups\n\n${colors.bold(\"USAGE:\")}\n forge storage-providers <subcommand> [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n list, ls List storage providers\n get <id> Get storage provider details\n create Create a storage provider\n delete <id> Delete a storage provider\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge storage-providers <subcommand> --help\")} for details.\n`);\n }\n}\n","import { getUser } from \"@studiometa/forge-core\";\n\nimport type { CommandContext } from \"../../context.ts\";\n\nimport { runCommand } from \"../../error-handler.ts\";\n\nexport async function userGet(ctx: CommandContext): Promise<void> {\n await runCommand(async () => {\n const token = ctx.getToken();\n const execCtx = ctx.createExecutorContext(token);\n const result = await getUser({}, execCtx);\n ctx.formatter.output(result.data);\n }, ctx.formatter);\n}\n","import { createCommandRouter } from \"../../utils/command-router.ts\";\nimport { userGet } from \"./handlers.ts\";\n\nexport const handleUserCommand = createCommandRouter({\n resource: \"user\",\n handlers: {\n get: userGet,\n },\n});\n","import { colors } from \"../../utils/colors.ts\";\n\nexport function showUserHelp(subcommand?: string): void {\n if (subcommand === \"get\") {\n console.log(`\n${colors.bold(\"forge user get\")} - Get the authenticated user profile\n\n${colors.bold(\"USAGE:\")}\n forge user get [options]\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n`);\n } else {\n console.log(`\n${colors.bold(\"forge user\")} - Display authenticated user profile\n\n${colors.bold(\"USAGE:\")}\n forge user [subcommand] [options]\n\n${colors.bold(\"SUBCOMMANDS:\")}\n get Get the authenticated user profile\n\n${colors.bold(\"OPTIONS:\")}\n -f, --format <fmt> Output format: json, human, table\n\nRun ${colors.cyan(\"forge user <subcommand> --help\")} for details.\n`);\n }\n}\n","/**\n * Simple argument parser using native Node.js.\n * Parses process.argv into a structured format with no external deps.\n */\n\nexport type OptionValue = string | boolean | string[];\nexport type CommandOptions = Record<string, OptionValue>;\n\nexport interface ParsedArgs {\n command: string[];\n options: Record<string, OptionValue>;\n positional: string[];\n}\n\n/**\n * Whether an argument can be the value of the option before it.\n * A lone \"-\" is a value (it means stdin), other \"-\" prefixed arguments are options.\n */\nfunction isOptionValue(arg: string): boolean {\n return arg === \"-\" || !arg.startsWith(\"-\");\n}\n\n/**\n * Options that accept several values. Every other option keeps the last value.\n */\nconst REPEATABLE = new Set([\"server\", \"tag\", \"databases\"]);\n\n/**\n * Long options that never take a value, so the argument after them stays a command\n * or a positional argument (`forge --exact deployments deploy`).\n */\nconst FLAGS = new Set([\"exact\"]);\n\n/**\n * Set an option value. A repeatable option given more than once collects its string\n * values into an array (`--server 1 --server 2` → `[\"1\", \"2\"]`).\n */\nfunction setOption(\n options: Record<string, OptionValue>,\n key: string,\n value: string | boolean,\n): void {\n const previous = options[key];\n if (\n REPEATABLE.has(key) &&\n typeof value === \"string\" &&\n previous !== undefined &&\n typeof previous !== \"boolean\"\n ) {\n options[key] = [previous, value].flat();\n } else {\n options[key] = value;\n }\n}\n\nexport function parseArgs(argv: string[] = process.argv.slice(2)): ParsedArgs {\n const options: Record<string, OptionValue> = {};\n const positional: string[] = [];\n const command: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (arg.startsWith(\"--\")) {\n // Long option: --key=value or --key value or --flag\n const equalIndex = arg.indexOf(\"=\");\n if (equalIndex > -1) {\n const key = arg.slice(2, equalIndex);\n const value = arg.slice(equalIndex + 1);\n setOption(options, key, value);\n } else {\n const key = arg.slice(2);\n const nextArg = argv[i + 1];\n\n if (!FLAGS.has(key) && nextArg !== undefined && isOptionValue(nextArg)) {\n setOption(options, key, nextArg);\n i++;\n } else {\n setOption(options, key, true);\n }\n }\n } else if (arg.startsWith(\"-\") && arg.length > 1) {\n // Short option: -k value or -abc (multiple flags)\n if (arg.length === 2) {\n const key = arg[1];\n const nextArg = argv[i + 1];\n\n if (nextArg !== undefined && isOptionValue(nextArg)) {\n setOption(options, key, nextArg);\n i++;\n } else {\n setOption(options, key, true);\n }\n } else {\n // Multiple short flags: -abc -> -a -b -c\n for (let j = 1; j < arg.length; j++) {\n options[arg[j]] = true;\n }\n }\n } else {\n // Positional argument or command\n // First two non-option args are command and subcommand\n if (command.length < 2) {\n command.push(arg);\n } else {\n positional.push(arg);\n }\n }\n }\n\n return { command, options, positional };\n}\n\nexport function getOption(\n options: Record<string, OptionValue>,\n names: string[],\n defaultValue?: string,\n): string | undefined {\n for (const name of names) {\n if (name in options) {\n const value = options[name];\n return typeof value === \"string\" ? value : undefined;\n }\n }\n return defaultValue;\n}\n\nexport function hasFlag(options: Record<string, OptionValue>, names: string[]): boolean {\n return names.some((name) => options[name] === true);\n}\n\n/**\n * Whether the arguments ask for the CLI version: a bare `--version` or `-v`\n * with no command. Commands such as `php config` and `services restart` take\n * `--version <value>`, so a bare `--version` after a command is not a version request.\n */\nexport function isVersionRequest({ command, options }: ParsedArgs): boolean {\n return command.length === 0 && (options.version === true || options.v === true);\n}\n","#!/usr/bin/env node\n\nimport { handleBackupsCommand, showBackupsHelp } from \"./commands/backups/index.ts\";\nimport { handleCompletionCommand, showCompletionHelp } from \"./commands/completion.ts\";\nimport { handleCertificatesCommand, showCertificatesHelp } from \"./commands/certificates/index.ts\";\nimport { handleCommandsCommand, showCommandsHelp } from \"./commands/commands/index.ts\";\nimport { handleConfigCommand, showConfigHelp } from \"./commands/config.ts\";\nimport { handleDaemonsCommand, showDaemonsHelp } from \"./commands/daemons/index.ts\";\nimport { handleDatabasesCommand, showDatabasesHelp } from \"./commands/databases/index.ts\";\nimport {\n handleDatabaseUsersCommand,\n showDatabaseUsersHelp,\n} from \"./commands/database-users/index.ts\";\nimport { handleDeploymentsCommand, showDeploymentsHelp } from \"./commands/deployments/index.ts\";\nimport { handleEnvCommand, showEnvHelp } from \"./commands/env/index.ts\";\nimport {\n handleFirewallRulesCommand,\n showFirewallRulesHelp,\n} from \"./commands/firewall-rules/index.ts\";\nimport { handleMonitorsCommand, showMonitorsHelp } from \"./commands/monitors/index.ts\";\nimport { handleNginxCommand, showNginxHelp } from \"./commands/nginx/index.ts\";\nimport {\n handleNginxTemplatesCommand,\n showNginxTemplatesHelp,\n} from \"./commands/nginx-templates/index.ts\";\nimport { handlePhpCommand, showPhpHelp } from \"./commands/php/index.ts\";\nimport { handleRecipesCommand, showRecipesHelp } from \"./commands/recipes/index.ts\";\nimport {\n handleRedirectRulesCommand,\n showRedirectRulesHelp,\n} from \"./commands/redirect-rules/index.ts\";\nimport {\n handleScheduledJobsCommand,\n showScheduledJobsHelp,\n} from \"./commands/scheduled-jobs/index.ts\";\nimport {\n handleSecurityRulesCommand,\n showSecurityRulesHelp,\n} from \"./commands/security-rules/index.ts\";\nimport { handleServersCommand, showServersHelp } from \"./commands/servers/index.ts\";\nimport { handleServicesCommand, showServicesHelp } from \"./commands/services/index.ts\";\nimport { handleSitesCommand, showSitesHelp } from \"./commands/sites/index.ts\";\nimport { handleSshCommand, showSshHelp } from \"./commands/ssh/index.ts\";\nimport { handleSshKeysCommand, showSshKeysHelp } from \"./commands/ssh-keys/index.ts\";\nimport {\n handleStorageProvidersCommand,\n showStorageProvidersHelp,\n} from \"./commands/storage-providers/index.ts\";\nimport { handleUserCommand, showUserHelp } from \"./commands/user/index.ts\";\nimport { colors, setColorEnabled } from \"./utils/colors.ts\";\nimport { isVersionRequest, parseArgs } from \"./utils/args.ts\";\n\ndeclare const __VERSION__: string;\nconst VERSION = __VERSION__;\n\nfunction showHelp(): void {\n console.log(`\n${colors.bold(\"forge\")} v${VERSION}\n\n${colors.bold(\"USAGE:\")}\n forge <command> [subcommand] [options]\n\n${colors.bold(\"COMMANDS:\")}\n config Manage CLI configuration\n set <token> Save API token\n get Show current token (masked)\n delete Delete stored token\n\n servers, s Manage servers\n list, ls List all servers\n get <id> Get server details\n create Create a server (requires --name, and --ip-address for custom)\n reboot <id> Reboot a server\n\n sites Manage sites\n list, ls List sites (requires --server)\n get <id> Get site details (requires --server)\n apply Make a site match a site file (--file, --check)\n\n deployments, d Manage deployments\n list, ls List deployments (requires --server --site)\n deploy Trigger a deployment (requires --server --site)\n logs [id] Show deployment output (requires --server --site)\n script Show the deployment script (requires --server --site)\n update-script Update the deployment script (requires --server --site --file|--content) [--check]\n\n databases, db Manage databases\n list, ls List databases (requires --server)\n get <id> Get database details (requires --server)\n\n database-users Manage database users\n list, ls List database users (requires --server)\n get <id> Get database user details (requires --server)\n create Create a database user (requires --server --name --password)\n delete <id> Delete a database user (requires --server)\n\n daemons Manage daemons\n list, ls List daemons (requires --server)\n get <id> Get daemon details (requires --server)\n restart <id> Restart a daemon (requires --server)\n\n env Manage environment variables\n get Get env variables (requires --server --site)\n update Update env variables (requires --server --site --file|--content) [--check]\n\n nginx Manage nginx configuration\n get Get nginx config (requires --server --site)\n update Update nginx config (requires --server --site --file|--content) [--check]\n\n certificates, certs Manage SSL certificates (per-domain in v2)\n get Get certificate for a domain (requires --server --site --domain)\n get <id> Get certificate details (requires --server --site)\n activate <id> Activate a certificate (requires --server --site)\n\n firewall-rules, fw Manage firewall rules\n list, ls List firewall rules (requires --server)\n get <id> Get firewall rule details (requires --server)\n\n ssh <server> Open an SSH session to a server\n --user <name> (default: forge), --private, --port <n>\n\n ssh-keys Manage SSH keys\n list, ls List SSH keys (requires --server)\n get <id> Get SSH key details (requires --server)\n sync Make server SSH keys match a file (requires --file, --server|--all-servers)\n\n backups Manage database backup configurations\n list, ls List backup configurations (requires --server)\n get <id> Get backup configuration details (requires --server)\n create Create a backup configuration (requires --server --storage-provider --frequency --databases)\n update <id> Update a backup configuration (requires --server --storage-provider --frequency --retention --databases)\n delete <id> Delete a backup configuration (requires --server)\n\n storage-providers Manage the storage providers of database backups\n list, ls List storage providers\n get <id> Get storage provider details\n create Create a storage provider (requires --name --provider)\n delete <id> Delete a storage provider\n\n commands Manage site commands\n list, ls List commands (requires --server --site)\n get <id> Get command details (requires --server --site)\n create Execute a command (requires --server --site --command)\n\n scheduled-jobs Manage scheduled jobs (cron)\n list, ls List scheduled jobs (requires --server)\n get <id> Get scheduled job details (requires --server)\n create Create a scheduled job (requires --server --command)\n delete <id> Delete a scheduled job (requires --server)\n\n services List and restart server services\n list, ls List services on a server (forge services list <server>)\n restart <service> Restart a service (forge services restart <server> <service>)\n\n php Manage PHP versions, configuration, limits and OPcache\n list, ls List installed PHP versions (requires --server)\n config Show a configuration file (requires --server --version --type)\n update-config Replace a configuration file (requires --server --version --type --file|--content) [--check]\n max-upload-size Show the max upload size (requires --server)\n set-max-upload-size <mb>\n Set the max upload size (requires --server)\n max-execution-time Show the max execution time (requires --server)\n set-max-execution-time <seconds>\n Set the max execution time (requires --server)\n opcache Show the OPcache status (requires --server)\n enable-opcache Enable OPcache (requires --server)\n disable-opcache Disable OPcache (requires --server)\n\n user Display authenticated user profile\n get Get the authenticated user profile\n\n monitors Manage server monitors\n list, ls List monitors (requires --server)\n get <id> Get monitor details (requires --server)\n create Create a monitor (requires --server --type --operator --threshold --minutes)\n delete <id> Delete a monitor (requires --server)\n\n nginx-templates Manage Nginx templates\n list, ls List Nginx templates (requires --server)\n get <id> Get Nginx template details (requires --server)\n create Create a Nginx template (requires --server --name --content)\n update <id> Update a Nginx template (requires --server)\n delete <id> Delete a Nginx template (requires --server)\n\n security-rules Manage site security rules\n list, ls List security rules (requires --server --site)\n get <id> Get security rule details (requires --server --site)\n create Create a security rule (requires --server --site --name)\n delete <id> Delete a security rule (requires --server --site)\n\n redirect-rules Manage site redirect rules\n list, ls List redirect rules (requires --server --site)\n get <id> Get redirect rule details (requires --server --site)\n create Create a redirect rule (requires --server --site --from --to)\n delete <id> Delete a redirect rule (requires --server --site)\n\n recipes Manage recipes\n list, ls List all recipes\n get <id> Get recipe details\n run <id> Run a recipe (requires --servers)\n\n completion Generate shell completion script\n bash Install Bash completion\n zsh Install Zsh completion\n fish Install Fish completion\n\n${colors.bold(\"OPTIONS:\")}\n --token <token> Forge API token (overrides config and env)\n --org <slug> Organization slug (overrides config and FORGE_ORG)\n --server <id> Server ID (required for server-scoped commands)\n --site <id> Site ID (required for site-scoped commands)\n --exact Match --server and --site names exactly (no partial match)\n --domain <id> Domain record ID (for certificate commands)\n -f, --format <fmt> Output format: json, human, table (default: human)\n --no-color Disable colored output\n -h, --help Show help\n -v, --version Show version\n\n${colors.bold(\"EXAMPLES:\")}\n # Configure API token\n forge config set YOUR_TOKEN\n\n # Or pass token directly\n forge servers list --token YOUR_TOKEN\n\n # List all servers\n forge servers list\n\n # List sites on a server\n forge sites list --server 123\n\n # Deploy a site\n forge deployments deploy --server 123 --site 456\n\n # Get JSON output (for AI agents)\n forge servers list --format json\n\n${colors.bold(\"CREDENTIAL PRIORITY:\")}\n 1. CLI argument (--token)\n 2. Environment variable (FORGE_API_TOKEN)\n 3. Config file (~/.config/forge-tools/config.json)\n\n${colors.bold(\"ENVIRONMENT VARIABLES:\")}\n FORGE_API_TOKEN API token\n FORGE_ORG Organization slug (e.g. studio-meta)\n FORGE_EXACT_MATCH Set to 1 to match --server and --site names exactly (same as --exact)\n NO_COLOR Disable colors\n XDG_CONFIG_HOME Config directory (respects XDG spec)\n`);\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs();\n const { command, options, positional } = args;\n\n const [mainCommand, subcommand] = command;\n const wantsHelp = options.help !== undefined || options.h !== undefined;\n\n if (wantsHelp && !mainCommand) {\n showHelp();\n process.exit(0);\n }\n\n // Only a bare `--version`/`-v` with no command is the version request. After a\n // command, `--version` is a command option (e.g. `forge php config --version 8.3`),\n // and a missing value must reach the command to fail its validation.\n if (isVersionRequest(args)) {\n console.log(VERSION);\n process.exit(0);\n }\n\n if (options[\"no-color\"]) {\n setColorEnabled(false);\n }\n\n if (!mainCommand) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (mainCommand) {\n case \"config\":\n if (wantsHelp) {\n showConfigHelp();\n process.exit(0);\n }\n handleConfigCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"servers\":\n case \"s\":\n if (wantsHelp) {\n showServersHelp(subcommand);\n process.exit(0);\n }\n await handleServersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"sites\":\n if (wantsHelp) {\n showSitesHelp(subcommand);\n process.exit(0);\n }\n await handleSitesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"deployments\":\n case \"d\":\n if (wantsHelp) {\n showDeploymentsHelp(subcommand);\n process.exit(0);\n }\n await handleDeploymentsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"databases\":\n case \"db\":\n if (wantsHelp) {\n showDatabasesHelp(subcommand);\n process.exit(0);\n }\n await handleDatabasesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"database-users\":\n if (wantsHelp) {\n showDatabaseUsersHelp(subcommand);\n process.exit(0);\n }\n await handleDatabaseUsersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"daemons\":\n if (wantsHelp) {\n showDaemonsHelp(subcommand);\n process.exit(0);\n }\n await handleDaemonsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"env\":\n if (wantsHelp) {\n showEnvHelp(subcommand);\n process.exit(0);\n }\n await handleEnvCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"nginx\":\n if (wantsHelp) {\n showNginxHelp(subcommand);\n process.exit(0);\n }\n await handleNginxCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"certificates\":\n case \"certs\":\n if (wantsHelp) {\n showCertificatesHelp(subcommand);\n process.exit(0);\n }\n await handleCertificatesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"firewall-rules\":\n case \"fw\":\n if (wantsHelp) {\n showFirewallRulesHelp(subcommand);\n process.exit(0);\n }\n await handleFirewallRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"ssh\":\n if (wantsHelp) {\n showSshHelp();\n process.exit(0);\n }\n await handleSshCommand(subcommand, positional, options);\n break;\n\n case \"ssh-keys\":\n if (wantsHelp) {\n showSshKeysHelp(subcommand);\n process.exit(0);\n }\n await handleSshKeysCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"backups\":\n if (wantsHelp) {\n showBackupsHelp(subcommand);\n process.exit(0);\n }\n await handleBackupsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"storage-providers\":\n if (wantsHelp) {\n showStorageProvidersHelp(subcommand);\n process.exit(0);\n }\n await handleStorageProvidersCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"commands\":\n if (wantsHelp) {\n showCommandsHelp(subcommand);\n process.exit(0);\n }\n await handleCommandsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"scheduled-jobs\":\n if (wantsHelp) {\n showScheduledJobsHelp(subcommand);\n process.exit(0);\n }\n await handleScheduledJobsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"services\":\n if (wantsHelp) {\n showServicesHelp(subcommand);\n process.exit(0);\n }\n await handleServicesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"php\":\n if (wantsHelp) {\n showPhpHelp(subcommand);\n process.exit(0);\n }\n await handlePhpCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"user\":\n if (wantsHelp) {\n showUserHelp(subcommand);\n process.exit(0);\n }\n await handleUserCommand(subcommand ?? \"get\", positional, options);\n break;\n\n case \"monitors\":\n if (wantsHelp) {\n showMonitorsHelp(subcommand);\n process.exit(0);\n }\n await handleMonitorsCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"nginx-templates\":\n if (wantsHelp) {\n showNginxTemplatesHelp(subcommand);\n process.exit(0);\n }\n await handleNginxTemplatesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"security-rules\":\n if (wantsHelp) {\n showSecurityRulesHelp(subcommand);\n process.exit(0);\n }\n await handleSecurityRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"redirect-rules\":\n if (wantsHelp) {\n showRedirectRulesHelp(subcommand);\n process.exit(0);\n }\n await handleRedirectRulesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"recipes\":\n if (wantsHelp) {\n showRecipesHelp(subcommand);\n process.exit(0);\n }\n await handleRecipesCommand(subcommand ?? \"list\", positional, options);\n break;\n\n case \"completion\":\n if (wantsHelp || !subcommand) {\n showCompletionHelp();\n process.exit(0);\n }\n handleCompletionCommand(subcommand, options);\n break;\n\n default:\n console.error(colors.red(`Unknown command: ${mainCommand}`));\n console.log(`Run ${colors.cyan(\"forge --help\")} for usage information`);\n process.exit(1);\n }\n } catch (error) {\n console.error(colors.red(\"Fatal error:\"), error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(colors.red(\"Unhandled error:\"), error);\n process.exit(1);\n});\n"],"mappings":"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"}