{"version":3,"file":"index.cjs","names":["logger","endpoint: string","token: string","DokployApi","prompt","message: string","resolve","err: Error","char: Buffer","options: LoginOptions","options: LogoutOptions","config: GkmConfig","options: BuildOptions","providers: LegacyProvider[]","mainProvider: MainProvider","providersConfig?: ProvidersConfig","providersConfig: ProvidersConfig","config:\n\t\t| boolean\n\t\t| AWSApiGatewayConfig\n\t\t| AWSLambdaConfig\n\t\t| ServerConfig\n\t\t| undefined","ConstructGenerator","context: BuildContext","constructs: GeneratedConstruct<\n\t\t\tCron<any, any, any, any, any, any, any, any>\n\t\t>[]","outputDir: string","options?: GeneratorOptions","logger","cronInfos: CronInfo[]","value: any","sourceFile: string","exportName: string","ConstructGenerator","value: any","context: BuildContext","constructs: GeneratedConstruct<\n\t\t\tFunction<any, any, any, any, any, any, any, any, any, any, any, any>\n\t\t>[]","outputDir: string","options?: GeneratorOptions","logger","functionInfos: FunctionInfo[]","sourceFile: string","exportName: string","ConstructGenerator","value: any","context: BuildContext","constructs: GeneratedConstruct<Queue<any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","logger","queueInfos: QueueInfo[]","sourceFile: string","exportName: string","queues: GeneratedConstruct<Queue<any, any, any, any>>[]","exports","ConstructGenerator","value: any","context: BuildContext","constructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","outputDir: string","options?: GeneratorOptions","logger","subscriberInfos: SubscriberInfo[]","sourceFile: string","exportName: string","_subscriber: Subscriber<any, any, any, any, any, any>","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","exports","ConstructGenerator","value: any","_context: BuildContext","constructs: GeneratedConstruct<Topic<any, any>>[]","_outputDir: string","_options?: GeneratorOptions","logger","logger","commandArgs: string[]","options: ExecOptions","resolve","code: number | null","error: Error","logger","config: GkmConfig['telescope']","isEnabled","telescopeConfig: TelescopeConfig","config: GkmConfig['studio']","studioConfig: StudioConfig","config: GkmConfig['hooks']","cwd: string","cliProduction: boolean","configProduction?: ProductionConfig","config: GkmConfig","options: DevOptions","appRoot: string","secretsRoot: string","workspaceAppName: string | undefined","workspaceAppPort: number | undefined","workspace: NormalizedWorkspace | undefined","OPENAPI_OUTPUT_PATH","buildContext: BuildContext","runtime: Runtime","secretsJsonPath: string | undefined","rebuildTimeout: NodeJS.Timeout | null","workspace: NormalizedWorkspace","env: Record<string, string>","conflicts: { app1: string; app2: string; port: number }[]","FRONTEND_FRAMEWORKS: Record<FrontendFramework, FrontendFrameworkSpec>","fullPath: string","deps: Record<string, string>","order: FrontendFramework[]","name","appName: string","appPath: string","workspaceRoot: string","framework?: FrontendFramework","errors: string[]","warnings: string[]","pkg: {\n\t\tdependencies?: Record<string, string>;\n\t\tdevDependencies?: Record<string, string>;\n\t\tscripts?: Record<string, string>;\n\t}","pkg","results: FrontendValidationResult[]","turboFilter: string[]","turboEnv: Record<string, string>","resolve","config: any","context: BuildContext","provider: LegacyProvider","enableOpenApi: boolean","EndpointGenerator","wrapperPath: string","entryPath: string","watch: boolean","port: number","restartTimeout: NodeJS.Timeout | null","options: {\n\tsecretsJsonPath?: string;\n\truntime?: Runtime;\n\tenableOpenApi?: boolean;\n\tappImportPath?: string;\n}","requestedPort: number","portExplicit: boolean","telescope: NormalizedTelescopeConfig | undefined","studio: NormalizedStudioConfig | undefined","secretsJsonPath?: string","lines: string[]","s: string","logger","field: ManifestField<T>","fieldName: string","typeName: string","partitioned: boolean","outputDir: string","routes: ManifestField<RouteInfo>","functions: ManifestField<FunctionInfo>","crons: ManifestField<CronInfo>","subscribers: ManifestField<SubscriberInfo>","queues: ManifestField<QueueInfo>","topics: ManifestField<TopicInfo>","appInfo: ServerAppInfo","result: Record<string, RouteInfo[]>","r: RouteInfo","result: Record<\n\t\tstring,\n\t\t{ path: string; method: string; authorizer: string }[]\n\t>","s: SubscriberInfo","result: Record<\n\t\tstring,\n\t\t{ name: string; subscribedEvents: readonly string[] }[]\n\t>","q: QueueInfo","result: Record<string, { name: string }[]>","t: TopicInfo","result: Record<string, { name: string; events: readonly string[] }[]>","constructs: GeneratedConstruct<T>[]","infos: T[]","constructs: GeneratedConstruct<any>[]","groups: Record<string, T[]>","logger","options: BuildOptions","buildContext: BuildContext","EndpointGenerator","result: BuildResult","provider: LegacyProvider","context: BuildContext","rootOutputDir: string","endpointGenerator: EndpointGenerator","functionGenerator: FunctionGenerator","cronGenerator: CronGenerator","subscriberGenerator: SubscriberGenerator","queueGenerator: QueueGenerator","topicGenerator: TopicGenerator","endpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[]","functions: GeneratedConstruct<Function<any, any, any, any>>[]","crons: GeneratedConstruct<Cron<any, any, any, any>>[]","subscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[]","queues: GeneratedConstruct<Queue<any, any, any, any>>[]","topics: GeneratedConstruct<Topic<any, any>>[]","enableOpenApi: boolean","skipBundle: boolean","stage?: string","routeMetadata: RouteInfo[]","appInfo: ServerAppInfo","masterKey: string | undefined","detectPackageManager","pm: 'pnpm' | 'npm' | 'yarn'","filter?: string","workspace: NormalizedWorkspace","results: AppBuildResult[]","name","resolve","_appName: string","app: NormalizedAppConfig","routes: Routes","infos: T[]","constructs: GeneratedConstruct<any>[]","error: unknown","output","stage: string","projectId: string","environmentId: string","state: DokployStageState | null","appName: string","state: DokployStageState","applicationId: string","postgresId: string","redisId: string","credentials: AppDbCredentials","secretName: string","value: string","hostname: string","serverIp: string","name: string","type: string","name","type","record: Omit<CreatedDnsRecord, 'createdAt'>","backupState: BackupState","backupId: string","value: unknown","options: CreateDnsProviderOptions","logger","config: DnsConfig","hostname: string","dnsConfig: Record<string, DnsProviderConfig>","appHostnames: Map<string, string>","rootDomain: string","serverIp: string","records: RequiredDnsRecord[]","type","status: string","providerConfig: DnsProviderConfig","provider: DnsProvider | null","results: RequiredDnsRecord[]","upsertRecords: UpsertDnsRecord[]","dnsConfig: DnsConfig | undefined","dokployEndpoint: string","state?: DokployStageState","allRecords: RequiredDnsRecord[]","state: DokployStageState","results: DnsVerificationResult[]","appName: string","app: NormalizedAppConfig","stage: string","dokployConfig: DokployWorkspaceConfig | undefined","isMainFrontend: boolean","allApps: Record<string, NormalizedAppConfig>","name","DEFAULT_SERVICE_IMAGES: Record<ComposeServiceName, string>","DEFAULT_SERVICE_VERSIONS: Record<ComposeServiceName, string>","serviceName: ComposeServiceName","services: ComposeServicesConfig | ComposeServiceName[]","name","version","options: ComposeOptions","yaml","options: Omit<ComposeOptions, 'services'>","workspace: NormalizedWorkspace","options: WorkspaceComposeOptions","serviceName: 'postgres' | 'redis' | 'minio'","config: boolean | { version?: string; image?: string } | undefined","defaults: Record<'postgres' | 'redis' | 'minio', string>","baseImages: Record<'postgres' | 'redis' | 'minio', string>","appName: string","app: NormalizedAppConfig","allApps: [string, NormalizedAppConfig][]","options: {\n\t\tregistry?: string;\n\t\tprojectName: string;\n\t\thasPostgres: boolean;\n\t\thasRedis: boolean;\n\t\thasMinio: boolean;\n\t\thasMail: boolean;\n\t\teventsBackend?: import('../types').EventsBackend;\n\t}","dependencies: string[]","dependencies","LOCKFILES: [string, PackageManager][]","detectPackageManager","cwd: string","pm: PackageManager","commands: Record<PackageManager, string>","options: MultiStageDockerfileOptions","options: DockerTemplateOptions","resolveDockerConfig","config: GkmConfig","pkg","options: FrontendDockerfileOptions","options: FrontendDockerfileOptions & { healthCheckPath?: string }","options: EntryDockerfileOptions","logger","options: DockerOptions","pkg","result: DockerGeneratedFiles","cwd: string","imageName: string","appPath: string","workspace: NormalizedWorkspace","results: AppDockerResult[]","dockerfile: string","getAppNameFromCwd","pkg","logger","registry: string | undefined","imageName: string","tag: string","imageRef: string","appName?: string","buildArgs?: string[]","options: DockerDeployOptions","config: GkmConfig","logger","getApiToken","createApi","endpoint: string","DokployApi","options: DokployDeployOptions","registryOptions: {\n\t\tregistryId?: string;\n\t\tusername?: string;\n\t\tpassword?: string;\n\t\tregistryUrl?: string;\n\t}","envVars: Record<string, string>","state: DokployStageState","appName: string","secretName: string","credentials: AppDbCredentials","postgres: { host: string; port: number; database: string }","redis: {\n\thost: string;\n\tport: number;\n\tpassword?: string;\n}","varName: string","context: EnvResolverContext","requiredVars: string[]","resolved: Record<string, string>","missing: string[]","stage: string","logger","providedEndpoint?: string","endpoint: string","DokployApi","config: DokployDeployConfig","cwd: string","newContent: string","options: DeployInitOptions","projectId: string","environmentId: string","options: {\n\tendpoint?: string;\n\tresource: 'projects' | 'registries';\n}","value: unknown","options: CreateStateProviderOptions","CachedStateProvider","stageSecrets: StageSecrets","sniffedEnv: SniffedEnvironment","filtered: EmbeddableSecrets","found: string[]","missing: string[]","filteredSecrets: FilteredAppSecrets","sniffedApps: Map<string, SniffedEnvironment>","encryptedApps: Map<string, EncryptedAppSecrets>","appsWithSecrets: string[]","appsWithoutSecrets: string[]","appsWithMissingSecrets: Array<{ appName: string; missing: string[] }>","__filename","__dirname","require","baseName: string","app: NormalizedAppConfig","appName: string","workspacePath: string","options: SniffAppOptions","sniffedVars: string[]","sniffedOptional: string[]","configPaths: string[]","envVars: string[]","optionalEnvVars: string[]","markOptional: boolean","entryPath: string","appPath: string","routes: string | string[]","envParserPath: string","SnifferEnvironmentParser: any","sniffWithFireAndForget: any","module","apps: Record<string, NormalizedAppConfig>","logger","message: string","resolve","char: Buffer","host: string","port: number","user: string","password: string","database: string","PgClient","api: DokployApi","postgres: DokployPostgres","serverHostname: string","users: DbUserConfig[]","endpoint: string","projectId: string","environmentId: string | undefined","projectName: string","services?: DockerComposeServices","existingServiceIds?: { postgresId?: string; redisId?: string }","serviceUrls: ServiceUrls","serviceIds: { postgresId?: string; redisId?: string }","postgres: DokployPostgres | null","redis: DokployRedis | null","config: GkmConfig","dockerConfig: DockerDeployConfig","stage: string","DokployApi","environmentId","provisionResult","environmentId: string","applicationId: string","dokployConfig: DokployDeployConfig","workspace: NormalizedWorkspace","options: DeployOptions","name","provisionedPostgres: DokployPostgres | null","provisionedRedis: DokployRedis | null","usersToCreate: DbUserConfig[]","publicUrls: Record<string, string>","results: AppDeployResult[]","frontendUrls: string[]","application: DokployApplication | null","buildArgs: string[]","dependencyUrls: Record<string, string>","envContext: EnvResolverContext","envVars: string[]","publicUrlArgNames: string[]","dokployConfig: DokployDeployConfig | undefined","dockerServices: DockerComposeServices | undefined","masterKey: string | undefined","result: DeployResult","options: StateCommandOptions","CachedStateProvider","options: StateCommandOptions & { json?: boolean }","state: DokployStageState","name","require","options: TemplateOptions","options: TemplateOptions","template: TemplateConfig","files: GeneratedFile[]","files","_template: TemplateConfig","_helpers: ConfigHelperOptions","options: TemplateOptions","template: TemplateConfig","dbApps?: DatabaseAppConfig[]","services: string[]","volumes: string[]","files: GeneratedFile[]","apps: DatabaseAppConfig[]","_eventsBackend?: EventsBackend","options: TemplateOptions","_template: TemplateConfig","files: GeneratedFile[]","options: TemplateOptions","options: TemplateOptions","options: TemplateOptions","_template: TemplateConfig","files: GeneratedFile[]","apiTemplate: TemplateConfig","options: TemplateOptions","name","file: string","files: GeneratedFile[]","minimalTemplate: TemplateConfig","options: TemplateOptions","file: string","files: GeneratedFile[]","serverlessTemplate: TemplateConfig","options: TemplateOptions","file: string","files: GeneratedFile[]","workerTemplate: TemplateConfig","options: TemplateOptions","file: string","files: GeneratedFile[]","OPENAPI_OUTPUT_PATH","templates: Record<\n\tExclude<TemplateName, 'fullstack'>,\n\tTemplateConfig\n>","name: TemplateName","name","options: TemplateOptions","template: TemplateConfig","dependencies","devDependencies","scripts","name","obj: Record<string, string>","OPENAPI_OUTPUT_PATH","options: TemplateOptions","template: TemplateConfig","options: TemplateOptions","_template: TemplateConfig","options: TemplateOptions","options: TemplateOptions","options: TemplateOptions","cwd: string","name: string","name","pkgManager: PackageManager","script: string","lockfileByPm: Record<PackageManager, string>","pm: PackageManager","pkg","root: string","results: string[]","projectName?: string","options: InitOptions","value: string","name","template: TemplateName","servicesArray: string[]","eventsBackend: EventsBackend | undefined","services: ServicesSelection","pkgManager: PackageManager","deployTarget: DeployTarget","frontendFramework: FullstackFrontendFramework | undefined","templateOptions: TemplateOptions","isMonorepo","dbApps: DatabaseAppConfig[]","secretServices: ComposeServiceName[]","customSecrets: Record<string, string>","projectName: string","options: TemplateOptions","devCommand","logger","services: ComposeServicesConfig | ComposeServiceName[] | undefined","name","options: SecretsInitOptions","projectName: string | undefined","workspaceSecrets: Record<string, string> | undefined","chunks: Buffer[]","key: string","value: string | undefined","options: SecretsSetOptions","options: SecretsShowOptions","options: SecretsRotateOptions","file: string","options: SecretsImportOptions","importedSecrets: Record<string, string>","url: string","options: TestOptions","filtered: Record<string, string>","args: string[]","resolve","env: Record<string, string>","options: UpgradeOptions","dependencies","packageJsonPaths: string[]","results: FoundDependency[]","pkg","name","version","packageNames: string[]","dep: FoundDependency","latestVersions: Map<string, string>","infos: UpgradeInfo[]","status: string","upgradable: UpgradeInfo[]","pm: PackageManager","packages: string[]","cwd: string","Command","pkg","name: string | undefined","options: InitOptions","name","options: SetupOptions","options: {\n\t\t\tprovider?: string;\n\t\t\tproviders?: string;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tproduction?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tstage?: string;\n\t\t\tmarkOptional?: boolean;\n\t\t}","options: {\n\t\t\tport?: string;\n\t\t\tentry?: string;\n\t\t\twatch?: boolean;\n\t\t\tenableOpenapi?: boolean;\n\t\t}","commandArgs: string[]","pattern: string | undefined","options: TestOptions","options: { app?: string }","options: { input?: string; output?: string; name?: string }","options: DockerOptions","options: {\n\t\t\tbuild?: boolean;\n\t\t\tpush?: boolean;\n\t\t\ttag?: string;\n\t\t\tregistry?: string;\n\t\t\tslim?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tturbo?: boolean;\n\t\t\tturboPackage?: string;\n\t\t}","options: { stage: string; force?: boolean }","key: string","value: string | undefined","options: { stage: string }","options: { stage: string; reveal?: boolean }","options: { stage: string; service?: ComposeServiceName }","file: string","options: { stage: string; merge?: boolean }","options: {\n\t\t\tprovider: string;\n\t\t\tstage: string;\n\t\t\ttag?: string;\n\t\t\tskipPush?: boolean;\n\t\t\tskipBuild?: boolean;\n\t\t}","options: {\n\t\t\tendpoint?: string;\n\t\t\tproject: string;\n\t\t\tapp: string;\n\t\t\tprojectId?: string;\n\t\t\tregistryId?: string;\n\t\t}","options: {\n\t\t\tendpoint?: string;\n\t\t\tprojects?: boolean;\n\t\t\tregistries?: boolean;\n\t\t}","options: { service: string; token?: string; endpoint?: string }","options: { service: string }","options: { stage: string; json?: boolean }","options: UpgradeOptions"],"sources":["../package.json","../src/auth/index.ts","../src/build/providerResolver.ts","../src/generators/CronGenerator.ts","../src/generators/FunctionGenerator.ts","../src/generators/QueueGenerator.ts","../src/generators/SubscriberGenerator.ts","../src/generators/TopicGenerator.ts","../src/exec/index.ts","../src/dev/index.ts","../src/build/manifests.ts","../src/build/partitions.ts","../src/build/index.ts","../src/debug.ts","../src/deploy/state.ts","../src/deploy/dns/DnsProvider.ts","../src/deploy/dns/index.ts","../src/deploy/domain.ts","../src/docker/compose.ts","../src/docker/templates.ts","../src/docker/index.ts","../src/deploy/docker.ts","../src/deploy/dokploy.ts","../src/deploy/env-resolver.ts","../src/deploy/init.ts","../src/deploy/StateProvider.ts","../src/deploy/secrets.ts","../src/deploy/sniffer.ts","../src/deploy/index.ts","../src/deploy/state-commands.ts","../src/init/versions.ts","../src/init/generators/auth.ts","../src/init/generators/config.ts","../src/init/generators/docker.ts","../src/init/generators/env.ts","../src/init/generators/mobile-expo.ts","../src/init/generators/models.ts","../src/init/generators/monorepo.ts","../src/init/templates/api.ts","../src/init/templates/minimal.ts","../src/init/templates/serverless.ts","../src/init/templates/worker.ts","../src/init/templates/index.ts","../src/init/generators/package.ts","../src/init/generators/source.ts","../src/init/generators/test.ts","../src/init/generators/ui.ts","../src/init/generators/web.ts","../src/init/generators/web-tanstack.ts","../src/init/utils.ts","../src/init/index.ts","../src/secrets/index.ts","../src/test/index.ts","../src/upgrade/index.ts","../src/index.ts"],"sourcesContent":["{\n\t\"name\": \"@geekmidas/cli\",\n\t\"version\": \"1.11.0\",\n\t\"description\": \"CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs\",\n\t\"private\": false,\n\t\"type\": \"module\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./config\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/config.d.mts\",\n\t\t\t\t\"default\": \"./dist/config.mjs\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/config.d.cts\",\n\t\t\t\t\"default\": \"./dist/config.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./workspace\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/workspace/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/workspace/index.mjs\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/workspace/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/workspace/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./openapi\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/openapi.d.mts\",\n\t\t\t\t\"default\": \"./dist/openapi.mjs\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/openapi.d.cts\",\n\t\t\t\t\"default\": \"./dist/openapi.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./openapi-react-query\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/openapi-react-query.d.mts\",\n\t\t\t\t\"default\": \"./dist/openapi-react-query.mjs\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/openapi-react-query.d.cts\",\n\t\t\t\t\"default\": \"./dist/openapi-react-query.cjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"bin\": {\n\t\t\"gkm\": \"./bin/gkm.mjs\"\n\t},\n\t\"scripts\": {\n\t\t\"ts\": \"tsc --noEmit --skipLibCheck src/**/*.ts\",\n\t\t\"sync-versions\": \"tsx scripts/sync-versions.ts\",\n\t\t\"prebuild\": \"pnpm sync-versions\",\n\t\t\"test\": \"vitest\",\n\t\t\"test:once\": \"vitest run\",\n\t\t\"test:coverage\": \"vitest run --coverage\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/geekmidas/toolbox\"\n\t},\n\t\"dependencies\": {\n\t\t\"@apidevtools/swagger-parser\": \"^10.1.0\",\n\t\t\"@aws-sdk/client-iam\": \"~3.992.0\",\n\t\t\"@aws-sdk/client-route-53\": \"~3.992.0\",\n\t\t\"@aws-sdk/client-s3\": \"~3.992.0\",\n\t\t\"@aws-sdk/client-ssm\": \"~3.992.0\",\n\t\t\"@aws-sdk/credential-providers\": \"~3.992.0\",\n\t\t\"@geekmidas/constructs\": \"workspace:~\",\n\t\t\"@geekmidas/envkit\": \"workspace:~\",\n\t\t\"@geekmidas/errors\": \"workspace:~\",\n\t\t\"@geekmidas/logger\": \"workspace:~\",\n\t\t\"@geekmidas/manifest\": \"workspace:*\",\n\t\t\"@geekmidas/schema\": \"workspace:~\",\n\t\t\"chokidar\": \"~4.0.3\",\n\t\t\"commander\": \"^12.1.0\",\n\t\t\"dotenv\": \"~17.2.3\",\n\t\t\"fast-glob\": \"^3.3.2\",\n\t\t\"hono\": \"~4.8.0\",\n\t\t\"lodash.kebabcase\": \"^4.1.1\",\n\t\t\"openapi-typescript\": \"^7.4.2\",\n\t\t\"pg\": \"~8.17.1\",\n\t\t\"prompts\": \"~2.4.2\",\n\t\t\"tsx\": \"~4.20.3\",\n\t\t\"yaml\": \"~2.8.2\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@geekmidas/testkit\": \"workspace:*\",\n\t\t\"@types/lodash.kebabcase\": \"^4.1.9\",\n\t\t\"@types/node\": \"~24.9.1\",\n\t\t\"@types/pg\": \"~8.16.0\",\n\t\t\"@types/prompts\": \"~2.4.9\",\n\t\t\"typescript\": \"^5.8.2\",\n\t\t\"vitest\": \"^3.2.4\",\n\t\t\"zod\": \"~4.1.13\"\n\t},\n\t\"peerDependencies\": {\n\t\t\"@geekmidas/telescope\": \"workspace:~\"\n\t},\n\t\"peerDependenciesMeta\": {\n\t\t\"@geekmidas/telescope\": {\n\t\t\t\"optional\": true\n\t\t}\n\t}\n}\n","import { stdin as input, stdout as output } from 'node:process';\nimport * as readline from 'node:readline/promises';\nimport {\n\tgetCredentialsPath,\n\tgetDokployCredentials,\n\tremoveDokployCredentials,\n\tstoreDokployCredentials,\n} from './credentials';\n\nconst logger = console;\n\nexport interface LoginOptions {\n\t/** Service to login to */\n\tservice: 'dokploy';\n\t/** API token (if not provided, will prompt) */\n\ttoken?: string;\n\t/** Endpoint URL */\n\tendpoint?: string;\n}\n\nexport interface LogoutOptions {\n\t/** Service to logout from */\n\tservice?: 'dokploy' | 'all';\n}\n\n/**\n * Validate Dokploy token by making a test API call\n */\nexport async function validateDokployToken(\n\tendpoint: string,\n\ttoken: string,\n): Promise<boolean> {\n\tconst { DokployApi } = await import('../deploy/dokploy-api');\n\tconst api = new DokployApi({ baseUrl: endpoint, token });\n\treturn api.validateToken();\n}\n\n/**\n * Prompt for input (handles both TTY and non-TTY)\n */\nasync function prompt(message: string, hidden = false): Promise<string> {\n\tif (!process.stdin.isTTY) {\n\t\tthrow new Error(\n\t\t\t'Interactive input required. Please provide --token option.',\n\t\t);\n\t}\n\n\tif (hidden) {\n\t\t// For hidden input, use raw mode directly without readline\n\t\tprocess.stdout.write(message);\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet value = '';\n\n\t\t\tconst cleanup = () => {\n\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\tprocess.stdin.pause();\n\t\t\t\tprocess.stdin.removeListener('data', onData);\n\t\t\t\tprocess.stdin.removeListener('error', onError);\n\t\t\t};\n\n\t\t\tconst onError = (err: Error) => {\n\t\t\t\tcleanup();\n\t\t\t\treject(err);\n\t\t\t};\n\n\t\t\tconst onData = (char: Buffer) => {\n\t\t\t\tconst c = char.toString();\n\n\t\t\t\tif (c === '\\n' || c === '\\r') {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tresolve(value);\n\t\t\t\t} else if (c === '\\u0003') {\n\t\t\t\t\t// Ctrl+C\n\t\t\t\t\tcleanup();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t} else if (c === '\\u007F' || c === '\\b') {\n\t\t\t\t\t// Backspace\n\t\t\t\t\tif (value.length > 0) {\n\t\t\t\t\t\tvalue = value.slice(0, -1);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvalue += c;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t\tprocess.stdin.resume();\n\t\t\tprocess.stdin.on('data', onData);\n\t\t\tprocess.stdin.on('error', onError);\n\t\t});\n\t} else {\n\t\t// For visible input, use readline\n\t\tconst rl = readline.createInterface({ input, output });\n\t\ttry {\n\t\t\treturn await rl.question(message);\n\t\t} finally {\n\t\t\trl.close();\n\t\t}\n\t}\n}\n\n/**\n * Login to a service\n */\nexport async function loginCommand(options: LoginOptions): Promise<void> {\n\tconst { service, token: providedToken, endpoint: providedEndpoint } = options;\n\n\tif (service === 'dokploy') {\n\t\tlogger.log('\\n🔐 Logging in to Dokploy...\\n');\n\n\t\t// Get endpoint\n\t\tlet endpoint = providedEndpoint;\n\t\tif (!endpoint) {\n\t\t\tendpoint = await prompt(\n\t\t\t\t'Dokploy URL (e.g., https://dokploy.example.com): ',\n\t\t\t);\n\t\t}\n\n\t\t// Normalize endpoint (remove trailing slash)\n\t\tendpoint = endpoint.replace(/\\/$/, '');\n\n\t\t// Validate endpoint format\n\t\ttry {\n\t\t\tnew URL(endpoint);\n\t\t} catch {\n\t\t\tlogger.error('Invalid URL format');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Get token\n\t\tlet token = providedToken;\n\t\tif (!token) {\n\t\t\tlogger.log(`\\nGenerate a token at: ${endpoint}/settings/profile\\n`);\n\t\t\ttoken = await prompt('API Token: ', true);\n\t\t}\n\n\t\tif (!token) {\n\t\t\tlogger.error('Token is required');\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Validate token\n\t\tlogger.log('\\nValidating credentials...');\n\t\tconst isValid = await validateDokployToken(endpoint, token);\n\n\t\tif (!isValid) {\n\t\t\tlogger.error(\n\t\t\t\t'\\n✗ Invalid credentials. Please check your token and try again.',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t// Store credentials\n\t\tawait storeDokployCredentials(token, endpoint);\n\n\t\tlogger.log('\\n✓ Successfully logged in to Dokploy!');\n\t\tlogger.log(`  Endpoint: ${endpoint}`);\n\t\tlogger.log(`  Credentials stored in: ${getCredentialsPath()}`);\n\t\tlogger.log(\n\t\t\t'\\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n}\n\n/**\n * Logout from a service\n */\nexport async function logoutCommand(options: LogoutOptions): Promise<void> {\n\tconst { service = 'dokploy' } = options;\n\n\tif (service === 'all') {\n\t\tconst dokployRemoved = await removeDokployCredentials();\n\n\t\tif (dokployRemoved) {\n\t\t\tlogger.log('\\n✓ Logged out from all services');\n\t\t} else {\n\t\t\tlogger.log('\\nNo stored credentials found');\n\t\t}\n\t\treturn;\n\t}\n\n\tif (service === 'dokploy') {\n\t\tconst removed = await removeDokployCredentials();\n\n\t\tif (removed) {\n\t\t\tlogger.log('\\n✓ Logged out from Dokploy');\n\t\t} else {\n\t\t\tlogger.log('\\nNo Dokploy credentials found');\n\t\t}\n\t}\n}\n\n/**\n * Show current login status\n */\nexport async function whoamiCommand(): Promise<void> {\n\tlogger.log('\\n📋 Current credentials:\\n');\n\n\tconst dokploy = await getDokployCredentials();\n\n\tif (dokploy) {\n\t\tlogger.log('  Dokploy:');\n\t\tlogger.log(`    Endpoint: ${dokploy.endpoint}`);\n\t\tlogger.log(`    Token: ${maskToken(dokploy.token)}`);\n\t} else {\n\t\tlogger.log('  Dokploy: Not logged in');\n\t}\n\n\tlogger.log(`\\n  Credentials file: ${getCredentialsPath()}`);\n}\n\n/**\n * Mask a token for display\n */\nexport function maskToken(token: string): string {\n\tif (token.length <= 8) {\n\t\treturn '****';\n\t}\n\treturn `${token.slice(0, 4)}...${token.slice(-4)}`;\n}\n\n// Re-export credentials utilities for use in other modules\nexport {\n\tgetDokployCredentials,\n\tgetDokployEndpoint,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployCredentials,\n\tstoreDokployRegistryId,\n} from './credentials';\n","import type {\n\tAWSApiGatewayConfig,\n\tAWSLambdaConfig,\n\tBuildOptions,\n\tGkmConfig,\n\tLegacyProvider,\n\tMainProvider,\n\tProvidersConfig,\n\tServerConfig,\n} from '../types';\n\nexport interface ResolvedProviders {\n\tproviders: LegacyProvider[];\n\tenableOpenApi: boolean;\n}\n\n/**\n * Resolves provider configuration from the new simplified system\n * to the internal legacy format for backward compatibility\n */\nexport function resolveProviders(\n\tconfig: GkmConfig,\n\toptions: BuildOptions,\n): ResolvedProviders {\n\tconst providers: LegacyProvider[] = [];\n\tlet enableOpenApi = options.enableOpenApi || false;\n\n\t// Handle legacy providers option (deprecated)\n\tif (options.providers) {\n\t\treturn {\n\t\t\tproviders: options.providers,\n\t\t\tenableOpenApi,\n\t\t};\n\t}\n\n\t// Handle new provider option\n\tif (options.provider) {\n\t\tconst resolvedProviders = resolveMainProvider(\n\t\t\toptions.provider,\n\t\t\tconfig.providers,\n\t\t);\n\t\tproviders.push(...resolvedProviders.providers);\n\t\tenableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;\n\t}\n\t// Default: build all configured providers\n\telse if (config.providers) {\n\t\tconst resolvedProviders = resolveAllConfiguredProviders(config.providers);\n\t\tproviders.push(...resolvedProviders.providers);\n\t\tenableOpenApi = resolvedProviders.enableOpenApi || enableOpenApi;\n\t}\n\t// Fallback: use default AWS configuration\n\telse {\n\t\tproviders.push('aws-apigatewayv2', 'aws-lambda');\n\t}\n\n\treturn {\n\t\tproviders: [...new Set(providers)], // Remove duplicates\n\t\tenableOpenApi,\n\t};\n}\n\nfunction resolveMainProvider(\n\tmainProvider: MainProvider,\n\tprovidersConfig?: ProvidersConfig,\n): ResolvedProviders {\n\tconst providers: LegacyProvider[] = [];\n\tlet enableOpenApi = false;\n\n\tif (mainProvider === 'aws') {\n\t\tconst awsConfig = providersConfig?.aws;\n\n\t\t// Resolve API Gateway providers\n\t\tif (awsConfig?.apiGateway) {\n\t\t\tif (isEnabled(awsConfig.apiGateway.v1)) {\n\t\t\t\tproviders.push('aws-apigatewayv1');\n\t\t\t}\n\t\t\tif (isEnabled(awsConfig.apiGateway.v2)) {\n\t\t\t\tproviders.push('aws-apigatewayv2');\n\t\t\t}\n\t\t} else {\n\t\t\t// Default: enable v2 if no specific config\n\t\t\tproviders.push('aws-apigatewayv2');\n\t\t}\n\n\t\t// Resolve Lambda providers\n\t\tif (awsConfig?.lambda) {\n\t\t\tif (\n\t\t\t\tisEnabled(awsConfig.lambda.functions) ||\n\t\t\t\tisEnabled(awsConfig.lambda.crons)\n\t\t\t) {\n\t\t\t\tproviders.push('aws-lambda');\n\t\t\t}\n\t\t} else {\n\t\t\t// Default: enable lambda if no specific config\n\t\t\tproviders.push('aws-lambda');\n\t\t}\n\t} else if (mainProvider === 'server') {\n\t\tproviders.push('server');\n\t\tconst serverConfig = providersConfig?.server;\n\n\t\tif (typeof serverConfig === 'object' && serverConfig?.enableOpenApi) {\n\t\t\tenableOpenApi = true;\n\t\t}\n\t}\n\n\treturn { providers, enableOpenApi };\n}\n\nfunction resolveAllConfiguredProviders(\n\tprovidersConfig: ProvidersConfig,\n): ResolvedProviders {\n\tconst providers: LegacyProvider[] = [];\n\tlet enableOpenApi = false;\n\n\t// AWS providers\n\tif (providersConfig.aws) {\n\t\tconst awsProviders = resolveMainProvider('aws', providersConfig);\n\t\tproviders.push(...awsProviders.providers);\n\t}\n\n\t// Server provider\n\tif (providersConfig.server && isEnabled(providersConfig.server)) {\n\t\tproviders.push('server');\n\t\tif (\n\t\t\ttypeof providersConfig.server === 'object' &&\n\t\t\tprovidersConfig.server.enableOpenApi\n\t\t) {\n\t\t\tenableOpenApi = true;\n\t\t}\n\t}\n\n\treturn { providers, enableOpenApi };\n}\n\nfunction isEnabled(\n\tconfig:\n\t\t| boolean\n\t\t| AWSApiGatewayConfig\n\t\t| AWSLambdaConfig\n\t\t| ServerConfig\n\t\t| undefined,\n): boolean {\n\tif (config === undefined) return false;\n\tif (typeof config === 'boolean') return config;\n\treturn config.enabled !== false; // Default to true if enabled is not explicitly false\n}\n\n/**\n * Gets configuration for a specific AWS service\n */\nexport function getAWSServiceConfig<\n\tT extends AWSApiGatewayConfig | AWSLambdaConfig,\n>(\n\tconfig: GkmConfig,\n\tservice: 'apiGateway' | 'lambda',\n\tsubService?: 'v1' | 'v2' | 'functions' | 'crons',\n): T | undefined {\n\tconst awsConfig = config.providers?.aws;\n\tif (!awsConfig) return undefined;\n\n\tif (service === 'apiGateway' && awsConfig.apiGateway) {\n\t\tconst apiConfig = subService\n\t\t\t? awsConfig.apiGateway[subService as 'v1' | 'v2']\n\t\t\t: undefined;\n\t\treturn typeof apiConfig === 'object' ? (apiConfig as T) : undefined;\n\t}\n\n\tif (service === 'lambda' && awsConfig.lambda) {\n\t\tconst lambdaConfig = subService\n\t\t\t? awsConfig.lambda[subService as 'functions' | 'crons']\n\t\t\t: undefined;\n\t\treturn typeof lambdaConfig === 'object' ? (lambdaConfig as T) : undefined;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Gets server configuration\n */\nexport function getServerConfig(config: GkmConfig): ServerConfig | undefined {\n\tconst serverConfig = config.providers?.server;\n\treturn typeof serverConfig === 'object' ? serverConfig : undefined;\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Cron } from '@geekmidas/constructs/crons';\nimport type { BuildContext } from '../build/types';\nimport type { CronInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\nexport class CronGenerator extends ConstructGenerator<\n\tCron<any, any, any, any, any, any, any, any>,\n\tCronInfo[]\n> {\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<\n\t\t\tCron<any, any, any, any, any, any, any, any>\n\t\t>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<CronInfo[]> {\n\t\tconst provider = options?.provider || 'aws-lambda';\n\t\tconst logger = console;\n\t\tconst cronInfos: CronInfo[] = [];\n\n\t\tif (constructs.length === 0 || provider !== 'aws-lambda') {\n\t\t\treturn cronInfos;\n\t\t}\n\n\t\t// Create crons subdirectory\n\t\tconst cronsDir = join(outputDir, 'crons');\n\t\tawait mkdir(cronsDir, { recursive: true });\n\n\t\t// Generate cron handlers\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateCronHandler(\n\t\t\t\tcronsDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tcronInfos.push({\n\t\t\t\tname: key,\n\t\t\t\thandler: relative(process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\tschedule: construct.schedule || 'rate(1 hour)',\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tlogger.log(`Generated cron handler: ${key}`);\n\t\t}\n\n\t\treturn cronInfos;\n\t}\n\n\tisConstruct(\n\t\tvalue: any,\n\t): value is Cron<any, any, any, any, any, any, any, any> {\n\t\treturn Cron.isCron(value);\n\t}\n\n\tprivate async generateCronHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\tcontext: BuildContext,\n\t): Promise<string> {\n\t\tconst handlerFileName = `${exportName}.ts`;\n\t\tconst handlerPath = join(outputDir, handlerFileName);\n\n\t\tconst relativePath = relative(dirname(handlerPath), sourceFile);\n\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\tconst relativeEnvParserPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.envParserPath,\n\t\t);\n\t\tconst relativeLoggerPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.loggerPath,\n\t\t);\n\n\t\tconst content = `import { AWSScheduledFunction } from '@geekmidas/constructs/crons';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\nimport ${context.loggerImportPattern} from '${relativeLoggerPath}';\n\nconst adapter = new AWSScheduledFunction(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Function } from '@geekmidas/constructs/functions';\nimport type { BuildContext } from '../build/types';\nimport type { FunctionInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\nexport class FunctionGenerator extends ConstructGenerator<\n\tFunction<any, any, any, any, any, any, any, any, any, any, any, any>,\n\tFunctionInfo[]\n> {\n\tisConstruct(\n\t\tvalue: any,\n\t): value is Function<\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany\n\t> {\n\t\treturn Function.isFunction(value);\n\t}\n\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<\n\t\t\tFunction<any, any, any, any, any, any, any, any, any, any, any, any>\n\t\t>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<FunctionInfo[]> {\n\t\tconst provider = options?.provider || 'aws-lambda';\n\t\tconst logger = console;\n\t\tconst functionInfos: FunctionInfo[] = [];\n\n\t\tif (constructs.length === 0 || provider !== 'aws-lambda') {\n\t\t\treturn functionInfos;\n\t\t}\n\n\t\t// Create functions subdirectory\n\t\tconst functionsDir = join(outputDir, 'functions');\n\t\tawait mkdir(functionsDir, { recursive: true });\n\n\t\t// Generate function handlers\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateFunctionHandler(\n\t\t\t\tfunctionsDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tfunctionInfos.push({\n\t\t\t\tname: key,\n\t\t\t\thandler: relative(process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tlogger.log(`Generated function handler: ${key}`);\n\t\t}\n\n\t\treturn functionInfos;\n\t}\n\n\tprivate async generateFunctionHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\tcontext: BuildContext,\n\t): Promise<string> {\n\t\tconst handlerFileName = `${exportName}.ts`;\n\t\tconst handlerPath = join(outputDir, handlerFileName);\n\n\t\tconst relativePath = relative(dirname(handlerPath), sourceFile);\n\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\tconst relativeEnvParserPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.envParserPath,\n\t\t);\n\t\tconst relativeLoggerPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.loggerPath,\n\t\t);\n\n\t\tconst content = `import { AWSLambdaFunction } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\nimport ${context.loggerImportPattern} from '${relativeLoggerPath}';\n\nconst adapter = new AWSLambdaFunction(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Queue } from '@geekmidas/constructs/queue';\nimport type { BuildContext } from '../build/types';\nimport type { QueueInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\n/**\n * Generates the runtime for `q` queue workers.\n *\n * - **server** (`gkm dev`): a single `queues.ts` exposing `setupQueues()` that\n *   runs an in-process pg-boss poller alongside the Hono server — no SQS/Lambda.\n *   Each queue subscribes by its **name** on the shared event connection.\n * - **aws-lambda**: one handler file per queue wrapping `AWSLambdaQueue`, backed\n *   by an SQS event-source mapping.\n */\nexport class QueueGenerator extends ConstructGenerator<\n\tQueue<any, any, any, any>,\n\tQueueInfo[]\n> {\n\tisConstruct(value: any): value is Queue<any, any, any, any> {\n\t\treturn Queue.isQueue(value);\n\t}\n\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<Queue<any, any, any, any>>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<QueueInfo[]> {\n\t\tconst provider = options?.provider || 'aws-lambda';\n\t\tconst logger = console;\n\t\tconst queueInfos: QueueInfo[] = [];\n\n\t\tif (provider === 'server') {\n\t\t\t// Generate queues.ts for in-process polling (even if empty, so the\n\t\t\t// server entry can always import setupQueues).\n\t\t\tawait this.generateServerQueuesFile(outputDir, constructs);\n\t\t\tlogger.log(\n\t\t\t\t`Generated server queues file with ${constructs.length} queues (polling mode)`,\n\t\t\t);\n\t\t\treturn queueInfos;\n\t\t}\n\n\t\tif (constructs.length === 0 || provider !== 'aws-lambda') {\n\t\t\treturn queueInfos;\n\t\t}\n\n\t\tconst queuesDir = join(outputDir, 'queues');\n\t\tawait mkdir(queuesDir, { recursive: true });\n\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateQueueHandler(\n\t\t\t\tqueuesDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tqueueInfos.push({\n\t\t\t\tname: construct.name,\n\t\t\t\thandler: relative(process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\tbatchSize: construct.batchSize,\n\t\t\t\tfifo: construct.fifo,\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tlogger.log(`Generated queue handler: ${key}`);\n\t\t}\n\n\t\treturn queueInfos;\n\t}\n\n\tprivate async generateQueueHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\tcontext: BuildContext,\n\t): Promise<string> {\n\t\tconst handlerPath = join(outputDir, `${exportName}.ts`);\n\t\tconst importPath = relative(dirname(handlerPath), sourceFile).replace(\n\t\t\t/\\.ts$/,\n\t\t\t'.js',\n\t\t);\n\t\tconst relativeEnvParserPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.envParserPath,\n\t\t);\n\n\t\tconst content = `import { AWSLambdaQueue } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaQueue(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n\n\tprivate async generateServerQueuesFile(\n\t\toutputDir: string,\n\t\tqueues: GeneratedConstruct<Queue<any, any, any, any>>[],\n\t): Promise<string> {\n\t\tawait mkdir(outputDir, { recursive: true });\n\n\t\tconst queuesPath = join(outputDir, 'queues.ts');\n\n\t\t// Group imports by file\n\t\tconst importsByFile = new Map<string, string[]>();\n\t\tfor (const { path, key } of queues) {\n\t\t\tconst importPath = relative(dirname(queuesPath), path.relative).replace(\n\t\t\t\t/\\.ts$/,\n\t\t\t\t'.js',\n\t\t\t);\n\t\t\tif (!importsByFile.has(importPath)) {\n\t\t\t\timportsByFile.set(importPath, []);\n\t\t\t}\n\t\t\timportsByFile.get(importPath)?.push(key);\n\t\t}\n\n\t\tconst imports = Array.from(importsByFile.entries())\n\t\t\t.map(\n\t\t\t\t([importPath, exports]) =>\n\t\t\t\t\t`import { ${exports.join(', ')} } from '${importPath}';`,\n\t\t\t)\n\t\t\t.join('\\n');\n\n\t\tconst allExportNames = queues.map(({ key }) => key);\n\n\t\tconst content = `/**\n * Generated queue workers setup\n *\n * ⚠️  WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This runs an in-process pg-boss poller alongside the HTTP server. Each queue\n * subscribes by its name on the shared event connection\n * (EVENT_SUBSCRIBER_CONNECTION_STRING), so producers using\n * <NAME>_PUBLISHER_CONNECTION_STRING (pgboss:// locally) reach it.\n *\n * For production, queues run as AWS Lambda with SQS event-source mappings.\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst queues = [\n  ${allExportNames.join(',\\n  ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupQueues(\n  envParser: EnvironmentParser<any>,\n  logger: Logger,\n): Promise<void> {\n  if (queues.length === 0) {\n    return;\n  }\n\n  logger.info('Setting up queue workers in polling mode (local development)');\n\n  const config = envParser.create((get) => ({\n    connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string(),\n  })).parse();\n\n  const serviceDiscovery = ServiceDiscovery.getInstance(envParser);\n\n  let connection: EventConnection;\n  try {\n    connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n    const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n    logger.info({ connectionType }, 'Created shared event connection for queues');\n  } catch (error) {\n    logger.error({ error }, 'Failed to create event connection for queues');\n    return;\n  }\n\n  for (const queue of queues) {\n    try {\n      const eventSubscriber = await Subscriber.fromConnection(connection);\n\n      const services = queue.services.length > 0\n        ? await serviceDiscovery.register(queue.services)\n        : {};\n\n      // A queue subscribes to a single \"type\" — its own name.\n      await eventSubscriber.subscribe([queue.name], async (message) => {\n        try {\n          const validation = await queue.messageSchema['~standard'].validate(message.payload);\n          if (validation.issues) {\n            logger.error({ issues: validation.issues, queue: queue.name }, 'Queue message failed validation');\n            return;\n          }\n\n          await queue.handler({\n            messages: [validation.value],\n            services: services,\n            logger: queue.logger,\n          });\n\n          logger.debug({ queue: queue.name }, 'Successfully processed queue message');\n        } catch (error) {\n          logger.error({ error, queue: queue.name }, 'Failed to process queue message');\n          // Message will become visible again for retry.\n        }\n      });\n\n      activeSubscribers.push(eventSubscriber);\n      logger.info({ queue: queue.name }, 'Queue worker started polling');\n    } catch (error) {\n      logger.error({ error, queue: queue.name }, 'Failed to setup queue worker');\n    }\n  }\n\n  const shutdown = () => {\n    logger.info('Stopping all queue workers');\n    for (const _ of activeSubscribers) {\n      connection.stop();\n    }\n  };\n\n  process.on('SIGTERM', shutdown);\n  process.on('SIGINT', shutdown);\n}\n`;\n\n\t\tawait writeFile(queuesPath, content);\n\t\treturn queuesPath;\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { BuildContext } from '../build/types';\nimport type { SubscriberInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\nexport class SubscriberGenerator extends ConstructGenerator<\n\tSubscriber<any, any, any, any, any, any>,\n\tSubscriberInfo[]\n> {\n\tisConstruct(value: any): value is Subscriber<any, any, any, any, any, any> {\n\t\treturn Subscriber.isSubscriber(value);\n\t}\n\n\tasync build(\n\t\tcontext: BuildContext,\n\t\tconstructs: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n\t\toutputDir: string,\n\t\toptions?: GeneratorOptions,\n\t): Promise<SubscriberInfo[]> {\n\t\tconst provider = options?.provider || 'aws-lambda';\n\t\tconst logger = console;\n\t\tconst subscriberInfos: SubscriberInfo[] = [];\n\n\t\tif (provider === 'server') {\n\t\t\t// Generate subscribers.ts for server-based polling (even if empty)\n\t\t\tawait this.generateServerSubscribersFile(outputDir, constructs);\n\n\t\t\tlogger.log(\n\t\t\t\t`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`,\n\t\t\t);\n\n\t\t\t// Return empty array as server subscribers don't have individual handlers\n\t\t\treturn subscriberInfos;\n\t\t}\n\n\t\tif (constructs.length === 0) {\n\t\t\treturn subscriberInfos;\n\t\t}\n\n\t\tif (provider !== 'aws-lambda') {\n\t\t\treturn subscriberInfos;\n\t\t}\n\n\t\t// Create subscribers subdirectory\n\t\tconst subscribersDir = join(outputDir, 'subscribers');\n\t\tawait mkdir(subscribersDir, { recursive: true });\n\n\t\t// Generate subscriber handlers\n\t\tfor (const { key, construct, path } of constructs) {\n\t\t\tconst handlerFile = await this.generateSubscriberHandler(\n\t\t\t\tsubscribersDir,\n\t\t\t\tpath.relative,\n\t\t\t\tkey,\n\t\t\t\tconstruct,\n\t\t\t\tcontext,\n\t\t\t);\n\n\t\t\tsubscriberInfos.push({\n\t\t\t\tname: key,\n\t\t\t\thandler: relative(process.cwd(), handlerFile).replace(\n\t\t\t\t\t/\\.ts$/,\n\t\t\t\t\t'.handler',\n\t\t\t\t),\n\t\t\t\tsubscribedEvents: construct.subscribedEvents || [],\n\t\t\t\t// A subscriber bound to a topic (via `s.topic(topic)`) records the\n\t\t\t\t// binding so infra wires the SNS subscription.\n\t\t\t\t...(construct.topicName\n\t\t\t\t\t? { transport: 'topic' as const, topic: construct.topicName }\n\t\t\t\t\t: {}),\n\t\t\t\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment({\n\t\t\t\t\tmarkOptional: context.markOptional,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tlogger.log(`Generated subscriber handler: ${key}`);\n\t\t}\n\n\t\treturn subscriberInfos;\n\t}\n\n\tprivate async generateSubscriberHandler(\n\t\toutputDir: string,\n\t\tsourceFile: string,\n\t\texportName: string,\n\t\t_subscriber: Subscriber<any, any, any, any, any, any>,\n\t\tcontext: BuildContext,\n\t): Promise<string> {\n\t\tconst handlerFileName = `${exportName}.ts`;\n\t\tconst handlerPath = join(outputDir, handlerFileName);\n\n\t\tconst relativePath = relative(dirname(handlerPath), sourceFile);\n\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\tconst relativeEnvParserPath = relative(\n\t\t\tdirname(handlerPath),\n\t\t\tcontext.envParserPath,\n\t\t);\n\n\t\tconst content = `import { AWSLambdaSubscriber } from '@geekmidas/constructs/aws';\nimport { ${exportName} } from '${importPath}';\nimport ${context.envParserImportPattern} from '${relativeEnvParserPath}';\n\nconst adapter = new AWSLambdaSubscriber(envParser, ${exportName});\n\nexport const handler = adapter.handler;\n`;\n\n\t\tawait writeFile(handlerPath, content);\n\t\treturn handlerPath;\n\t}\n\n\tprivate async generateServerSubscribersFile(\n\t\toutputDir: string,\n\t\tsubscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n\t): Promise<string> {\n\t\t// Ensure output directory exists\n\t\tawait mkdir(outputDir, { recursive: true });\n\n\t\tconst subscribersFileName = 'subscribers.ts';\n\t\tconst subscribersPath = join(outputDir, subscribersFileName);\n\n\t\t// Group imports by file\n\t\tconst importsByFile = new Map<string, string[]>();\n\n\t\tfor (const { path, key } of subscribers) {\n\t\t\tconst relativePath = relative(dirname(subscribersPath), path.relative);\n\t\t\tconst importPath = relativePath.replace(/\\.ts$/, '.js');\n\n\t\t\tif (!importsByFile.has(importPath)) {\n\t\t\t\timportsByFile.set(importPath, []);\n\t\t\t}\n\t\t\timportsByFile.get(importPath)?.push(key);\n\t\t}\n\n\t\t// Generate import statements\n\t\tconst imports = Array.from(importsByFile.entries())\n\t\t\t.map(\n\t\t\t\t([importPath, exports]) =>\n\t\t\t\t\t`import { ${exports.join(', ')} } from '${importPath}';`,\n\t\t\t)\n\t\t\t.join('\\n');\n\n\t\tconst allExportNames = subscribers.map(({ key }) => key);\n\n\t\tconst content = `/**\n * Generated subscribers setup\n *\n * ⚠️  WARNING: This is for LOCAL DEVELOPMENT ONLY\n * This uses event polling which is not suitable for production.\n *\n * For production, use AWS Lambda with SQS/SNS event source mappings.\n * Lambda automatically:\n * - Scales based on queue depth\n * - Handles batch processing and retries\n * - Manages dead letter queues\n * - Provides better cost optimization\n *\n * This polling implementation is useful for:\n * - Local development and testing\n * - Understanding event flow without Lambda deployment\n *\n * Supported connection strings:\n * - sqs://region/account-id/queue-name (SQS queue)\n * - sns://region/account-id/topic-name (SNS topic)\n * - rabbitmq://host:port/queue-name (RabbitMQ)\n * - pgboss://user:pass@host:port/database (pg-boss / PostgreSQL)\n * - basic://in-memory (In-memory for testing)\n */\nimport type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { EventConnectionFactory, Subscriber } from '@geekmidas/events';\nimport type { EventConnection, EventSubscriber } from '@geekmidas/events';\nimport { ServiceDiscovery } from '@geekmidas/services';\n${imports}\n\nconst subscribers = [\n  ${allExportNames.join(',\\n  ')}\n];\n\nconst activeSubscribers: EventSubscriber<any>[] = [];\n\nexport async function setupSubscribers(\n  envParser: EnvironmentParser<any>,\n  logger: Logger,\n): Promise<void> {\n  if (subscribers.length === 0) {\n    return;\n  }\n\n  logger.info('Setting up subscribers in polling mode (local development)');\n\n  const config = envParser.create((get) => ({\n    connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string(),\n  })).parse();\n\n  const serviceDiscovery = ServiceDiscovery.getInstance(envParser);\n\n  // Create connection once, outside the loop (more efficient)\n  // EventConnectionFactory automatically determines the right connection type\n  let connection: EventConnection;\n  try {\n    connection = await EventConnectionFactory.fromConnectionString(config.connectionString);\n\n    const connectionType = new URL(config.connectionString).protocol.replace(':', '');\n    logger.info({ connectionType }, 'Created shared event connection');\n  } catch (error) {\n    logger.error({ error }, 'Failed to create event connection');\n    return;\n  }\n\n  for (const subscriber of subscribers) {\n    try {\n      // Create subscriber from shared connection\n      const eventSubscriber = await Subscriber.fromConnection(connection);\n\n      // Register services\n      const services = subscriber.services.length > 0\n        ? await serviceDiscovery.register(subscriber.services)\n        : {};\n\n      // Subscribe to events\n      const subscribedEvents = subscriber.subscribedEvents || [];\n\n      if (subscribedEvents.length === 0) {\n        logger.warn({ subscriber: subscriber.constructor.name }, 'Subscriber has no subscribed events, skipping');\n        continue;\n      }\n\n      await eventSubscriber.subscribe(subscribedEvents, async (event) => {\n        try {\n          // Process single event (batch of 1)\n          await subscriber.handler({\n            events: [event],\n            services: services as any,\n            logger: subscriber.logger,\n          });\n\n          logger.debug({ eventType: event.type }, 'Successfully processed event');\n        } catch (error) {\n          logger.error({ error, event }, 'Failed to process event');\n          // Event will become visible again for retry\n        }\n      });\n\n      activeSubscribers.push(eventSubscriber);\n\n      logger.info(\n        {\n          events: subscribedEvents,\n        },\n        'Subscriber started polling'\n      );\n    } catch (error) {\n      logger.error({ error, subscriber: subscriber.constructor.name }, 'Failed to setup subscriber');\n    }\n  }\n\n  // Setup graceful shutdown\n  const shutdown = () => {\n    logger.info('Stopping all subscribers');\n    for (const eventSubscriber of activeSubscribers) {\n      connection.stop();\n    }\n  };\n\n  process.on('SIGTERM', shutdown);\n  process.on('SIGINT', shutdown);\n}\n`;\n\n\t\tawait writeFile(subscribersPath, content);\n\t\treturn subscribersPath;\n\t}\n}\n","import { Topic } from '@geekmidas/constructs/topic';\nimport type { BuildContext } from '../build/types';\nimport type { TopicInfo } from '../types';\nimport {\n\tConstructGenerator,\n\ttype GeneratedConstruct,\n\ttype GeneratorOptions,\n} from './Generator';\n\n/**\n * Discovers `t` topics into `manifest.topics`. A topic is a *resource*, not a\n * function — it has no handler to generate. Producers reach it via its derived\n * publisher (`topic.publisher`, whose connection string is sniffed onto the\n * producing construct) and subscribers bind via `s.topic(topic)`; this generator\n * only records the topic + its event contract so infra can provision the SNS\n * topic. Identical output for every provider (locally pg-boss routes by event\n * name, so there's nothing to run).\n */\nexport class TopicGenerator extends ConstructGenerator<\n\tTopic<any, any>,\n\tTopicInfo[]\n> {\n\tisConstruct(value: any): value is Topic<any, any> {\n\t\treturn Topic.isTopic(value);\n\t}\n\n\tasync build(\n\t\t_context: BuildContext,\n\t\tconstructs: GeneratedConstruct<Topic<any, any>>[],\n\t\t_outputDir: string,\n\t\t_options?: GeneratorOptions,\n\t): Promise<TopicInfo[]> {\n\t\tconst logger = console;\n\t\tconst topicInfos = constructs.map(({ construct }) => ({\n\t\t\tname: construct.name,\n\t\t\tevents: construct.eventTypes,\n\t\t}));\n\n\t\tfor (const topic of topicInfos) {\n\t\t\tlogger.log(`Discovered topic: ${topic.name}`);\n\t\t}\n\n\t\treturn topicInfos;\n\t}\n}\n","import { spawn } from 'node:child_process';\nimport { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\n\nconst logger = console;\n\n/**\n * Options for the exec command.\n */\nexport interface ExecOptions {\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Run a command with secrets injected into Credentials.\n * Uses Node's --import flag to preload a script that populates Credentials\n * before the command loads any modules that depend on them.\n *\n * @example\n * ```bash\n * gkm exec -- npx @better-auth/cli migrate\n * gkm exec -- npx prisma migrate dev\n * ```\n */\nexport async function execCommand(\n\tcommandArgs: string[],\n\toptions: ExecOptions = {},\n): Promise<void> {\n\tconst cwd = options.cwd ?? process.cwd();\n\n\tif (commandArgs.length === 0) {\n\t\tthrow new Error('No command specified. Usage: gkm exec -- <command>');\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials: loads secrets, resolves Docker ports, rewrites URLs,\n\t// injects dependency URLs. Uses readonly port mode (no probing for new ports).\n\tconst { credentials, secretsJsonPath, appName } =\n\t\tawait prepareEntryCredentials({ cwd, resolveDockerPorts: 'readonly' });\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName}`);\n\t}\n\n\tconst secretCount = Object.keys(credentials).filter(\n\t\t(k) => k !== 'PORT',\n\t).length;\n\tif (secretCount > 0) {\n\t\tlogger.log(`🔐 Loaded ${secretCount} secret(s)`);\n\t}\n\n\t// Create preload script that injects Credentials\n\t// Written as .mjs (plain ESM) so it doesn't need tsx — this avoids\n\t// breaking frameworks like Next.js whose workers inherit NODE_OPTIONS.\n\tconst preloadDir = join(cwd, '.gkm');\n\tawait mkdir(preloadDir, { recursive: true });\n\tconst preloadPath = join(preloadDir, 'credentials-preload.mjs');\n\tawait createCredentialsPreload(preloadPath, secretsJsonPath);\n\n\t// Build command\n\tconst [cmd, ...args] = commandArgs;\n\n\tif (!cmd) {\n\t\tthrow new Error('No command specified');\n\t}\n\n\tlogger.log(`🚀 Running: ${[cmd, ...args].join(' ')}`);\n\n\t// Build NODE_OPTIONS for the child process.\n\t// Strip any --import flags from the inherited NODE_OPTIONS — the gkm binary\n\t// adds --import=tsx for itself, but the spawned command (e.g. next, prisma)\n\t// doesn't need it and it breaks frameworks that spawn their own workers.\n\tconst existingNodeOptions = (process.env.NODE_OPTIONS ?? '')\n\t\t.replace(/--import[= ]\\S+/g, '')\n\t\t.trim();\n\tconst preloadImport = `--import=${preloadPath}`;\n\n\tconst nodeOptions = [existingNodeOptions, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Spawn the command with secrets in both:\n\t// 1. Environment variables (for tools that read process.env directly)\n\t// 2. Preload script (for tools that use Credentials object)\n\tconst child = spawn(cmd, args, {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...credentials, // Inject secrets as env vars\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for the command to complete\n\tconst exitCode = await new Promise<number>((resolve) => {\n\t\tchild.on('close', (code: number | null) => resolve(code ?? 0));\n\t\tchild.on('error', (error: Error) => {\n\t\t\tlogger.error(`Failed to run command: ${error.message}`);\n\t\t\tresolve(1);\n\t\t});\n\t});\n\n\tif (exitCode !== 0) {\n\t\tprocess.exit(exitCode);\n\t}\n}\n","import { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport chokidar from 'chokidar';\nimport fg from 'fast-glob';\nimport { resolveProviders } from '../build/providerResolver';\nimport type {\n\tBuildContext,\n\tNormalizedHooksConfig,\n\tNormalizedProductionConfig,\n\tNormalizedStudioConfig,\n\tNormalizedTelescopeConfig,\n} from '../build/types';\nimport {\n\tgetAppNameFromCwd,\n\tloadAppConfig,\n\tloadWorkspaceConfig,\n\tparseModuleConfig,\n} from '../config';\nimport {\n\tcreateEntryWrapper,\n\tfindAvailablePort,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadSecretsForApp,\n\tprepareEntryCredentials,\n\tresolveServicePorts,\n\trewriteUrlsWithPorts,\n\tstartWorkspaceServices,\n} from '../credentials';\nimport {\n\tCronGenerator,\n\tEndpointGenerator,\n\tFunctionGenerator,\n\tQueueGenerator,\n\tSubscriberGenerator,\n\tTopicGenerator,\n} from '../generators';\nimport {\n\tgenerateOpenApi,\n\tOPENAPI_OUTPUT_PATH,\n\tresolveOpenApiConfig,\n} from '../openapi';\nimport {\n\treadStageSecrets,\n\tsecretsExist,\n\ttoEmbeddableSecrets,\n} from '../secrets/storage.js';\nimport type {\n\tGkmConfig,\n\tLegacyProvider,\n\tProductionConfig,\n\tRuntime,\n\tServerConfig,\n\tStudioConfig,\n\tTelescopeConfig,\n} from '../types';\nimport {\n\ttype FrontendFramework,\n\tgetAppBuildOrder,\n\tgetDependencyEnvVars,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\n\n// Re-export shared utilities from credentials module so existing imports\n// from '../dev' or '../dev/index' continue to work.\nexport {\n\tbuildDockerComposeEnv,\n\ttype ComposePortMapping,\n\tcreateCredentialsPreload,\n\tcreateEntryWrapper,\n\ttype EntryCredentialsResult,\n\tfindAvailablePort,\n\tfindSecretsRoot,\n\tgetContainerHostPort,\n\tisPortAvailable,\n\tloadEnvFiles,\n\tloadPortState,\n\tloadSecretsForApp,\n\ttype PortState,\n\tparseComposePortMappings,\n\tparseComposeServiceNames,\n\tprepareEntryCredentials,\n\ttype ResolvedServicePorts,\n\treplacePortInUrl,\n\tresolveServicePorts,\n\trewriteUrlsWithPorts,\n\tsavePortState,\n\tstartComposeServices,\n\tstartWorkspaceServices,\n} from '../credentials';\n\n// Re-export execCommand from its own module\nexport { type ExecOptions, execCommand } from '../exec';\n\nconst logger = console;\n\n/**\n * Normalize telescope configuration\n * @internal Exported for testing\n */\nexport function normalizeTelescopeConfig(\n\tconfig: GkmConfig['telescope'],\n): NormalizedTelescopeConfig | undefined {\n\tif (config === false) {\n\t\treturn undefined;\n\t}\n\n\t// Handle string path (e.g., './src/config/telescope')\n\tif (typeof config === 'string') {\n\t\tconst { path: telescopePath, importPattern: telescopeImportPattern } =\n\t\t\tparseModuleConfig(config, 'telescope');\n\n\t\treturn {\n\t\t\tenabled: true,\n\t\t\ttelescopePath,\n\t\t\ttelescopeImportPattern,\n\t\t\tpath: '/__telescope',\n\t\t\tignore: [],\n\t\t\trecordBody: true,\n\t\t\tmaxEntries: 1000,\n\t\t\twebsocket: true,\n\t\t};\n\t}\n\n\t// Default to enabled in development mode\n\tconst isEnabled =\n\t\tconfig === true || config === undefined || config.enabled !== false;\n\n\tif (!isEnabled) {\n\t\treturn undefined;\n\t}\n\n\tconst telescopeConfig: TelescopeConfig =\n\t\ttypeof config === 'object' ? config : {};\n\n\treturn {\n\t\tenabled: true,\n\t\tpath: telescopeConfig.path ?? '/__telescope',\n\t\tignore: telescopeConfig.ignore ?? [],\n\t\trecordBody: telescopeConfig.recordBody ?? true,\n\t\tmaxEntries: telescopeConfig.maxEntries ?? 1000,\n\t\twebsocket: telescopeConfig.websocket ?? true,\n\t};\n}\n\n/**\n * Normalize studio configuration\n * @internal Exported for testing\n */\nexport function normalizeStudioConfig(\n\tconfig: GkmConfig['studio'],\n): NormalizedStudioConfig | undefined {\n\tif (config === false) {\n\t\treturn undefined;\n\t}\n\n\t// Handle string path (e.g., './src/config/studio')\n\tif (typeof config === 'string') {\n\t\tconst { path: studioPath, importPattern: studioImportPattern } =\n\t\t\tparseModuleConfig(config, 'studio');\n\n\t\treturn {\n\t\t\tenabled: true,\n\t\t\tstudioPath,\n\t\t\tstudioImportPattern,\n\t\t\tpath: '/__studio',\n\t\t\tschema: 'public',\n\t\t};\n\t}\n\n\t// Default to enabled in development mode\n\tconst isEnabled =\n\t\tconfig === true || config === undefined || config.enabled !== false;\n\n\tif (!isEnabled) {\n\t\treturn undefined;\n\t}\n\n\tconst studioConfig: StudioConfig = typeof config === 'object' ? config : {};\n\n\treturn {\n\t\tenabled: true,\n\t\tpath: studioConfig.path ?? '/__studio',\n\t\tschema: studioConfig.schema ?? 'public',\n\t};\n}\n\n/**\n * Normalize hooks configuration\n * @internal Exported for testing\n */\nexport function normalizeHooksConfig(\n\tconfig: GkmConfig['hooks'],\n\tcwd: string = process.cwd(),\n): NormalizedHooksConfig | undefined {\n\tif (!config?.server) {\n\t\treturn undefined;\n\t}\n\n\t// Resolve the path (handle .ts extension)\n\tconst serverPath = config.server.endsWith('.ts')\n\t\t? config.server\n\t\t: `${config.server}.ts`;\n\n\tconst resolvedPath = resolve(cwd, serverPath);\n\n\treturn {\n\t\tserverHooksPath: resolvedPath,\n\t};\n}\n\n/**\n * Normalize production configuration\n * @internal Exported for testing\n */\nexport function normalizeProductionConfig(\n\tcliProduction: boolean,\n\tconfigProduction?: ProductionConfig,\n): NormalizedProductionConfig | undefined {\n\t// Production mode is only enabled if --production CLI flag is passed\n\tif (!cliProduction) {\n\t\treturn undefined;\n\t}\n\n\t// Merge CLI flag with config options\n\tconst config = configProduction ?? {};\n\n\treturn {\n\t\tenabled: true,\n\t\tbundle: config.bundle ?? true,\n\t\tminify: config.minify ?? true,\n\t\thealthCheck: config.healthCheck ?? '/health',\n\t\tgracefulShutdown: config.gracefulShutdown ?? true,\n\t\texternal: config.external ?? [],\n\t\tsubscribers: config.subscribers ?? 'exclude',\n\t\topenapi: config.openapi ?? false,\n\t\toptimizedHandlers: config.optimizedHandlers ?? true, // Default to optimized handlers in production\n\t};\n}\n\n/**\n * Get production config from GkmConfig\n * @internal\n */\nexport function getProductionConfigFromGkm(\n\tconfig: GkmConfig,\n): ProductionConfig | undefined {\n\tconst serverConfig = config.providers?.server;\n\tif (typeof serverConfig === 'object') {\n\t\treturn (serverConfig as ServerConfig).production;\n\t}\n\treturn undefined;\n}\n\nexport interface DevOptions {\n\tport?: number;\n\tportExplicit?: boolean;\n\tenableOpenApi?: boolean;\n\t/** Specific app to run in workspace mode (default: all apps) */\n\tapp?: string;\n\t/** Filter apps by pattern (passed to turbo --filter) */\n\tfilter?: string;\n\t/** Entry file to run (bypasses gkm config) */\n\tentry?: string;\n\t/** Watch for file changes (default: true with --entry) */\n\twatch?: boolean;\n}\n\nexport async function devCommand(options: DevOptions): Promise<void> {\n\t// Handle --entry mode: run any file with secret injection\n\tif (options.entry) {\n\t\treturn entryDevCommand(options);\n\t}\n\n\t// Load default .env file BEFORE loading config\n\t// This ensures env vars are available when config and its dependencies are loaded\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Check if we're in an app subdirectory\n\tconst appName = getAppNameFromCwd();\n\tlet config: GkmConfig;\n\tlet appRoot: string = process.cwd();\n\tlet secretsRoot: string = process.cwd(); // Where .gkm/secrets/ lives\n\tlet workspaceAppName: string | undefined; // Set if in workspace mode\n\tlet workspaceAppPort: number | undefined; // Port from workspace config\n\tlet workspace: NormalizedWorkspace | undefined; // Set if in workspace mode\n\n\tif (appName) {\n\t\t// Try to load app-specific config from workspace\n\t\ttry {\n\t\t\tconst appConfig = await loadAppConfig();\n\t\t\tconfig = appConfig.gkmConfig;\n\t\t\tappRoot = appConfig.appRoot;\n\t\t\tsecretsRoot = appConfig.workspaceRoot;\n\t\t\tworkspaceAppName = appConfig.appName;\n\t\t\tworkspaceAppPort = appConfig.app.port;\n\t\t\tworkspace = appConfig.workspace;\n\t\t\tlogger.log(\n\t\t\t\t`📦 Running app: ${appConfig.appName} on port ${workspaceAppPort}`,\n\t\t\t);\n\n\t\t\t// Check if app has an entry point (non-gkm app like better-auth)\n\t\t\tif (appConfig.app.entry) {\n\t\t\t\tlogger.log(`📄 Using entry point: ${appConfig.app.entry}`);\n\t\t\t\treturn entryDevCommand({\n\t\t\t\t\t...options,\n\t\t\t\t\tentry: appConfig.app.entry,\n\t\t\t\t\tport: workspaceAppPort,\n\t\t\t\t\tportExplicit: true,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not in a workspace or app not found in workspace - fall back to regular loading\n\t\t\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t\t\t// Route to workspace dev mode for multi-app workspaces\n\t\t\tif (loadedConfig.type === 'workspace') {\n\t\t\t\tlogger.log('📦 Detected workspace configuration');\n\t\t\t\treturn workspaceDevCommand(loadedConfig.workspace, options);\n\t\t\t}\n\n\t\t\tconfig = loadedConfig.raw as GkmConfig;\n\t\t}\n\t} else {\n\t\t// Try to load workspace config\n\t\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t\t// Route to workspace dev mode for multi-app workspaces\n\t\tif (loadedConfig.type === 'workspace') {\n\t\t\tlogger.log('📦 Detected workspace configuration');\n\t\t\treturn workspaceDevCommand(loadedConfig.workspace, options);\n\t\t}\n\n\t\t// Single-app mode - use existing logic\n\t\tconfig = loadedConfig.raw as GkmConfig;\n\t}\n\n\t// Load any additional env files specified in config\n\tif (config.env) {\n\t\tconst { loaded, missing } = loadEnvFiles(config.env, appRoot);\n\t\tif (loaded.length > 0) {\n\t\t\tlogger.log(`📦 Loaded env: ${loaded.join(', ')}`);\n\t\t}\n\t\tif (missing.length > 0) {\n\t\t\tlogger.warn(`⚠️  Missing env files: ${missing.join(', ')}`);\n\t\t}\n\t}\n\n\t// Force server provider for dev mode\n\tconst resolved = resolveProviders(config, { provider: 'server' });\n\n\tlogger.log('🚀 Starting development server...');\n\tlogger.log(`Loading routes from: ${config.routes}`);\n\tif (config.functions) {\n\t\tlogger.log(`Loading functions from: ${config.functions}`);\n\t}\n\tif (config.crons) {\n\t\tlogger.log(`Loading crons from: ${config.crons}`);\n\t}\n\tif (config.subscribers) {\n\t\tlogger.log(`Loading subscribers from: ${config.subscribers}`);\n\t}\n\tlogger.log(`Using envParser: ${config.envParser}`);\n\n\t// Parse envParser and logger configuration\n\tconst { path: envParserPath, importPattern: envParserImportPattern } =\n\t\tparseModuleConfig(config.envParser, 'envParser');\n\tconst { path: loggerPath, importPattern: loggerImportPattern } =\n\t\tparseModuleConfig(config.logger, 'logger');\n\n\t// Normalize telescope configuration\n\tconst telescope = normalizeTelescopeConfig(config.telescope);\n\tif (telescope) {\n\t\tlogger.log(`🔭 Telescope enabled at ${telescope.path}`);\n\t}\n\n\t// Normalize studio configuration\n\tconst studio = normalizeStudioConfig(config.studio);\n\tif (studio) {\n\t\tlogger.log(`🗄️  Studio enabled at ${studio.path}`);\n\t}\n\n\t// Normalize hooks configuration\n\tconst hooks = normalizeHooksConfig(config.hooks, appRoot);\n\tif (hooks) {\n\t\tlogger.log(`🪝 Server hooks enabled from ${config.hooks?.server}`);\n\t}\n\n\t// Resolve OpenAPI configuration\n\tconst openApiConfig = resolveOpenApiConfig(config);\n\t// Enable OpenAPI docs endpoint if either root config or provider config enables it\n\tconst enableOpenApi = openApiConfig.enabled || resolved.enableOpenApi;\n\tif (enableOpenApi) {\n\t\tlogger.log(`📄 OpenAPI output: ${OPENAPI_OUTPUT_PATH}`);\n\t}\n\n\tconst buildContext: BuildContext = {\n\t\tenvParserPath,\n\t\tenvParserImportPattern,\n\t\tloggerPath,\n\t\tloggerImportPattern,\n\t\ttelescope,\n\t\tstudio,\n\t\thooks,\n\t};\n\n\t// Build initial version\n\tawait buildServer(\n\t\tconfig,\n\t\tbuildContext,\n\t\tresolved.providers[0] as LegacyProvider,\n\t\tenableOpenApi,\n\t\tappRoot,\n\t);\n\n\t// Generate OpenAPI spec on startup\n\tif (enableOpenApi) {\n\t\tawait generateOpenApi(config);\n\t}\n\n\t// Determine runtime (default to node)\n\tconst runtime: Runtime = config.runtime ?? 'node';\n\n\t// Load secrets for dev mode, resolve Docker ports, and write to JSON file\n\tlet secretsJsonPath: string | undefined;\n\tconst appSecrets = await loadSecretsForApp(secretsRoot, workspaceAppName);\n\n\t// Resolve Docker service ports and rewrite connection URLs\n\tconst resolvedPorts = await resolveServicePorts(secretsRoot);\n\tif (Object.keys(resolvedPorts.ports).length > 0) {\n\t\tconst rewritten = rewriteUrlsWithPorts(appSecrets, resolvedPorts);\n\t\tObject.assign(appSecrets, rewritten);\n\t\tlogger.log(\n\t\t\t`🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`,\n\t\t);\n\t}\n\n\t// Inject dependency URLs if in workspace mode\n\tif (workspace && workspaceAppName) {\n\t\tconst depEnv = getDependencyEnvVars(workspace, workspaceAppName);\n\t\tObject.assign(appSecrets, depEnv);\n\t}\n\n\tif (Object.keys(appSecrets).length > 0) {\n\t\tconst secretsDir = join(secretsRoot, '.gkm');\n\t\tawait mkdir(secretsDir, { recursive: true });\n\t\tconst secretsFileName = workspaceAppName\n\t\t\t? `dev-secrets-${workspaceAppName}.json`\n\t\t\t: 'dev-secrets.json';\n\t\tsecretsJsonPath = join(secretsDir, secretsFileName);\n\t\tawait writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));\n\t\tlogger.log(`🔐 Loaded ${Object.keys(appSecrets).length} secret(s)`);\n\t}\n\n\t// Start the dev server\n\t// Priority: explicit --port option > workspace app port > default 3000\n\tconst devServer = new DevServer(\n\t\tresolved.providers[0] as LegacyProvider,\n\t\toptions.port ?? workspaceAppPort ?? 3000,\n\t\toptions.portExplicit ?? false,\n\t\tenableOpenApi,\n\t\ttelescope,\n\t\tstudio,\n\t\truntime,\n\t\tappRoot,\n\t\tsecretsJsonPath,\n\t);\n\n\tawait devServer.start();\n\n\t// Watch for file changes\n\tconst envParserFile = config.envParser.split('#')[0] ?? config.envParser;\n\tconst loggerFile = config.logger.split('#')[0] ?? config.logger;\n\n\t// Get hooks file path for watching\n\tconst hooksFileParts = config.hooks?.server?.split('#');\n\tconst hooksFile = hooksFileParts?.[0];\n\n\tconst watchPatterns = [\n\t\tconfig.routes,\n\t\t...(config.functions ? [config.functions] : []),\n\t\t...(config.crons ? [config.crons] : []),\n\t\t...(config.subscribers ? [config.subscribers] : []),\n\t\t// Add .ts extension if not present for config files\n\t\tenvParserFile.endsWith('.ts') ? envParserFile : `${envParserFile}.ts`,\n\t\tloggerFile.endsWith('.ts') ? loggerFile : `${loggerFile}.ts`,\n\t\t// Add hooks file to watch list\n\t\t...(hooksFile\n\t\t\t? [hooksFile.endsWith('.ts') ? hooksFile : `${hooksFile}.ts`]\n\t\t\t: []),\n\t]\n\t\t.flat()\n\t\t.filter((p): p is string => typeof p === 'string');\n\n\t// Normalize patterns - remove leading ./ when using cwd option\n\tconst normalizedPatterns = watchPatterns.map((p) =>\n\t\tp.startsWith('./') ? p.slice(2) : p,\n\t);\n\n\tlogger.log(`👀 Watching for changes in: ${normalizedPatterns.join(', ')}`);\n\n\t// Resolve glob patterns to actual files (chokidar 4.x doesn't support globs)\n\tconst resolvedFiles = await fg(normalizedPatterns, {\n\t\tcwd: appRoot,\n\t\tabsolute: false,\n\t\tonlyFiles: true,\n\t});\n\n\t// Also watch the directories for new files\n\tconst dirsToWatch = [\n\t\t...new Set(\n\t\t\tresolvedFiles.map((f) => {\n\t\t\t\tconst parts = f.split('/');\n\t\t\t\treturn parts.slice(0, -1).join('/');\n\t\t\t}),\n\t\t),\n\t];\n\n\tlogger.log(\n\t\t`📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`,\n\t);\n\n\tconst watcher = chokidar.watch([...resolvedFiles, ...dirsToWatch], {\n\t\tignored: /(^|[/\\\\])\\../, // ignore dotfiles\n\t\tpersistent: true,\n\t\tignoreInitial: true,\n\t\tcwd: appRoot,\n\t});\n\n\twatcher.on('ready', () => {\n\t\tlogger.log('🔍 File watcher ready');\n\t});\n\n\twatcher.on('error', (error) => {\n\t\tlogger.error('❌ Watcher error:', error);\n\t});\n\n\tlet rebuildTimeout: NodeJS.Timeout | null = null;\n\n\twatcher.on('change', async (path) => {\n\t\tlogger.log(`📝 File changed: ${path}`);\n\n\t\t// Debounce rebuilds\n\t\tif (rebuildTimeout) {\n\t\t\tclearTimeout(rebuildTimeout);\n\t\t}\n\n\t\trebuildTimeout = setTimeout(async () => {\n\t\t\ttry {\n\t\t\t\tlogger.log('🔄 Rebuilding...');\n\t\t\t\tawait buildServer(\n\t\t\t\t\tconfig,\n\t\t\t\t\tbuildContext,\n\t\t\t\t\tresolved.providers[0] as LegacyProvider,\n\t\t\t\t\tenableOpenApi,\n\t\t\t\t\tappRoot,\n\t\t\t\t\ttrue, // bust module cache on rebuild\n\t\t\t\t);\n\n\t\t\t\t// Regenerate OpenAPI if enabled\n\t\t\t\tif (enableOpenApi) {\n\t\t\t\t\tawait generateOpenApi(config, { silent: true, bustCache: true });\n\t\t\t\t}\n\n\t\t\t\tlogger.log('✅ Rebuild complete, restarting server...');\n\t\t\t\tawait devServer.restart();\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tlogger.error(`❌ Rebuild failed: ${err.message}`);\n\t\t\t\tif (err.stack) {\n\t\t\t\t\tlogger.error(err.stack);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 300);\n\t});\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\n\t\t// Use sync-style shutdown to ensure it completes before exit\n\t\tPromise.all([watcher.close(), devServer.stop()])\n\t\t\t.catch((err) => {\n\t\t\t\tlogger.error('Error during shutdown:', err);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tprocess.exit(0);\n\t\t\t});\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n}\n\n/**\n * Generate all dependency environment variables for all apps.\n * Returns a flat object with all {APP_NAME}_URL variables.\n * @internal Exported for testing\n */\nexport function generateAllDependencyEnvVars(\n\tworkspace: NormalizedWorkspace,\n\turlPrefix = 'http://localhost',\n): Record<string, string> {\n\tconst env: Record<string, string> = {};\n\n\tfor (const appName of Object.keys(workspace.apps)) {\n\t\tconst appEnv = getDependencyEnvVars(workspace, appName, urlPrefix);\n\t\tObject.assign(env, appEnv);\n\t}\n\n\treturn env;\n}\n\n/**\n * Check for port conflicts across all apps.\n * Returns list of conflicts if any ports are duplicated.\n * @internal Exported for testing\n */\nexport function checkPortConflicts(\n\tworkspace: NormalizedWorkspace,\n): { app1: string; app2: string; port: number }[] {\n\tconst conflicts: { app1: string; app2: string; port: number }[] = [];\n\tconst portToApp = new Map<number, string>();\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tconst existingApp = portToApp.get(app.port);\n\t\tif (existingApp) {\n\t\t\tconflicts.push({ app1: existingApp, app2: appName, port: app.port });\n\t\t} else {\n\t\t\tportToApp.set(app.port, appName);\n\t\t}\n\t}\n\n\treturn conflicts;\n}\n\n/**\n * Per-framework validation spec for supported frontend frameworks.\n */\ninterface FrontendFrameworkSpec {\n\tdisplayName: string;\n\tconfigFiles: string[];\n\tdependency: string;\n\tinstallCommand: string;\n}\n\nconst FRONTEND_FRAMEWORKS: Record<FrontendFramework, FrontendFrameworkSpec> = {\n\tnextjs: {\n\t\tdisplayName: 'Next.js',\n\t\tconfigFiles: [\n\t\t\t'next.config.js',\n\t\t\t'next.config.ts',\n\t\t\t'next.config.mjs',\n\t\t\t'next.config.cjs',\n\t\t],\n\t\tdependency: 'next',\n\t\tinstallCommand: 'pnpm add next react react-dom',\n\t},\n\tremix: {\n\t\tdisplayName: 'Remix',\n\t\tconfigFiles: [\n\t\t\t'remix.config.js',\n\t\t\t'remix.config.mjs',\n\t\t\t'remix.config.ts',\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@remix-run/dev',\n\t\tinstallCommand: 'pnpm add -D @remix-run/dev',\n\t},\n\tvite: {\n\t\tdisplayName: 'Vite',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: 'vite',\n\t\tinstallCommand: 'pnpm add -D vite',\n\t},\n\t'tanstack-start': {\n\t\tdisplayName: 'TanStack Start',\n\t\tconfigFiles: [\n\t\t\t'vite.config.js',\n\t\t\t'vite.config.ts',\n\t\t\t'vite.config.mjs',\n\t\t\t'vite.config.cjs',\n\t\t],\n\t\tdependency: '@tanstack/react-start',\n\t\tinstallCommand: 'pnpm add @tanstack/react-start @tanstack/react-router',\n\t},\n\texpo: {\n\t\tdisplayName: 'Expo',\n\t\tconfigFiles: ['app.config.ts', 'app.config.js', 'app.json'],\n\t\tdependency: 'expo',\n\t\tinstallCommand: 'pnpm add expo',\n\t},\n};\n\n/**\n * Auto-detect the frontend framework by scanning package.json deps and config\n * files. Dependency match wins over config file match because deps are more\n * distinctive (a Remix app has both vite.config.ts AND @remix-run/dev).\n */\nfunction detectFrontendFramework(\n\tfullPath: string,\n\tdeps: Record<string, string>,\n): FrontendFramework | undefined {\n\t// tanstack-start before vite/remix so its more specific dep wins; vite last\n\t// because plain vite is the fallback when neither nextjs/remix/tanstack match.\n\t// Order matters: more specific deps win over general ones.\n\t// expo first (own dep), then tanstack-start (uses vite), remix (uses vite),\n\t// nextjs (own dep), and plain vite last as the fallback.\n\tconst order: FrontendFramework[] = [\n\t\t'expo',\n\t\t'tanstack-start',\n\t\t'nextjs',\n\t\t'remix',\n\t\t'vite',\n\t];\n\tfor (const name of order) {\n\t\tif (deps[FRONTEND_FRAMEWORKS[name].dependency]) {\n\t\t\treturn name;\n\t\t}\n\t}\n\tfor (const name of order) {\n\t\tconst hasConfig = FRONTEND_FRAMEWORKS[name].configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (hasConfig) {\n\t\t\treturn name;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * Validation result for a frontend app.\n */\nexport interface FrontendValidationResult {\n\tappName: string;\n\tvalid: boolean;\n\terrors: string[];\n\twarnings: string[];\n}\n\n/**\n * Validate a frontend app configuration.\n *\n * If `framework` is provided, validates strictly against that framework's\n * expected config file and dependency. Otherwise auto-detects the framework\n * from package.json and config files. If no recognized framework is found, the\n * app is allowed through with a warning provided it has a `dev` script.\n *\n * @internal Exported for testing\n */\nexport async function validateFrontendApp(\n\tappName: string,\n\tappPath: string,\n\tworkspaceRoot: string,\n\tframework?: FrontendFramework,\n): Promise<FrontendValidationResult> {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst fullPath = join(workspaceRoot, appPath);\n\n\tconst packageJsonPath = join(fullPath, 'package.json');\n\tif (!existsSync(packageJsonPath)) {\n\t\terrors.push(\n\t\t\t`package.json not found at ${appPath}. Run: pnpm init in the app directory.`,\n\t\t);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tlet pkg: {\n\t\tdependencies?: Record<string, string>;\n\t\tdevDependencies?: Record<string, string>;\n\t\tscripts?: Record<string, string>;\n\t};\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tpkg = require(packageJsonPath);\n\t} catch {\n\t\terrors.push(`Failed to read package.json at ${packageJsonPath}`);\n\t\treturn { appName, valid: false, errors, warnings };\n\t}\n\n\tconst deps: Record<string, string> = {\n\t\t...pkg.dependencies,\n\t\t...pkg.devDependencies,\n\t};\n\n\tconst resolvedFramework =\n\t\tframework ?? detectFrontendFramework(fullPath, deps);\n\n\tif (resolvedFramework) {\n\t\tconst spec = FRONTEND_FRAMEWORKS[resolvedFramework];\n\t\tconst hasConfig = spec.configFiles.some((file) =>\n\t\t\texistsSync(join(fullPath, file)),\n\t\t);\n\t\tif (!hasConfig) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} config file not found. Expected one of: ${spec.configFiles.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (!deps[spec.dependency]) {\n\t\t\terrors.push(\n\t\t\t\t`${spec.displayName} not found in dependencies. Run: ${spec.installCommand}`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\twarnings.push(\n\t\t\t'No recognized frontend framework detected (Next.js, Vite, Remix). ' +\n\t\t\t\t'The app will run via its \"dev\" script. Set `framework` in your app config to enable strict validation.',\n\t\t);\n\t}\n\n\tif (!pkg.scripts?.dev) {\n\t\tif (resolvedFramework) {\n\t\t\twarnings.push(\n\t\t\t\t'No \"dev\" script found in package.json. Turbo expects a \"dev\" script to run.',\n\t\t\t);\n\t\t} else {\n\t\t\terrors.push(\n\t\t\t\t'No \"dev\" script found in package.json. Without a recognized framework or a dev script, there is nothing to run.',\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tappName,\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n/**\n * Validate all frontend apps in the workspace.\n * Returns validation results for each frontend app.\n * @internal Exported for testing\n */\nexport async function validateFrontendApps(\n\tworkspace: NormalizedWorkspace,\n): Promise<FrontendValidationResult[]> {\n\tconst results: FrontendValidationResult[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'web') {\n\t\t\tconst result = await validateFrontendApp(\n\t\t\t\tappName,\n\t\t\t\tapp.path,\n\t\t\t\tworkspace.root,\n\t\t\t\tapp.framework as FrontendFramework | undefined,\n\t\t\t);\n\t\t\tresults.push(result);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Load secrets for development stage.\n * Returns env vars to inject, or empty object if secrets not configured/found.\n * @internal Exported for testing\n */\nexport async function loadDevSecrets(\n\tworkspace: NormalizedWorkspace,\n): Promise<Record<string, string>> {\n\t// Check if secrets are enabled in workspace config\n\tif (!workspace.secrets.enabled) {\n\t\treturn {};\n\t}\n\n\t// Try 'dev' stage first, then 'development'\n\tconst stages = ['dev', 'development'];\n\n\tfor (const stage of stages) {\n\t\tif (secretsExist(stage, workspace.root)) {\n\t\t\tconst secrets = await readStageSecrets(stage, workspace.root);\n\t\t\tif (secrets) {\n\t\t\t\tlogger.log(`🔐 Loading secrets from stage: ${stage}`);\n\t\t\t\treturn toEmbeddableSecrets(secrets);\n\t\t\t}\n\t\t}\n\t}\n\n\tlogger.warn(\n\t\t'⚠️  Secrets enabled but no dev/development secrets found. Run \"gkm setup\" to initialize your development environment',\n\t);\n\treturn {};\n}\n\n/**\n * Workspace dev command - orchestrates multi-app development using Turbo.\n *\n * Flow:\n * 1. Check for port conflicts\n * 2. Start docker-compose services (db, cache, mail)\n * 3. Generate dependency URLs ({APP_NAME}_URL)\n * 4. Spawn turbo run dev with injected env vars\n */\nasync function workspaceDevCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: DevOptions,\n): Promise<void> {\n\tconst appCount = Object.keys(workspace.apps).length;\n\tconst backendApps = Object.entries(workspace.apps).filter(\n\t\t([_, app]) => app.type === 'backend',\n\t);\n\tconst frontendApps = Object.entries(workspace.apps).filter(\n\t\t([_, app]) => app.type === 'web',\n\t);\n\tconst mobileApps = Object.entries(workspace.apps).filter(\n\t\t([_, app]) => app.type === 'mobile',\n\t);\n\n\tlogger.log(`\\n🚀 Starting workspace: ${workspace.name}`);\n\tconst counts = [\n\t\t`${backendApps.length} backend`,\n\t\t`${frontendApps.length} web`,\n\t];\n\tif (mobileApps.length > 0) counts.push(`${mobileApps.length} mobile`);\n\tlogger.log(`   ${counts.join(', ')} app(s)`);\n\n\t// Check for port conflicts\n\tconst conflicts = checkPortConflicts(workspace);\n\tif (conflicts.length > 0) {\n\t\tfor (const conflict of conflicts) {\n\t\t\tlogger.error(\n\t\t\t\t`❌ Port conflict: Apps \"${conflict.app1}\" and \"${conflict.app2}\" both use port ${conflict.port}`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(\n\t\t\t'Port conflicts detected. Please assign unique ports to each app.',\n\t\t);\n\t}\n\n\t// Validate frontend apps (Next.js setup)\n\tif (frontendApps.length > 0) {\n\t\tlogger.log('\\n🔍 Validating frontend apps...');\n\t\tconst validationResults = await validateFrontendApps(workspace);\n\n\t\tlet hasErrors = false;\n\t\tfor (const result of validationResults) {\n\t\t\tif (!result.valid) {\n\t\t\t\thasErrors = true;\n\t\t\t\tlogger.error(\n\t\t\t\t\t`\\n❌ Frontend app \"${result.appName}\" validation failed:`,\n\t\t\t\t);\n\t\t\t\tfor (const error of result.errors) {\n\t\t\t\t\tlogger.error(`   • ${error}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const warning of result.warnings) {\n\t\t\t\tlogger.warn(`   ⚠️  ${result.appName}: ${warning}`);\n\t\t\t}\n\t\t}\n\n\t\tif (hasErrors) {\n\t\t\tthrow new Error(\n\t\t\t\t'Frontend app validation failed. Fix the issues above and try again.',\n\t\t\t);\n\t\t}\n\t\tlogger.log('✅ Frontend apps validated');\n\t}\n\n\t// Frontend apps import API clients directly from backend packages\n\t// (e.g. import { createApi } from '@myapp/api/client')\n\t// No file copying needed — pnpm workspace resolution handles it.\n\n\t// Resolve dynamic service ports from docker-compose.yml\n\tconst resolvedPorts = await resolveServicePorts(workspace.root);\n\n\t// Load secrets BEFORE starting Docker so POSTGRES_USER, POSTGRES_PASSWORD,\n\t// etc. are available for docker-compose variable interpolation\n\tconst rawSecrets = await loadDevSecrets(workspace);\n\n\t// Start docker-compose services with resolved ports AND secrets\n\tawait startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);\n\n\t// Rewrite URLs with resolved ports (hostnames and port numbers)\n\tconst secretsEnv = rewriteUrlsWithPorts(rawSecrets, resolvedPorts);\n\tif (Object.keys(secretsEnv).length > 0) {\n\t\tlogger.log(`   Loaded ${Object.keys(secretsEnv).length} secret(s)`);\n\t}\n\n\t// Generate dependency URLs\n\tconst dependencyEnv = generateAllDependencyEnvVars(workspace);\n\tif (Object.keys(dependencyEnv).length > 0) {\n\t\tlogger.log('📡 Dependency URLs:');\n\t\tfor (const [key, value] of Object.entries(dependencyEnv)) {\n\t\t\tlogger.log(`   ${key}=${value}`);\n\t\t}\n\t}\n\n\t// Build turbo filter\n\tlet turboFilter: string[] = [];\n\tif (options.app) {\n\t\t// Run specific app\n\t\tif (!workspace.apps[options.app]) {\n\t\t\tconst appNames = Object.keys(workspace.apps).join(', ');\n\t\t\tthrow new Error(\n\t\t\t\t`App \"${options.app}\" not found. Available apps: ${appNames}`,\n\t\t\t);\n\t\t}\n\t\tturboFilter = ['--filter', options.app];\n\t\tlogger.log(`\\n🎯 Running single app: ${options.app}`);\n\t} else if (options.filter) {\n\t\t// Use custom filter\n\t\tturboFilter = ['--filter', options.filter];\n\t\tlogger.log(`\\n🔍 Using filter: ${options.filter}`);\n\t} else {\n\t\t// Run all apps\n\t\tlogger.log(`\\n🎯 Running all ${appCount} apps`);\n\t}\n\n\t// List apps and their ports\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlogger.log('\\n📋 Apps (in dependency order):');\n\tfor (const appName of buildOrder) {\n\t\tconst app = workspace.apps[appName];\n\t\tif (!app) continue;\n\t\tconst deps =\n\t\t\tapp.dependencies.length > 0\n\t\t\t\t? ` (depends on: ${app.dependencies.join(', ')})`\n\t\t\t\t: '';\n\t\tconst icon =\n\t\t\tapp.type === 'backend' ? '🔧' : app.type === 'mobile' ? '📱' : '🌐';\n\t\tlogger.log(`   ${icon} ${appName} → http://localhost:${app.port}${deps}`);\n\t}\n\n\t// Find the config file path for GKM_CONFIG_PATH\n\tconst configFiles = ['gkm.config.ts', 'gkm.config.js', 'gkm.config.json'];\n\tlet configPath = '';\n\tfor (const file of configFiles) {\n\t\tconst fullPath = join(workspace.root, file);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconfigPath = fullPath;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Prepare environment variables\n\t// Order matters: secrets first, then dependencies (dependencies can override)\n\tconst turboEnv: Record<string, string> = {\n\t\t...process.env,\n\t\t...secretsEnv,\n\t\t...dependencyEnv,\n\t\tNODE_ENV: 'development',\n\t\t// Inject config path so child processes can find the workspace config\n\t\t...(configPath ? { GKM_CONFIG_PATH: configPath } : {}),\n\t};\n\n\t// Spawn turbo run dev\n\tlogger.log('\\n🏃 Starting turbo run dev...\\n');\n\n\tconst turboProcess = spawn('pnpm', ['turbo', 'run', 'dev', ...turboFilter], {\n\t\tcwd: workspace.root,\n\t\tstdio: 'inherit',\n\t\tenv: turboEnv,\n\t\tdetached: true,\n\t});\n\n\t// No file watcher needed — frontend apps import API clients directly\n\t// from backend packages via workspace dependencies.\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down workspace...');\n\n\t\t// Kill turbo process group\n\t\tconst pid = turboProcess.pid;\n\t\tif (pid) {\n\t\t\ttry {\n\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\t// Process already dead\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Force kill after timeout if processes are still alive\n\t\tsetTimeout(() => {\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tprocess.exit(0);\n\t\t}, 3000);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Wait for turbo to exit\n\treturn new Promise((resolve, reject) => {\n\t\tturboProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Turbo error:', error);\n\t\t\treject(error);\n\t\t});\n\n\t\tturboProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0) {\n\t\t\t\treject(new Error(`Turbo exited with code ${code}`));\n\t\t\t} else {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t});\n}\n\nasync function buildServer(\n\tconfig: any,\n\tcontext: BuildContext,\n\tprovider: LegacyProvider,\n\tenableOpenApi: boolean,\n\tappRoot: string = process.cwd(),\n\tbustCache = false,\n): Promise<void> {\n\t// Initialize generators\n\tconst endpointGenerator = new EndpointGenerator();\n\tconst functionGenerator = new FunctionGenerator();\n\tconst cronGenerator = new CronGenerator();\n\tconst subscriberGenerator = new SubscriberGenerator();\n\tconst queueGenerator = new QueueGenerator();\n\tconst topicGenerator = new TopicGenerator();\n\n\t// Load all constructs (resolve paths relative to appRoot)\n\tconst [\n\t\tallEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t] = await Promise.all([\n\t\tendpointGenerator.load(config.routes, appRoot, bustCache),\n\t\tconfig.functions\n\t\t\t? functionGenerator.load(config.functions, appRoot, bustCache)\n\t\t\t: [],\n\t\tconfig.crons ? cronGenerator.load(config.crons, appRoot, bustCache) : [],\n\t\tconfig.subscribers\n\t\t\t? subscriberGenerator.load(config.subscribers, appRoot, bustCache)\n\t\t\t: [],\n\t\tconfig.queues ? queueGenerator.load(config.queues, appRoot, bustCache) : [],\n\t\tconfig.topics ? topicGenerator.load(config.topics, appRoot, bustCache) : [],\n\t]);\n\n\t// Ensure .gkm directory exists in app root\n\tconst outputDir = join(appRoot, '.gkm', provider);\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build for server provider\n\tawait Promise.all([\n\t\tendpointGenerator.build(context, allEndpoints, outputDir, {\n\t\t\tprovider,\n\t\t\tenableOpenApi,\n\t\t}),\n\t\tfunctionGenerator.build(context, allFunctions, outputDir, { provider }),\n\t\tcronGenerator.build(context, allCrons, outputDir, { provider }),\n\t\tsubscriberGenerator.build(context, allSubscribers, outputDir, { provider }),\n\t\tqueueGenerator.build(context, allQueues, outputDir, { provider }),\n\t\ttopicGenerator.build(context, allTopics, outputDir, { provider }),\n\t]);\n}\n\n/**\n * Run any TypeScript file with secret injection.\n * Does not require gkm.config.ts.\n */\nasync function entryDevCommand(options: DevOptions): Promise<void> {\n\tconst { entry, watch = true } = options;\n\n\tif (!entry) {\n\t\tthrow new Error('--entry requires a file path');\n\t}\n\n\tconst entryPath = resolve(process.cwd(), entry);\n\n\tif (!existsSync(entryPath)) {\n\t\tthrow new Error(`Entry file not found: ${entryPath}`);\n\t}\n\n\t// Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tlogger.log(`📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// Prepare credentials (loads workspace config, secrets, injects PORT)\n\t// Only pass explicitPort if --port was actually specified by the user\n\tconst { credentials, resolvedPort, secretsJsonPath, appName } =\n\t\tawait prepareEntryCredentials({\n\t\t\texplicitPort: options.portExplicit ? options.port : undefined,\n\t\t});\n\n\tif (appName) {\n\t\tlogger.log(`📦 App: ${appName} (port ${resolvedPort})`);\n\t}\n\n\tlogger.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);\n\n\tif (Object.keys(credentials).length > 1) {\n\t\tlogger.log(\n\t\t\t`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`,\n\t\t);\n\t}\n\n\t// Create wrapper entry that injects secrets before importing user's file\n\tconst wrapperDir = join(process.cwd(), '.gkm');\n\tawait mkdir(wrapperDir, { recursive: true });\n\tconst wrapperPath = join(wrapperDir, 'entry-wrapper.ts');\n\tawait createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);\n\n\t// Start with tsx\n\tconst runner = new EntryRunner(wrapperPath, entryPath, watch, resolvedPort);\n\tawait runner.start();\n\n\t// Handle graceful shutdown\n\tlet isShuttingDown = false;\n\tconst shutdown = () => {\n\t\tif (isShuttingDown) return;\n\t\tisShuttingDown = true;\n\n\t\tlogger.log('\\n🛑 Shutting down...');\n\t\trunner.stop();\n\t\tprocess.exit(0);\n\t};\n\n\tprocess.on('SIGINT', shutdown);\n\tprocess.on('SIGTERM', shutdown);\n\n\t// Keep the process alive\n\tawait new Promise(() => {});\n}\n\n/**\n * Runs and watches a TypeScript entry file using tsx.\n */\nclass EntryRunner {\n\tprivate childProcess: ChildProcess | null = null;\n\tprivate watcher: ReturnType<typeof chokidar.watch> | null = null;\n\tprivate isRunning = false;\n\n\tconstructor(\n\t\tprivate wrapperPath: string,\n\t\tprivate entryPath: string,\n\t\tprivate watch: boolean,\n\t\tprivate port: number,\n\t) {}\n\n\tasync start(): Promise<void> {\n\t\tawait this.runProcess();\n\n\t\tif (this.watch) {\n\t\t\t// Watch the entry file's directory for changes\n\t\t\tconst watchDir = dirname(this.entryPath);\n\n\t\t\tthis.watcher = chokidar.watch(watchDir, {\n\t\t\t\tignored: /(^|[/\\\\])\\../,\n\t\t\t\tpersistent: true,\n\t\t\t\tignoreInitial: true,\n\t\t\t});\n\n\t\t\tlet restartTimeout: NodeJS.Timeout | null = null;\n\n\t\t\tthis.watcher.on('change', (path) => {\n\t\t\t\tlogger.log(`📝 File changed: ${path}`);\n\n\t\t\t\t// Debounce restarts\n\t\t\t\tif (restartTimeout) {\n\t\t\t\t\tclearTimeout(restartTimeout);\n\t\t\t\t}\n\n\t\t\t\trestartTimeout = setTimeout(async () => {\n\t\t\t\t\tlogger.log('🔄 Restarting...');\n\t\t\t\t\tawait this.restart();\n\t\t\t\t}, 300);\n\t\t\t});\n\n\t\t\tlogger.log(`👀 Watching for changes in: ${watchDir}`);\n\t\t}\n\t}\n\n\tprivate async runProcess(): Promise<void> {\n\t\t// Pass PORT as environment variable\n\t\tconst env = { ...process.env, PORT: String(this.port) };\n\n\t\tthis.childProcess = spawn('npx', ['tsx', this.wrapperPath], {\n\t\t\tstdio: 'inherit',\n\t\t\tenv,\n\t\t\tdetached: true,\n\t\t});\n\n\t\tthis.isRunning = true;\n\n\t\tthis.childProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Process error:', error);\n\t\t});\n\n\t\tthis.childProcess.on('exit', (code) => {\n\t\t\tif (code !== null && code !== 0 && code !== 143) {\n\t\t\t\t// 143 = SIGTERM\n\t\t\t\tlogger.error(`❌ Process exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t});\n\n\t\t// Give the process a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t\tif (this.isRunning) {\n\t\t\tlogger.log('');\n\t\t\tlogger.log(\n\t\t\t\t`  \\x1b[32m✓ Ready\\x1b[0m at \\x1b[36mhttp://localhost:${this.port}\\x1b[0m`,\n\t\t\t);\n\t\t\tlogger.log('');\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tthis.stopProcess();\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\tawait this.runProcess();\n\t}\n\n\tstop(): void {\n\t\tthis.watcher?.close();\n\t\tthis.stopProcess();\n\t}\n\n\tprivate stopProcess(): void {\n\t\tif (this.childProcess && this.isRunning) {\n\t\t\tconst pid = this.childProcess.pid;\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGTERM');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGTERM');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process already dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.childProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\t}\n}\n\n/**\n * Generate the content of the dev server entry file (server.ts).\n * Uses dynamic import for createApp so Credentials are populated\n * before any app modules evaluate.\n * @internal Exported for testing\n */\nexport function generateServerEntryContent(options: {\n\tsecretsJsonPath?: string;\n\truntime?: Runtime;\n\tenableOpenApi?: boolean;\n\tappImportPath?: string;\n}): string {\n\tconst {\n\t\tsecretsJsonPath,\n\t\truntime = 'node',\n\t\tenableOpenApi = false,\n\t\tappImportPath = './app.js',\n\t} = options;\n\n\tconst credentialsInjection = secretsJsonPath\n\t\t? `import { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets via globalThis (must happen before app import)\nconst secretsPath = '${secretsJsonPath}';\nif (existsSync(secretsPath)) {\n  const __secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));\n  globalThis.__gkm_credentials__ = __secrets;\n  Object.assign(process.env, __secrets);\n}\n\n`\n\t\t: '';\n\n\tconst serveCode =\n\t\truntime === 'bun'\n\t\t\t? `Bun.serve({\n      port,\n      fetch: app.fetch,\n    });`\n\t\t\t: `const { serve } = await import('@hono/node-server');\n    const server = serve({\n      fetch: app.fetch,\n      port,\n    });\n    // Inject WebSocket support if available\n    const injectWs = (app as any).__injectWebSocket;\n    if (injectWs) {\n      injectWs(server);\n      console.log('🔌 Telescope real-time updates enabled');\n    }`;\n\n\treturn `#!/usr/bin/env node\n/**\n * Development server entry point\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}\nconst port = process.argv.includes('--port')\n  ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n  : 3000;\n\n// Dynamic import so Credentials are populated before env.ts evaluates\nconst { createApp } = await import('${appImportPath}');\n\n// createApp is async to support optional WebSocket setup\nconst { app, start } = await createApp(undefined, ${enableOpenApi});\n\n// Start the server\nstart({\n  port,\n  serve: async (app, port) => {\n    ${serveCode}\n  },\n}).catch((error) => {\n  console.error('Failed to start server:', error);\n  process.exit(1);\n});\n`;\n}\n\nclass DevServer {\n\tprivate serverProcess: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate actualPort: number;\n\tprivate startTime = Date.now();\n\n\tconstructor(\n\t\tprivate provider: LegacyProvider,\n\t\tprivate requestedPort: number,\n\t\tprivate portExplicit: boolean,\n\t\tprivate enableOpenApi: boolean,\n\t\tprivate telescope: NormalizedTelescopeConfig | undefined,\n\t\tprivate studio: NormalizedStudioConfig | undefined,\n\t\tprivate runtime: Runtime = 'node',\n\t\tprivate appRoot: string = process.cwd(),\n\t\tprivate secretsJsonPath?: string,\n\t) {\n\t\tthis.actualPort = requestedPort;\n\t}\n\n\tasync start(): Promise<void> {\n\t\tthis.startTime = Date.now();\n\t\tif (this.isRunning) {\n\t\t\tawait this.stop();\n\t\t}\n\n\t\t// Check port availability\n\t\tif (this.portExplicit) {\n\t\t\t// Port was explicitly specified - throw if unavailable\n\t\t\tconst available = await isPortAvailable(this.requestedPort);\n\t\t\tif (!available) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Port ${this.requestedPort} is already in use. ` +\n\t\t\t\t\t\t`Either stop the process using that port or omit -p/--port to auto-select an available port.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.actualPort = this.requestedPort;\n\t\t} else {\n\t\t\t// Find an available port starting from the default\n\t\t\tthis.actualPort = await findAvailablePort(this.requestedPort);\n\n\t\t\tif (this.actualPort !== this.requestedPort) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`ℹ️  Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst serverEntryPath = join(\n\t\t\tthis.appRoot,\n\t\t\t'.gkm',\n\t\t\tthis.provider,\n\t\t\t'server.ts',\n\t\t);\n\n\t\t// Create server entry file\n\t\tawait this.createServerEntry();\n\n\t\tlogger.log(`\\n⏳ Starting server...`);\n\n\t\t// Start the server using tsx (TypeScript execution)\n\t\t// Use detached: true so we can kill the entire process tree\n\t\tthis.serverProcess = spawn(\n\t\t\t'npx',\n\t\t\t['tsx', serverEntryPath, '--port', this.actualPort.toString()],\n\t\t\t{\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv: { ...process.env, NODE_ENV: 'development' },\n\t\t\t\tdetached: true,\n\t\t\t},\n\t\t);\n\n\t\tthis.isRunning = true;\n\n\t\tthis.serverProcess.on('error', (error) => {\n\t\t\tlogger.error('❌ Server error:', error);\n\t\t});\n\n\t\tthis.serverProcess.on('exit', (code, signal) => {\n\t\t\tif (code !== null && code !== 0 && signal !== 'SIGTERM') {\n\t\t\t\tlogger.error(`❌ Server exited with code ${code}`);\n\t\t\t}\n\t\t\tthis.isRunning = false;\n\t\t});\n\n\t\t// Give the server a moment to start\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\n\t\tif (this.isRunning) {\n\t\t\tconst base = `http://localhost:${this.actualPort}`;\n\t\t\tconst lines: string[] = [`  Local:     ${base}`];\n\t\t\tif (this.enableOpenApi) {\n\t\t\t\tlines.push(`  API Docs:  ${base}/__docs`);\n\t\t\t}\n\t\t\tif (this.telescope) {\n\t\t\t\tlines.push(`  Telescope: ${base}${this.telescope.path}`);\n\t\t\t}\n\t\t\tif (this.studio) {\n\t\t\t\tlines.push(`  Studio:    ${base}${this.studio.path}`);\n\t\t\t}\n\n\t\t\tconst maxLen = Math.max(...lines.map((l) => l.length));\n\t\t\tconst pad = (s: string) => s.padEnd(maxLen);\n\t\t\tconst border = '─'.repeat(maxLen + 2);\n\n\t\t\tlogger.log('');\n\t\t\tlogger.log(\n\t\t\t\t`  \\x1b[32m✓ Ready\\x1b[0m in ${((Date.now() - this.startTime) / 1000).toFixed(1)}s`,\n\t\t\t);\n\t\t\tlogger.log('');\n\t\t\tlogger.log(`  ┌${border}┐`);\n\t\t\tfor (const line of lines) {\n\t\t\t\tlogger.log(`  │ ${pad(line)} │`);\n\t\t\t}\n\t\t\tlogger.log(`  └${border}┘`);\n\t\t\tlogger.log('');\n\t\t}\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tconst port = this.actualPort;\n\n\t\tif (this.serverProcess && this.isRunning) {\n\t\t\tconst pid = this.serverProcess.pid;\n\n\t\t\t// Use SIGKILL directly since the server ignores SIGTERM\n\t\t\tif (pid) {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, 'SIGKILL');\n\t\t\t\t} catch {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 'SIGKILL');\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Process might already be dead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.serverProcess = null;\n\t\t\tthis.isRunning = false;\n\t\t}\n\n\t\t// Also kill any processes still holding the port\n\t\tthis.killProcessesOnPort(port);\n\t}\n\n\tprivate killProcessesOnPort(port: number): void {\n\t\ttry {\n\t\t\t// Use lsof to find PIDs on the port and kill them with -9\n\t\t\texecSync(`lsof -ti tcp:${port} | xargs kill -9 2>/dev/null || true`, {\n\t\t\t\tstdio: 'ignore',\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors - port may already be free\n\t\t}\n\t}\n\n\tasync restart(): Promise<void> {\n\t\tconst portToReuse = this.actualPort;\n\t\tawait this.stop();\n\n\t\t// Wait for port to be released (up to 3 seconds)\n\t\tlet attempts = 0;\n\t\twhile (attempts < 30) {\n\t\t\tif (await isPortAvailable(portToReuse)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\t\t\tattempts++;\n\t\t}\n\n\t\t// Force reuse the same port\n\t\tthis.requestedPort = portToReuse;\n\t\tawait this.start();\n\t}\n\n\tprivate async createServerEntry(): Promise<void> {\n\t\tconst { writeFile: fsWriteFile } = await import('node:fs/promises');\n\n\t\tconst serverPath = join(this.appRoot, '.gkm', this.provider, 'server.ts');\n\n\t\tconst content = generateServerEntryContent({\n\t\t\tsecretsJsonPath: this.secretsJsonPath,\n\t\t\truntime: this.runtime,\n\t\t\tenableOpenApi: this.enableOpenApi,\n\t\t});\n\n\t\tawait fsWriteFile(serverPath, content);\n\t}\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type {\n\tCronInfo,\n\tFunctionInfo,\n\tQueueInfo,\n\tRouteInfo,\n\tSubscriberInfo,\n\tTopicInfo,\n} from '../types';\n\nconst logger = console;\n\nexport type ManifestProvider = 'aws' | 'server';\n\nexport interface ServerAppInfo {\n\thandler: string;\n\tendpoints: string;\n}\n\n/**\n * A manifest field is either a flat array (no partition) or\n * an object keyed by partition name (partitioned).\n */\nexport type ManifestField<T> = T[] | Record<string, T[]>;\n\nfunction isPartitioned<T>(\n\tfield: ManifestField<T>,\n): field is Record<string, T[]> {\n\treturn !Array.isArray(field);\n}\n\n/**\n * Serialize a manifest field to a TypeScript string.\n * Flat arrays serialize as JSON arrays, partitioned fields as objects of arrays.\n */\nfunction serializeField<T>(field: ManifestField<T>, indent = 2): string {\n\tif (Array.isArray(field)) {\n\t\treturn JSON.stringify(field, null, indent);\n\t}\n\t// Partitioned: { admin: [...], default: [...] }\n\tconst entries = Object.entries(field)\n\t\t.map(\n\t\t\t([key, value]) =>\n\t\t\t\t`    ${JSON.stringify(key)}: ${JSON.stringify(value, null, indent)}`,\n\t\t)\n\t\t.join(',\\n');\n\treturn `{\\n${entries},\\n  }`;\n}\n\n/**\n * Count total items across a manifest field (flat or partitioned).\n */\nfunction countItems<T>(field: ManifestField<T>): number {\n\tif (Array.isArray(field)) return field.length;\n\treturn Object.values(field).reduce((sum, arr) => sum + arr.length, 0);\n}\n\n/**\n * Generate derived types for a construct field.\n * @param fieldName - The field name in the manifest (e.g., 'routes')\n * @param typeName - The exported type name (e.g., 'Route')\n * @param partitioned - Whether this field is partitioned\n */\nfunction generateDerivedType(\n\tfieldName: string,\n\ttypeName: string,\n\tpartitioned: boolean,\n): string {\n\tif (partitioned) {\n\t\tconst partitionTypeName = `${typeName}Partition`;\n\t\treturn [\n\t\t\t`export type ${partitionTypeName} = keyof typeof manifest.${fieldName};`,\n\t\t\t`export type ${typeName}<P extends ${partitionTypeName} = ${partitionTypeName}> = (typeof manifest.${fieldName})[P][number];`,\n\t\t].join('\\n');\n\t}\n\treturn `export type ${typeName} = (typeof manifest.${fieldName})[number];`;\n}\n\nexport async function generateAwsManifest(\n\toutputDir: string,\n\troutes: ManifestField<RouteInfo>,\n\tfunctions: ManifestField<FunctionInfo>,\n\tcrons: ManifestField<CronInfo>,\n\tsubscribers: ManifestField<SubscriberInfo>,\n\tqueues: ManifestField<QueueInfo> = [],\n\ttopics: ManifestField<TopicInfo> = [],\n): Promise<void> {\n\tconst manifestDir = join(outputDir, 'manifest');\n\tawait mkdir(manifestDir, { recursive: true });\n\n\t// Filter out 'ALL' method routes (server-specific)\n\tconst awsRoutes = filterAllRoutes(routes);\n\n\tconst routesPartitioned = isPartitioned(awsRoutes);\n\tconst functionsPartitioned = isPartitioned(functions);\n\tconst cronsPartitioned = isPartitioned(crons);\n\tconst subscribersPartitioned = isPartitioned(subscribers);\n\tconst queuesPartitioned = isPartitioned(queues);\n\tconst topicsPartitioned = isPartitioned(topics);\n\n\tconst content = `export const manifest = {\n  routes: ${serializeField(awsRoutes)},\n  functions: ${serializeField(functions)},\n  crons: ${serializeField(crons)},\n  subscribers: ${serializeField(subscribers)},\n  queues: ${serializeField(queues)},\n  topics: ${serializeField(topics)},\n} as const;\n\n// Derived types\n${generateDerivedType('routes', 'Route', routesPartitioned)}\n${generateDerivedType('functions', 'Function', functionsPartitioned)}\n${generateDerivedType('crons', 'Cron', cronsPartitioned)}\n${generateDerivedType('subscribers', 'Subscriber', subscribersPartitioned)}\n${generateDerivedType('queues', 'Queue', queuesPartitioned)}\n${generateDerivedType('topics', 'Topic', topicsPartitioned)}\n\n// Useful union types\nexport type Authorizer = Route['authorizer'];\nexport type HttpMethod = Route['method'];\nexport type RoutePath = Route['path'];\n`;\n\n\tconst manifestPath = join(manifestDir, 'aws.ts');\n\tawait writeFile(manifestPath, content);\n\n\tlogger.log(\n\t\t`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers, ${countItems(queues)} queues, ${countItems(topics)} topics`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\n}\n\nexport async function generateServerManifest(\n\toutputDir: string,\n\tappInfo: ServerAppInfo,\n\troutes: ManifestField<RouteInfo>,\n\tsubscribers: ManifestField<SubscriberInfo>,\n\tqueues: ManifestField<QueueInfo> = [],\n\ttopics: ManifestField<TopicInfo> = [],\n): Promise<void> {\n\tconst manifestDir = join(outputDir, 'manifest');\n\tawait mkdir(manifestDir, { recursive: true });\n\n\t// For server, extract route metadata (path, method, authorizer)\n\tconst serverRoutes = mapRouteMetadata(filterAllRoutes(routes));\n\n\t// Server subscribers only need name and events\n\tconst serverSubscribers = mapSubscriberMetadata(subscribers);\n\n\t// Server queues only need their name (the worker is wired by setupQueues)\n\tconst serverQueues = mapQueueMetadata(queues);\n\n\t// Server topics only need name + events (pg-boss routes by event name locally)\n\tconst serverTopics = mapTopicMetadata(topics);\n\n\tconst routesPartitioned = isPartitioned(serverRoutes);\n\tconst subscribersPartitioned = isPartitioned(serverSubscribers);\n\tconst queuesPartitioned = isPartitioned(serverQueues);\n\tconst topicsPartitioned = isPartitioned(serverTopics);\n\n\tconst content = `export const manifest = {\n  app: ${JSON.stringify(appInfo, null, 2)},\n  routes: ${serializeField(serverRoutes)},\n  subscribers: ${serializeField(serverSubscribers)},\n  queues: ${serializeField(serverQueues)},\n  topics: ${serializeField(serverTopics)},\n} as const;\n\n// Derived types\n${generateDerivedType('routes', 'Route', routesPartitioned)}\n${generateDerivedType('subscribers', 'Subscriber', subscribersPartitioned)}\n${generateDerivedType('queues', 'Queue', queuesPartitioned)}\n${generateDerivedType('topics', 'Topic', topicsPartitioned)}\n\n// Useful union types\nexport type Authorizer = Route['authorizer'];\nexport type HttpMethod = Route['method'];\nexport type RoutePath = Route['path'];\n`;\n\n\tconst manifestPath = join(manifestDir, 'server.ts');\n\tawait writeFile(manifestPath, content);\n\n\tlogger.log(\n\t\t`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\n}\n\n/**\n * Filter out 'ALL' method routes from a manifest field (flat or partitioned).\n */\nfunction filterAllRoutes(\n\troutes: ManifestField<RouteInfo>,\n): ManifestField<RouteInfo> {\n\tif (Array.isArray(routes)) {\n\t\treturn routes.filter((r) => r.method !== 'ALL');\n\t}\n\tconst result: Record<string, RouteInfo[]> = {};\n\tfor (const [partition, partitionRoutes] of Object.entries(routes)) {\n\t\tresult[partition] = partitionRoutes.filter((r) => r.method !== 'ALL');\n\t}\n\treturn result;\n}\n\n/**\n * Map routes to server metadata (path, method, authorizer only).\n */\nfunction mapRouteMetadata(\n\troutes: ManifestField<RouteInfo>,\n): ManifestField<{ path: string; method: string; authorizer: string }> {\n\tconst mapFn = (r: RouteInfo) => ({\n\t\tpath: r.path,\n\t\tmethod: r.method,\n\t\tauthorizer: r.authorizer,\n\t});\n\n\tif (Array.isArray(routes)) {\n\t\treturn routes.map(mapFn);\n\t}\n\tconst result: Record<\n\t\tstring,\n\t\t{ path: string; method: string; authorizer: string }[]\n\t> = {};\n\tfor (const [partition, partitionRoutes] of Object.entries(routes)) {\n\t\tresult[partition] = partitionRoutes.map(mapFn);\n\t}\n\treturn result;\n}\n\n/**\n * Map subscribers to server metadata (name, subscribedEvents only).\n */\nfunction mapSubscriberMetadata(\n\tsubscribers: ManifestField<SubscriberInfo>,\n): ManifestField<{ name: string; subscribedEvents: readonly string[] }> {\n\tconst mapFn = (s: SubscriberInfo) => ({\n\t\tname: s.name,\n\t\tsubscribedEvents: s.subscribedEvents,\n\t});\n\n\tif (Array.isArray(subscribers)) {\n\t\treturn subscribers.map(mapFn);\n\t}\n\tconst result: Record<\n\t\tstring,\n\t\t{ name: string; subscribedEvents: readonly string[] }[]\n\t> = {};\n\tfor (const [partition, partitionSubs] of Object.entries(subscribers)) {\n\t\tresult[partition] = partitionSubs.map(mapFn);\n\t}\n\treturn result;\n}\n\nfunction mapQueueMetadata(\n\tqueues: ManifestField<QueueInfo>,\n): ManifestField<{ name: string }> {\n\tconst mapFn = (q: QueueInfo) => ({ name: q.name });\n\n\tif (Array.isArray(queues)) {\n\t\treturn queues.map(mapFn);\n\t}\n\tconst result: Record<string, { name: string }[]> = {};\n\tfor (const [partition, partitionQueues] of Object.entries(queues)) {\n\t\tresult[partition] = partitionQueues.map(mapFn);\n\t}\n\treturn result;\n}\n\nfunction mapTopicMetadata(\n\ttopics: ManifestField<TopicInfo>,\n): ManifestField<{ name: string; events: readonly string[] }> {\n\tconst mapFn = (t: TopicInfo) => ({ name: t.name, events: t.events });\n\n\tif (Array.isArray(topics)) {\n\t\treturn topics.map(mapFn);\n\t}\n\tconst result: Record<string, { name: string; events: readonly string[] }[]> =\n\t\t{};\n\tfor (const [partition, partitionTopics] of Object.entries(topics)) {\n\t\tresult[partition] = partitionTopics.map(mapFn);\n\t}\n\treturn result;\n}\n","import type { Construct } from '@geekmidas/constructs';\nimport type { GeneratedConstruct } from '../generators/Generator';\n\nexport const DEFAULT_PARTITION = 'default';\n\n/**\n * Group constructs by their partition field.\n * Constructs without a partition are placed in the 'default' group.\n */\nexport function groupByPartition<T extends Construct>(\n\tconstructs: GeneratedConstruct<T>[],\n): Map<string, GeneratedConstruct<T>[]> {\n\tconst groups = new Map<string, GeneratedConstruct<T>[]>();\n\n\tfor (const construct of constructs) {\n\t\tconst partition = construct.partition ?? DEFAULT_PARTITION;\n\t\tconst group = groups.get(partition);\n\t\tif (group) {\n\t\t\tgroup.push(construct);\n\t\t} else {\n\t\t\tgroups.set(partition, [construct]);\n\t\t}\n\t}\n\n\treturn groups;\n}\n\n/**\n * Check if any construct across the given arrays has a non-undefined partition.\n * When true, the manifest should use the partitioned shape for that construct type.\n */\nexport function hasPartitions<T extends Construct>(\n\tconstructs: GeneratedConstruct<T>[],\n): boolean {\n\treturn constructs.some((c) => c.partition !== undefined);\n}\n\n/**\n * Group an info array by partition, using the partition values from\n * the corresponding construct array. Both arrays must be the same length\n * and in the same order.\n */\nexport function groupInfosByPartition<T>(\n\tinfos: T[],\n\tconstructs: GeneratedConstruct<any>[],\n): Record<string, T[]> {\n\tconst groups: Record<string, T[]> = {};\n\n\tfor (let i = 0; i < infos.length; i++) {\n\t\tconst partition = constructs[i]?.partition ?? DEFAULT_PARTITION;\n\t\tif (!groups[partition]) {\n\t\t\tgroups[partition] = [];\n\t\t}\n\t\tgroups[partition].push(infos[i]!);\n\t}\n\n\treturn groups;\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport { join, relative, resolve } from 'node:path';\nimport type { Cron } from '@geekmidas/constructs/crons';\nimport type { Endpoint } from '@geekmidas/constructs/endpoints';\nimport type { Function } from '@geekmidas/constructs/functions';\nimport type { Queue } from '@geekmidas/constructs/queue';\nimport type { Subscriber } from '@geekmidas/constructs/subscribers';\nimport type { Topic } from '@geekmidas/constructs/topic';\nimport {\n\tloadAppConfig,\n\tloadConfig,\n\tloadWorkspaceConfig,\n\tparseModuleConfig,\n} from '../config';\nimport {\n\tgetProductionConfigFromGkm,\n\tnormalizeHooksConfig,\n\tnormalizeProductionConfig,\n\tnormalizeStudioConfig,\n\tnormalizeTelescopeConfig,\n} from '../dev';\nimport {\n\tCronGenerator,\n\tEndpointGenerator,\n\tFunctionGenerator,\n\ttype GeneratedConstruct,\n\tQueueGenerator,\n\tSubscriberGenerator,\n\tTopicGenerator,\n} from '../generators';\nimport { generateOpenApi, openapiCommand } from '../openapi.js';\nimport {\n\ttype BuildOptions,\n\ttype BuildResult,\n\tisPartitionedRoutes,\n\ttype LegacyProvider,\n\ttype RouteInfo,\n\ttype Routes,\n} from '../types';\nimport {\n\tgetAppBuildOrder,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport {\n\tgenerateAwsManifest,\n\tgenerateServerManifest,\n\ttype ManifestField,\n\ttype ServerAppInfo,\n} from './manifests';\nimport { groupInfosByPartition, hasPartitions } from './partitions';\nimport { resolveProviders } from './providerResolver';\nimport type { BuildContext } from './types';\n\nconst logger = console;\n\nexport async function buildCommand(\n\toptions: BuildOptions,\n): Promise<BuildResult> {\n\t// Load config with workspace detection\n\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t// Route to workspace build mode for multi-app workspaces\n\t// BUT only if we're at the workspace root (prevents recursive builds when\n\t// Turbo runs gkm build in each app subdirectory)\n\tif (loadedConfig.type === 'workspace') {\n\t\tconst cwd = resolve(process.cwd());\n\t\tconst workspaceRoot = resolve(loadedConfig.workspace.root);\n\t\tconst isAtWorkspaceRoot = cwd === workspaceRoot;\n\n\t\tif (isAtWorkspaceRoot) {\n\t\t\tlogger.log('📦 Detected workspace configuration');\n\t\t\treturn workspaceBuildCommand(loadedConfig.workspace, options);\n\t\t}\n\t\t// When running from inside an app directory, use app-specific config\n\t}\n\n\t// Single-app build - use app config if in workspace, otherwise legacy config\n\tconst config =\n\t\tloadedConfig.type === 'workspace'\n\t\t\t? (await loadAppConfig()).gkmConfig\n\t\t\t: await loadConfig();\n\n\t// Resolve providers from new config format\n\tconst resolved = resolveProviders(config, options);\n\n\t// Normalize production configuration\n\tconst productionConfigFromGkm = getProductionConfigFromGkm(config);\n\tconst production = normalizeProductionConfig(\n\t\toptions.production ?? false,\n\t\tproductionConfigFromGkm,\n\t);\n\n\tif (production) {\n\t\tlogger.log(`🏭 Building for PRODUCTION`);\n\t}\n\n\tlogger.log(`Building with providers: ${resolved.providers.join(', ')}`);\n\tlogger.log(`Loading routes from: ${formatRoutes(config.routes)}`);\n\tif (config.functions) {\n\t\tlogger.log(`Loading functions from: ${formatRoutes(config.functions)}`);\n\t}\n\tif (config.crons) {\n\t\tlogger.log(`Loading crons from: ${formatRoutes(config.crons)}`);\n\t}\n\tif (config.subscribers) {\n\t\tlogger.log(`Loading subscribers from: ${formatRoutes(config.subscribers)}`);\n\t}\n\tlogger.log(`Using envParser: ${config.envParser}`);\n\n\t// Parse envParser and logger configuration\n\tconst { path: envParserPath, importPattern: envParserImportPattern } =\n\t\tparseModuleConfig(config.envParser, 'envParser');\n\tconst { path: loggerPath, importPattern: loggerImportPattern } =\n\t\tparseModuleConfig(config.logger, 'logger');\n\n\t// Normalize telescope configuration (disabled in production)\n\tconst telescope = production\n\t\t? undefined\n\t\t: normalizeTelescopeConfig(config.telescope);\n\tif (telescope) {\n\t\tlogger.log(`🔭 Telescope enabled at ${telescope.path}`);\n\t}\n\n\t// Normalize studio configuration (disabled in production)\n\tconst studio = production ? undefined : normalizeStudioConfig(config.studio);\n\tif (studio) {\n\t\tlogger.log(`🗄️  Studio enabled at ${studio.path}`);\n\t}\n\n\t// Normalize hooks configuration\n\tconst hooks = normalizeHooksConfig(config.hooks);\n\tif (hooks) {\n\t\tlogger.log(`🪝 Server hooks enabled`);\n\t}\n\n\t// Extract docker compose services for env var auto-population\n\tconst services = config.docker?.compose?.services;\n\tconst dockerServices = services\n\t\t? Array.isArray(services)\n\t\t\t? {\n\t\t\t\t\tpostgres: services.includes('postgres'),\n\t\t\t\t\tredis: services.includes('redis'),\n\t\t\t\t\trabbitmq: services.includes('rabbitmq'),\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tpostgres: Boolean(services.postgres),\n\t\t\t\t\tredis: Boolean(services.redis),\n\t\t\t\t\trabbitmq: Boolean(services.rabbitmq),\n\t\t\t\t}\n\t\t: undefined;\n\n\tconst buildContext: BuildContext = {\n\t\tenvParserPath,\n\t\tenvParserImportPattern,\n\t\tloggerPath,\n\t\tloggerImportPattern,\n\t\ttelescope,\n\t\tstudio,\n\t\thooks,\n\t\tproduction,\n\t\tdockerServices,\n\t\tmarkOptional: options.markOptional ?? false,\n\t};\n\n\t// Initialize generators\n\tconst endpointGenerator = new EndpointGenerator();\n\tconst functionGenerator = new FunctionGenerator();\n\tconst cronGenerator = new CronGenerator();\n\tconst subscriberGenerator = new SubscriberGenerator();\n\tconst queueGenerator = new QueueGenerator();\n\tconst topicGenerator = new TopicGenerator();\n\n\t// Load all constructs in parallel\n\tconst [\n\t\tallEndpoints,\n\t\tallFunctions,\n\t\tallCrons,\n\t\tallSubscribers,\n\t\tallQueues,\n\t\tallTopics,\n\t] = await Promise.all([\n\t\tendpointGenerator.load(config.routes),\n\t\tconfig.functions ? functionGenerator.load(config.functions) : [],\n\t\tconfig.crons ? cronGenerator.load(config.crons) : [],\n\t\tconfig.subscribers ? subscriberGenerator.load(config.subscribers) : [],\n\t\tconfig.queues ? queueGenerator.load(config.queues) : [],\n\t\tconfig.topics ? topicGenerator.load(config.topics) : [],\n\t]);\n\n\tlogger.log(`Found ${allEndpoints.length} endpoints`);\n\tlogger.log(`Found ${allFunctions.length} functions`);\n\tlogger.log(`Found ${allCrons.length} crons`);\n\tlogger.log(`Found ${allSubscribers.length} subscribers`);\n\tlogger.log(`Found ${allQueues.length} queues`);\n\tlogger.log(`Found ${allTopics.length} topics`);\n\n\tif (\n\t\tallEndpoints.length === 0 &&\n\t\tallFunctions.length === 0 &&\n\t\tallCrons.length === 0 &&\n\t\tallSubscribers.length === 0 &&\n\t\tallQueues.length === 0 &&\n\t\tallTopics.length === 0\n\t) {\n\t\tlogger.log(\n\t\t\t'No endpoints, functions, crons, subscribers, queues, or topics found to process',\n\t\t);\n\t\treturn {};\n\t}\n\n\t// Ensure .gkm directory exists\n\tconst rootOutputDir = join(process.cwd(), '.gkm');\n\tawait mkdir(rootOutputDir, { recursive: true });\n\n\t// Build for each provider and generate per-provider manifests\n\tlet result: BuildResult = {};\n\tfor (const provider of resolved.providers) {\n\t\tconst providerResult = await buildForProvider(\n\t\t\tprovider,\n\t\t\tbuildContext,\n\t\t\trootOutputDir,\n\t\t\tendpointGenerator,\n\t\t\tfunctionGenerator,\n\t\t\tcronGenerator,\n\t\t\tsubscriberGenerator,\n\t\t\tqueueGenerator,\n\t\t\ttopicGenerator,\n\t\t\tallEndpoints,\n\t\t\tallFunctions,\n\t\t\tallCrons,\n\t\t\tallSubscribers,\n\t\t\tallQueues,\n\t\t\tallTopics,\n\t\t\tresolved.enableOpenApi,\n\t\t\toptions.skipBundle ?? false,\n\t\t\toptions.stage,\n\t\t);\n\t\t// Keep the master key from the server provider\n\t\tif (providerResult.masterKey) {\n\t\t\tresult = providerResult;\n\t\t}\n\t}\n\n\t// Generate OpenAPI spec as part of the build\n\tawait generateOpenApi(config, { bustCache: true });\n\n\treturn result;\n}\n\nasync function buildForProvider(\n\tprovider: LegacyProvider,\n\tcontext: BuildContext,\n\trootOutputDir: string,\n\tendpointGenerator: EndpointGenerator,\n\tfunctionGenerator: FunctionGenerator,\n\tcronGenerator: CronGenerator,\n\tsubscriberGenerator: SubscriberGenerator,\n\tqueueGenerator: QueueGenerator,\n\ttopicGenerator: TopicGenerator,\n\tendpoints: GeneratedConstruct<Endpoint<any, any, any, any, any, any>>[],\n\tfunctions: GeneratedConstruct<Function<any, any, any, any>>[],\n\tcrons: GeneratedConstruct<Cron<any, any, any, any>>[],\n\tsubscribers: GeneratedConstruct<Subscriber<any, any, any, any, any, any>>[],\n\tqueues: GeneratedConstruct<Queue<any, any, any, any>>[],\n\ttopics: GeneratedConstruct<Topic<any, any>>[],\n\tenableOpenApi: boolean,\n\tskipBundle: boolean,\n\tstage?: string,\n): Promise<BuildResult> {\n\tconst outputDir = join(process.cwd(), '.gkm', provider);\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\tlogger.log(`\\nGenerating handlers for provider: ${provider}`);\n\n\t// Build all constructs in parallel.\n\t// context.markOptional is forwarded to each generator so that\n\t// getEnvironment({ markOptional }) produces `VARNAME?` for optional vars.\n\tconst [\n\t\troutes,\n\t\tfunctionInfos,\n\t\tcronInfos,\n\t\tsubscriberInfos,\n\t\tqueueInfos,\n\t\ttopicInfos,\n\t] = await Promise.all([\n\t\tendpointGenerator.build(context, endpoints, outputDir, {\n\t\t\tprovider,\n\t\t\tenableOpenApi,\n\t\t}),\n\t\tfunctionGenerator.build(context, functions, outputDir, { provider }),\n\t\tcronGenerator.build(context, crons, outputDir, { provider }),\n\t\tsubscriberGenerator.build(context, subscribers, outputDir, { provider }),\n\t\tqueueGenerator.build(context, queues, outputDir, { provider }),\n\t\ttopicGenerator.build(context, topics, outputDir, { provider }),\n\t]);\n\n\tlogger.log(\n\t\t`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${provider}`,\n\t);\n\n\t// Assemble manifest fields (flat or partitioned per construct type)\n\tconst manifestRoutes = assembleManifestField(routes, endpoints);\n\tconst manifestFunctions = assembleManifestField(functionInfos, functions);\n\tconst manifestCrons = assembleManifestField(cronInfos, crons);\n\tconst manifestQueues = assembleManifestField(queueInfos, queues);\n\tconst manifestTopics = assembleManifestField(topicInfos, topics);\n\tconst manifestSubscribers = assembleManifestField(\n\t\tsubscriberInfos,\n\t\tsubscribers,\n\t);\n\n\t// Generate provider-specific manifest\n\tif (provider === 'server') {\n\t\t// For server, collect actual route metadata from endpoint constructs\n\t\tconst routeMetadata: RouteInfo[] = await Promise.all(\n\t\t\tendpoints.map(async ({ construct }) => ({\n\t\t\t\tpath: construct._path,\n\t\t\t\tmethod: construct.method,\n\t\t\t\thandler: '', // Not needed for server manifest\n\t\t\t\tauthorizer: construct.authorizer?.name ?? 'none',\n\t\t\t})),\n\t\t);\n\n\t\tconst serverRouteField = assembleManifestField(routeMetadata, endpoints);\n\n\t\tconst appInfo: ServerAppInfo = {\n\t\t\thandler: relative(process.cwd(), join(outputDir, 'app.ts')),\n\t\t\tendpoints: relative(process.cwd(), join(outputDir, 'endpoints.ts')),\n\t\t};\n\n\t\tawait generateServerManifest(\n\t\t\trootOutputDir,\n\t\t\tappInfo,\n\t\t\tserverRouteField,\n\t\t\tmanifestSubscribers,\n\t\t\tmanifestQueues,\n\t\t\tmanifestTopics,\n\t\t);\n\n\t\t// Bundle for production if enabled\n\t\tlet masterKey: string | undefined;\n\t\tif (context.production?.bundle && !skipBundle) {\n\t\t\tlogger.log(`\\n📦 Bundling production server...`);\n\t\t\tconst { bundleServer } = await import('./bundler');\n\n\t\t\t// Collect all constructs for environment variable validation\n\t\t\tconst allConstructs = [\n\t\t\t\t...endpoints.map((e) => e.construct),\n\t\t\t\t...functions.map((f) => f.construct),\n\t\t\t\t...crons.map((c) => c.construct),\n\t\t\t\t...subscribers.map((s) => s.construct),\n\t\t\t\t...queues.map((q) => q.construct),\n\t\t\t];\n\n\t\t\t// Get docker compose services for auto-populating env vars\n\t\t\tconst dockerServices = context.dockerServices;\n\n\t\t\tconst bundleResult = await bundleServer({\n\t\t\t\tentryPoint: join(outputDir, 'server.ts'),\n\t\t\t\toutputDir: join(outputDir, 'dist'),\n\t\t\t\tminify: context.production.minify,\n\t\t\t\tsourcemap: false,\n\t\t\t\texternal: context.production.external,\n\t\t\t\tstage,\n\t\t\t\tconstructs: allConstructs,\n\t\t\t\tdockerServices,\n\t\t\t});\n\t\t\tmasterKey = bundleResult.masterKey;\n\t\t\tlogger.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);\n\n\t\t\t// Display master key if secrets were injected\n\t\t\tif (masterKey) {\n\t\t\t\tlogger.log(`\\n🔐 Secrets encrypted for deployment`);\n\t\t\t\tlogger.log(`   Deploy with: GKM_MASTER_KEY=${masterKey}`);\n\t\t\t}\n\t\t}\n\n\t\treturn { masterKey };\n\t} else {\n\t\t// For AWS providers, generate AWS manifest\n\t\tawait generateAwsManifest(\n\t\t\trootOutputDir,\n\t\t\tmanifestRoutes,\n\t\t\tmanifestFunctions,\n\t\t\tmanifestCrons,\n\t\t\tmanifestSubscribers,\n\t\t\tmanifestQueues,\n\t\t\tmanifestTopics,\n\t\t);\n\t}\n\n\treturn {};\n}\n\n/**\n * Result of building a single app in a workspace.\n */\nexport interface AppBuildResult {\n\tappName: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tsuccess: boolean;\n\toutputPath?: string;\n\terror?: string;\n}\n\n/**\n * Result of workspace build command.\n */\nexport interface WorkspaceBuildResult extends BuildResult {\n\tapps: AppBuildResult[];\n}\n\n/**\n * Detect available package manager.\n * @internal Exported for testing\n */\nexport function detectPackageManager(): 'pnpm' | 'npm' | 'yarn' {\n\tif (existsSync('pnpm-lock.yaml')) return 'pnpm';\n\tif (existsSync('yarn.lock')) return 'yarn';\n\treturn 'npm';\n}\n\n/**\n * Get the turbo command for running builds.\n * @internal Exported for testing\n */\nexport function getTurboCommand(\n\tpm: 'pnpm' | 'npm' | 'yarn',\n\tfilter?: string,\n): string {\n\tconst filterArg = filter ? ` --filter=${filter}` : '';\n\tswitch (pm) {\n\t\tcase 'pnpm':\n\t\t\treturn `pnpm exec turbo run build${filterArg}`;\n\t\tcase 'yarn':\n\t\t\treturn `yarn turbo run build${filterArg}`;\n\t\tcase 'npm':\n\t\t\treturn `npx turbo run build${filterArg}`;\n\t}\n}\n\n/**\n * Build all apps in a workspace using Turbo for dependency-ordered parallel builds.\n * @internal Exported for testing\n */\nexport async function workspaceBuildCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: BuildOptions,\n): Promise<WorkspaceBuildResult> {\n\tconst results: AppBuildResult[] = [];\n\tconst apps = Object.entries(workspace.apps);\n\tconst backendApps = apps.filter(([, app]) => app.type === 'backend');\n\tconst frontendApps = apps.filter(([, app]) => app.type === 'web');\n\n\tlogger.log(`\\n🏗️  Building workspace: ${workspace.name}`);\n\tlogger.log(\n\t\t`   Backend apps: ${backendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\tlogger.log(\n\t\t`   Frontend apps: ${frontendApps.map(([name]) => name).join(', ') || 'none'}`,\n\t);\n\n\tif (options.production) {\n\t\tlogger.log(`   🏭 Production mode enabled`);\n\t}\n\n\t// Get build order (topologically sorted by dependencies)\n\tconst buildOrder = getAppBuildOrder(workspace);\n\tlogger.log(`   Build order: ${buildOrder.join(' → ')}`);\n\n\t// Use Turbo for parallel builds with dependency awareness\n\tconst pm = detectPackageManager();\n\tlogger.log(`\\n📦 Using ${pm} with Turbo for parallel builds...\\n`);\n\n\ttry {\n\t\t// Run turbo build which handles dependency ordering and parallelization\n\t\tconst turboCommand = getTurboCommand(pm);\n\t\tlogger.log(`Running: ${turboCommand}`);\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst child = spawn(turboCommand, {\n\t\t\t\tshell: true,\n\t\t\t\tcwd: workspace.root,\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t\t// Pass production flag to builds\n\t\t\t\t\tNODE_ENV: options.production ? 'production' : 'development',\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tchild.on('close', (code) => {\n\t\t\t\tif (code === 0) {\n\t\t\t\t\tresolve();\n\t\t\t\t} else {\n\t\t\t\t\treject(new Error(`Turbo build failed with exit code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.on('error', (err) => {\n\t\t\t\treject(err);\n\t\t\t});\n\t\t});\n\n\t\t// Mark all apps as successful\n\t\tfor (const [appName, app] of apps) {\n\t\t\tconst outputPath = getAppOutputPath(workspace, appName, app);\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: true,\n\t\t\t\toutputPath,\n\t\t\t});\n\t\t}\n\n\t\tlogger.log(`\\n✅ Workspace build complete!`);\n\n\t\t// Generate OpenAPI specs and copy to frontend apps\n\t\tawait openapiCommand({ cwd: workspace.root });\n\n\t\t// Summary\n\t\tlogger.log(`\\n📋 Build Summary:`);\n\t\tfor (const result of results) {\n\t\t\tconst icon =\n\t\t\t\tresult.type === 'backend'\n\t\t\t\t\t? '⚙️'\n\t\t\t\t\t: result.type === 'mobile'\n\t\t\t\t\t\t? '📱'\n\t\t\t\t\t\t: '🌐';\n\t\t\tlogger.log(\n\t\t\t\t`   ${icon} ${result.appName}: ${result.outputPath || 'built'}`,\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tconst errorMessage =\n\t\t\terror instanceof Error ? error.message : 'Build failed';\n\t\tlogger.log(`\\n❌ Build failed: ${errorMessage}`);\n\n\t\t// Mark all apps as failed\n\t\tfor (const [appName, app] of apps) {\n\t\t\tresults.push({\n\t\t\t\tappName,\n\t\t\t\ttype: app.type,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t});\n\t\t}\n\n\t\tthrow error;\n\t}\n\n\treturn { apps: results };\n}\n\n/**\n * Get the output path for a built app.\n */\nfunction getAppOutputPath(\n\tworkspace: NormalizedWorkspace,\n\t_appName: string,\n\tapp: NormalizedAppConfig,\n): string {\n\tconst appPath = join(workspace.root, app.path);\n\n\tif (app.type === 'mobile') {\n\t\t// Mobile builds are produced by the framework's own toolchain\n\t\t// (e.g. EAS Build) — no local output path.\n\t\treturn '';\n\t}\n\tif (app.type === 'web') {\n\t\tswitch (app.framework) {\n\t\t\tcase 'vite':\n\t\t\tcase 'tanstack-start':\n\t\t\t\treturn join(appPath, 'dist');\n\t\t\tcase 'remix':\n\t\t\t\treturn join(appPath, 'build');\n\t\t\tdefault:\n\t\t\t\treturn join(appPath, '.next');\n\t\t}\n\t}\n\t// Backend .gkm output\n\treturn join(appPath, '.gkm');\n}\n\n/**\n * Format routes for logging, handling PartitionedRoutes.\n */\nfunction formatRoutes(routes: Routes): string {\n\tif (isPartitionedRoutes(routes)) {\n\t\tconst paths = Array.isArray(routes.paths)\n\t\t\t? routes.paths.join(', ')\n\t\t\t: routes.paths;\n\t\treturn `${paths} (partitioned)`;\n\t}\n\treturn Array.isArray(routes) ? routes.join(', ') : routes;\n}\n\n/**\n * Assemble a ManifestField from build infos and constructs.\n * If any construct has a partition, returns a Record<string, T[]>.\n * Otherwise, returns a flat T[].\n */\nfunction assembleManifestField<T>(\n\tinfos: T[],\n\tconstructs: GeneratedConstruct<any>[],\n): ManifestField<T> {\n\tif (!hasPartitions(constructs)) {\n\t\treturn infos;\n\t}\n\treturn groupInfosByPartition(infos, constructs);\n}\n","let _debug = false;\n\n/**\n * Enable debug mode globally.\n * When enabled, verbose error details are shown everywhere.\n */\nexport function enableDebug(): void {\n\t_debug = true;\n}\n\n/**\n * Check if debug mode is active.\n * Activated by `--debug` flag or `GKM_DEBUG=1` env var.\n */\nexport function isDebug(): boolean {\n\treturn _debug || process.env.GKM_DEBUG === '1';\n}\n\n/**\n * Log a message only when debug mode is active.\n */\nexport function debug(...args: unknown[]): void {\n\tif (isDebug()) {\n\t\tconsole.debug('[debug]', ...args);\n\t}\n}\n\n/**\n * Format a fatal error for display.\n * Always includes the full stack trace since these are process-ending errors.\n */\nexport function formatError(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tlet output = error.stack ?? error.message;\n\n\t// Include cause chain if present\n\tlet cause = error.cause;\n\twhile (cause) {\n\t\tif (cause instanceof Error) {\n\t\t\toutput += `\\n\\nCaused by: ${cause.stack ?? cause.message}`;\n\t\t\tcause = cause.cause;\n\t\t} else {\n\t\t\toutput += `\\n\\nCaused by: ${String(cause)}`;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn output;\n}\n\n/**\n * Format a non-fatal error for display.\n * Shows only the message by default, full stack in debug mode.\n */\nexport function formatWarning(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\n\tif (!isDebug()) {\n\t\treturn error.message;\n\t}\n\n\treturn error.stack ?? error.message;\n}\n","/**\n * Deploy state management for Dokploy deployments\n *\n * Stores resource IDs (applications, services) per stage to avoid\n * re-creating resources on subsequent deploys.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/**\n * Per-app database credentials\n */\nexport interface AppDbCredentials {\n\tdbUser: string;\n\tdbPassword: string;\n}\n\n/**\n * DNS verification record for a hostname\n */\nexport interface DnsVerificationRecord {\n\tserverIp: string;\n\tverifiedAt: string;\n}\n\n/**\n * A DNS record that was created during deploy\n */\nexport interface CreatedDnsRecord {\n\t/** The domain this record belongs to (e.g., 'example.com') */\n\tdomain: string;\n\t/** Record name/subdomain (e.g., 'api' or '@' for root) */\n\tname: string;\n\t/** Record type (A, CNAME, etc.) */\n\ttype: string;\n\t/** Record value (IP address, hostname, etc.) */\n\tvalue: string;\n\t/** TTL in seconds */\n\tttl: number;\n\t/** When this record was created */\n\tcreatedAt: string;\n}\n\n/**\n * Backup destination state\n */\nexport interface BackupState {\n\t/** S3 bucket name for backups */\n\tbucketName: string;\n\t/** S3 bucket ARN */\n\tbucketArn: string;\n\t/** IAM user name created for backup access */\n\tiamUserName: string;\n\t/** IAM access key ID */\n\tiamAccessKeyId: string;\n\t/** IAM secret access key */\n\tiamSecretAccessKey: string;\n\t/** Dokploy destination ID */\n\tdestinationId: string;\n\t/** Dokploy backup schedule ID for postgres (if configured) */\n\tpostgresBackupId?: string;\n\t/** AWS region where bucket was created */\n\tregion: string;\n\t/** Timestamp when backup was configured */\n\tcreatedAt: string;\n}\n\n/**\n * State for a single stage deployment\n */\nexport interface DokployStageState {\n\tprovider: 'dokploy';\n\tstage: string;\n\t/** Dokploy project ID - created on first deploy */\n\tprojectId: string;\n\tenvironmentId: string;\n\tapplications: Record<string, string>; // appName -> applicationId\n\tservices: {\n\t\tpostgresId?: string;\n\t\tredisId?: string;\n\t};\n\t/** Per-app database credentials for reuse on subsequent deploys */\n\tappCredentials?: Record<string, AppDbCredentials>;\n\t/** Auto-generated secrets per app (e.g., BETTER_AUTH_SECRET) */\n\tgeneratedSecrets?: Record<string, Record<string, string>>;\n\t/** DNS verification state per hostname */\n\tdnsVerified?: Record<string, DnsVerificationRecord>;\n\t/** DNS records created during deploy (keyed by \"name:type\", e.g., \"api:A\") */\n\tdnsRecords?: Record<string, CreatedDnsRecord>;\n\t/** Backup destination state */\n\tbackups?: BackupState;\n\tlastDeployedAt: string;\n}\n\n/**\n * Get the state file path for a stage\n */\nfunction getStateFilePath(workspaceRoot: string, stage: string): string {\n\treturn join(workspaceRoot, '.gkm', `deploy-${stage}.json`);\n}\n\n/**\n * Read the deploy state for a stage\n * Returns null if state file doesn't exist\n */\nexport async function readStageState(\n\tworkspaceRoot: string,\n\tstage: string,\n): Promise<DokployStageState | null> {\n\tconst filePath = getStateFilePath(workspaceRoot, stage);\n\n\ttry {\n\t\tconst content = await readFile(filePath, 'utf-8');\n\t\treturn JSON.parse(content) as DokployStageState;\n\t} catch (error) {\n\t\t// File doesn't exist or is invalid - return null\n\t\tif ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\treturn null;\n\t\t}\n\t\t// Log other errors but don't fail\n\t\tconsole.warn(`Warning: Could not read deploy state: ${error}`);\n\t\treturn null;\n\t}\n}\n\n/**\n * Write the deploy state for a stage\n */\nexport async function writeStageState(\n\tworkspaceRoot: string,\n\tstage: string,\n\tstate: DokployStageState,\n): Promise<void> {\n\tconst filePath = getStateFilePath(workspaceRoot, stage);\n\tconst dir = join(workspaceRoot, '.gkm');\n\n\t// Ensure .gkm directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Update last deployed timestamp\n\tstate.lastDeployedAt = new Date().toISOString();\n\n\tawait writeFile(filePath, JSON.stringify(state, null, 2));\n}\n\n/**\n * Create a new empty state for a stage\n */\nexport function createEmptyState(\n\tstage: string,\n\tprojectId: string,\n\tenvironmentId: string,\n): DokployStageState {\n\treturn {\n\t\tprovider: 'dokploy',\n\t\tstage,\n\t\tprojectId,\n\t\tenvironmentId,\n\t\tapplications: {},\n\t\tservices: {},\n\t\tlastDeployedAt: new Date().toISOString(),\n\t};\n}\n\n/**\n * Get application ID from state\n */\nexport function getApplicationId(\n\tstate: DokployStageState | null,\n\tappName: string,\n): string | undefined {\n\treturn state?.applications[appName];\n}\n\n/**\n * Set application ID in state (mutates state)\n */\nexport function setApplicationId(\n\tstate: DokployStageState,\n\tappName: string,\n\tapplicationId: string,\n): void {\n\tstate.applications[appName] = applicationId;\n}\n\n/**\n * Get postgres ID from state\n */\nexport function getPostgresId(\n\tstate: DokployStageState | null,\n): string | undefined {\n\treturn state?.services.postgresId;\n}\n\n/**\n * Set postgres ID in state (mutates state)\n */\nexport function setPostgresId(\n\tstate: DokployStageState,\n\tpostgresId: string,\n): void {\n\tstate.services.postgresId = postgresId;\n}\n\n/**\n * Get redis ID from state\n */\nexport function getRedisId(\n\tstate: DokployStageState | null,\n): string | undefined {\n\treturn state?.services.redisId;\n}\n\n/**\n * Set redis ID in state (mutates state)\n */\nexport function setRedisId(state: DokployStageState, redisId: string): void {\n\tstate.services.redisId = redisId;\n}\n\n/**\n * Get app credentials from state\n */\nexport function getAppCredentials(\n\tstate: DokployStageState | null,\n\tappName: string,\n): AppDbCredentials | undefined {\n\treturn state?.appCredentials?.[appName];\n}\n\n/**\n * Set app credentials in state (mutates state)\n */\nexport function setAppCredentials(\n\tstate: DokployStageState,\n\tappName: string,\n\tcredentials: AppDbCredentials,\n): void {\n\tif (!state.appCredentials) {\n\t\tstate.appCredentials = {};\n\t}\n\tstate.appCredentials[appName] = credentials;\n}\n\n/**\n * Get all app credentials from state\n */\nexport function getAllAppCredentials(\n\tstate: DokployStageState | null,\n): Record<string, AppDbCredentials> {\n\treturn state?.appCredentials ?? {};\n}\n\n// ============================================================================\n// Generated Secrets\n// ============================================================================\n\n/**\n * Get a generated secret for an app\n */\nexport function getGeneratedSecret(\n\tstate: DokployStageState | null,\n\tappName: string,\n\tsecretName: string,\n): string | undefined {\n\treturn state?.generatedSecrets?.[appName]?.[secretName];\n}\n\n/**\n * Set a generated secret for an app (mutates state)\n */\nexport function setGeneratedSecret(\n\tstate: DokployStageState,\n\tappName: string,\n\tsecretName: string,\n\tvalue: string,\n): void {\n\tif (!state.generatedSecrets) {\n\t\tstate.generatedSecrets = {};\n\t}\n\tif (!state.generatedSecrets[appName]) {\n\t\tstate.generatedSecrets[appName] = {};\n\t}\n\tstate.generatedSecrets[appName][secretName] = value;\n}\n\n/**\n * Get all generated secrets for an app\n */\nexport function getAppGeneratedSecrets(\n\tstate: DokployStageState | null,\n\tappName: string,\n): Record<string, string> {\n\treturn state?.generatedSecrets?.[appName] ?? {};\n}\n\n/**\n * Get all generated secrets from state\n */\nexport function getAllGeneratedSecrets(\n\tstate: DokployStageState | null,\n): Record<string, Record<string, string>> {\n\treturn state?.generatedSecrets ?? {};\n}\n\n// ============================================================================\n// DNS Verification\n// ============================================================================\n\n/**\n * Get DNS verification record for a hostname\n */\nexport function getDnsVerification(\n\tstate: DokployStageState | null,\n\thostname: string,\n): DnsVerificationRecord | undefined {\n\treturn state?.dnsVerified?.[hostname];\n}\n\n/**\n * Set DNS verification record for a hostname (mutates state)\n */\nexport function setDnsVerification(\n\tstate: DokployStageState,\n\thostname: string,\n\tserverIp: string,\n): void {\n\tif (!state.dnsVerified) {\n\t\tstate.dnsVerified = {};\n\t}\n\tstate.dnsVerified[hostname] = {\n\t\tserverIp,\n\t\tverifiedAt: new Date().toISOString(),\n\t};\n}\n\n/**\n * Check if a hostname is already verified with the given IP\n */\nexport function isDnsVerified(\n\tstate: DokployStageState | null,\n\thostname: string,\n\tserverIp: string,\n): boolean {\n\tconst record = state?.dnsVerified?.[hostname];\n\treturn record?.serverIp === serverIp;\n}\n\n/**\n * Get all DNS verification records from state\n */\nexport function getAllDnsVerifications(\n\tstate: DokployStageState | null,\n): Record<string, DnsVerificationRecord> {\n\treturn state?.dnsVerified ?? {};\n}\n\n// ============================================================================\n// DNS Records\n// ============================================================================\n\n/**\n * Get the key for a DNS record in state\n */\nfunction getDnsRecordKey(name: string, type: string): string {\n\treturn `${name}:${type}`;\n}\n\n/**\n * Get a created DNS record from state\n */\nexport function getDnsRecord(\n\tstate: DokployStageState | null,\n\tname: string,\n\ttype: string,\n): CreatedDnsRecord | undefined {\n\treturn state?.dnsRecords?.[getDnsRecordKey(name, type)];\n}\n\n/**\n * Set a created DNS record in state (mutates state)\n */\nexport function setDnsRecord(\n\tstate: DokployStageState,\n\trecord: Omit<CreatedDnsRecord, 'createdAt'>,\n): void {\n\tif (!state.dnsRecords) {\n\t\tstate.dnsRecords = {};\n\t}\n\tconst key = getDnsRecordKey(record.name, record.type);\n\tstate.dnsRecords[key] = {\n\t\t...record,\n\t\tcreatedAt: new Date().toISOString(),\n\t};\n}\n\n/**\n * Remove a DNS record from state (mutates state)\n */\nexport function removeDnsRecord(\n\tstate: DokployStageState,\n\tname: string,\n\ttype: string,\n): void {\n\tif (state.dnsRecords) {\n\t\tdelete state.dnsRecords[getDnsRecordKey(name, type)];\n\t}\n}\n\n/**\n * Get all created DNS records from state\n */\nexport function getAllDnsRecords(\n\tstate: DokployStageState | null,\n): CreatedDnsRecord[] {\n\tif (!state?.dnsRecords) {\n\t\treturn [];\n\t}\n\treturn Object.values(state.dnsRecords);\n}\n\n/**\n * Clear all DNS records from state (mutates state)\n */\nexport function clearDnsRecords(state: DokployStageState): void {\n\tstate.dnsRecords = {};\n\tstate.dnsVerified = {};\n}\n\n// ============================================================================\n// Backup State\n// ============================================================================\n\n/**\n * Get backup state from state\n */\nexport function getBackupState(\n\tstate: DokployStageState | null,\n): BackupState | undefined {\n\treturn state?.backups;\n}\n\n/**\n * Set backup state (mutates state)\n */\nexport function setBackupState(\n\tstate: DokployStageState,\n\tbackupState: BackupState,\n): void {\n\tstate.backups = backupState;\n}\n\n/**\n * Get backup destination ID from state\n */\nexport function getBackupDestinationId(\n\tstate: DokployStageState | null,\n): string | undefined {\n\treturn state?.backups?.destinationId;\n}\n\n/**\n * Get postgres backup ID from state\n */\nexport function getPostgresBackupId(\n\tstate: DokployStageState | null,\n): string | undefined {\n\treturn state?.backups?.postgresBackupId;\n}\n\n/**\n * Set postgres backup ID in state (mutates state)\n */\nexport function setPostgresBackupId(\n\tstate: DokployStageState,\n\tbackupId: string,\n): void {\n\tif (state.backups) {\n\t\tstate.backups.postgresBackupId = backupId;\n\t}\n}\n","/**\n * DNS Provider Interface\n *\n * Abstracts DNS operations for different providers.\n * Built-in providers: HostingerProvider, Route53Provider\n * Users can also supply custom implementations.\n */\n\nimport type { z } from 'zod/v4';\nimport type {\n\tCloudflareDnsProviderSchema,\n\tCustomDnsProviderSchema,\n\tDnsProviderSchema,\n\tDnsRecordSchema,\n\tDnsRecordTypeSchema,\n\tHostingerDnsProviderSchema,\n\tManualDnsProviderSchema,\n\tRoute53DnsProviderSchema,\n\tUpsertDnsRecordSchema,\n\tUpsertResultSchema,\n} from '../../workspace/schema';\n\n// =============================================================================\n// DNS Record Types (derived from Zod schemas)\n// =============================================================================\n\n/**\n * DNS record types supported across providers.\n */\nexport type DnsRecordType = z.infer<typeof DnsRecordTypeSchema>;\n\n/**\n * A DNS record as returned by the provider.\n */\nexport type DnsRecord = z.infer<typeof DnsRecordSchema>;\n\n/**\n * A DNS record to create or update.\n */\nexport type UpsertDnsRecord = z.infer<typeof UpsertDnsRecordSchema>;\n\n/**\n * Result of an upsert operation.\n */\nexport type UpsertResult = z.infer<typeof UpsertResultSchema>;\n\n// =============================================================================\n// DNS Provider Interface\n// =============================================================================\n\n/**\n * A record to delete from DNS.\n */\nexport interface DeleteDnsRecord {\n\t/** Record name/subdomain (e.g., 'api' or '@' for root) */\n\tname: string;\n\t/** Record type (A, CNAME, etc.) */\n\ttype: DnsRecordType;\n}\n\n/**\n * Result of a delete operation.\n */\nexport interface DeleteResult {\n\t/** The record that was requested for deletion */\n\trecord: DeleteDnsRecord;\n\t/** Whether the record was deleted */\n\tdeleted: boolean;\n\t/** Whether the record was not found (already deleted) */\n\tnotFound: boolean;\n\t/** Error message if deletion failed */\n\terror?: string;\n}\n\n/**\n * Interface for DNS providers.\n *\n * Implementations must handle:\n * - Getting all records for a domain\n * - Creating or updating records for a domain\n * - Deleting records from a domain\n */\nexport interface DnsProvider {\n\t/** Provider name for logging */\n\treadonly name: string;\n\n\t/**\n\t * Get all DNS records for a domain.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @returns Array of DNS records\n\t */\n\tgetRecords(domain: string): Promise<DnsRecord[]>;\n\n\t/**\n\t * Create or update DNS records.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @param records - Records to create or update\n\t * @returns Results of the upsert operations\n\t */\n\tupsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]>;\n\n\t/**\n\t * Delete DNS records.\n\t *\n\t * @param domain - Root domain (e.g., 'example.com')\n\t * @param records - Records to delete\n\t * @returns Results of the delete operations\n\t */\n\tdeleteRecords(\n\t\tdomain: string,\n\t\trecords: DeleteDnsRecord[],\n\t): Promise<DeleteResult[]>;\n}\n\n// =============================================================================\n// DNS Provider Config Types (derived from Zod schemas)\n// =============================================================================\n\nexport type HostingerDnsConfig = z.infer<typeof HostingerDnsProviderSchema>;\nexport type Route53DnsConfig = z.infer<typeof Route53DnsProviderSchema>;\nexport type CloudflareDnsConfig = z.infer<typeof CloudflareDnsProviderSchema>;\nexport type ManualDnsConfig = z.infer<typeof ManualDnsProviderSchema>;\nexport type CustomDnsConfig = z.infer<typeof CustomDnsProviderSchema>;\n/** Single DNS provider config (for one domain) */\nexport type DnsConfig = z.infer<typeof DnsProviderSchema>;\n\n// =============================================================================\n// DNS Provider Factory\n// =============================================================================\n\n/**\n * Check if value is a DnsProvider implementation.\n */\nexport function isDnsProvider(value: unknown): value is DnsProvider {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as DnsProvider).name === 'string' &&\n\t\ttypeof (value as DnsProvider).getRecords === 'function' &&\n\t\ttypeof (value as DnsProvider).upsertRecords === 'function' &&\n\t\ttypeof (value as DnsProvider).deleteRecords === 'function'\n\t);\n}\n\nexport interface CreateDnsProviderOptions {\n\t/** DNS config from workspace */\n\tconfig: DnsConfig;\n}\n\n/**\n * Create a DNS provider based on configuration.\n *\n * - 'hostinger': HostingerProvider\n * - 'route53': Route53Provider\n * - 'manual': Returns null (user handles DNS)\n * - Custom: Use provided DnsProvider implementation\n */\nexport async function createDnsProvider(\n\toptions: CreateDnsProviderOptions,\n): Promise<DnsProvider | null> {\n\tconst { config } = options;\n\n\t// Manual mode - no provider needed\n\tif (config.provider === 'manual') {\n\t\treturn null;\n\t}\n\n\t// Custom provider implementation\n\tif (isDnsProvider(config.provider)) {\n\t\treturn config.provider;\n\t}\n\n\t// Built-in providers\n\tconst provider = config.provider;\n\n\tif (provider === 'hostinger') {\n\t\tconst { HostingerProvider } = await import('./HostingerProvider');\n\t\treturn new HostingerProvider();\n\t}\n\n\tif (provider === 'route53') {\n\t\tconst { Route53Provider } = await import('./Route53Provider');\n\t\tconst route53Config = config as Route53DnsConfig;\n\t\treturn new Route53Provider({\n\t\t\tregion: route53Config.region,\n\t\t\tprofile: route53Config.profile,\n\t\t\thostedZoneId: route53Config.hostedZoneId,\n\t\t});\n\t}\n\n\tif (provider === 'cloudflare') {\n\t\tthrow new Error('Cloudflare DNS provider not yet implemented');\n\t}\n\n\tthrow new Error(`Unknown DNS provider: ${JSON.stringify(config)}`);\n}\n","/**\n * DNS orchestration for deployments\n *\n * Handles automatic DNS record creation for deployed applications.\n */\n\nimport { lookup } from 'node:dns/promises';\nimport type {\n\tDnsConfig,\n\tDnsProvider as DnsProviderConfig,\n} from '../../workspace/types';\nimport {\n\ttype DokployStageState,\n\tisDnsVerified,\n\tsetDnsRecord,\n\tsetDnsVerification,\n} from '../state';\nimport {\n\tcreateDnsProvider,\n\ttype DnsProvider,\n\ttype DnsConfig as SchemaDnsConfig,\n\ttype UpsertDnsRecord,\n} from './DnsProvider';\n\nconst logger = console;\n\n/**\n * Check if DNS config is legacy format (single domain with `domain` property)\n */\nexport function isLegacyDnsConfig(\n\tconfig: DnsConfig,\n): config is SchemaDnsConfig & { domain: string } {\n\treturn (\n\t\ttypeof config === 'object' &&\n\t\tconfig !== null &&\n\t\t'provider' in config &&\n\t\t'domain' in config\n\t);\n}\n\n/**\n * Normalize DNS config to new multi-domain format\n */\nexport function normalizeDnsConfig(\n\tconfig: DnsConfig,\n): Record<string, DnsProviderConfig> {\n\tif (isLegacyDnsConfig(config)) {\n\t\t// Convert legacy format to new format\n\t\tconst { domain, ...providerConfig } = config;\n\t\treturn { [domain]: providerConfig as DnsProviderConfig };\n\t}\n\treturn config as Record<string, DnsProviderConfig>;\n}\n\n/**\n * Find the root domain for a hostname from available DNS configs\n *\n * @example\n * findRootDomain('api.geekmidas.com', { 'geekmidas.com': {...}, 'geekmidas.dev': {...} })\n * // Returns 'geekmidas.com'\n */\nexport function findRootDomain(\n\thostname: string,\n\tdnsConfig: Record<string, DnsProviderConfig>,\n): string | null {\n\t// Sort domains by length descending to match most specific first\n\tconst domains = Object.keys(dnsConfig).sort((a, b) => b.length - a.length);\n\n\tfor (const domain of domains) {\n\t\tif (hostname === domain || hostname.endsWith(`.${domain}`)) {\n\t\t\treturn domain;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Group hostnames by their root domain\n */\nexport function groupHostnamesByDomain(\n\tappHostnames: Map<string, string>,\n\tdnsConfig: Record<string, DnsProviderConfig>,\n): Map<string, Map<string, string>> {\n\tconst grouped = new Map<string, Map<string, string>>();\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\tconst rootDomain = findRootDomain(hostname, dnsConfig);\n\t\tif (!rootDomain) {\n\t\t\tlogger.log(`   ⚠ No DNS config found for hostname: ${hostname}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!grouped.has(rootDomain)) {\n\t\t\tgrouped.set(rootDomain, new Map());\n\t\t}\n\t\tgrouped.get(rootDomain)!.set(appName, hostname);\n\t}\n\n\treturn grouped;\n}\n\n/**\n * Required DNS record for an app\n */\nexport interface RequiredDnsRecord {\n\t/** Full hostname (e.g., 'api.joemoer.traflabs.io') */\n\thostname: string;\n\t/** Subdomain part for the DNS provider (e.g., 'api.joemoer') */\n\tsubdomain: string;\n\t/** Record type */\n\ttype: 'A' | 'CNAME';\n\t/** Target value (IP or hostname) */\n\tvalue: string;\n\t/** App name */\n\tappName: string;\n\t/** Whether the record was created */\n\tcreated?: boolean;\n\t/** Whether the record already existed */\n\texisted?: boolean;\n\t/** Error if creation failed */\n\terror?: string;\n}\n\n/**\n * Result of DNS record creation\n */\nexport interface DnsCreationResult {\n\trecords: RequiredDnsRecord[];\n\tsuccess: boolean;\n\tserverIp: string;\n}\n\n/**\n * Resolve IP address from a hostname\n */\nexport async function resolveHostnameToIp(hostname: string): Promise<string> {\n\ttry {\n\t\tconst addresses = await lookup(hostname, { family: 4 });\n\t\treturn addresses.address;\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to resolve IP for ${hostname}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n}\n\n/**\n * Extract subdomain from full hostname relative to root domain\n *\n * @example\n * extractSubdomain('api.joemoer.traflabs.io', 'traflabs.io') => 'api.joemoer'\n * extractSubdomain('joemoer.traflabs.io', 'traflabs.io') => 'joemoer'\n */\nexport function extractSubdomain(hostname: string, rootDomain: string): string {\n\tif (!hostname.endsWith(rootDomain)) {\n\t\tthrow new Error(\n\t\t\t`Hostname ${hostname} is not under root domain ${rootDomain}`,\n\t\t);\n\t}\n\n\tconst subdomain = hostname.slice(0, -(rootDomain.length + 1)); // +1 for the dot\n\treturn subdomain || '@'; // '@' represents the root domain itself\n}\n\n/**\n * Generate required DNS records for a deployment\n */\nexport function generateRequiredRecords(\n\tappHostnames: Map<string, string>, // appName -> hostname\n\trootDomain: string,\n\tserverIp: string,\n): RequiredDnsRecord[] {\n\tconst records: RequiredDnsRecord[] = [];\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\tconst subdomain = extractSubdomain(hostname, rootDomain);\n\t\trecords.push({\n\t\t\thostname,\n\t\t\tsubdomain,\n\t\t\ttype: 'A',\n\t\t\tvalue: serverIp,\n\t\t\tappName,\n\t\t});\n\t}\n\n\treturn records;\n}\n\n/**\n * Print DNS records table\n */\nexport function printDnsRecordsTable(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n): void {\n\tlogger.log(`\\n   📋 DNS Records for ${rootDomain}:`);\n\tlogger.log(\n\t\t'   ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐',\n\t);\n\tlogger.log(\n\t\t'   │ Subdomain                           │ Type │ Value           │ Status │',\n\t);\n\tlogger.log(\n\t\t'   ├─────────────────────────────────────┼──────┼─────────────────┼────────┤',\n\t);\n\n\tfor (const record of records) {\n\t\tconst subdomain = record.subdomain.padEnd(35);\n\t\tconst type = record.type.padEnd(4);\n\t\tconst value = record.value.padEnd(15);\n\t\tlet status: string;\n\n\t\tif (record.error) {\n\t\t\tstatus = '✗';\n\t\t} else if (record.created) {\n\t\t\tstatus = '✓ new';\n\t\t} else if (record.existed) {\n\t\t\tstatus = '✓';\n\t\t} else {\n\t\t\tstatus = '?';\n\t\t}\n\n\t\tlogger.log(\n\t\t\t`   │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`,\n\t\t);\n\t}\n\n\tlogger.log(\n\t\t'   └─────────────────────────────────────┴──────┴─────────────────┴────────┘',\n\t);\n}\n\n/**\n * Print DNS records in a simple format for manual setup\n */\nexport function printDnsRecordsSimple(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n): void {\n\tlogger.log('\\n   📋 Required DNS Records:');\n\tlogger.log(`   Add these A records to your DNS provider (${rootDomain}):\\n`);\n\n\tfor (const record of records) {\n\t\tlogger.log(`   ${record.subdomain}  →  ${record.value}  (A record)`);\n\t}\n\n\tlogger.log('');\n}\n\n/**\n * Create DNS records for a single domain using its configured provider\n */\nexport async function createDnsRecordsForDomain(\n\trecords: RequiredDnsRecord[],\n\trootDomain: string,\n\tproviderConfig: DnsProviderConfig,\n): Promise<RequiredDnsRecord[]> {\n\t// Get TTL from config, default to 300. Manual mode doesn't have ttl property.\n\tconst ttl =\n\t\t'ttl' in providerConfig && providerConfig.ttl ? providerConfig.ttl : 300;\n\n\t// Get DNS provider from factory\n\tlet provider: DnsProvider | null;\n\ttry {\n\t\t// Cast to schema-derived DnsConfig for provider factory\n\t\tprovider = await createDnsProvider({\n\t\t\tconfig: providerConfig as SchemaDnsConfig,\n\t\t});\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(\n\t\t\t`   ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`,\n\t\t);\n\t\treturn records.map((r) => ({ ...r, error: message }));\n\t}\n\n\t// Manual mode - no provider, just mark records as needing manual creation\n\tif (!provider) {\n\t\treturn records.map((r) => ({ ...r, created: false, existed: false }));\n\t}\n\n\tconst results: RequiredDnsRecord[] = [];\n\n\t// Convert RequiredDnsRecord to UpsertDnsRecord format\n\tconst upsertRecords: UpsertDnsRecord[] = records.map((r) => ({\n\t\tname: r.subdomain,\n\t\ttype: r.type,\n\t\tttl,\n\t\tvalue: r.value,\n\t}));\n\n\ttry {\n\t\t// Use provider to upsert records\n\t\tconst upsertResults = await provider.upsertRecords(\n\t\t\trootDomain,\n\t\t\tupsertRecords,\n\t\t);\n\n\t\t// Map results back to RequiredDnsRecord format\n\t\tfor (const [i, record] of records.entries()) {\n\t\t\tconst result = upsertResults[i];\n\n\t\t\t// Handle case where upsertResults has fewer items (shouldn't happen but be safe)\n\t\t\tif (!result) {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\terror: 'No result returned from provider',\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (result.unchanged) {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\texisted: true,\n\t\t\t\t\tcreated: false,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tresults.push({\n\t\t\t\t\thostname: record.hostname,\n\t\t\t\t\tsubdomain: record.subdomain,\n\t\t\t\t\ttype: record.type,\n\t\t\t\t\tvalue: record.value,\n\t\t\t\t\tappName: record.appName,\n\t\t\t\t\tcreated: result.created,\n\t\t\t\t\texisted: !result.created,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(\n\t\t\t`   ⚠ Failed to create DNS records for ${rootDomain}: ${message}`,\n\t\t);\n\t\treturn records.map((r) => ({\n\t\t\thostname: r.hostname,\n\t\t\tsubdomain: r.subdomain,\n\t\t\ttype: r.type,\n\t\t\tvalue: r.value,\n\t\t\tappName: r.appName,\n\t\t\terror: message,\n\t\t}));\n\t}\n\n\treturn results;\n}\n\n/**\n * Create DNS records using the configured provider\n * @deprecated Use createDnsRecordsForDomain for multi-domain support\n */\nexport async function createDnsRecords(\n\trecords: RequiredDnsRecord[],\n\tdnsConfig: DnsConfig,\n): Promise<RequiredDnsRecord[]> {\n\t// Handle legacy config format\n\tif (!isLegacyDnsConfig(dnsConfig)) {\n\t\tthrow new Error(\n\t\t\t'createDnsRecords requires legacy DnsConfig with domain property. Use createDnsRecordsForDomain instead.',\n\t\t);\n\t}\n\tconst { domain: rootDomain, ...providerConfig } = dnsConfig;\n\treturn createDnsRecordsForDomain(\n\t\trecords,\n\t\trootDomain,\n\t\tproviderConfig as DnsProviderConfig,\n\t);\n}\n\n/**\n * Main DNS orchestration function for deployments\n *\n * Supports both legacy single-domain format and new multi-domain format:\n * - Legacy: { provider: 'hostinger', domain: 'example.com' }\n * - Multi:  { 'example.com': { provider: 'hostinger' }, 'example.dev': { provider: 'route53' } }\n *\n * @param appHostnames - Map of app names to hostnames\n * @param dnsConfig - DNS configuration (legacy or multi-domain)\n * @param dokployEndpoint - Dokploy server endpoint to resolve IP from\n * @param state - Optional state to save created records for later deletion\n */\nexport async function orchestrateDns(\n\tappHostnames: Map<string, string>, // appName -> hostname\n\tdnsConfig: DnsConfig | undefined,\n\tdokployEndpoint: string,\n\tstate?: DokployStageState,\n): Promise<DnsCreationResult | null> {\n\tif (!dnsConfig) {\n\t\treturn null;\n\t}\n\n\t// Normalize config to multi-domain format\n\tconst normalizedConfig = normalizeDnsConfig(dnsConfig);\n\n\t// Resolve Dokploy server IP from endpoint\n\tlogger.log('\\n🌐 Setting up DNS records...');\n\tlet serverIp: string;\n\n\ttry {\n\t\tconst endpointUrl = new URL(dokployEndpoint);\n\t\tserverIp = await resolveHostnameToIp(endpointUrl.hostname);\n\t\tlogger.log(`   Server IP: ${serverIp} (from ${endpointUrl.hostname})`);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\tlogger.log(`   ⚠ Failed to resolve server IP: ${message}`);\n\t\treturn null;\n\t}\n\n\t// Group hostnames by their root domain\n\tconst groupedHostnames = groupHostnamesByDomain(\n\t\tappHostnames,\n\t\tnormalizedConfig,\n\t);\n\n\tif (groupedHostnames.size === 0) {\n\t\tlogger.log(\n\t\t\t'   No DNS records needed (no hostnames match configured domains)',\n\t\t);\n\t\treturn { records: [], success: true, serverIp };\n\t}\n\n\tconst allRecords: RequiredDnsRecord[] = [];\n\tlet hasFailures = false;\n\n\t// Process each domain group with its specific provider\n\tfor (const [rootDomain, domainHostnames] of groupedHostnames) {\n\t\tconst providerConfig = normalizedConfig[rootDomain];\n\t\tif (!providerConfig) {\n\t\t\tlogger.log(`   ⚠ No provider config for ${rootDomain}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst providerName =\n\t\t\ttypeof providerConfig.provider === 'string'\n\t\t\t\t? providerConfig.provider\n\t\t\t\t: 'custom';\n\n\t\t// Generate required records for this domain\n\t\tconst requiredRecords = generateRequiredRecords(\n\t\t\tdomainHostnames,\n\t\t\trootDomain,\n\t\t\tserverIp,\n\t\t);\n\n\t\tif (requiredRecords.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Create records for this domain\n\t\tlogger.log(\n\t\t\t`   Creating DNS records for ${rootDomain} (${providerName})...`,\n\t\t);\n\t\tconst domainRecords = await createDnsRecordsForDomain(\n\t\t\trequiredRecords,\n\t\t\trootDomain,\n\t\t\tproviderConfig,\n\t\t);\n\n\t\tallRecords.push(...domainRecords);\n\n\t\tconst created = domainRecords.filter((r) => r.created).length;\n\t\tconst existed = domainRecords.filter((r) => r.existed).length;\n\t\tconst failed = domainRecords.filter((r) => r.error).length;\n\n\t\tif (created > 0) {\n\t\t\tlogger.log(`   ✓ Created ${created} DNS record(s) for ${rootDomain}`);\n\t\t}\n\t\tif (existed > 0) {\n\t\t\tlogger.log(`   ✓ ${existed} record(s) already exist for ${rootDomain}`);\n\t\t}\n\t\tif (failed > 0) {\n\t\t\tlogger.log(`   ⚠ ${failed} record(s) failed for ${rootDomain}`);\n\t\t\thasFailures = true;\n\t\t}\n\n\t\t// Save created/existing records to state for later deletion during undeploy\n\t\tif (state) {\n\t\t\tfor (const record of domainRecords) {\n\t\t\t\tif (record.created || record.existed) {\n\t\t\t\t\tsetDnsRecord(state, {\n\t\t\t\t\t\tdomain: rootDomain,\n\t\t\t\t\t\tname: record.subdomain,\n\t\t\t\t\t\ttype: record.type,\n\t\t\t\t\t\tvalue: record.value,\n\t\t\t\t\t\tttl:\n\t\t\t\t\t\t\t'ttl' in providerConfig && providerConfig.ttl\n\t\t\t\t\t\t\t\t? providerConfig.ttl\n\t\t\t\t\t\t\t\t: 300,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Print summary table for this domain\n\t\tprintDnsRecordsTable(domainRecords, rootDomain);\n\n\t\t// If manual mode or some failed, print simple instructions\n\t\tif (providerConfig.provider === 'manual' || failed > 0) {\n\t\t\tprintDnsRecordsSimple(\n\t\t\t\tdomainRecords.filter((r) => !r.created && !r.existed),\n\t\t\t\trootDomain,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\trecords: allRecords,\n\t\tsuccess: !hasFailures,\n\t\tserverIp,\n\t};\n}\n\n/**\n * Result of DNS verification for a single hostname\n */\nexport interface DnsVerificationResult {\n\thostname: string;\n\tappName: string;\n\tverified: boolean;\n\tresolvedIp?: string;\n\texpectedIp: string;\n\terror?: string;\n\tskipped?: boolean; // True if already verified in state\n}\n\n/**\n * Verify DNS records resolve correctly after deployment.\n *\n * This function:\n * 1. Checks state for previously verified hostnames (skips if already verified with same IP)\n * 2. Attempts to resolve each hostname to an IP\n * 3. Compares resolved IP with expected server IP\n * 4. Updates state with verification results\n *\n * @param appHostnames - Map of app names to hostnames\n * @param serverIp - Expected IP address the hostnames should resolve to\n * @param state - Deploy state for caching verification results\n * @returns Array of verification results\n */\nexport async function verifyDnsRecords(\n\tappHostnames: Map<string, string>,\n\tserverIp: string,\n\tstate: DokployStageState,\n): Promise<DnsVerificationResult[]> {\n\tconst results: DnsVerificationResult[] = [];\n\n\tlogger.log('\\n🔍 Verifying DNS records...');\n\n\tfor (const [appName, hostname] of appHostnames) {\n\t\t// Check if already verified with same IP\n\t\tif (isDnsVerified(state, hostname, serverIp)) {\n\t\t\tlogger.log(`   ✓ ${hostname} (previously verified)`);\n\t\t\tresults.push({\n\t\t\t\thostname,\n\t\t\t\tappName,\n\t\t\t\tverified: true,\n\t\t\t\texpectedIp: serverIp,\n\t\t\t\tskipped: true,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Attempt to resolve hostname\n\t\ttry {\n\t\t\tconst resolvedIp = await resolveHostnameToIp(hostname);\n\n\t\t\tif (resolvedIp === serverIp) {\n\t\t\t\t// DNS verified successfully\n\t\t\t\tsetDnsVerification(state, hostname, serverIp);\n\t\t\t\tlogger.log(`   ✓ ${hostname} → ${resolvedIp}`);\n\t\t\t\tresults.push({\n\t\t\t\t\thostname,\n\t\t\t\t\tappName,\n\t\t\t\t\tverified: true,\n\t\t\t\t\tresolvedIp,\n\t\t\t\t\texpectedIp: serverIp,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// DNS resolves but to wrong IP\n\t\t\t\tlogger.log(\n\t\t\t\t\t`   ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`,\n\t\t\t\t);\n\t\t\t\tresults.push({\n\t\t\t\t\thostname,\n\t\t\t\t\tappName,\n\t\t\t\t\tverified: false,\n\t\t\t\t\tresolvedIp,\n\t\t\t\t\texpectedIp: serverIp,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// DNS resolution failed\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\t\tlogger.log(`   ⚠ ${hostname} DNS not propagated (${message})`);\n\t\t\tresults.push({\n\t\t\t\thostname,\n\t\t\t\tappName,\n\t\t\t\tverified: false,\n\t\t\t\texpectedIp: serverIp,\n\t\t\t\terror: message,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Summary\n\tconst verified = results.filter((r) => r.verified).length;\n\tconst skipped = results.filter((r) => r.skipped).length;\n\tconst pending = results.filter((r) => !r.verified).length;\n\n\tif (pending > 0) {\n\t\tlogger.log(`\\n   ${verified} verified, ${pending} pending propagation`);\n\t\tlogger.log('   DNS changes may take 5-30 minutes to propagate');\n\t} else if (skipped > 0) {\n\t\tlogger.log(`   ${verified} verified (${skipped} from cache)`);\n\t}\n\n\treturn results;\n}\n","import { getPublicEnvPrefix } from '../workspace/index.js';\nimport type {\n\tDokployWorkspaceConfig,\n\tNormalizedAppConfig,\n} from '../workspace/types.js';\n\n/**\n * Resolve the hostname for an app based on stage configuration.\n *\n * Domain resolution priority:\n * 1. Explicit app.domain override (string or stage-specific)\n * 2. Default pattern based on app type:\n *    - Main frontend app gets base domain (e.g., 'myapp.com')\n *    - Other apps get prefixed domain (e.g., 'api.myapp.com')\n *\n * @param appName - The name of the app\n * @param app - The normalized app configuration\n * @param stage - The deployment stage (e.g., 'production', 'development')\n * @param dokployConfig - Dokploy workspace configuration with domain mappings\n * @param isMainFrontend - Whether this is the main frontend app\n * @returns The resolved hostname for the app\n * @throws Error if no domain configuration is found for the stage\n */\nexport function resolveHost(\n\tappName: string,\n\tapp: NormalizedAppConfig,\n\tstage: string,\n\tdokployConfig: DokployWorkspaceConfig | undefined,\n\tisMainFrontend: boolean,\n): string {\n\t// 1. Check for explicit app domain override\n\tif (app.domain) {\n\t\tif (typeof app.domain === 'string') {\n\t\t\treturn app.domain;\n\t\t}\n\t\tif (app.domain[stage]) {\n\t\t\treturn app.domain[stage]!;\n\t\t}\n\t}\n\n\t// 2. Get base domain for this stage\n\tconst baseDomain = dokployConfig?.domains?.[stage];\n\tif (!baseDomain) {\n\t\tthrow new Error(\n\t\t\t`No domain configured for stage \"${stage}\". ` +\n\t\t\t\t`Add deploy.dokploy.domains.${stage} to gkm.config.ts`,\n\t\t);\n\t}\n\n\t// 3. Main frontend app gets base domain, others get prefix\n\tif (isMainFrontend) {\n\t\treturn baseDomain;\n\t}\n\n\treturn `${appName}.${baseDomain}`;\n}\n\n/**\n * Determine if an app is the \"main\" frontend (gets base domain).\n *\n * An app is considered the main frontend if:\n * 1. It's named 'web' and is a frontend type\n * 2. It's the first frontend app in the apps list\n *\n * @param appName - The name of the app to check\n * @param app - The app configuration\n * @param allApps - All apps in the workspace\n * @returns True if this is the main frontend app\n */\nexport function isMainFrontendApp(\n\tappName: string,\n\tapp: NormalizedAppConfig,\n\tallApps: Record<string, NormalizedAppConfig>,\n): boolean {\n\tif (app.type !== 'web') {\n\t\treturn false;\n\t}\n\n\t// App named 'web' is always main\n\tif (appName === 'web') {\n\t\treturn true;\n\t}\n\n\t// Otherwise, check if this is the first frontend\n\tfor (const [name, a] of Object.entries(allApps)) {\n\t\tif (a.type === 'web') {\n\t\t\treturn name === appName;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Generate public URL build args for a web/mobile app based on its dependencies.\n *\n * The prefix is chosen by the app's framework (NEXT_PUBLIC_, VITE_,\n * EXPO_PUBLIC_, or none for Remix). Apps without a public prefix get no\n * build args — they should fetch URLs at runtime instead.\n *\n * @param app - The web/mobile app configuration\n * @param deployedUrls - Map of app name to deployed public URL\n * @returns Array of build args like 'NEXT_PUBLIC_API_URL=https://api.example.com'\n */\nexport function generatePublicUrlBuildArgs(\n\tapp: NormalizedAppConfig,\n\tdeployedUrls: Record<string, string>,\n): string[] {\n\tconst prefix = getPublicEnvPrefix(app);\n\tif (!prefix) return [];\n\n\tconst buildArgs: string[] = [];\n\tfor (const dep of app.dependencies) {\n\t\tconst publicUrl = deployedUrls[dep];\n\t\tif (publicUrl) {\n\t\t\tbuildArgs.push(`${prefix}${dep.toUpperCase()}_URL=${publicUrl}`);\n\t\t}\n\t}\n\n\treturn buildArgs;\n}\n\n/**\n * Get public URL arg names from app dependencies.\n *\n * @param app - The web/mobile app configuration\n * @returns Array of arg names like 'NEXT_PUBLIC_API_URL', or [] for frameworks\n *   without a public prefix (e.g. Remix).\n */\nexport function getPublicUrlArgNames(app: NormalizedAppConfig): string[] {\n\tconst prefix = getPublicEnvPrefix(app);\n\tif (!prefix) return [];\n\treturn app.dependencies.map((dep) => `${prefix}${dep.toUpperCase()}_URL`);\n}\n","import type {\n\tComposeServiceName,\n\tComposeServicesConfig,\n\tServiceConfig,\n} from '../types';\nimport type {\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from '../workspace/types.js';\n\n/** Default Docker images for services */\nexport const DEFAULT_SERVICE_IMAGES: Record<ComposeServiceName, string> = {\n\tpostgres: 'postgres',\n\tredis: 'redis',\n\trabbitmq: 'rabbitmq',\n\tminio: 'minio/minio',\n\tmailpit: 'axllent/mailpit',\n\tlocalstack: 'localstack/localstack',\n};\n\n/** Default Docker image versions for services */\nexport const DEFAULT_SERVICE_VERSIONS: Record<ComposeServiceName, string> = {\n\tpostgres: '18-alpine',\n\tredis: '7-alpine',\n\trabbitmq: '3-management-alpine',\n\tminio: 'latest',\n\tmailpit: 'latest',\n\tlocalstack: 'latest',\n};\n\nexport interface ComposeOptions {\n\timageName: string;\n\tregistry: string;\n\tport: number;\n\thealthCheckPath: string;\n\t/** Services config - object format or legacy array format */\n\tservices: ComposeServicesConfig | ComposeServiceName[];\n}\n\n/** Get the default full image reference for a service */\nfunction getDefaultImage(serviceName: ComposeServiceName): string {\n\treturn `${DEFAULT_SERVICE_IMAGES[serviceName]}:${DEFAULT_SERVICE_VERSIONS[serviceName]}`;\n}\n\n/** Normalize services config to a consistent format - returns Map of service name to full image reference */\nfunction normalizeServices(\n\tservices: ComposeServicesConfig | ComposeServiceName[],\n): Map<ComposeServiceName, string> {\n\tconst result = new Map<ComposeServiceName, string>();\n\n\tif (Array.isArray(services)) {\n\t\t// Legacy array format - use default images\n\t\tfor (const name of services) {\n\t\t\tresult.set(name, getDefaultImage(name));\n\t\t}\n\t} else {\n\t\t// Object format\n\t\tfor (const [name, config] of Object.entries(services)) {\n\t\t\tconst serviceName = name as ComposeServiceName;\n\t\t\tif (config === true) {\n\t\t\t\t// boolean true - use default image\n\t\t\t\tresult.set(serviceName, getDefaultImage(serviceName));\n\t\t\t} else if (config && typeof config === 'object') {\n\t\t\t\tconst serviceConfig = config as ServiceConfig;\n\t\t\t\tif (serviceConfig.image) {\n\t\t\t\t\t// Full image reference provided\n\t\t\t\t\tresult.set(serviceName, serviceConfig.image);\n\t\t\t\t} else {\n\t\t\t\t\t// Version only - use default image name with custom version\n\t\t\t\t\tconst version =\n\t\t\t\t\t\tserviceConfig.version ?? DEFAULT_SERVICE_VERSIONS[serviceName];\n\t\t\t\t\tresult.set(\n\t\t\t\t\t\tserviceName,\n\t\t\t\t\t\t`${DEFAULT_SERVICE_IMAGES[serviceName]}:${version}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// false or undefined - skip\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Generate docker-compose.yml for production deployment\n */\nexport function generateDockerCompose(options: ComposeOptions): string {\n\tconst { imageName, registry, port, healthCheckPath, services } = options;\n\n\t// Normalize services to Map<name, version>\n\tconst serviceMap = normalizeServices(services);\n\n\tconst imageRef = registry ? `\\${REGISTRY:-${registry}}/` : '';\n\n\tlet yaml = `# Use \"gkm dev\" or \"gkm test\" to start services.\n# Running \"docker compose up\" directly will not inject secrets or resolve ports.\nversion: '3.8'\n\nservices:\n  api:\n    build:\n      context: ../..\n      dockerfile: .gkm/docker/Dockerfile\n    image: ${imageRef}\\${IMAGE_NAME:-${imageName}}:\\${TAG:-latest}\n    container_name: ${imageName}\n    restart: unless-stopped\n    ports:\n      - \"\\${PORT:-${port}}:${port}\"\n    environment:\n      - NODE_ENV=production\n`;\n\n\t// Add environment variables based on services\n\tif (serviceMap.has('postgres')) {\n\t\tyaml += `      - DATABASE_URL=\\${DATABASE_URL:-postgresql://\\${POSTGRES_USER:-postgres}:\\${POSTGRES_PASSWORD:-postgres}@postgres:5432/\\${POSTGRES_DB:-app}}\n`;\n\t}\n\n\tif (serviceMap.has('redis')) {\n\t\tyaml += `      - REDIS_URL=\\${REDIS_URL:-redis://redis:6379}\n`;\n\t}\n\n\tif (serviceMap.has('rabbitmq')) {\n\t\tyaml += `      - RABBITMQ_URL=\\${RABBITMQ_URL:-amqp://rabbitmq:5672}\n`;\n\t}\n\n\tif (serviceMap.has('minio')) {\n\t\tyaml += `      - STORAGE_ENDPOINT=\\${STORAGE_ENDPOINT:-http://minio:9000}\n      - STORAGE_ACCESS_KEY_ID=\\${STORAGE_ACCESS_KEY_ID:-${imageName}}\n      - STORAGE_SECRET_ACCESS_KEY=\\${STORAGE_SECRET_ACCESS_KEY:-${imageName}}\n      - STORAGE_BUCKET=\\${STORAGE_BUCKET:-${imageName}}\n      - STORAGE_REGION=\\${STORAGE_REGION:-eu-west-1}\n      - STORAGE_FORCE_PATH_STYLE=true\n`;\n\t}\n\n\tif (serviceMap.has('mailpit')) {\n\t\tyaml += `      - SMTP_HOST=\\${SMTP_HOST:-mailpit}\n      - SMTP_PORT=\\${SMTP_PORT:-1025}\n      - SMTP_USER=\\${SMTP_USER:-${imageName}}\n      - SMTP_PASS=\\${SMTP_PASS:-${imageName}}\n      - SMTP_SECURE=\\${SMTP_SECURE:-false}\n      - MAIL_FROM=\\${MAIL_FROM:-noreply@localhost}\n`;\n\t}\n\n\tif (serviceMap.has('localstack')) {\n\t\tyaml += `      - AWS_ACCESS_KEY_ID=\\${AWS_ACCESS_KEY_ID:-localstack}\n      - AWS_SECRET_ACCESS_KEY=\\${AWS_SECRET_ACCESS_KEY:-localstack}\n      - AWS_REGION=\\${AWS_REGION:-us-east-1}\n      - AWS_ENDPOINT_URL=\\${AWS_ENDPOINT_URL:-http://localstack:4566}\n`;\n\t}\n\n\tyaml += `    healthcheck:\n      test: [\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:${port}${healthCheckPath}\"]\n      interval: 30s\n      timeout: 3s\n      retries: 3\n`;\n\n\t// Add depends_on if there are services\n\tif (serviceMap.size > 0) {\n\t\tyaml += `    depends_on:\n`;\n\t\tfor (const serviceName of serviceMap.keys()) {\n\t\t\tyaml += `      ${serviceName}:\n        condition: service_healthy\n`;\n\t\t}\n\t}\n\n\tyaml += `    networks:\n      - app-network\n`;\n\n\t// Add service definitions with images\n\tconst postgresImage = serviceMap.get('postgres');\n\tif (postgresImage) {\n\t\tyaml += `\n  postgres:\n    image: ${postgresImage}\n    container_name: postgres\n    restart: unless-stopped\n    environment:\n      POSTGRES_USER: \\${POSTGRES_USER:-postgres}\n      POSTGRES_PASSWORD: \\${POSTGRES_PASSWORD:-postgres}\n      POSTGRES_DB: \\${POSTGRES_DB:-app}\n    volumes:\n      - dbdata:/var/lib/postgresql/18/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U $$POSTGRES_USER\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\tconst redisImage = serviceMap.get('redis');\n\tif (redisImage) {\n\t\tyaml += `\n  redis:\n    image: ${redisImage}\n    container_name: redis\n    restart: unless-stopped\n    volumes:\n      - redis_data:/data\n    healthcheck:\n      test: [\"CMD\", \"redis-cli\", \"ping\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\tconst rabbitmqImage = serviceMap.get('rabbitmq');\n\tif (rabbitmqImage) {\n\t\tyaml += `\n  rabbitmq:\n    image: ${rabbitmqImage}\n    container_name: rabbitmq\n    restart: unless-stopped\n    environment:\n      RABBITMQ_DEFAULT_USER: \\${RABBITMQ_USER:-guest}\n      RABBITMQ_DEFAULT_PASS: \\${RABBITMQ_PASSWORD:-guest}\n    ports:\n      - \"15672:15672\"  # Management UI\n    volumes:\n      - rabbitmq_data:/var/lib/rabbitmq\n    healthcheck:\n      test: [\"CMD\", \"rabbitmq-diagnostics\", \"-q\", \"ping\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\tconst minioImage = serviceMap.get('minio');\n\tif (minioImage) {\n\t\tyaml += `\n  minio:\n    image: ${minioImage}\n    container_name: minio\n    restart: unless-stopped\n    entrypoint: sh\n    command: -c 'mkdir -p /data/\\${STORAGE_BUCKET:-${imageName}} && /usr/bin/docker-entrypoint.sh server --console-address \":9001\" /data'\n    environment:\n      MINIO_ROOT_USER: \\${STORAGE_ACCESS_KEY_ID:-${imageName}}\n      MINIO_ROOT_PASSWORD: \\${STORAGE_SECRET_ACCESS_KEY:-${imageName}}\n    ports:\n      - \"\\${MINIO_API_PORT:-9000}:9000\"\n      - \"\\${MINIO_CONSOLE_PORT:-9001}:9001\"\n    volumes:\n      - minio_data:/data\n    healthcheck:\n      test: [\"CMD\", \"mc\", \"ready\", \"local\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\tconst mailpitImage = serviceMap.get('mailpit');\n\tif (mailpitImage) {\n\t\tyaml += `\n  mailpit:\n    image: ${mailpitImage}\n    container_name: mailpit\n    restart: unless-stopped\n    environment:\n      MP_SMTP_AUTH: \\${SMTP_USER:-${imageName}}:\\${SMTP_PASS:-${imageName}}\n      MP_SMTP_AUTH_ALLOW_INSECURE: true\n    ports:\n      - \"\\${MAILPIT_PORT:-8025}:8025\"  # Web UI / API\n      - \"\\${SMTP_PORT:-1025}:1025\"  # SMTP\n    healthcheck:\n      test: [\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:8025\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\tconst localstackImage = serviceMap.get('localstack');\n\tif (localstackImage) {\n\t\tyaml += `\n  localstack:\n    image: ${localstackImage}\n    container_name: localstack\n    restart: unless-stopped\n    environment:\n      SERVICES: sns,sqs\n      AWS_DEFAULT_REGION: \\${AWS_REGION:-us-east-1}\n      AWS_ACCESS_KEY_ID: \\${AWS_ACCESS_KEY_ID:-localstack}\n      AWS_SECRET_ACCESS_KEY: \\${AWS_SECRET_ACCESS_KEY:-localstack}\n    ports:\n      - \"\\${LOCALSTACK_PORT:-4566}:4566\"\n    volumes:\n      - localstack_data:/var/lib/localstack\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:4566/_localstack/health\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - app-network\n`;\n\t}\n\n\t// Add volumes\n\tyaml += `\nvolumes:\n`;\n\n\tif (serviceMap.has('postgres')) {\n\t\tyaml += `  dbdata:\n`;\n\t}\n\n\tif (serviceMap.has('redis')) {\n\t\tyaml += `  redis_data:\n`;\n\t}\n\n\tif (serviceMap.has('rabbitmq')) {\n\t\tyaml += `  rabbitmq_data:\n`;\n\t}\n\n\tif (serviceMap.has('minio')) {\n\t\tyaml += `  minio_data:\n`;\n\t}\n\n\tif (serviceMap.has('localstack')) {\n\t\tyaml += `  localstack_data:\n`;\n\t}\n\n\t// Add networks\n\tyaml += `\nnetworks:\n  app-network:\n    driver: bridge\n`;\n\n\treturn yaml;\n}\n\n/**\n * Generate a minimal docker-compose.yml for API only\n */\nexport function generateMinimalDockerCompose(\n\toptions: Omit<ComposeOptions, 'services'>,\n): string {\n\tconst { imageName, registry, port, healthCheckPath } = options;\n\n\tconst imageRef = registry ? `\\${REGISTRY:-${registry}}/` : '';\n\n\treturn `# Use \"gkm dev\" or \"gkm test\" to start services.\n# Running \"docker compose up\" directly will not inject secrets or resolve ports.\nversion: '3.8'\n\nservices:\n  api:\n    build:\n      context: ../..\n      dockerfile: .gkm/docker/Dockerfile\n    image: ${imageRef}\\${IMAGE_NAME:-${imageName}}:\\${TAG:-latest}\n    container_name: ${imageName}\n    restart: unless-stopped\n    ports:\n      - \"\\${PORT:-${port}}:${port}\"\n    environment:\n      - NODE_ENV=production\n    healthcheck:\n      test: [\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:${port}${healthCheckPath}\"]\n      interval: 30s\n      timeout: 3s\n      retries: 3\n    networks:\n      - app-network\n\nnetworks:\n  app-network:\n    driver: bridge\n`;\n}\n\n/**\n * Options for workspace compose generation.\n */\nexport interface WorkspaceComposeOptions {\n\t/** Container registry URL */\n\tregistry?: string;\n}\n\n/**\n * Generate docker-compose.yml for a workspace with all apps as services.\n * Apps can communicate with each other via service names.\n * @internal Exported for testing\n */\nexport function generateWorkspaceCompose(\n\tworkspace: NormalizedWorkspace,\n\toptions: WorkspaceComposeOptions = {},\n): string {\n\tconst { registry } = options;\n\tconst apps = Object.entries(workspace.apps);\n\tconst services = workspace.services;\n\n\t// Determine which infrastructure services to include\n\tconst hasPostgres = services.db !== undefined && services.db !== false;\n\tconst hasRedis = services.cache !== undefined && services.cache !== false;\n\tconst hasMail = services.mail !== undefined && services.mail !== false;\n\tconst hasMinio = services.storage !== undefined && services.storage !== false;\n\tconst eventsBackend = services.events;\n\tconst hasLocalStack = eventsBackend === 'sns';\n\tconst hasRabbitMQ =\n\t\teventsBackend === 'rabbitmq' ||\n\t\t(services as Record<string, unknown>).rabbitmq !== undefined;\n\n\t// Get image versions from config\n\tconst postgresImage = getInfraServiceImage('postgres', services.db);\n\tconst redisImage = getInfraServiceImage('redis', services.cache);\n\tconst minioImage = getInfraServiceImage('minio', services.storage);\n\n\tlet yaml = `# Docker Compose for ${workspace.name} workspace\n# Use \"gkm dev\" or \"gkm test\" to start services.\n# Running \"docker compose up\" directly will not inject secrets or resolve ports.\n\nservices:\n`;\n\n\t// Generate service for each app (mobile apps deploy via their own\n\t// toolchain — no compose service)\n\tfor (const [appName, app] of apps) {\n\t\tif (app.type === 'mobile') continue;\n\t\tyaml += generateAppService(appName, app, apps, {\n\t\t\tregistry,\n\t\t\tprojectName: workspace.name,\n\t\t\thasPostgres,\n\t\t\thasRedis,\n\t\t\thasMinio,\n\t\t\thasMail,\n\t\t\teventsBackend,\n\t\t});\n\t}\n\n\t// Add infrastructure services\n\tif (hasPostgres) {\n\t\tyaml += `\n  postgres:\n    image: ${postgresImage}\n    container_name: ${workspace.name}-postgres\n    restart: unless-stopped\n    environment:\n      POSTGRES_USER: \\${POSTGRES_USER:-postgres}\n      POSTGRES_PASSWORD: \\${POSTGRES_PASSWORD:-postgres}\n      POSTGRES_DB: \\${POSTGRES_DB:-app}\n    volumes:\n      - dbdata:/var/lib/postgresql/18/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U $$POSTGRES_USER\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\tif (hasRedis) {\n\t\tyaml += `\n  redis:\n    image: ${redisImage}\n    container_name: ${workspace.name}-redis\n    restart: unless-stopped\n    volumes:\n      - redis_data:/data\n    healthcheck:\n      test: [\"CMD\", \"redis-cli\", \"ping\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\tif (hasMail) {\n\t\tyaml += `\n  mailpit:\n    image: axllent/mailpit:latest\n    container_name: ${workspace.name}-mailpit\n    restart: unless-stopped\n    environment:\n      MP_SMTP_AUTH: \\${SMTP_USER:-${workspace.name}}:\\${SMTP_PASS:-${workspace.name}}\n      MP_SMTP_AUTH_ALLOW_INSECURE: true\n    ports:\n      - \"\\${MAILPIT_PORT:-8025}:8025\"  # Web UI / API\n      - \"\\${SMTP_PORT:-1025}:1025\"  # SMTP\n    healthcheck:\n      test: [\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:8025\"]\n      interval: 5s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\tif (hasMinio) {\n\t\tyaml += `\n  minio:\n    image: ${minioImage}\n    container_name: ${workspace.name}-minio\n    restart: unless-stopped\n    entrypoint: sh\n    command: -c 'mkdir -p /data/\\${STORAGE_BUCKET:-${workspace.name}} && /usr/bin/docker-entrypoint.sh server --console-address \":9001\" /data'\n    environment:\n      MINIO_ROOT_USER: \\${STORAGE_ACCESS_KEY_ID:-${workspace.name}}\n      MINIO_ROOT_PASSWORD: \\${STORAGE_SECRET_ACCESS_KEY:-${workspace.name}}\n    ports:\n      - \"\\${MINIO_API_PORT:-9000}:9000\"\n      - \"\\${MINIO_CONSOLE_PORT:-9001}:9001\"\n    volumes:\n      - minio_data:/data\n    healthcheck:\n      test: [\"CMD\", \"mc\", \"ready\", \"local\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\tif (hasLocalStack) {\n\t\tyaml += `\n  localstack:\n    image: localstack/localstack:latest\n    container_name: ${workspace.name}-localstack\n    restart: unless-stopped\n    environment:\n      SERVICES: sns,sqs\n      AWS_DEFAULT_REGION: \\${AWS_REGION:-us-east-1}\n      AWS_ACCESS_KEY_ID: \\${AWS_ACCESS_KEY_ID:-localstack}\n      AWS_SECRET_ACCESS_KEY: \\${AWS_SECRET_ACCESS_KEY:-localstack}\n    ports:\n      - \"\\${LOCALSTACK_PORT:-4566}:4566\"\n    volumes:\n      - localstack_data:/var/lib/localstack\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:4566/_localstack/health\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\tif (hasRabbitMQ) {\n\t\tyaml += `\n  rabbitmq:\n    image: rabbitmq:3-management-alpine\n    container_name: ${workspace.name}-rabbitmq\n    restart: unless-stopped\n    environment:\n      RABBITMQ_DEFAULT_USER: \\${RABBITMQ_USER:-guest}\n      RABBITMQ_DEFAULT_PASS: \\${RABBITMQ_PASSWORD:-guest}\n    ports:\n      - \"\\${RABBITMQ_HOST_PORT:-5672}:5672\"\n      - \"\\${RABBITMQ_MGMT_HOST_PORT:-15672}:15672\"\n    volumes:\n      - rabbitmq_data:/var/lib/rabbitmq\n    healthcheck:\n      test: [\"CMD\", \"rabbitmq-diagnostics\", \"-q\", \"ping\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - workspace-network\n`;\n\t}\n\n\t// Add volumes section\n\tyaml += `\nvolumes:\n`;\n\n\tif (hasPostgres) {\n\t\tyaml += `  dbdata:\n`;\n\t}\n\n\tif (hasRedis) {\n\t\tyaml += `  redis_data:\n`;\n\t}\n\n\tif (hasMinio) {\n\t\tyaml += `  minio_data:\n`;\n\t}\n\n\tif (hasLocalStack) {\n\t\tyaml += `  localstack_data:\n`;\n\t}\n\n\tif (hasRabbitMQ) {\n\t\tyaml += `  rabbitmq_data:\n`;\n\t}\n\n\t// Add networks section\n\tyaml += `\nnetworks:\n  workspace-network:\n    driver: bridge\n`;\n\n\treturn yaml;\n}\n\n/**\n * Get infrastructure service image with version.\n */\nfunction getInfraServiceImage(\n\tserviceName: 'postgres' | 'redis' | 'minio',\n\tconfig: boolean | { version?: string; image?: string } | undefined,\n): string {\n\tconst defaults: Record<'postgres' | 'redis' | 'minio', string> = {\n\t\tpostgres: 'postgres:18-alpine',\n\t\tredis: 'redis:7-alpine',\n\t\tminio: 'minio/minio:latest',\n\t};\n\n\tif (!config || config === true) {\n\t\treturn defaults[serviceName];\n\t}\n\n\tif (typeof config === 'object') {\n\t\tif (config.image) {\n\t\t\treturn config.image;\n\t\t}\n\t\tif (config.version) {\n\t\t\tconst baseImages: Record<'postgres' | 'redis' | 'minio', string> = {\n\t\t\t\tpostgres: 'postgres',\n\t\t\t\tredis: 'redis',\n\t\t\t\tminio: 'minio/minio',\n\t\t\t};\n\t\t\treturn `${baseImages[serviceName]}:${config.version}`;\n\t\t}\n\t}\n\n\treturn defaults[serviceName];\n}\n\n/**\n * Generate a service definition for an app.\n */\nfunction generateAppService(\n\tappName: string,\n\tapp: NormalizedAppConfig,\n\tallApps: [string, NormalizedAppConfig][],\n\toptions: {\n\t\tregistry?: string;\n\t\tprojectName: string;\n\t\thasPostgres: boolean;\n\t\thasRedis: boolean;\n\t\thasMinio: boolean;\n\t\thasMail: boolean;\n\t\teventsBackend?: import('../types').EventsBackend;\n\t},\n): string {\n\tconst {\n\t\tregistry,\n\t\tprojectName,\n\t\thasPostgres,\n\t\thasRedis,\n\t\thasMinio,\n\t\thasMail,\n\t\teventsBackend,\n\t} = options;\n\tconst imageRef = registry ? `\\${REGISTRY:-${registry}}/` : '';\n\n\t// Health check path - frontends use /, backends use /health\n\tconst healthCheckPath = app.type === 'web' ? '/' : '/health';\n\tconst healthCheckCmd =\n\t\tapp.type === 'web'\n\t\t\t? `[\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:${app.port}/\"]`\n\t\t\t: `[\"CMD\", \"wget\", \"-q\", \"--spider\", \"http://localhost:${app.port}${healthCheckPath}\"]`;\n\n\tlet yaml = `\n  ${appName}:\n    build:\n      context: .\n      dockerfile: .gkm/docker/Dockerfile.${appName}\n    image: ${imageRef}\\${${appName.toUpperCase()}_IMAGE:-${appName}}:\\${TAG:-latest}\n    container_name: ${appName}\n    restart: unless-stopped\n    ports:\n      - \"\\${${appName.toUpperCase()}_PORT:-${app.port}}:${app.port}\"\n    environment:\n      - NODE_ENV=production\n      - PORT=${app.port}\n`;\n\n\t// Add dependency URLs - apps can reach other apps by service name\n\tfor (const dep of app.dependencies) {\n\t\tconst depApp = allApps.find(([name]) => name === dep)?.[1];\n\t\tif (depApp) {\n\t\t\tyaml += `      - ${dep.toUpperCase()}_URL=http://${dep}:${depApp.port}\n`;\n\t\t}\n\t}\n\n\t// Add infrastructure service URLs for backend apps\n\tif (app.type === 'backend') {\n\t\tif (hasPostgres) {\n\t\t\tyaml += `      - DATABASE_URL=\\${DATABASE_URL:-postgresql://\\${POSTGRES_USER:-postgres}:\\${POSTGRES_PASSWORD:-postgres}@postgres:5432/\\${POSTGRES_DB:-app}}\n`;\n\t\t}\n\t\tif (hasRedis) {\n\t\t\tyaml += `      - REDIS_URL=\\${REDIS_URL:-redis://redis:6379}\n`;\n\t\t}\n\t\tif (hasMinio) {\n\t\t\tyaml += `      - STORAGE_ENDPOINT=\\${STORAGE_ENDPOINT:-http://minio:9000}\n      - STORAGE_ACCESS_KEY_ID=\\${STORAGE_ACCESS_KEY_ID:-${projectName}}\n      - STORAGE_SECRET_ACCESS_KEY=\\${STORAGE_SECRET_ACCESS_KEY:-${projectName}}\n      - STORAGE_BUCKET=\\${STORAGE_BUCKET:-${projectName}}\n      - STORAGE_REGION=\\${STORAGE_REGION:-eu-west-1}\n      - STORAGE_FORCE_PATH_STYLE=true\n`;\n\t\t}\n\t\tif (hasMail) {\n\t\t\tyaml += `      - SMTP_HOST=\\${SMTP_HOST:-mailpit}\n      - SMTP_PORT=\\${SMTP_PORT:-1025}\n      - SMTP_USER=\\${SMTP_USER:-${projectName}}\n      - SMTP_PASS=\\${SMTP_PASS:-${projectName}}\n      - SMTP_SECURE=\\${SMTP_SECURE:-false}\n      - MAIL_FROM=\\${MAIL_FROM:-noreply@localhost}\n`;\n\t\t}\n\t\tif (eventsBackend) {\n\t\t\tyaml += `      - EVENT_PUBLISHER_CONNECTION_STRING=\\${EVENT_PUBLISHER_CONNECTION_STRING}\n      - EVENT_SUBSCRIBER_CONNECTION_STRING=\\${EVENT_SUBSCRIBER_CONNECTION_STRING}\n`;\n\t\t\tif (eventsBackend === 'sns') {\n\t\t\t\tyaml += `      - AWS_ACCESS_KEY_ID=\\${AWS_ACCESS_KEY_ID:-localstack}\n      - AWS_SECRET_ACCESS_KEY=\\${AWS_SECRET_ACCESS_KEY:-localstack}\n      - AWS_REGION=\\${AWS_REGION:-us-east-1}\n      - AWS_ENDPOINT_URL=\\${AWS_ENDPOINT_URL:-http://localstack:4566}\n`;\n\t\t\t}\n\t\t}\n\t}\n\n\tyaml += `    healthcheck:\n      test: ${healthCheckCmd}\n      interval: 30s\n      timeout: 3s\n      retries: 3\n`;\n\n\t// Add depends_on for dependencies and infrastructure\n\tconst dependencies: string[] = [...app.dependencies];\n\tif (app.type === 'backend') {\n\t\tif (hasPostgres) dependencies.push('postgres');\n\t\tif (hasRedis) dependencies.push('redis');\n\t\tif (hasMinio) dependencies.push('minio');\n\t\tif (hasMail) dependencies.push('mailpit');\n\t\tif (eventsBackend === 'sns') dependencies.push('localstack');\n\t\tif (eventsBackend === 'rabbitmq') dependencies.push('rabbitmq');\n\t}\n\n\tif (dependencies.length > 0) {\n\t\tyaml += `    depends_on:\n`;\n\t\tfor (const dep of dependencies) {\n\t\t\tyaml += `      ${dep}:\n        condition: service_healthy\n`;\n\t\t}\n\t}\n\n\tyaml += `    networks:\n      - workspace-network\n`;\n\n\treturn yaml;\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { DockerConfig, GkmConfig } from '../types';\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\nexport interface DockerTemplateOptions {\n\timageName: string;\n\tbaseImage: string;\n\tport: number;\n\thealthCheckPath: string;\n\t/** Whether the build is pre-built (slim Dockerfile) or needs building */\n\tprebuilt: boolean;\n\t/** Detected package manager */\n\tpackageManager: PackageManager;\n}\n\nexport interface FrontendDockerfileOptions {\n\timageName: string;\n\tbaseImage: string;\n\tport: number;\n\t/** App path relative to workspace root */\n\tappPath: string;\n\t/** Package name for turbo prune */\n\tturboPackage: string;\n\t/** Detected package manager */\n\tpackageManager: PackageManager;\n\t/**\n\t * Public URL build args to include in the Dockerfile.\n\t * These will be declared as ARG and converted to ENV for Next.js build.\n\t * Example: ['NEXT_PUBLIC_API_URL', 'NEXT_PUBLIC_AUTH_URL']\n\t */\n\tpublicUrlArgs?: string[];\n}\n\nexport interface MultiStageDockerfileOptions extends DockerTemplateOptions {\n\t/** Enable turbo prune for monorepo optimization */\n\tturbo?: boolean;\n\t/** Package name for turbo prune (defaults to current directory name) */\n\tturboPackage?: string;\n}\n\nconst LOCKFILES: [string, PackageManager][] = [\n\t['pnpm-lock.yaml', 'pnpm'],\n\t['bun.lockb', 'bun'],\n\t['yarn.lock', 'yarn'],\n\t['package-lock.json', 'npm'],\n];\n\n/**\n * Detect package manager from lockfiles\n * Walks up the directory tree to find lockfile (for monorepos)\n */\nexport function detectPackageManager(\n\tcwd: string = process.cwd(),\n): PackageManager {\n\tlet dir = cwd;\n\tconst root = parse(dir).root;\n\n\t// Walk up the directory tree\n\twhile (dir !== root) {\n\t\tfor (const [lockfile, pm] of LOCKFILES) {\n\t\t\tif (existsSync(join(dir, lockfile))) {\n\t\t\t\treturn pm;\n\t\t\t}\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\n\t// Check root directory\n\tfor (const [lockfile, pm] of LOCKFILES) {\n\t\tif (existsSync(join(root, lockfile))) {\n\t\t\treturn pm;\n\t\t}\n\t}\n\n\treturn 'pnpm'; // default\n}\n\n/**\n * Find the lockfile path by walking up the directory tree\n * Returns the full path to the lockfile, or null if not found\n */\nexport function findLockfilePath(cwd: string = process.cwd()): string | null {\n\tlet dir = cwd;\n\tconst root = parse(dir).root;\n\n\t// Walk up the directory tree\n\twhile (dir !== root) {\n\t\tfor (const [lockfile] of LOCKFILES) {\n\t\t\tconst lockfilePath = join(dir, lockfile);\n\t\t\tif (existsSync(lockfilePath)) {\n\t\t\t\treturn lockfilePath;\n\t\t\t}\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\n\t// Check root directory\n\tfor (const [lockfile] of LOCKFILES) {\n\t\tconst lockfilePath = join(root, lockfile);\n\t\tif (existsSync(lockfilePath)) {\n\t\t\treturn lockfilePath;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Get the lockfile name for a package manager\n */\nexport function getLockfileName(pm: PackageManager): string {\n\tconst lockfileMap: Record<PackageManager, string> = {\n\t\tpnpm: 'pnpm-lock.yaml',\n\t\tnpm: 'package-lock.json',\n\t\tyarn: 'yarn.lock',\n\t\tbun: 'bun.lockb',\n\t};\n\treturn lockfileMap[pm];\n}\n\n/**\n * Check if we're in a monorepo (lockfile is in a parent directory)\n */\nexport function isMonorepo(cwd: string = process.cwd()): boolean {\n\tconst lockfilePath = findLockfilePath(cwd);\n\tif (!lockfilePath) {\n\t\treturn false;\n\t}\n\n\t// Check if lockfile is in a parent directory (not in cwd)\n\tconst lockfileDir = dirname(lockfilePath);\n\treturn lockfileDir !== cwd;\n}\n\n/**\n * Check if turbo.json exists (walks up directory tree)\n */\nexport function hasTurboConfig(cwd: string = process.cwd()): boolean {\n\tlet dir = cwd;\n\tconst root = parse(dir).root;\n\n\twhile (dir !== root) {\n\t\tif (existsSync(join(dir, 'turbo.json'))) {\n\t\t\treturn true;\n\t\t}\n\t\tdir = dirname(dir);\n\t}\n\n\treturn existsSync(join(root, 'turbo.json'));\n}\n\n/**\n * Get install command for turbo builds (without frozen lockfile)\n * Turbo prune creates a subset that may not perfectly match the lockfile\n */\nfunction getTurboInstallCmd(pm: PackageManager): string {\n\tconst commands: Record<PackageManager, string> = {\n\t\tpnpm: 'pnpm install',\n\t\tnpm: 'npm install',\n\t\tyarn: 'yarn install',\n\t\tbun: 'bun install',\n\t};\n\treturn commands[pm];\n}\n\n/**\n * Get package manager specific commands and paths\n */\nfunction getPmConfig(pm: PackageManager) {\n\tconst configs = {\n\t\tpnpm: {\n\t\t\tinstall: 'corepack enable && corepack prepare pnpm@latest --activate',\n\t\t\tlockfile: 'pnpm-lock.yaml',\n\t\t\tfetch: 'pnpm fetch',\n\t\t\tinstallCmd: 'pnpm install --frozen-lockfile --offline',\n\t\t\tcacheTarget: '/root/.local/share/pnpm/store',\n\t\t\tcacheId: 'pnpm',\n\t\t\trun: 'pnpm',\n\t\t\texec: 'pnpm exec',\n\t\t\tdlx: 'pnpm dlx',\n\t\t\taddGlobal: 'pnpm add -g',\n\t\t},\n\t\tnpm: {\n\t\t\tinstall: '', // npm comes with node\n\t\t\tlockfile: 'package-lock.json',\n\t\t\tfetch: '', // npm doesn't have fetch\n\t\t\tinstallCmd: 'npm ci',\n\t\t\tcacheTarget: '/root/.npm',\n\t\t\tcacheId: 'npm',\n\t\t\trun: 'npm run',\n\t\t\texec: 'npx',\n\t\t\tdlx: 'npx',\n\t\t\taddGlobal: 'npm install -g',\n\t\t},\n\t\tyarn: {\n\t\t\tinstall: 'corepack enable && corepack prepare yarn@stable --activate',\n\t\t\tlockfile: 'yarn.lock',\n\t\t\tfetch: '', // yarn doesn't have fetch\n\t\t\tinstallCmd: 'yarn install --frozen-lockfile',\n\t\t\tcacheTarget: '/root/.yarn/cache',\n\t\t\tcacheId: 'yarn',\n\t\t\trun: 'yarn',\n\t\t\texec: 'yarn exec',\n\t\t\tdlx: 'yarn dlx',\n\t\t\taddGlobal: 'yarn global add',\n\t\t},\n\t\tbun: {\n\t\t\tinstall: 'npm install -g bun',\n\t\t\tlockfile: 'bun.lockb',\n\t\t\tfetch: '', // bun doesn't have fetch\n\t\t\tinstallCmd: 'bun install --frozen-lockfile',\n\t\t\tcacheTarget: '/root/.bun/install/cache',\n\t\t\tcacheId: 'bun',\n\t\t\trun: 'bun run',\n\t\t\texec: 'bunx',\n\t\t\tdlx: 'bunx',\n\t\t\taddGlobal: 'bun add -g',\n\t\t},\n\t};\n\treturn configs[pm];\n}\n\n/**\n * Generate a multi-stage Dockerfile for building from source\n * Optimized for build speed with:\n * - BuildKit cache mounts for package manager store\n * - pnpm fetch for better layer caching (when using pnpm)\n * - Optional turbo prune for monorepos\n */\nexport function generateMultiStageDockerfile(\n\toptions: MultiStageDockerfileOptions,\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\thealthCheckPath,\n\t\tturbo,\n\t\tturboPackage,\n\t\tpackageManager,\n\t} = options;\n\n\tif (turbo) {\n\t\treturn generateTurboDockerfile({\n\t\t\t...options,\n\t\t\tturboPackage: turboPackage ?? 'api',\n\t\t});\n\t}\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install\n\t\t? `\\n# Install ${packageManager}\\nRUN ${pm.install}\\n`\n\t\t: '';\n\tconst hasFetch = packageManager === 'pnpm';\n\n\t// pnpm has fetch which allows better caching\n\tconst depsStage = hasFetch\n\t\t? `# Copy lockfile first for better caching\nCOPY ${pm.lockfile} ./\n\n# Fetch dependencies (downloads to virtual store, cached separately)\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${pm.fetch}\n\n# Copy package.json after fetch\nCOPY package.json ./\n\n# Install from cache (fast - no network needed)\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${pm.installCmd}`\n\t\t: `# Copy package files\nCOPY package.json ${pm.lockfile} ./\n\n# Install dependencies with cache\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${pm.installCmd}`;\n\n\treturn `# syntax=docker/dockerfile:1\n# Stage 1: Dependencies\nFROM ${baseImage} AS deps\n\nWORKDIR /app\n${installPm}\n${depsStage}\n\n# Stage 2: Build\nFROM deps AS builder\n\nWORKDIR /app\n\n# Copy source (deps already installed)\nCOPY . .\n\n# Build production server using gkm\nRUN ${pm.exec} gkm build --provider server --production\n\n# Stage 3: Production\nFROM ${baseImage} AS runner\n\nWORKDIR /app\n\n# Install tini for proper signal handling as PID 1\nRUN apk add --no-cache tini\n\n# Create non-root user\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 hono\n\n# Copy bundled server\nCOPY --from=builder --chown=hono:nodejs /app/.gkm/server/dist/server.mjs ./\n\n# Environment\nENV NODE_ENV=production\nENV PORT=${port}\n\n# Health check\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\\\n  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1\n\n# Switch to non-root user\nUSER hono\n\nEXPOSE ${port}\n\n# Use tini as entrypoint to handle PID 1 responsibilities\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"server.mjs\"]\n`;\n}\n\n/**\n * Generate a Dockerfile optimized for Turbo monorepos\n * Uses turbo prune to create minimal Docker context\n */\nfunction generateTurboDockerfile(options: MultiStageDockerfileOptions): string {\n\tconst { baseImage, port, healthCheckPath, turboPackage, packageManager } =\n\t\toptions;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\n\t// For turbo builds, we can't use --frozen-lockfile because turbo prune\n\t// creates a subset that may not perfectly match. Use relaxed install.\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\n\t// Use pnpm dlx for pnpm (avoids global bin dir issues in Docker)\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\n\treturn `# syntax=docker/dockerfile:1\n# Stage 1: Prune monorepo\nFROM ${baseImage} AS pruner\n\nWORKDIR /app\n\n${installPm}\n\nCOPY . .\n\n# Prune to only include necessary packages\nRUN ${turboCmd} prune ${turboPackage} --docker\n\n# Stage 2: Install dependencies\nFROM ${baseImage} AS deps\n\nWORKDIR /app\n\n${installPm}\n\n# Copy pruned lockfile and package.jsons\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\n\n# Install dependencies (no frozen-lockfile since turbo prune creates a subset)\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\n# Stage 3: Build\nFROM deps AS builder\n\nWORKDIR /app\n\n# Copy pruned source\nCOPY --from=pruner /app/out/full/ ./\n\n# Build production server using gkm\nRUN ${pm.exec} gkm build --provider server --production\n\n# Stage 4: Production\nFROM ${baseImage} AS runner\n\nWORKDIR /app\n\nRUN apk add --no-cache tini\n\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 hono\n\nCOPY --from=builder --chown=hono:nodejs /app/.gkm/server/dist/server.mjs ./\n\nENV NODE_ENV=production\nENV PORT=${port}\n\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\\\n  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1\n\nUSER hono\n\nEXPOSE ${port}\n\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"server.mjs\"]\n`;\n}\n\n/**\n * Generate a slim Dockerfile for pre-built bundles\n */\nexport function generateSlimDockerfile(options: DockerTemplateOptions): string {\n\tconst { baseImage, port, healthCheckPath } = options;\n\n\treturn `# Slim Dockerfile for pre-built production bundle\nFROM ${baseImage}\n\nWORKDIR /app\n\n# Install tini for proper signal handling as PID 1\n# Handles SIGTERM propagation and zombie process reaping\nRUN apk add --no-cache tini\n\n# Create non-root user\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 hono\n\n# Copy pre-built bundle\nCOPY .gkm/server/dist/server.mjs ./\n\n# Environment\nENV NODE_ENV=production\nENV PORT=${port}\n\n# Health check\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\\\n  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1\n\n# Switch to non-root user\nUSER hono\n\nEXPOSE ${port}\n\n# Use tini as entrypoint to handle PID 1 responsibilities\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"server.mjs\"]\n`;\n}\n\n/**\n * Generate .dockerignore file\n */\nexport function generateDockerignore(): string {\n\treturn `# Dependencies\nnode_modules\n.pnpm-store\n\n# Build output (except what we need)\n.gkm/aws*\n.gkm/server/*.ts\n!.gkm/server/dist\n\n# IDE and editor\n.idea\n.vscode\n*.swp\n*.swo\n\n# Git\n.git\n.gitignore\n\n# Logs\n*.log\nnpm-debug.log*\npnpm-debug.log*\n\n# Test files\n**/*.test.ts\n**/*.spec.ts\n**/__tests__\ncoverage\n\n# Documentation\ndocs\n*.md\n!README.md\n\n# Environment files (handle secrets separately)\n.env\n.env.*\n!.env.example\n\n# Docker files (don't copy recursively)\nDockerfile*\ndocker-compose*\n.dockerignore\n`;\n}\n\n/**\n * Generate docker-entrypoint.sh for custom startup logic\n */\nexport function generateDockerEntrypoint(): string {\n\treturn `#!/bin/sh\nset -e\n\n# Run any custom startup scripts here\n# Example: wait for database\n# until nc -z $DB_HOST $DB_PORT; do\n#   echo \"Waiting for database...\"\n#   sleep 1\n# done\n\n# Execute the main command\nexec \"$@\"\n`;\n}\n\n/**\n * Resolve Docker configuration from GkmConfig with defaults\n */\nexport function resolveDockerConfig(\n\tconfig: GkmConfig,\n): Required<Omit<DockerConfig, 'compose'>> & Pick<DockerConfig, 'compose'> {\n\tconst docker = config.docker ?? {};\n\n\t// Try to get image name from package.json name\n\tlet defaultImageName = 'api';\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst pkg = require(`${process.cwd()}/package.json`);\n\t\tif (pkg.name) {\n\t\t\t// Remove scope and use just the package name\n\t\t\tdefaultImageName = pkg.name.replace(/^@[^/]+\\//, '');\n\t\t}\n\t} catch {\n\t\t// Ignore if package.json doesn't exist\n\t}\n\n\treturn {\n\t\tregistry: docker.registry ?? '',\n\t\timageName: docker.imageName ?? defaultImageName,\n\t\tbaseImage: docker.baseImage ?? 'node:22-alpine',\n\t\tport: docker.port ?? 3000,\n\t\tcompose: docker.compose,\n\t};\n}\n\n/**\n * Generate a Dockerfile for Next.js frontend apps using standalone output.\n * Uses turbo prune for monorepo optimization.\n * @internal Exported for testing\n */\nexport function generateNextjsDockerfile(\n\toptions: FrontendDockerfileOptions,\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\tappPath,\n\t\tturboPackage,\n\t\tpackageManager,\n\t\tpublicUrlArgs = ['NEXT_PUBLIC_API_URL', 'NEXT_PUBLIC_AUTH_URL'],\n\t} = options;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\n\t// For turbo builds, we can't use --frozen-lockfile because turbo prune\n\t// creates a subset that may not perfectly match. Use relaxed install.\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\n\t// Use pnpm dlx for pnpm (avoids global bin dir issues in Docker)\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\n\t// Generate ARG and ENV declarations for public URLs\n\tconst publicUrlArgDeclarations = publicUrlArgs\n\t\t.map((arg) => `ARG ${arg}=\"\"`)\n\t\t.join('\\n');\n\tconst publicUrlEnvDeclarations = publicUrlArgs\n\t\t.map((arg) => `ENV ${arg}=$${arg}`)\n\t\t.join('\\n');\n\n\treturn `# syntax=docker/dockerfile:1\n# Next.js standalone Dockerfile with turbo prune optimization\n\n# Stage 1: Prune monorepo\nFROM ${baseImage} AS pruner\n\nWORKDIR /app\n\n${installPm}\n\nCOPY . .\n\n# Prune to only include necessary packages\nRUN ${turboCmd} prune ${turboPackage} --docker\n\n# Stage 2: Install dependencies\nFROM ${baseImage} AS deps\n\nWORKDIR /app\n\n${installPm}\n\n# Copy pruned lockfile and package.jsons\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\n\n# Install dependencies\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\n# Stage 3: Build\nFROM deps AS builder\n\nWORKDIR /app\n\n# Build-time args for public API URLs (populated by gkm deploy)\n# These get baked into the Next.js build as public environment variables\n${publicUrlArgDeclarations}\n\n# Convert ARGs to ENVs for Next.js build\n${publicUrlEnvDeclarations}\n\n# Copy pruned source\nCOPY --from=pruner /app/out/full/ ./\n\n# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)\n# Using wildcard to make it optional for single-app projects\nCOPY --from=pruner /app/tsconfig.* ./\n\n# Ensure public directory exists (may be empty for scaffolded projects)\nRUN mkdir -p ${appPath}/public\n\n# Set Next.js to produce standalone output\nENV NEXT_TELEMETRY_DISABLED=1\n\n# Build the application\nRUN ${turboCmd} run build --filter=${turboPackage}\n\n# Stage 4: Production\nFROM ${baseImage} AS runner\n\nWORKDIR /app\n\n# Install tini for proper signal handling\nRUN apk add --no-cache tini\n\n# Create non-root user\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 nextjs\n\n# Set environment\nENV NODE_ENV=production\nENV NEXT_TELEMETRY_DISABLED=1\nENV PORT=${port}\nENV HOSTNAME=\"0.0.0.0\"\n\n# Copy static files and standalone output\nCOPY --from=builder --chown=nextjs:nodejs /app/${appPath}/.next/standalone ./\nCOPY --from=builder --chown=nextjs:nodejs /app/${appPath}/.next/static ./${appPath}/.next/static\nCOPY --from=builder --chown=nextjs:nodejs /app/${appPath}/public ./${appPath}/public\n\nUSER nextjs\n\nEXPOSE ${port}\n\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"${appPath}/server.js\"]\n`;\n}\n\n/**\n * Generate a Dockerfile for backend apps in a workspace.\n * Uses turbo prune for monorepo optimization.\n * @internal Exported for testing\n */\nexport function generateBackendDockerfile(\n\toptions: FrontendDockerfileOptions & { healthCheckPath?: string },\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\tappPath,\n\t\tturboPackage,\n\t\tpackageManager,\n\t\thealthCheckPath = '/health',\n\t} = options;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\n\treturn `# syntax=docker/dockerfile:1\n# Backend Dockerfile with turbo prune optimization\n\n# Stage 1: Prune monorepo\nFROM ${baseImage} AS pruner\n\nWORKDIR /app\n\n${installPm}\n\nCOPY . .\n\n# Prune to only include necessary packages\nRUN ${turboCmd} prune ${turboPackage} --docker\n\n# Stage 2: Install dependencies\nFROM ${baseImage} AS deps\n\nWORKDIR /app\n\n${installPm}\n\n# Copy pruned lockfile and package.jsons\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\n\n# Install dependencies\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\n# Stage 3: Build\nFROM deps AS builder\n\nWORKDIR /app\n\n# Build-time args for encrypted secrets\nARG GKM_ENCRYPTED_CREDENTIALS=\"\"\nARG GKM_CREDENTIALS_IV=\"\"\n\n# Copy pruned source\nCOPY --from=pruner /app/out/full/ ./\n\n# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)\n# Using wildcard to make it optional for single-app projects\nCOPY --from=pruner /app/gkm.config.* ./\nCOPY --from=pruner /app/tsconfig.* ./\n\n# Write encrypted credentials for gkm build to embed\nRUN if [ -n \"$GKM_ENCRYPTED_CREDENTIALS\" ]; then \\\n      mkdir -p ${appPath}/.gkm && \\\n      echo \"$GKM_ENCRYPTED_CREDENTIALS\" > ${appPath}/.gkm/credentials.enc && \\\n      echo \"$GKM_CREDENTIALS_IV\" > ${appPath}/.gkm/credentials.iv; \\\n    fi\n\n# Build production server using gkm\nRUN cd ${appPath} && ${pm.exec} gkm build --provider server --production\n\n# Stage 4: Production\nFROM ${baseImage} AS runner\n\nWORKDIR /app\n\nRUN apk add --no-cache tini\n\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 hono\n\n# Copy bundled server\nCOPY --from=builder --chown=hono:nodejs /app/${appPath}/.gkm/server/dist/server.mjs ./\n\nENV NODE_ENV=production\nENV PORT=${port}\n\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\\\n  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1\n\nUSER hono\n\nEXPOSE ${port}\n\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"server.mjs\"]\n`;\n}\n\n/**\n * Options for entry-based Dockerfile generation.\n */\nexport interface EntryDockerfileOptions {\n\timageName: string;\n\tbaseImage: string;\n\tport: number;\n\t/** App path relative to workspace root */\n\tappPath: string;\n\t/** Entry file path relative to app path (e.g., './src/index.ts') */\n\tentry: string;\n\t/** Package name for turbo prune */\n\tturboPackage: string;\n\t/** Detected package manager */\n\tpackageManager: PackageManager;\n\t/** Health check path (default: '/health') */\n\thealthCheckPath?: string;\n}\n\n/**\n * Generate a Dockerfile for apps with a custom entry point.\n * Uses esbuild to bundle the entry point into dist/index.mjs with all dependencies.\n * This is used for apps that don't use gkm routes (e.g., Better Auth servers).\n * @internal Exported for testing\n */\nexport function generateEntryDockerfile(\n\toptions: EntryDockerfileOptions,\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\tappPath,\n\t\tentry,\n\t\tturboPackage,\n\t\tpackageManager,\n\t\thealthCheckPath = '/health',\n\t} = options;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\n\treturn `# syntax=docker/dockerfile:1\n# Entry-based Dockerfile with turbo prune + tsdown bundling\n\n# Stage 1: Prune monorepo\nFROM ${baseImage} AS pruner\n\nWORKDIR /app\n\n${installPm}\n\nCOPY . .\n\n# Prune to only include necessary packages\nRUN ${turboCmd} prune ${turboPackage} --docker\n\n# Stage 2: Install dependencies\nFROM ${baseImage} AS deps\n\nWORKDIR /app\n\n${installPm}\n\n# Copy pruned lockfile and package.jsons\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\n\n# Install dependencies\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\n# Stage 3: Build with tsdown\nFROM deps AS builder\n\nWORKDIR /app\n\n# Build-time args for encrypted secrets\nARG GKM_ENCRYPTED_CREDENTIALS=\"\"\nARG GKM_CREDENTIALS_IV=\"\"\n\n# Copy pruned source\nCOPY --from=pruner /app/out/full/ ./\n\n# Copy workspace root configs for turbo builds (turbo prune doesn't include root configs)\n# Using wildcard to make it optional for single-app projects\nCOPY --from=pruner /app/tsconfig.* ./\n\n# Write encrypted credentials for tsdown to embed via define\nRUN if [ -n \"$GKM_ENCRYPTED_CREDENTIALS\" ]; then \\\n      mkdir -p ${appPath}/.gkm && \\\n      echo \"$GKM_ENCRYPTED_CREDENTIALS\" > ${appPath}/.gkm/credentials.enc && \\\n      echo \"$GKM_CREDENTIALS_IV\" > ${appPath}/.gkm/credentials.iv; \\\n    fi\n\n# Bundle entry point with esbuild (outputs to dist/index.mjs)\n# Creates a fully standalone bundle with all dependencies included\n# Use define to embed credentials if present\nRUN cd ${appPath} && \\\n    if [ -f .gkm/credentials.enc ]; then \\\n      CREDS=$(cat .gkm/credentials.enc) && \\\n      IV=$(cat .gkm/credentials.iv) && \\\n      npx esbuild ${entry} --bundle --platform=node --target=node22 --format=esm \\\n        --outfile=dist/index.mjs --packages=bundle \\\n        --banner:js='import { createRequire } from \"module\"; const require = createRequire(import.meta.url);' \\\n        --define:__GKM_ENCRYPTED_CREDENTIALS__=\"'\\\\\"$CREDS\\\\\"'\" \\\n        --define:__GKM_CREDENTIALS_IV__=\"'\\\\\"$IV\\\\\"'\"; \\\n    else \\\n      npx esbuild ${entry} --bundle --platform=node --target=node22 --format=esm \\\n        --outfile=dist/index.mjs --packages=bundle \\\n        --banner:js='import { createRequire } from \"module\"; const require = createRequire(import.meta.url);'; \\\n    fi\n\n# Stage 4: Production\nFROM ${baseImage} AS runner\n\nWORKDIR /app\n\nRUN apk add --no-cache tini\n\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 app\n\n# Copy bundled output only (no node_modules needed - fully bundled)\nCOPY --from=builder --chown=app:nodejs /app/${appPath}/dist/index.mjs ./\n\nENV NODE_ENV=production\nENV PORT=${port}\n\nHEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\\\\n  CMD wget -qO- http://localhost:${port}${healthCheckPath} > /dev/null 2>&1 || exit 1\n\nUSER app\n\nEXPOSE ${port}\n\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"node\", \"index.mjs\"]\n`;\n}\n\n/**\n * Generate a Dockerfile for Node-based SSR web frameworks (TanStack Start,\n * Remix). Builds with turbo, then runs the framework's production start\n * script via `npm start`.\n *\n * Public URL build args are declared so framework bundlers (Vite, Vinxi)\n * can inline them at build time. Per-framework prefix is the caller's job.\n * @internal Exported for testing\n */\nexport function generateNodeWebDockerfile(\n\toptions: FrontendDockerfileOptions,\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\tappPath,\n\t\tturboPackage,\n\t\tpackageManager,\n\t\tpublicUrlArgs = [],\n\t} = options;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\tconst startCmd =\n\t\tpackageManager === 'pnpm'\n\t\t\t? 'pnpm start'\n\t\t\t: `${pm.lockfile.startsWith('package-lock') ? 'npm' : packageManager} start`;\n\n\tconst argDecls = publicUrlArgs.map((a) => `ARG ${a}=\"\"`).join('\\n');\n\tconst envDecls = publicUrlArgs.map((a) => `ENV ${a}=$${a}`).join('\\n');\n\n\treturn `# syntax=docker/dockerfile:1\n# Node SSR web Dockerfile (TanStack Start / Remix) with turbo prune\n\nFROM ${baseImage} AS pruner\nWORKDIR /app\n${installPm}\nCOPY . .\nRUN ${turboCmd} prune ${turboPackage} --docker\n\nFROM ${baseImage} AS deps\nWORKDIR /app\n${installPm}\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\nFROM deps AS builder\nWORKDIR /app\n${argDecls}\n${envDecls}\nCOPY --from=pruner /app/out/full/ ./\nCOPY --from=pruner /app/tsconfig.* ./\nRUN ${turboCmd} run build --filter=${turboPackage}\n\nFROM ${baseImage} AS runner\nWORKDIR /app\nRUN apk add --no-cache tini\nRUN addgroup --system --gid 1001 nodejs && \\\\\n    adduser --system --uid 1001 app\n\n# Copy the whole built workspace — frameworks differ on output paths\nCOPY --from=builder --chown=app:nodejs /app/ ./\n\nENV NODE_ENV=production\nENV PORT=${port}\nENV HOSTNAME=\"0.0.0.0\"\n\nUSER app\nEXPOSE ${port}\n\nENTRYPOINT [\"/sbin/tini\", \"--\"]\nCMD [\"sh\", \"-c\", \"cd ${appPath} && ${startCmd}\"]\n`;\n}\n\n/**\n * Generate a Dockerfile for Vite SPA apps. Builds the static bundle with\n * turbo, then serves it via nginx.\n * @internal Exported for testing\n */\nexport function generateViteStaticDockerfile(\n\toptions: FrontendDockerfileOptions,\n): string {\n\tconst {\n\t\tbaseImage,\n\t\tport,\n\t\tappPath,\n\t\tturboPackage,\n\t\tpackageManager,\n\t\tpublicUrlArgs = [],\n\t} = options;\n\n\tconst pm = getPmConfig(packageManager);\n\tconst installPm = pm.install ? `RUN ${pm.install}` : '';\n\tconst turboInstallCmd = getTurboInstallCmd(packageManager);\n\tconst turboCmd = packageManager === 'pnpm' ? 'pnpm dlx turbo' : 'npx turbo';\n\n\tconst argDecls = publicUrlArgs.map((a) => `ARG ${a}=\"\"`).join('\\n');\n\tconst envDecls = publicUrlArgs.map((a) => `ENV ${a}=$${a}`).join('\\n');\n\n\treturn `# syntax=docker/dockerfile:1\n# Vite SPA Dockerfile — builds static assets, serves via nginx\n\nFROM ${baseImage} AS pruner\nWORKDIR /app\n${installPm}\nCOPY . .\nRUN ${turboCmd} prune ${turboPackage} --docker\n\nFROM ${baseImage} AS deps\nWORKDIR /app\n${installPm}\nCOPY --from=pruner /app/out/${pm.lockfile} ./\nCOPY --from=pruner /app/out/json/ ./\nRUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\\\\n    ${turboInstallCmd}\n\nFROM deps AS builder\nWORKDIR /app\n${argDecls}\n${envDecls}\nCOPY --from=pruner /app/out/full/ ./\nCOPY --from=pruner /app/tsconfig.* ./\nRUN ${turboCmd} run build --filter=${turboPackage}\n\nFROM nginx:alpine AS runner\nCOPY --from=builder /app/${appPath}/dist /usr/share/nginx/html\nRUN printf 'server {\\\\n  listen ${port};\\\\n  root /usr/share/nginx/html;\\\\n  index index.html;\\\\n  location / { try_files $uri $uri/ /index.html; }\\\\n}\\\\n' \\\\\n    > /etc/nginx/conf.d/default.conf\nEXPOSE ${port}\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n`;\n}\n","import { execSync } from 'node:child_process';\nimport { copyFileSync, existsSync, readFileSync, unlinkSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { loadConfig, loadWorkspaceConfig } from '../config';\nimport { getPublicUrlArgNames } from '../deploy/domain.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport {\n\tgenerateDockerCompose,\n\tgenerateMinimalDockerCompose,\n\tgenerateWorkspaceCompose,\n} from './compose';\nimport {\n\tdetectPackageManager,\n\tfindLockfilePath,\n\tgenerateBackendDockerfile,\n\tgenerateDockerEntrypoint,\n\tgenerateDockerignore,\n\tgenerateEntryDockerfile,\n\tgenerateMultiStageDockerfile,\n\tgenerateNextjsDockerfile,\n\tgenerateNodeWebDockerfile,\n\tgenerateSlimDockerfile,\n\tgenerateViteStaticDockerfile,\n\thasTurboConfig,\n\tisMonorepo,\n\tresolveDockerConfig,\n} from './templates';\n\nexport {\n\tdetectPackageManager,\n\tfindLockfilePath,\n\thasTurboConfig,\n\tisMonorepo,\n} from './templates';\n\nconst logger = console;\n\nexport interface DockerOptions {\n\t/** Build Docker image after generating files */\n\tbuild?: boolean;\n\t/** Push image to registry after building */\n\tpush?: boolean;\n\t/** Image tag (default: 'latest') */\n\ttag?: string;\n\t/** Container registry URL */\n\tregistry?: string;\n\t/** Use slim Dockerfile (requires pre-built bundle from `gkm build --production`) */\n\tslim?: boolean;\n\t/** Enable turbo prune for monorepo optimization */\n\tturbo?: boolean;\n\t/** Package name for turbo prune (defaults to package.json name) */\n\tturboPackage?: string;\n}\n\nexport interface DockerGeneratedFiles {\n\tdockerfile: string;\n\tdockerCompose: string;\n\tdockerignore: string;\n\tentrypoint: string;\n}\n\n/**\n * Docker command implementation\n * Generates Dockerfile, docker-compose.yml, and related files\n *\n * Default: Multi-stage Dockerfile that builds from source inside Docker\n * --slim: Slim Dockerfile that copies pre-built bundle (requires prior build)\n */\nexport async function dockerCommand(\n\toptions: DockerOptions,\n): Promise<DockerGeneratedFiles | WorkspaceDockerResult> {\n\t// Load config with workspace detection\n\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t// Route to workspace docker mode for multi-app workspaces\n\tif (loadedConfig.type === 'workspace') {\n\t\tlogger.log('📦 Detected workspace configuration');\n\t\treturn workspaceDockerCommand(loadedConfig.workspace, options);\n\t}\n\n\t// Single-app mode - use existing logic\n\tconst config = await loadConfig();\n\tconst dockerConfig = resolveDockerConfig(config);\n\n\t// Get health check path from production config\n\tconst serverConfig =\n\t\ttypeof config.providers?.server === 'object'\n\t\t\t? config.providers.server\n\t\t\t: undefined;\n\tconst healthCheckPath = serverConfig?.production?.healthCheck ?? '/health';\n\n\t// Determine Dockerfile type\n\t// Default: Multi-stage (builds inside Docker for reproducibility)\n\t// --slim: Requires pre-built bundle\n\tconst useSlim = options.slim === true;\n\n\tif (useSlim) {\n\t\t// Verify pre-built bundle exists for slim mode\n\t\tconst distDir = join(process.cwd(), '.gkm', 'server', 'dist');\n\t\tconst hasBuild = existsSync(join(distDir, 'server.mjs'));\n\n\t\tif (!hasBuild) {\n\t\t\tthrow new Error(\n\t\t\t\t'Slim Dockerfile requires a pre-built bundle. Run `gkm build --provider server --production` first, or omit --slim to use multi-stage build.',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Generate Docker files\n\tconst dockerDir = join(process.cwd(), '.gkm', 'docker');\n\tawait mkdir(dockerDir, { recursive: true });\n\n\t// Detect package manager from lockfiles\n\tconst packageManager = detectPackageManager();\n\tconst inMonorepo = isMonorepo();\n\tconst hasTurbo = hasTurboConfig();\n\n\t// Auto-enable turbo for monorepos with turbo.json\n\tlet useTurbo = options.turbo ?? false;\n\tif (inMonorepo && !useSlim) {\n\t\tif (hasTurbo) {\n\t\t\tuseTurbo = true;\n\t\t\tlogger.log('   Detected monorepo with turbo.json - using turbo prune');\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Monorepo detected but turbo.json not found.\\n\\n' +\n\t\t\t\t\t'Docker builds in monorepos require Turborepo for proper dependency isolation.\\n\\n' +\n\t\t\t\t\t'To fix this:\\n' +\n\t\t\t\t\t'  1. Install turbo: pnpm add -Dw turbo\\n' +\n\t\t\t\t\t'  2. Create turbo.json in your monorepo root\\n' +\n\t\t\t\t\t'  3. Run this command again\\n\\n' +\n\t\t\t\t\t'See: https://turbo.build/repo/docs/guides/tools/docker',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Get the actual package name from package.json for turbo prune\n\tlet turboPackage = options.turboPackage ?? dockerConfig.imageName;\n\tif (useTurbo && !options.turboPackage) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\t\tconst pkg = require(`${process.cwd()}/package.json`);\n\t\t\tif (pkg.name) {\n\t\t\t\tturboPackage = pkg.name;\n\t\t\t\tlogger.log(`   Turbo package: ${turboPackage}`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall back to imageName\n\t\t}\n\t}\n\n\tconst templateOptions = {\n\t\timageName: dockerConfig.imageName,\n\t\tbaseImage: dockerConfig.baseImage,\n\t\tport: dockerConfig.port,\n\t\thealthCheckPath,\n\t\tprebuilt: useSlim,\n\t\tturbo: useTurbo,\n\t\tturboPackage,\n\t\tpackageManager,\n\t};\n\n\t// Generate Dockerfile\n\tconst dockerfile = useSlim\n\t\t? generateSlimDockerfile(templateOptions)\n\t\t: generateMultiStageDockerfile(templateOptions);\n\n\tconst dockerMode = useSlim ? 'slim' : useTurbo ? 'turbo' : 'multi-stage';\n\n\tconst dockerfilePath = join(dockerDir, 'Dockerfile');\n\tawait writeFile(dockerfilePath, dockerfile);\n\tlogger.log(\n\t\t`Generated: .gkm/docker/Dockerfile (${dockerMode}, ${packageManager})`,\n\t);\n\n\t// Generate docker-compose.yml\n\tconst composeOptions = {\n\t\timageName: dockerConfig.imageName,\n\t\tregistry: options.registry ?? dockerConfig.registry,\n\t\tport: dockerConfig.port,\n\t\thealthCheckPath,\n\t\tservices: dockerConfig.compose?.services ?? {},\n\t};\n\n\t// Check if there are any services configured\n\tconst hasServices = Array.isArray(composeOptions.services)\n\t\t? composeOptions.services.length > 0\n\t\t: Object.keys(composeOptions.services).length > 0;\n\n\tconst dockerCompose = hasServices\n\t\t? generateDockerCompose(composeOptions)\n\t\t: generateMinimalDockerCompose(composeOptions);\n\n\tconst composePath = join(dockerDir, 'docker-compose.yml');\n\tawait writeFile(composePath, dockerCompose);\n\tlogger.log('Generated: .gkm/docker/docker-compose.yml');\n\n\t// Generate .dockerignore in project root (Docker looks for it there)\n\tconst dockerignore = generateDockerignore();\n\tconst dockerignorePath = join(process.cwd(), '.dockerignore');\n\tawait writeFile(dockerignorePath, dockerignore);\n\tlogger.log('Generated: .dockerignore (project root)');\n\n\t// Generate docker-entrypoint.sh\n\tconst entrypoint = generateDockerEntrypoint();\n\tconst entrypointPath = join(dockerDir, 'docker-entrypoint.sh');\n\tawait writeFile(entrypointPath, entrypoint);\n\tlogger.log('Generated: .gkm/docker/docker-entrypoint.sh');\n\n\tconst result: DockerGeneratedFiles = {\n\t\tdockerfile: dockerfilePath,\n\t\tdockerCompose: composePath,\n\t\tdockerignore: dockerignorePath,\n\t\tentrypoint: entrypointPath,\n\t};\n\n\t// Build Docker image if requested\n\tif (options.build) {\n\t\tawait buildDockerImage(dockerConfig.imageName, options);\n\t}\n\n\t// Push Docker image if requested\n\tif (options.push) {\n\t\tawait pushDockerImage(dockerConfig.imageName, options);\n\t}\n\n\treturn result;\n}\n\n/**\n * Ensure lockfile exists in the build context\n * For monorepos, copies from workspace root if needed\n * Returns cleanup function if file was copied\n */\nfunction ensureLockfile(cwd: string): (() => void) | null {\n\tconst lockfilePath = findLockfilePath(cwd);\n\n\tif (!lockfilePath) {\n\t\tlogger.warn(\n\t\t\t'\\n⚠️  No lockfile found. Docker build may fail or use stale dependencies.',\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst lockfileName = basename(lockfilePath);\n\tconst localLockfile = join(cwd, lockfileName);\n\n\t// If lockfile exists locally (same directory), nothing to do\n\tif (lockfilePath === localLockfile) {\n\t\treturn null;\n\t}\n\n\tlogger.log(`   Copying ${lockfileName} from monorepo root...`);\n\tcopyFileSync(lockfilePath, localLockfile);\n\n\t// Return cleanup function\n\treturn () => {\n\t\ttry {\n\t\t\tunlinkSync(localLockfile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors\n\t\t}\n\t};\n}\n\n/**\n * Build Docker image\n * Uses BuildKit for cache mount support\n */\nasync function buildDockerImage(\n\timageName: string,\n\toptions: DockerOptions,\n): Promise<void> {\n\tconst tag = options.tag ?? 'latest';\n\tconst registry = options.registry;\n\n\tconst fullImageName = registry\n\t\t? `${registry}/${imageName}:${tag}`\n\t\t: `${imageName}:${tag}`;\n\n\tlogger.log(`\\n🐳 Building Docker image: ${fullImageName}`);\n\n\tconst cwd = process.cwd();\n\n\t// Ensure lockfile exists (copy from monorepo root if needed)\n\tconst cleanup = ensureLockfile(cwd);\n\n\ttry {\n\t\t// Use BuildKit for cache mount support (required for --mount=type=cache)\n\t\texecSync(\n\t\t\t`DOCKER_BUILDKIT=1 docker build -f .gkm/docker/Dockerfile -t ${fullImageName} .`,\n\t\t\t{\n\t\t\t\tcwd,\n\t\t\t\tstdio: 'inherit',\n\t\t\t\tenv: { ...process.env, DOCKER_BUILDKIT: '1' },\n\t\t\t},\n\t\t);\n\t\tlogger.log(`✅ Docker image built: ${fullImageName}`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to build Docker image: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t} finally {\n\t\t// Clean up copied lockfile\n\t\tcleanup?.();\n\t}\n}\n\n/**\n * Push Docker image to registry\n */\nasync function pushDockerImage(\n\timageName: string,\n\toptions: DockerOptions,\n): Promise<void> {\n\tconst tag = options.tag ?? 'latest';\n\tconst registry = options.registry;\n\n\tif (!registry) {\n\t\tthrow new Error(\n\t\t\t'Registry is required to push Docker image. Use --registry or configure docker.registry in gkm.config.ts',\n\t\t);\n\t}\n\n\tconst fullImageName = `${registry}/${imageName}:${tag}`;\n\n\tlogger.log(`\\n🚀 Pushing Docker image: ${fullImageName}`);\n\n\ttry {\n\t\texecSync(`docker push ${fullImageName}`, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\t\tlogger.log(`✅ Docker image pushed: ${fullImageName}`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to push Docker image: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n}\n\n/**\n * Result of generating Docker files for a single app in a workspace.\n */\nexport interface AppDockerResult {\n\tappName: string;\n\ttype: 'backend' | 'web' | 'mobile';\n\tdockerfile: string;\n\timageName: string;\n}\n\n/**\n * Result of workspace docker command.\n */\nexport interface WorkspaceDockerResult {\n\tapps: AppDockerResult[];\n\tdockerCompose: string;\n\tdockerignore: string;\n}\n\n/**\n * Get the package name from package.json in an app directory.\n */\nfunction getAppPackageName(appPath: string): string | undefined {\n\ttry {\n\t\tconst pkgPath = join(appPath, 'package.json');\n\t\tif (!existsSync(pkgPath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst content = readFileSync(pkgPath, 'utf-8');\n\t\tconst pkg = JSON.parse(content);\n\t\treturn pkg.name;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Generate Dockerfiles for all apps in a workspace.\n * @internal Exported for testing\n */\nexport async function workspaceDockerCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: DockerOptions,\n): Promise<WorkspaceDockerResult> {\n\tconst results: AppDockerResult[] = [];\n\tconst apps = Object.entries(workspace.apps);\n\n\tlogger.log(`\\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);\n\n\t// Create docker output directory\n\tconst dockerDir = join(workspace.root, '.gkm', 'docker');\n\tawait mkdir(dockerDir, { recursive: true });\n\n\t// Detect package manager\n\tconst packageManager = detectPackageManager(workspace.root);\n\tlogger.log(`   Package manager: ${packageManager}`);\n\n\t// Generate Dockerfile for each app\n\tfor (const [appName, app] of apps) {\n\t\t// Mobile apps deploy via their own toolchain (e.g. EAS Build for Expo)\n\t\t// — no Docker image is produced.\n\t\tif (app.type === 'mobile') {\n\t\t\tlogger.log(\n\t\t\t\t`\\n   📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst appPath = app.path;\n\t\tconst fullAppPath = join(workspace.root, appPath);\n\n\t\t// Get package name for turbo prune (use package.json name or app name)\n\t\tconst turboPackage = getAppPackageName(fullAppPath) ?? appName;\n\n\t\t// Determine image name\n\t\tconst imageName = appName;\n\n\t\tconst hasEntry = !!app.entry;\n\t\tconst buildType = hasEntry ? 'entry' : app.type;\n\t\tlogger.log(`\\n   📄 Generating Dockerfile for ${appName} (${buildType})`);\n\n\t\tlet dockerfile: string;\n\n\t\tif (app.type === 'web') {\n\t\t\tconst publicUrlArgs = getPublicUrlArgNames(app);\n\t\t\tconst webOpts = {\n\t\t\t\timageName,\n\t\t\t\tbaseImage: 'node:22-alpine',\n\t\t\t\tport: app.port,\n\t\t\t\tappPath,\n\t\t\t\tturboPackage,\n\t\t\t\tpackageManager,\n\t\t\t\tpublicUrlArgs,\n\t\t\t};\n\n\t\t\tswitch (app.framework) {\n\t\t\t\tcase 'vite':\n\t\t\t\t\tdockerfile = generateViteStaticDockerfile(webOpts);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'tanstack-start':\n\t\t\t\tcase 'remix':\n\t\t\t\t\tdockerfile = generateNodeWebDockerfile(webOpts);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// nextjs (and any unspecified web framework — schema requires\n\t\t\t\t\t// a valid framework, so this is just a default).\n\t\t\t\t\tdockerfile = generateNextjsDockerfile(webOpts);\n\t\t\t}\n\t\t} else if (app.entry) {\n\t\t\t// Backend with custom entry point - use tsdown bundling\n\t\t\tdockerfile = generateEntryDockerfile({\n\t\t\t\timageName,\n\t\t\t\tbaseImage: 'node:22-alpine',\n\t\t\t\tport: app.port,\n\t\t\t\tappPath,\n\t\t\t\tentry: app.entry,\n\t\t\t\tturboPackage,\n\t\t\t\tpackageManager,\n\t\t\t\thealthCheckPath: '/health',\n\t\t\t});\n\t\t} else {\n\t\t\t// Backend with gkm routes - use gkm build\n\t\t\tdockerfile = generateBackendDockerfile({\n\t\t\t\timageName,\n\t\t\t\tbaseImage: 'node:22-alpine',\n\t\t\t\tport: app.port,\n\t\t\t\tappPath,\n\t\t\t\tturboPackage,\n\t\t\t\tpackageManager,\n\t\t\t\thealthCheckPath: '/health',\n\t\t\t});\n\t\t}\n\n\t\t// Write Dockerfile with app-specific name\n\t\tconst dockerfilePath = join(dockerDir, `Dockerfile.${appName}`);\n\t\tawait writeFile(dockerfilePath, dockerfile);\n\t\tlogger.log(`      Generated: .gkm/docker/Dockerfile.${appName}`);\n\n\t\tresults.push({\n\t\t\tappName,\n\t\t\ttype: app.type,\n\t\t\tdockerfile: dockerfilePath,\n\t\t\timageName,\n\t\t});\n\t}\n\n\t// Generate shared .dockerignore\n\tconst dockerignore = generateDockerignore();\n\tconst dockerignorePath = join(workspace.root, '.dockerignore');\n\tawait writeFile(dockerignorePath, dockerignore);\n\tlogger.log(`\\n   Generated: .dockerignore (workspace root)`);\n\n\t// Generate docker-compose.yml for workspace\n\tconst dockerCompose = generateWorkspaceCompose(workspace, {\n\t\tregistry: options.registry,\n\t});\n\tconst composePath = join(dockerDir, 'docker-compose.yml');\n\tawait writeFile(composePath, dockerCompose);\n\tlogger.log(`   Generated: .gkm/docker/docker-compose.yml`);\n\n\t// Summary\n\tlogger.log(\n\t\t`\\n✅ Generated ${results.length} Dockerfile(s) + docker-compose.yml`,\n\t);\n\tlogger.log('\\n📋 Build commands:');\n\tfor (const result of results) {\n\t\tconst icon =\n\t\t\tresult.type === 'backend' ? '⚙️' : result.type === 'mobile' ? '📱' : '🌐';\n\t\tlogger.log(\n\t\t\t`   ${icon} docker build -f .gkm/docker/Dockerfile.${result.appName} -t ${result.imageName} .`,\n\t\t);\n\t}\n\tlogger.log('\\n📋 Run all services:');\n\tlogger.log('   docker compose -f .gkm/docker/docker-compose.yml up --build');\n\n\treturn {\n\t\tapps: results,\n\t\tdockerCompose: composePath,\n\t\tdockerignore: dockerignorePath,\n\t};\n}\n","import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { GkmConfig } from '../config';\nimport { dockerCommand, findLockfilePath } from '../docker';\nimport type { DeployResult, DockerDeployConfig } from './types';\n\n/**\n * Get app name from package.json in the current working directory\n * Used for Dokploy app/project naming\n */\nexport function getAppNameFromCwd(): string | undefined {\n\tconst packageJsonPath = join(process.cwd(), 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tif (pkg.name) {\n\t\t\t// Strip org scope if present (e.g., @myorg/app -> app)\n\t\t\treturn pkg.name.replace(/^@[^/]+\\//, '');\n\t\t}\n\t} catch {\n\t\t// Ignore parse errors\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Get app name from package.json adjacent to the lockfile (project root)\n * Used for Docker image naming\n */\nexport function getAppNameFromPackageJson(): string | undefined {\n\tconst cwd = process.cwd();\n\n\t// Find the lockfile to determine the project root\n\tconst lockfilePath = findLockfilePath(cwd);\n\tif (!lockfilePath) {\n\t\treturn undefined;\n\t}\n\n\t// Use the package.json adjacent to the lockfile\n\tconst projectRoot = dirname(lockfilePath);\n\tconst packageJsonPath = join(projectRoot, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tif (pkg.name) {\n\t\t\t// Strip org scope if present (e.g., @myorg/app -> app)\n\t\t\treturn pkg.name.replace(/^@[^/]+\\//, '');\n\t\t}\n\t} catch {\n\t\t// Ignore parse errors\n\t}\n\n\treturn undefined;\n}\n\nconst logger = console;\n\nexport interface DockerDeployOptions {\n\t/** Deployment stage */\n\tstage: string;\n\t/** Image tag */\n\ttag: string;\n\t/** Skip pushing to registry */\n\tskipPush?: boolean;\n\t/** Master key from build */\n\tmasterKey?: string;\n\t/** Docker config from gkm.config */\n\tconfig: DockerDeployConfig;\n\t/**\n\t * Build arguments to pass to docker build.\n\t * Format: ['KEY=value', 'KEY2=value2']\n\t */\n\tbuildArgs?: string[];\n\t/**\n\t * Public URL argument names for frontend Dockerfile generation.\n\t * Used to ensure the Dockerfile declares these as ARG/ENV.\n\t */\n\tpublicUrlArgs?: string[];\n}\n\n/**\n * Get the full image reference\n */\nexport function getImageRef(\n\tregistry: string | undefined,\n\timageName: string,\n\ttag: string,\n): string {\n\tif (registry) {\n\t\treturn `${registry}/${imageName}:${tag}`;\n\t}\n\treturn `${imageName}:${tag}`;\n}\n\n/**\n * Build Docker image\n * @param imageRef - Full image reference (registry/name:tag)\n * @param appName - Name of the app (used for Dockerfile.{appName} in workspaces)\n * @param buildArgs - Build arguments to pass to docker build\n */\nasync function buildImage(\n\timageRef: string,\n\tappName?: string,\n\tbuildArgs?: string[],\n): Promise<void> {\n\tlogger.log(`\\n🔨 Building Docker image: ${imageRef}`);\n\n\tconst cwd = process.cwd();\n\tconst lockfilePath = findLockfilePath(cwd);\n\tconst lockfileDir = lockfilePath ? dirname(lockfilePath) : cwd;\n\tconst inMonorepo = lockfileDir !== cwd;\n\n\t// Generate appropriate Dockerfile\n\tif (appName || inMonorepo) {\n\t\tlogger.log('   Generating Dockerfile for monorepo (turbo prune)...');\n\t} else {\n\t\tlogger.log('   Generating Dockerfile...');\n\t}\n\tawait dockerCommand({});\n\n\t// Determine build context and Dockerfile path\n\t// For workspaces with multiple apps, use per-app Dockerfile (Dockerfile.api, etc.)\n\tconst dockerfileSuffix = appName ? `.${appName}` : '';\n\tconst dockerfilePath = `.gkm/docker/Dockerfile${dockerfileSuffix}`;\n\n\t// Build from workspace/monorepo root when we have a lockfile elsewhere or appName is provided\n\tconst buildCwd = lockfilePath && (inMonorepo || appName) ? lockfileDir : cwd;\n\tif (buildCwd !== cwd) {\n\t\tlogger.log(`   Building from workspace root: ${buildCwd}`);\n\t}\n\n\t// Build the build args string\n\tconst buildArgsString =\n\t\tbuildArgs && buildArgs.length > 0\n\t\t\t? buildArgs.map((arg) => `--build-arg \"${arg}\"`).join(' ')\n\t\t\t: '';\n\n\ttry {\n\t\t// Build for linux/amd64 to ensure compatibility with most cloud servers\n\t\tconst cmd = [\n\t\t\t'DOCKER_BUILDKIT=1 docker build',\n\t\t\t'--platform linux/amd64',\n\t\t\t`-f ${dockerfilePath}`,\n\t\t\t`-t ${imageRef}`,\n\t\t\tbuildArgsString,\n\t\t\t'.',\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\n\t\texecSync(cmd, {\n\t\t\tcwd: buildCwd,\n\t\t\tstdio: 'inherit',\n\t\t\tenv: { ...process.env, DOCKER_BUILDKIT: '1' },\n\t\t});\n\t\tlogger.log(`✅ Image built: ${imageRef}`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to build Docker image: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n}\n\n/**\n * Push Docker image to registry\n */\nasync function pushImage(imageRef: string): Promise<void> {\n\tlogger.log(`\\n☁️  Pushing image: ${imageRef}`);\n\n\ttry {\n\t\texecSync(`docker push ${imageRef}`, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t});\n\t\tlogger.log(`✅ Image pushed: ${imageRef}`);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to push Docker image: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n}\n\n/**\n * Deploy using Docker (build and optionally push image)\n */\nexport async function deployDocker(\n\toptions: DockerDeployOptions,\n): Promise<DeployResult> {\n\tconst { stage, tag, skipPush, masterKey, config, buildArgs } = options;\n\n\t// imageName should always be set by resolveDockerConfig\n\tconst imageName = config.imageName!;\n\tconst imageRef = getImageRef(config.registry, imageName, tag);\n\n\t// Build image (pass appName for workspace Dockerfile selection)\n\tawait buildImage(imageRef, config.appName, buildArgs);\n\n\t// Push to registry if not skipped\n\tif (!skipPush) {\n\t\tif (!config.registry) {\n\t\t\tlogger.warn(\n\t\t\t\t'\\n⚠️  No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts',\n\t\t\t);\n\t\t} else {\n\t\t\tawait pushImage(imageRef);\n\t\t}\n\t}\n\n\t// Output deployment info\n\tlogger.log('\\n✅ Docker deployment ready!');\n\tlogger.log(`\\n📋 Deployment details:`);\n\tlogger.log(`   Image: ${imageRef}`);\n\tlogger.log(`   Stage: ${stage}`);\n\n\tif (masterKey) {\n\t\tlogger.log(`\\n🔐 Deploy with this environment variable:`);\n\t\tlogger.log(`   GKM_MASTER_KEY=${masterKey}`);\n\t\tlogger.log('\\n   Example docker run:');\n\t\tlogger.log(`   docker run -e GKM_MASTER_KEY=${masterKey} ${imageRef}`);\n\t}\n\n\treturn {\n\t\timageRef,\n\t\tmasterKey,\n\t};\n}\n\n/**\n * Resolve Docker deploy config from gkm config\n * - imageName: from config, or cwd package.json, or 'app' (for Docker image)\n * - projectName: from root package.json, or 'app' (for Dokploy project)\n * - appName: from cwd package.json, or projectName (for Dokploy app within project)\n */\nexport function resolveDockerConfig(config: GkmConfig): DockerDeployConfig {\n\t// projectName comes from root package.json (monorepo name)\n\tconst projectName = getAppNameFromPackageJson() ?? 'app';\n\n\t// appName comes from cwd package.json (the app being deployed)\n\tconst appName = getAppNameFromCwd() ?? projectName;\n\n\t// imageName defaults to appName (cwd package.json)\n\tconst imageName = config.docker?.imageName ?? appName;\n\n\treturn {\n\t\tregistry: config.docker?.registry,\n\t\timageName,\n\t\tprojectName,\n\t\tappName,\n\t};\n}\n","import { getDokployRegistryId, getDokployToken } from '../auth';\nimport { DokployApi } from './dokploy-api';\nimport type { DeployResult, DokployDeployConfig } from './types';\n\nconst logger = console;\n\nexport interface DokployDeployOptions {\n\t/** Deployment stage */\n\tstage: string;\n\t/** Image tag */\n\ttag: string;\n\t/** Image reference */\n\timageRef: string;\n\t/** Master key from build */\n\tmasterKey?: string;\n\t/** Dokploy config from gkm.config */\n\tconfig: DokployDeployConfig;\n}\n\n/**\n * Get the Dokploy API token from stored credentials or environment\n */\nasync function getApiToken(): Promise<string> {\n\tconst token = await getDokployToken();\n\tif (!token) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found.\\n' +\n\t\t\t\t'Run \"gkm login --service dokploy\" to authenticate, or set DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\treturn token;\n}\n\n/**\n * Create a Dokploy API client\n */\nasync function createApi(endpoint: string): Promise<DokployApi> {\n\tconst token = await getApiToken();\n\treturn new DokployApi({ baseUrl: endpoint, token });\n}\n\n/**\n * Deploy to Dokploy\n */\nexport async function deployDokploy(\n\toptions: DokployDeployOptions,\n): Promise<DeployResult> {\n\tconst { stage, imageRef, masterKey, config } = options;\n\n\tlogger.log(`\\n🎯 Deploying to Dokploy...`);\n\tlogger.log(`   Endpoint: ${config.endpoint}`);\n\tlogger.log(`   Application: ${config.applicationId}`);\n\n\tconst api = await createApi(config.endpoint);\n\n\t// Configure Docker provider with the image\n\tlogger.log(`  Configuring Docker image: ${imageRef}`);\n\n\t// Determine registry credentials\n\tconst registryOptions: {\n\t\tregistryId?: string;\n\t\tusername?: string;\n\t\tpassword?: string;\n\t\tregistryUrl?: string;\n\t} = {};\n\n\tif (config.registryId) {\n\t\t// Use registry ID from config\n\t\tregistryOptions.registryId = config.registryId;\n\t\tlogger.log(`  Using Dokploy registry: ${config.registryId}`);\n\t} else {\n\t\t// Try stored registry ID from credentials\n\t\tconst storedRegistryId = await getDokployRegistryId();\n\t\tif (storedRegistryId) {\n\t\t\tregistryOptions.registryId = storedRegistryId;\n\t\t\tlogger.log(`  Using stored Dokploy registry: ${storedRegistryId}`);\n\t\t} else if (config.registryCredentials) {\n\t\t\t// Use explicit credentials from config\n\t\t\tregistryOptions.username = config.registryCredentials.username;\n\t\t\tregistryOptions.password = config.registryCredentials.password;\n\t\t\tregistryOptions.registryUrl = config.registryCredentials.registryUrl;\n\t\t\tlogger.log(\n\t\t\t\t`  Using registry credentials for: ${config.registryCredentials.registryUrl}`,\n\t\t\t);\n\t\t} else {\n\t\t\t// Try environment variables\n\t\t\tconst username = process.env.DOCKER_REGISTRY_USERNAME;\n\t\t\tconst password = process.env.DOCKER_REGISTRY_PASSWORD;\n\t\t\tconst registryUrl = process.env.DOCKER_REGISTRY_URL || config.registry;\n\n\t\t\tif (username && password && registryUrl) {\n\t\t\t\tregistryOptions.username = username;\n\t\t\t\tregistryOptions.password = password;\n\t\t\t\tregistryOptions.registryUrl = registryUrl;\n\t\t\t\tlogger.log(`  Using registry credentials from environment`);\n\t\t\t}\n\t\t}\n\t}\n\n\tawait api.saveDockerProvider(config.applicationId, imageRef, registryOptions);\n\tlogger.log('  ✓ Docker provider configured');\n\n\t// Prepare environment variables\n\tconst envVars: Record<string, string> = {};\n\n\tif (masterKey) {\n\t\tenvVars.GKM_MASTER_KEY = masterKey;\n\t}\n\n\t// Update environment if we have variables to set\n\tif (Object.keys(envVars).length > 0) {\n\t\tlogger.log('  Updating environment variables...');\n\n\t\t// Convert env vars to the format Dokploy expects (KEY=VALUE per line)\n\t\tconst envString = Object.entries(envVars)\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join('\\n');\n\n\t\tawait api.saveApplicationEnv(config.applicationId, envString);\n\t\tlogger.log('  ✓ Environment variables updated');\n\t}\n\n\t// Trigger deployment\n\tlogger.log('  Triggering deployment...');\n\tawait api.deployApplication(config.applicationId);\n\tlogger.log('  ✓ Deployment triggered');\n\n\tlogger.log('\\n✅ Dokploy deployment initiated!');\n\tlogger.log(`\\n📋 Deployment details:`);\n\tlogger.log(`   Image: ${imageRef}`);\n\tlogger.log(`   Stage: ${stage}`);\n\tlogger.log(`   Application ID: ${config.applicationId}`);\n\n\tif (masterKey) {\n\t\tlogger.log(`\\n🔐 GKM_MASTER_KEY has been set in Dokploy environment`);\n\t}\n\n\t// Construct the probable deployment URL\n\tconst deploymentUrl = `${config.endpoint}/project/${config.projectId}`;\n\tlogger.log(`\\n🔗 View deployment: ${deploymentUrl}`);\n\n\treturn {\n\t\timageRef,\n\t\tmasterKey,\n\t\turl: deploymentUrl,\n\t};\n}\n\n/**\n * Validate Dokploy configuration\n */\nexport function validateDokployConfig(\n\tconfig: Partial<DokployDeployConfig> | undefined,\n): config is DokployDeployConfig {\n\tif (!config) {\n\t\treturn false;\n\t}\n\n\tconst required = ['endpoint', 'projectId', 'applicationId'] as const;\n\tconst missing = required.filter((key) => !config[key]);\n\n\tif (missing.length > 0) {\n\t\tthrow new Error(\n\t\t\t`Missing Dokploy configuration: ${missing.join(', ')}\\n` +\n\t\t\t\t'Configure in gkm.config.ts:\\n' +\n\t\t\t\t'  providers: {\\n' +\n\t\t\t\t'    dokploy: {\\n' +\n\t\t\t\t\"      endpoint: 'https://dokploy.example.com',\\n\" +\n\t\t\t\t\"      projectId: 'proj_xxx',\\n\" +\n\t\t\t\t\"      applicationId: 'app_xxx',\\n\" +\n\t\t\t\t'    },\\n' +\n\t\t\t\t'  }',\n\t\t);\n\t}\n\n\treturn true;\n}\n","/**\n * Environment Variable Resolution for Dokploy Deployments\n *\n * Resolves sniffed environment variables to actual values during deployment.\n * Auto-supports common variables like DATABASE_URL, REDIS_URL, BETTER_AUTH_*,\n * and falls back to user-provided secrets.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport type { StageSecrets } from '../secrets/types';\nimport { stripPublicPrefix } from '../workspace/publicEnv';\nimport type { NormalizedAppConfig } from '../workspace/types';\nimport {\n\ttype AppDbCredentials,\n\ttype DokployStageState,\n\tgetGeneratedSecret,\n\tsetGeneratedSecret,\n} from './state';\n\n/**\n * Context needed for environment variable resolution\n */\nexport interface EnvResolverContext {\n\t/** The app being deployed */\n\tapp: NormalizedAppConfig;\n\t/** The app name */\n\tappName: string;\n\t/** Deployment stage (production, staging, development) */\n\tstage: string;\n\t/** Deploy state (for persisting generated secrets) */\n\tstate: DokployStageState;\n\t/** Per-app database credentials (if postgres is enabled) */\n\tappCredentials?: AppDbCredentials;\n\t/** Postgres connection info (internal hostname) */\n\tpostgres?: {\n\t\thost: string;\n\t\tport: number;\n\t\tdatabase: string;\n\t};\n\t/** Redis connection info (internal hostname) */\n\tredis?: {\n\t\thost: string;\n\t\tport: number;\n\t\tpassword?: string;\n\t};\n\t/** Public hostname for this app */\n\tappHostname: string;\n\t/** All frontend app URLs (for BETTER_AUTH_TRUSTED_ORIGINS) */\n\tfrontendUrls: string[];\n\t/** User-provided secrets from secrets store */\n\tuserSecrets?: StageSecrets;\n\t/** Master key for runtime decryption (optional) */\n\tmasterKey?: string;\n\t/** URLs of deployed dependency apps (e.g., { auth: 'https://auth.example.com' }) */\n\tdependencyUrls?: Record<string, string>;\n}\n\n/**\n * Result of environment variable resolution\n */\nexport interface EnvResolutionResult {\n\t/** Successfully resolved environment variables */\n\tresolved: Record<string, string>;\n\t/** Environment variable names that could not be resolved */\n\tmissing: string[];\n}\n\n/**\n * Auto-supported environment variable names\n */\nexport const AUTO_SUPPORTED_VARS = [\n\t'PORT',\n\t'NODE_ENV',\n\t'STAGE',\n\t'DATABASE_URL',\n\t'REDIS_URL',\n\t'BETTER_AUTH_URL',\n\t'BETTER_AUTH_SECRET',\n\t'BETTER_AUTH_TRUSTED_ORIGINS',\n\t'GKM_MASTER_KEY',\n] as const;\n\nexport type AutoSupportedVar = (typeof AUTO_SUPPORTED_VARS)[number];\n\n/**\n * Check if a variable name is auto-supported\n */\nexport function isAutoSupportedVar(\n\tvarName: string,\n): varName is AutoSupportedVar {\n\treturn AUTO_SUPPORTED_VARS.includes(varName as AutoSupportedVar);\n}\n\n/**\n * Generate a secure random secret (64 hex characters = 32 bytes)\n */\nexport function generateSecret(): string {\n\treturn randomBytes(32).toString('hex');\n}\n\n/**\n * Get or generate a secret for an app.\n * If the secret already exists in state, returns it.\n * Otherwise generates a new one and stores it.\n */\nexport function getOrGenerateSecret(\n\tstate: DokployStageState,\n\tappName: string,\n\tsecretName: string,\n): string {\n\t// Check if already generated\n\tconst existing = getGeneratedSecret(state, appName, secretName);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\t// Generate new secret\n\tconst generated = generateSecret();\n\n\t// Store in state for persistence\n\tsetGeneratedSecret(state, appName, secretName, generated);\n\n\treturn generated;\n}\n\n/**\n * Build a DATABASE_URL for an app with per-app credentials\n */\nexport function buildDatabaseUrl(\n\tcredentials: AppDbCredentials,\n\tpostgres: { host: string; port: number; database: string },\n): string {\n\tconst { dbUser, dbPassword } = credentials;\n\tconst { host, port, database } = postgres;\n\treturn `postgresql://${encodeURIComponent(dbUser)}:${encodeURIComponent(dbPassword)}@${host}:${port}/${database}`;\n}\n\n/**\n * Build a REDIS_URL\n */\nexport function buildRedisUrl(redis: {\n\thost: string;\n\tport: number;\n\tpassword?: string;\n}): string {\n\tconst { host, port, password } = redis;\n\tif (password) {\n\t\treturn `redis://:${encodeURIComponent(password)}@${host}:${port}`;\n\t}\n\treturn `redis://${host}:${port}`;\n}\n\n/**\n * Resolve a single environment variable\n */\nexport function resolveEnvVar(\n\tvarName: string,\n\tcontext: EnvResolverContext,\n): string | undefined {\n\t// Auto-supported variables\n\tswitch (varName) {\n\t\tcase 'PORT':\n\t\t\treturn String(context.app.port);\n\n\t\tcase 'NODE_ENV':\n\t\t\t// Always 'production' for deployed apps (gkm dev handles development mode)\n\t\t\treturn 'production';\n\n\t\tcase 'STAGE':\n\t\t\treturn context.stage;\n\n\t\tcase 'DATABASE_URL':\n\t\t\tif (context.appCredentials && context.postgres) {\n\t\t\t\treturn buildDatabaseUrl(context.appCredentials, context.postgres);\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\n\t\tcase 'REDIS_URL':\n\t\t\tif (context.redis) {\n\t\t\t\treturn buildRedisUrl(context.redis);\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\n\t\tcase 'BETTER_AUTH_URL':\n\t\t\treturn `https://${context.appHostname}`;\n\n\t\tcase 'BETTER_AUTH_SECRET':\n\t\t\treturn getOrGenerateSecret(\n\t\t\t\tcontext.state,\n\t\t\t\tcontext.appName,\n\t\t\t\t'BETTER_AUTH_SECRET',\n\t\t\t);\n\n\t\tcase 'BETTER_AUTH_TRUSTED_ORIGINS':\n\t\t\tif (context.frontendUrls.length > 0) {\n\t\t\t\treturn context.frontendUrls.join(',');\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\n\t\tcase 'GKM_MASTER_KEY':\n\t\t\tif (context.masterKey) {\n\t\t\t\treturn context.masterKey;\n\t\t\t}\n\t\t\t// Fall through to check user secrets\n\t\t\tbreak;\n\t}\n\n\t// Check dependency URLs (e.g., AUTH_URL -> dependencyUrls.auth)\n\t// Also supports any known public prefix (NEXT_PUBLIC_, VITE_, ...) so\n\t// VITE_AUTH_URL and NEXT_PUBLIC_AUTH_URL both resolve to dependencyUrls.auth.\n\tif (context.dependencyUrls && varName.endsWith('_URL')) {\n\t\tconst stripped = stripPublicPrefix(varName) ?? varName;\n\t\tconst depName = stripped.slice(0, -4).toLowerCase();\n\n\t\tif (context.dependencyUrls[depName]) {\n\t\t\treturn context.dependencyUrls[depName];\n\t\t}\n\t}\n\n\t// Check user-provided secrets\n\tif (context.userSecrets) {\n\t\t// Check custom secrets first\n\t\tif (context.userSecrets.custom[varName]) {\n\t\t\treturn context.userSecrets.custom[varName];\n\t\t}\n\n\t\t// Check URLs (DATABASE_URL, REDIS_URL, RABBITMQ_URL)\n\t\tif (varName in context.userSecrets.urls) {\n\t\t\treturn context.userSecrets.urls[\n\t\t\t\tvarName as keyof typeof context.userSecrets.urls\n\t\t\t];\n\t\t}\n\n\t\t// Check service-specific vars\n\t\tif (\n\t\t\tvarName === 'POSTGRES_PASSWORD' &&\n\t\t\tcontext.userSecrets.services.postgres\n\t\t) {\n\t\t\treturn context.userSecrets.services.postgres.password;\n\t\t}\n\t\tif (varName === 'REDIS_PASSWORD' && context.userSecrets.services.redis) {\n\t\t\treturn context.userSecrets.services.redis.password;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Resolve all environment variables for an app\n */\nexport function resolveEnvVars(\n\trequiredVars: string[],\n\tcontext: EnvResolverContext,\n): EnvResolutionResult {\n\tconst resolved: Record<string, string> = {};\n\tconst missing: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tconst value = resolveEnvVar(varName, context);\n\t\tif (value !== undefined) {\n\t\t\tresolved[varName] = value;\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn { resolved, missing };\n}\n\n/**\n * Format missing variables error message\n */\nexport function formatMissingVarsError(\n\tappName: string,\n\tmissing: string[],\n\tstage: string,\n): string {\n\tconst varList = missing.map((v) => `  - ${v}`).join('\\n');\n\treturn (\n\t\t`Deployment failed: ${appName} is missing required environment variables:\\n` +\n\t\t`${varList}\\n\\n` +\n\t\t`Add them with:\\n` +\n\t\t`  gkm secrets:set <VAR_NAME> <value> --stage ${stage}\\n\\n` +\n\t\t`Or add them to the app's requiredEnv in gkm.config.ts to have them auto-resolved.`\n\t);\n}\n\n/**\n * Validate that all required environment variables can be resolved\n */\nexport function validateEnvVars(\n\trequiredVars: string[],\n\tcontext: EnvResolverContext,\n): { valid: boolean; missing: string[]; resolved: Record<string, string> } {\n\tconst { resolved, missing } = resolveEnvVars(requiredVars, context);\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing,\n\t\tresolved,\n\t};\n}\n","import { existsSync } from 'node:fs';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tgetDokployCredentials,\n\tgetDokployRegistryId,\n\tgetDokployToken,\n\tstoreDokployRegistryId,\n} from '../auth';\nimport { DokployApi } from './dokploy-api';\nimport type { DokployDeployConfig } from './types';\n\nconst logger = console;\n\nexport interface DeployInitOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Project name (creates new or uses existing) */\n\tprojectName: string;\n\t/** Application name */\n\tappName: string;\n\t/** Use existing project ID instead of creating/finding */\n\tprojectId?: string;\n\t/** Registry ID in Dokploy (optional, uses stored if available) */\n\tregistryId?: string;\n}\n\nexport interface RegistrySetupOptions {\n\t/** Dokploy endpoint URL (optional if logged in) */\n\tendpoint?: string;\n\t/** Registry name (for display in Dokploy) */\n\tregistryName: string;\n\t/** Registry URL (e.g., ghcr.io, docker.io) */\n\tregistryUrl: string;\n\t/** Registry username */\n\tusername: string;\n\t/** Registry password or token */\n\tpassword: string;\n\t/** Image prefix (optional, e.g., org-name) */\n\timagePrefix?: string;\n}\n\n/**\n * Get the Dokploy API token from stored credentials or environment\n */\nasync function getApiToken(): Promise<string> {\n\tconst token = await getDokployToken();\n\tif (!token) {\n\t\tthrow new Error(\n\t\t\t'Dokploy credentials not found.\\n' +\n\t\t\t\t'Run \"gkm login --service dokploy\" to authenticate, or set DOKPLOY_API_TOKEN.',\n\t\t);\n\t}\n\treturn token;\n}\n\n/**\n * Get Dokploy endpoint from options or stored credentials\n */\nasync function getEndpoint(providedEndpoint?: string): Promise<string> {\n\tif (providedEndpoint) {\n\t\treturn providedEndpoint;\n\t}\n\n\tconst stored = await getDokployCredentials();\n\tif (stored) {\n\t\treturn stored.endpoint;\n\t}\n\n\tthrow new Error(\n\t\t'Dokploy endpoint not specified.\\n' +\n\t\t\t'Either run \"gkm login --service dokploy\" first, or provide --endpoint.',\n\t);\n}\n\n/**\n * Create a Dokploy API client\n */\nasync function createApi(endpoint: string): Promise<DokployApi> {\n\tconst token = await getApiToken();\n\treturn new DokployApi({ baseUrl: endpoint, token });\n}\n\n/**\n * Update gkm.config.ts with Dokploy configuration\n */\nexport async function updateConfig(\n\tconfig: DokployDeployConfig,\n\tcwd: string = process.cwd(),\n): Promise<void> {\n\tconst configPath = join(cwd, 'gkm.config.ts');\n\n\tif (!existsSync(configPath)) {\n\t\tlogger.warn(\n\t\t\t'\\n  gkm.config.ts not found. Add this configuration manually:\\n',\n\t\t);\n\t\tlogger.log(`  providers: {`);\n\t\tlogger.log(`    dokploy: {`);\n\t\tlogger.log(`      endpoint: '${config.endpoint}',`);\n\t\tlogger.log(`      projectId: '${config.projectId}',`);\n\t\tlogger.log(`      applicationId: '${config.applicationId}',`);\n\t\tlogger.log(`    },`);\n\t\tlogger.log(`  },`);\n\t\treturn;\n\t}\n\n\tconst content = await readFile(configPath, 'utf-8');\n\n\t// Check if providers.dokploy already exists\n\tif (content.includes('dokploy:') && content.includes('applicationId:')) {\n\t\tlogger.log('\\n  Dokploy config already exists in gkm.config.ts');\n\t\tlogger.log('  Updating with new values...');\n\t}\n\n\t// Build the dokploy config string\n\tconst registryLine = config.registryId\n\t\t? `\\n\\t\\t\\tregistryId: '${config.registryId}',`\n\t\t: '';\n\tconst dokployConfigStr = `dokploy: {\n\t\t\tendpoint: '${config.endpoint}',\n\t\t\tprojectId: '${config.projectId}',\n\t\t\tapplicationId: '${config.applicationId}',${registryLine}\n\t\t}`;\n\n\t// Try to add or update the dokploy config\n\tlet newContent: string;\n\n\tif (content.includes('providers:')) {\n\t\t// Add dokploy to existing providers\n\t\tif (content.includes('dokploy:')) {\n\t\t\t// Update existing dokploy config (handle multi-line with registryId)\n\t\t\tnewContent = content.replace(/dokploy:\\s*\\{[^}]*\\}/s, dokployConfigStr);\n\t\t} else {\n\t\t\t// Add dokploy to providers\n\t\t\tnewContent = content.replace(\n\t\t\t\t/providers:\\s*\\{/,\n\t\t\t\t`providers: {\\n\\t\\t${dokployConfigStr},`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\t// Add providers section before the closing of defineConfig\n\t\tnewContent = content.replace(\n\t\t\t/}\\s*\\)\\s*;?\\s*$/,\n\t\t\t`\n\tproviders: {\n\t\t${dokployConfigStr},\n\t},\n});`,\n\t\t);\n\t}\n\n\tawait writeFile(configPath, newContent);\n\tlogger.log('\\n  ✓ Updated gkm.config.ts with Dokploy configuration');\n}\n\n/**\n * Initialize Dokploy deployment configuration\n */\nexport async function deployInitCommand(\n\toptions: DeployInitOptions,\n): Promise<DokployDeployConfig> {\n\tconst {\n\t\tprojectName,\n\t\tappName,\n\t\tprojectId: existingProjectId,\n\t\tregistryId,\n\t} = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🚀 Initializing Dokploy deployment...`);\n\tlogger.log(`   Endpoint: ${endpoint}`);\n\n\t// Step 1: Find or create project\n\tlet projectId: string;\n\n\tif (existingProjectId) {\n\t\tprojectId = existingProjectId;\n\t\tlogger.log(`\\n📁 Using existing project: ${projectId}`);\n\t} else {\n\t\tlogger.log(`\\n📁 Looking for project: ${projectName}`);\n\n\t\tconst projects = await api.listProjects();\n\t\tconst existingProject = projects.find(\n\t\t\t(p) => p.name.toLowerCase() === projectName.toLowerCase(),\n\t\t);\n\n\t\tif (existingProject) {\n\t\t\tprojectId = existingProject.projectId;\n\t\t\tlogger.log(`   Found existing project: ${projectId}`);\n\t\t} else {\n\t\t\tlogger.log(`   Creating new project...`);\n\t\t\tconst result = await api.createProject(projectName);\n\t\t\tprojectId = result.project.projectId;\n\t\t\tlogger.log(`   ✓ Created project: ${projectId}`);\n\t\t}\n\t}\n\n\t// Step 2: Get project to find environment\n\tconst project = await api.getProject(projectId);\n\tlet environmentId: string;\n\n\tconst firstEnv = project.environments?.[0];\n\tif (firstEnv) {\n\t\tenvironmentId = firstEnv.environmentId;\n\t} else {\n\t\t// Create a default environment\n\t\tlogger.log(`   Creating production environment...`);\n\t\tconst env = await api.createEnvironment(projectId, 'production');\n\t\tenvironmentId = env.environmentId;\n\t}\n\n\t// Step 3: Create application\n\tlogger.log(`\\n📦 Creating application: ${appName}`);\n\tconst application = await api.createApplication(\n\t\tappName,\n\t\tprojectId,\n\t\tenvironmentId,\n\t);\n\tlogger.log(`   ✓ Created application: ${application.applicationId}`);\n\n\t// Step 4: Configure registry if provided\n\tif (registryId) {\n\t\tlogger.log(`\\n🔧 Configuring registry: ${registryId}`);\n\t\tawait api.updateApplication(application.applicationId, { registryId });\n\t\tlogger.log(`   ✓ Registry configured`);\n\t} else {\n\t\t// List available registries\n\t\ttry {\n\t\t\tconst registries = await api.listRegistries();\n\t\t\tif (registries.length > 0) {\n\t\t\t\tlogger.log(`\\n📋 Available registries:`);\n\t\t\t\tfor (const reg of registries) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t`   - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlogger.log(`\\n   To use a registry, run with --registry-id <id>`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore registry listing errors\n\t\t}\n\t}\n\n\t// Step 5: Build config\n\tconst config: DokployDeployConfig = {\n\t\tendpoint,\n\t\tprojectId,\n\t\tapplicationId: application.applicationId,\n\t};\n\n\t// Step 6: Update gkm.config.ts\n\tawait updateConfig(config);\n\n\tlogger.log(`\\n✅ Dokploy deployment initialized!`);\n\tlogger.log(`\\n📋 Configuration:`);\n\tlogger.log(`   Project ID: ${projectId}`);\n\tlogger.log(`   Application ID: ${application.applicationId}`);\n\tlogger.log(`\\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);\n\tlogger.log(`\\n📝 Next steps:`);\n\tlogger.log(`   1. Initialize secrets: gkm secrets:init --stage production`);\n\tlogger.log(`   2. Deploy: gkm deploy --provider dokploy --stage production`);\n\n\treturn config;\n}\n\n/**\n * List available Dokploy resources\n */\nexport async function deployListCommand(options: {\n\tendpoint?: string;\n\tresource: 'projects' | 'registries';\n}): Promise<void> {\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tconst { resource } = options;\n\n\tif (resource === 'projects') {\n\t\tlogger.log(`\\n📁 Projects in ${endpoint}:`);\n\t\tconst projects = await api.listProjects();\n\n\t\tif (projects.length === 0) {\n\t\t\tlogger.log('   No projects found');\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const project of projects) {\n\t\t\tlogger.log(`\\n   ${project.name} (${project.projectId})`);\n\t\t\tif (project.description) {\n\t\t\t\tlogger.log(`     ${project.description}`);\n\t\t\t}\n\t\t}\n\t} else if (resource === 'registries') {\n\t\tlogger.log(`\\n🐳 Registries in ${endpoint}:`);\n\t\tconst registries = await api.listRegistries();\n\n\t\tif (registries.length === 0) {\n\t\t\tlogger.log('   No registries configured');\n\t\t\tlogger.log('   Run \"gkm registry:setup\" to configure a registry');\n\t\t\treturn;\n\t\t}\n\n\t\tconst storedRegistryId = await getDokployRegistryId();\n\n\t\tfor (const registry of registries) {\n\t\t\tconst isDefault = registry.registryId === storedRegistryId;\n\t\t\tconst marker = isDefault ? ' (default)' : '';\n\t\t\tlogger.log(\n\t\t\t\t`\\n   ${registry.registryName}${marker} (${registry.registryId})`,\n\t\t\t);\n\t\t\tlogger.log(`     URL: ${registry.registryUrl}`);\n\t\t\tlogger.log(`     Username: ${registry.username}`);\n\t\t\tif (registry.imagePrefix) {\n\t\t\t\tlogger.log(`     Prefix: ${registry.imagePrefix}`);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Setup a Docker registry in Dokploy\n */\nexport async function registrySetupCommand(\n\toptions: RegistrySetupOptions,\n): Promise<string> {\n\tconst { registryName, registryUrl, username, password, imagePrefix } =\n\t\toptions;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🐳 Setting up Docker registry in Dokploy...`);\n\tlogger.log(`   Endpoint: ${endpoint}`);\n\n\t// Check if registry with same URL already exists\n\tconst existingRegistries = await api.listRegistries();\n\tconst existing = existingRegistries.find(\n\t\t(r) =>\n\t\t\tr.registryUrl === registryUrl ||\n\t\t\tr.registryName.toLowerCase() === registryName.toLowerCase(),\n\t);\n\n\tlet registryId: string;\n\n\tif (existing) {\n\t\tlogger.log(`\\n📋 Found existing registry: ${existing.registryName}`);\n\t\tlogger.log(`   Updating credentials...`);\n\n\t\tawait api.updateRegistry(existing.registryId, {\n\t\t\tregistryName,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\timagePrefix,\n\t\t});\n\n\t\tregistryId = existing.registryId;\n\t\tlogger.log(`   ✓ Registry updated: ${registryId}`);\n\t} else {\n\t\tlogger.log(`\\n📦 Creating registry: ${registryName}`);\n\n\t\tconst registry = await api.createRegistry(\n\t\t\tregistryName,\n\t\t\tregistryUrl,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\t{ imagePrefix },\n\t\t);\n\n\t\tregistryId = registry.registryId;\n\t\tlogger.log(`   ✓ Registry created: ${registryId}`);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\tlogger.log(`\\n💾 Saved registry ID to ~/.gkm/credentials.json`);\n\n\tlogger.log(`\\n✅ Registry setup complete!`);\n\tlogger.log(`\\n📋 Registry Details:`);\n\tlogger.log(`   ID: ${registryId}`);\n\tlogger.log(`   Name: ${registryName}`);\n\tlogger.log(`   URL: ${registryUrl}`);\n\tlogger.log(`   Username: ${username}`);\n\tif (imagePrefix) {\n\t\tlogger.log(`   Prefix: ${imagePrefix}`);\n\t}\n\n\tlogger.log(\n\t\t`\\n📝 The registry ID is now stored and will be used automatically`,\n\t);\n\tlogger.log(`   when deploying with \"gkm deploy --provider dokploy\"`);\n\n\treturn registryId;\n}\n\n/**\n * Use an existing registry (set as default)\n */\nexport async function registryUseCommand(options: {\n\tendpoint?: string;\n\tregistryId: string;\n}): Promise<void> {\n\tconst { registryId } = options;\n\n\tconst endpoint = await getEndpoint(options.endpoint);\n\tconst api = await createApi(endpoint);\n\n\tlogger.log(`\\n🔧 Setting default registry...`);\n\n\t// Verify the registry exists\n\ttry {\n\t\tconst registry = await api.getRegistry(registryId);\n\t\tlogger.log(`   Found registry: ${registry.registryName}`);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Registry not found: ${registryId}\\n` +\n\t\t\t\t'Run \"gkm deploy:list registries\" to see available registries.',\n\t\t);\n\t}\n\n\t// Store registry ID in credentials\n\tawait storeDokployRegistryId(registryId);\n\n\tlogger.log(`\\n✅ Default registry set: ${registryId}`);\n\tlogger.log(`   This registry will be used for future deployments.`);\n}\n","/**\n * State Provider Interface\n *\n * Abstracts the storage backend for deployment state.\n * Built-in providers: LocalStateProvider, SSMStateProvider\n * Users can also supply custom implementations.\n */\n\nimport type { DokployStageState } from './state';\n\n/**\n * Interface for deployment state storage providers.\n *\n * Implementations must handle:\n * - Reading state for a stage (returns null if not found)\n * - Writing state for a stage (creates or updates)\n */\nexport interface StateProvider {\n\t/**\n\t * Read deployment state for a stage.\n\t *\n\t * @param stage - The deployment stage (e.g., 'development', 'production')\n\t * @returns The state object or null if not found\n\t */\n\tread(stage: string): Promise<DokployStageState | null>;\n\n\t/**\n\t * Write deployment state for a stage.\n\t *\n\t * @param stage - The deployment stage\n\t * @param state - The state object to persist\n\t */\n\twrite(stage: string, state: DokployStageState): Promise<void>;\n}\n\n/**\n * Valid AWS regions.\n */\nexport type AwsRegion =\n\t| 'us-east-1'\n\t| 'us-east-2'\n\t| 'us-west-1'\n\t| 'us-west-2'\n\t| 'af-south-1'\n\t| 'ap-east-1'\n\t| 'ap-south-1'\n\t| 'ap-south-2'\n\t| 'ap-southeast-1'\n\t| 'ap-southeast-2'\n\t| 'ap-southeast-3'\n\t| 'ap-southeast-4'\n\t| 'ap-northeast-1'\n\t| 'ap-northeast-2'\n\t| 'ap-northeast-3'\n\t| 'ca-central-1'\n\t| 'eu-central-1'\n\t| 'eu-central-2'\n\t| 'eu-west-1'\n\t| 'eu-west-2'\n\t| 'eu-west-3'\n\t| 'eu-south-1'\n\t| 'eu-south-2'\n\t| 'eu-north-1'\n\t| 'me-south-1'\n\t| 'me-central-1'\n\t| 'sa-east-1';\n\n/**\n * Local state provider config.\n */\nexport interface LocalStateConfig {\n\tprovider: 'local';\n}\n\n/**\n * SSM state provider config (requires region).\n */\nexport interface SSMStateConfig {\n\tprovider: 'ssm';\n\t/** AWS region (required for SSM provider) */\n\tregion: AwsRegion;\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile?: string;\n}\n\n/**\n * Custom state provider config.\n */\nexport interface CustomStateConfig {\n\t/** Custom StateProvider implementation */\n\tprovider: StateProvider;\n}\n\n/**\n * State configuration types.\n */\nexport type StateConfig = LocalStateConfig | SSMStateConfig | CustomStateConfig;\n\n/**\n * Check if value is a StateProvider implementation.\n */\nexport function isStateProvider(value: unknown): value is StateProvider {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as StateProvider).read === 'function' &&\n\t\ttypeof (value as StateProvider).write === 'function'\n\t);\n}\n\nexport interface CreateStateProviderOptions {\n\t/** State config from workspace */\n\tconfig?: StateConfig;\n\t/** Workspace root directory (for local provider) */\n\tworkspaceRoot: string;\n\t/** Workspace name (for SSM parameter path) */\n\tworkspaceName: string;\n}\n\n/**\n * Create a state provider based on configuration.\n *\n * - 'local': LocalStateProvider (default)\n * - 'ssm': CachedStateProvider with SSM as source of truth\n * - Custom: Use provided StateProvider implementation\n */\nexport async function createStateProvider(\n\toptions: CreateStateProviderOptions,\n): Promise<StateProvider> {\n\tconst { config, workspaceRoot, workspaceName } = options;\n\n\t// Default to local provider if no config\n\tif (!config) {\n\t\tconst { LocalStateProvider } = await import('./LocalStateProvider');\n\t\treturn new LocalStateProvider(workspaceRoot);\n\t}\n\n\t// Custom provider implementation\n\tif (isStateProvider(config.provider)) {\n\t\treturn config.provider;\n\t}\n\n\t// Built-in providers (discriminated by provider string)\n\tconst provider = config.provider;\n\n\tif (provider === 'local') {\n\t\tconst { LocalStateProvider } = await import('./LocalStateProvider');\n\t\treturn new LocalStateProvider(workspaceRoot);\n\t}\n\n\tif (provider === 'ssm') {\n\t\tif (!workspaceName) {\n\t\t\tthrow new Error(\n\t\t\t\t'Workspace name is required for SSM state provider. Set \"name\" in gkm.config.ts.',\n\t\t\t);\n\t\t}\n\n\t\tconst { LocalStateProvider } = await import('./LocalStateProvider');\n\t\tconst { SSMStateProvider } = await import('./SSMStateProvider');\n\t\tconst { CachedStateProvider } = await import('./CachedStateProvider');\n\n\t\tconst ssmConfig = config as SSMStateConfig;\n\t\tconst local = new LocalStateProvider(workspaceRoot);\n\t\tconst ssm = SSMStateProvider.create({\n\t\t\tworkspaceName,\n\t\t\tregion: ssmConfig.region,\n\t\t\tprofile: ssmConfig.profile,\n\t\t});\n\n\t\treturn new CachedStateProvider(ssm, local);\n\t}\n\n\t// Should never reach here - custom providers handled above\n\tthrow new Error(`Unknown state provider: ${JSON.stringify(config)}`);\n}\n","import { encryptSecrets } from '../secrets/encryption.js';\nimport { toEmbeddableSecrets } from '../secrets/storage.js';\nimport type {\n\tEmbeddableSecrets,\n\tEncryptedPayload,\n\tStageSecrets,\n} from '../secrets/types.js';\nimport type { SniffedEnvironment } from './sniffer.js';\n\n/**\n * Result of filtering secrets for an app.\n */\nexport interface FilteredAppSecrets {\n\tappName: string;\n\t/** Secrets filtered to only include what the app needs */\n\tsecrets: EmbeddableSecrets;\n\t/** List of required env vars that were found in secrets */\n\tfound: string[];\n\t/** List of required env vars that were NOT found in secrets */\n\tmissing: string[];\n}\n\n/**\n * Filter secrets to only include the env vars that an app requires.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedEnv - The sniffed environment requirements for the app\n * @returns Filtered secrets with found/missing tracking\n */\nexport function filterSecretsForApp(\n\tstageSecrets: StageSecrets,\n\tsniffedEnv: SniffedEnvironment,\n): FilteredAppSecrets {\n\t// Convert stage secrets to flat embeddable format\n\tconst allSecrets = toEmbeddableSecrets(stageSecrets);\n\tconst filtered: EmbeddableSecrets = {};\n\tconst found: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Filter to only required env vars\n\tfor (const key of sniffedEnv.requiredEnvVars) {\n\t\tif (key in allSecrets) {\n\t\t\tfiltered[key] = allSecrets[key]!;\n\t\t\tfound.push(key);\n\t\t} else {\n\t\t\tmissing.push(key);\n\t\t}\n\t}\n\n\treturn {\n\t\tappName: sniffedEnv.appName,\n\t\tsecrets: filtered,\n\t\tfound: found.sort(),\n\t\tmissing: missing.sort(),\n\t};\n}\n\n/**\n * Result of encrypting secrets for an app.\n */\nexport interface EncryptedAppSecrets {\n\tappName: string;\n\t/** Encrypted payload with credentials and IV */\n\tpayload: EncryptedPayload;\n\t/** Master key for runtime decryption (hex encoded) */\n\tmasterKey: string;\n\t/** Number of secrets encrypted */\n\tsecretCount: number;\n\t/** List of required env vars that were NOT found in secrets */\n\tmissingSecrets: string[];\n}\n\n/**\n * Encrypt filtered secrets for an app.\n * Generates an ephemeral master key that should be injected into Dokploy.\n *\n * @param filteredSecrets - The filtered secrets for the app\n * @returns Encrypted payload with master key\n */\nexport function encryptSecretsForApp(\n\tfilteredSecrets: FilteredAppSecrets,\n): EncryptedAppSecrets {\n\tconst payload = encryptSecrets(filteredSecrets.secrets);\n\n\treturn {\n\t\tappName: filteredSecrets.appName,\n\t\tpayload,\n\t\tmasterKey: payload.masterKey,\n\t\tsecretCount: Object.keys(filteredSecrets.secrets).length,\n\t\tmissingSecrets: filteredSecrets.missing,\n\t};\n}\n\n/**\n * Filter and encrypt secrets for an app in one step.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedEnv - The sniffed environment requirements for the app\n * @returns Encrypted secrets with master key\n */\nexport function prepareSecretsForApp(\n\tstageSecrets: StageSecrets,\n\tsniffedEnv: SniffedEnvironment,\n): EncryptedAppSecrets {\n\tconst filtered = filterSecretsForApp(stageSecrets, sniffedEnv);\n\treturn encryptSecretsForApp(filtered);\n}\n\n/**\n * Prepare secrets for multiple apps.\n *\n * @param stageSecrets - All secrets for the stage\n * @param sniffedApps - Map of app name to sniffed environment\n * @returns Map of app name to encrypted secrets\n */\nexport function prepareSecretsForAllApps(\n\tstageSecrets: StageSecrets,\n\tsniffedApps: Map<string, SniffedEnvironment>,\n): Map<string, EncryptedAppSecrets> {\n\tconst results = new Map<string, EncryptedAppSecrets>();\n\n\tfor (const [appName, sniffedEnv] of sniffedApps) {\n\t\t// Only prepare secrets for apps that have required env vars\n\t\tif (sniffedEnv.requiredEnvVars.length > 0) {\n\t\t\tconst encrypted = prepareSecretsForApp(stageSecrets, sniffedEnv);\n\t\t\tresults.set(appName, encrypted);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Report on secrets preparation status for all apps.\n */\nexport interface SecretsReport {\n\t/** Total number of apps processed */\n\ttotalApps: number;\n\t/** Apps with encrypted secrets */\n\tappsWithSecrets: string[];\n\t/** Apps without secrets (frontends or no env requirements) */\n\tappsWithoutSecrets: string[];\n\t/** Apps with missing secrets (warnings) */\n\tappsWithMissingSecrets: Array<{\n\t\tappName: string;\n\t\tmissing: string[];\n\t}>;\n}\n\n/**\n * Generate a report on secrets preparation.\n */\nexport function generateSecretsReport(\n\tencryptedApps: Map<string, EncryptedAppSecrets>,\n\tsniffedApps: Map<string, SniffedEnvironment>,\n): SecretsReport {\n\tconst appsWithSecrets: string[] = [];\n\tconst appsWithoutSecrets: string[] = [];\n\tconst appsWithMissingSecrets: Array<{ appName: string; missing: string[] }> =\n\t\t[];\n\n\tfor (const [appName, sniffedEnv] of sniffedApps) {\n\t\tif (sniffedEnv.requiredEnvVars.length === 0) {\n\t\t\tappsWithoutSecrets.push(appName);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst encrypted = encryptedApps.get(appName);\n\t\tif (encrypted) {\n\t\t\tappsWithSecrets.push(appName);\n\n\t\t\tif (encrypted.missingSecrets.length > 0) {\n\t\t\t\tappsWithMissingSecrets.push({\n\t\t\t\t\tappName,\n\t\t\t\t\tmissing: encrypted.missingSecrets,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttotalApps: sniffedApps.size,\n\t\tappsWithSecrets: appsWithSecrets.sort(),\n\t\tappsWithoutSecrets: appsWithoutSecrets.sort(),\n\t\tappsWithMissingSecrets,\n\t};\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport type { SniffResult } from '@geekmidas/envkit/sniffer';\nimport { normalizeRoutes } from '../workspace/client-generator.js';\nimport { getPublicEnvPrefix } from '../workspace/publicEnv.js';\nimport type { NormalizedAppConfig } from '../workspace/types.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Resolve the tsx package path from the CLI package's dependencies.\n * This ensures tsx is available regardless of whether the target project has it installed.\n */\nfunction resolveTsxPath(): string {\n\tconst require = createRequire(import.meta.url);\n\treturn require.resolve('tsx');\n}\n\n/**\n * Resolve the path to a sniffer helper file.\n * Handles both dev (.ts with tsx) and production (.mjs from dist).\n *\n * In production: sniffer.ts is bundled into dist/index.mjs, but sniffer helper\n * files are output to dist/deploy/ as standalone modules for subprocess loading.\n *\n * In development: All files are in src/deploy/ and loaded via tsx.\n */\nfunction resolveSnifferFile(baseName: string): string {\n\t// Try deploy/ subdirectory first (production: bundled code is at dist/index.mjs,\n\t// but sniffer files are at dist/deploy/)\n\tconst deployMjsPath = resolve(__dirname, 'deploy', `${baseName}.mjs`);\n\tif (existsSync(deployMjsPath)) {\n\t\treturn deployMjsPath;\n\t}\n\n\t// Try same directory .mjs (production: if running from dist/deploy/ directly)\n\tconst mjsPath = resolve(__dirname, `${baseName}.mjs`);\n\tif (existsSync(mjsPath)) {\n\t\treturn mjsPath;\n\t}\n\n\t// Try same directory .ts (development with tsx: all files in src/deploy/)\n\tconst tsPath = resolve(__dirname, `${baseName}.ts`);\n\tif (existsSync(tsPath)) {\n\t\treturn tsPath;\n\t}\n\n\t// Fallback to .ts (will error if neither exists)\n\treturn tsPath;\n}\n\n// Re-export SniffResult for consumers\nexport type { SniffResult } from '@geekmidas/envkit/sniffer';\n\n/**\n * Result of sniffing an app's environment requirements.\n */\nexport interface SniffedEnvironment {\n\tappName: string;\n\t/**\n\t * All required environment variable names.\n\t * When `SniffAppOptions.markOptional` is true, optional variables are\n\t * suffixed with `?` (e.g. `PORT?`).\n\t */\n\trequiredEnvVars: string[];\n\t/**\n\t * Subset of variables that are optional (accessed via `.optional()` or\n\t * `.default()`). Always populated regardless of `markOptional`.\n\t */\n\toptionalEnvVars: string[];\n}\n\n/**\n * Options for sniffing an app's environment.\n */\nexport interface SniffAppOptions {\n\t/** Whether to log warnings for errors encountered during sniffing. Defaults to true. */\n\tlogWarnings?: boolean;\n\t/**\n\t * When true, optional variables (those with `.optional()` or `.default()`)\n\t * are suffixed with `?` in `requiredEnvVars` (e.g. `PORT?`).\n\t * Defaults to false.\n\t */\n\tmarkOptional?: boolean;\n}\n\n/**\n * Get required environment variables for an app.\n *\n * Detection strategy (in order):\n * 1. Frontend apps: Returns empty (no server secrets)\n * 2. Apps with `requiredEnv`: Uses explicit list from config\n * 3. Entry apps: Imports entry file in subprocess to capture config.parse() calls\n * 4. Route-based apps: Loads route files and calls getEnvironment() on each construct\n * 5. Apps with `envParser` (no routes): Runs SnifferEnvironmentParser to detect usage\n * 6. Apps with neither: Returns empty\n *\n * This function handles \"fire and forget\" async operations gracefully,\n * capturing errors and unhandled rejections without failing the build.\n *\n * @param app - The normalized app configuration\n * @param appName - The name of the app\n * @param workspacePath - Absolute path to the workspace root\n * @param options - Optional configuration for sniffing behavior\n * @returns The sniffed environment with required variables\n */\nexport async function sniffAppEnvironment(\n\tapp: NormalizedAppConfig,\n\tappName: string,\n\tworkspacePath: string,\n\toptions: SniffAppOptions = {},\n): Promise<SniffedEnvironment> {\n\tconst { logWarnings = true, markOptional = false } = options;\n\n\t// 1. Frontend apps - handle dependencies and config sniffing\n\tif (app.type === 'web' || app.type === 'mobile') {\n\t\t// Auto-generate {prefix}{DEP}_URL from dependencies, where prefix matches\n\t\t// the framework's public-var convention (NEXT_PUBLIC_, VITE_, ...).\n\t\t// For frameworks without a prefix (e.g. Remix), no dep var is required.\n\t\tconst publicPrefix = getPublicEnvPrefix(app.framework);\n\t\tconst depVars = publicPrefix\n\t\t\t? (app.dependencies ?? []).map(\n\t\t\t\t\t(dep) => `${publicPrefix}${dep.toUpperCase()}_URL`,\n\t\t\t\t)\n\t\t\t: [];\n\n\t\t// If config specified, sniff by importing the file(s)\n\t\t// The file calls .parse() at module load, which triggers sniffer to capture vars\n\t\tif (app.config) {\n\t\t\tconst sniffedVars: string[] = [];\n\t\t\tconst sniffedOptional: string[] = [];\n\n\t\t\t// Collect config paths to sniff\n\t\t\tconst configPaths: string[] = [];\n\t\t\tif (app.config.client) configPaths.push(app.config.client);\n\t\t\tif (app.config.server) configPaths.push(app.config.server);\n\n\t\t\t// Sniff each config file\n\t\t\tfor (const configPath of configPaths) {\n\t\t\t\tconst result = await sniffEntryFile(\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tapp.path,\n\t\t\t\t\tworkspacePath,\n\t\t\t\t);\n\n\t\t\t\tif (logWarnings && result.error) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sniffer] ${appName}: Config file \"${configPath}\" threw error during sniffing (env vars still captured): ${result.error.message}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tsniffedVars.push(...result.envVars);\n\t\t\t\tsniffedOptional.push(...result.optionalEnvVars);\n\t\t\t}\n\n\t\t\tconst optionalEnvVars = [...new Set(sniffedOptional)];\n\t\t\t// Combine: dependency vars + sniffed vars (deduplicated)\n\t\t\tconst allVars = applyMarkOptional(\n\t\t\t\t[...new Set([...depVars, ...sniffedVars])],\n\t\t\t\toptionalEnvVars,\n\t\t\t\tmarkOptional,\n\t\t\t);\n\t\t\treturn { appName, requiredEnvVars: allVars, optionalEnvVars };\n\t\t}\n\n\t\treturn { appName, requiredEnvVars: depVars, optionalEnvVars: [] };\n\t}\n\n\t// 2. Entry apps - import entry file in subprocess to trigger config.parse()\n\tif (app.entry) {\n\t\tconst result = await sniffEntryFile(app.entry, app.path, workspacePath);\n\n\t\tif (logWarnings && result.error) {\n\t\t\tconsole.warn(\n\t\t\t\t`[sniffer] ${appName}: Entry file threw error during sniffing (env vars still captured): ${result.error.message}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tappName,\n\t\t\trequiredEnvVars: applyMarkOptional(\n\t\t\t\tresult.envVars,\n\t\t\t\tresult.optionalEnvVars,\n\t\t\t\tmarkOptional,\n\t\t\t),\n\t\t\toptionalEnvVars: result.optionalEnvVars,\n\t\t};\n\t}\n\n\t// 4. Route-based apps - load routes and call getEnvironment() on each construct\n\tif (app.routes) {\n\t\tconst result = await sniffRouteFiles(\n\t\t\tnormalizeRoutes(app.routes),\n\t\t\tapp.path,\n\t\t\tworkspacePath,\n\t\t);\n\n\t\tif (logWarnings && result.error) {\n\t\t\tconsole.warn(\n\t\t\t\t`[sniffer] ${appName}: Route sniffing threw error (env vars still captured): ${result.error.message}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tappName,\n\t\t\trequiredEnvVars: applyMarkOptional(\n\t\t\t\tresult.envVars,\n\t\t\t\tresult.optionalEnvVars,\n\t\t\t\tmarkOptional,\n\t\t\t),\n\t\t\toptionalEnvVars: result.optionalEnvVars,\n\t\t};\n\t}\n\n\t// 5. Apps with envParser but no routes - run sniffer to detect env var usage\n\tif (app.envParser) {\n\t\tconst result = await sniffEnvParser(app.envParser, app.path, workspacePath);\n\n\t\t// Log any issues for debugging\n\t\tif (logWarnings) {\n\t\t\tif (result.error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[sniffer] ${appName}: envParser threw error during sniffing (env vars still captured): ${result.error.message}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (result.unhandledRejections.length > 0) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[sniffer] ${appName}: Fire-and-forget rejections during sniffing (suppressed): ${result.unhandledRejections.map((e) => e.message).join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tappName,\n\t\t\trequiredEnvVars: applyMarkOptional(\n\t\t\t\tresult.envVars,\n\t\t\t\tresult.optionalEnvVars,\n\t\t\t\tmarkOptional,\n\t\t\t),\n\t\t\toptionalEnvVars: result.optionalEnvVars,\n\t\t};\n\t}\n\n\t// No env detection method available\n\treturn { appName, requiredEnvVars: [], optionalEnvVars: [] };\n}\n\n/**\n * Apply the `?` suffix to optional variables in an env var list.\n * Only modifies the list when `markOptional` is true and there are optional vars.\n */\nfunction applyMarkOptional(\n\tenvVars: string[],\n\toptionalEnvVars: string[],\n\tmarkOptional: boolean,\n): string[] {\n\tif (!markOptional || optionalEnvVars.length === 0) return envVars;\n\tconst optionalSet = new Set(optionalEnvVars);\n\treturn envVars.map((v) => (optionalSet.has(v) ? `${v}?` : v));\n}\n\n/**\n * Result from sniffing an entry file.\n */\ninterface EntrySniffResult {\n\tenvVars: string[];\n\toptionalEnvVars: string[];\n\terror?: Error;\n}\n\n/**\n * Sniff an entry file by importing it in a subprocess.\n *\n * Entry apps call `config.parse()` at module load time. To capture which\n * env vars are accessed, we:\n * 1. Spawn a subprocess with a module loader hook\n * 2. The loader intercepts `@geekmidas/envkit` and replaces EnvironmentParser\n *    with SnifferEnvironmentParser\n * 3. Import the entry file (triggers config.parse())\n * 4. Capture and return the accessed env var names\n *\n * This approach provides process isolation - each app is sniffed in its own\n * subprocess, preventing module cache pollution.\n *\n * @param entryPath - Relative path to the entry file (e.g., './src/index.ts')\n * @param appPath - The app's path relative to workspace (e.g., 'apps/auth')\n * @param workspacePath - Absolute path to workspace root\n * @returns EntrySniffResult with env vars and optional error\n */\nasync function sniffEntryFile(\n\tentryPath: string,\n\tappPath: string,\n\tworkspacePath: string,\n): Promise<EntrySniffResult> {\n\tconst fullEntryPath = resolve(workspacePath, appPath, entryPath);\n\tconst loaderPath = resolveSnifferFile('sniffer-loader');\n\tconst workerPath = resolveSnifferFile('sniffer-worker');\n\n\treturn new Promise((resolvePromise) => {\n\t\tconst child = spawn(\n\t\t\t'node',\n\t\t\t['--import', loaderPath, workerPath, fullEntryPath],\n\t\t\t{\n\t\t\t\tcwd: resolve(workspacePath, appPath),\n\t\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t\t// Ensure tsx is available for TypeScript entry files\n\t\t\t\t\tNODE_OPTIONS: '--import=tsx',\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\n\t\tchild.stdout.on('data', (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tchild.stderr.on('data', (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tchild.on('close', (code) => {\n\t\t\t// Try to parse the JSON output from the worker\n\t\t\ttry {\n\t\t\t\t// Find the last JSON object in stdout (worker may emit other output)\n\t\t\t\tconst jsonMatch = stdout.match(/\\{[^{}]*\"envVars\"[^{}]*\\}[^{]*$/);\n\t\t\t\tif (jsonMatch) {\n\t\t\t\t\tconst result = JSON.parse(jsonMatch[0]);\n\t\t\t\t\tresolvePromise({\n\t\t\t\t\t\tenvVars: result.envVars || [],\n\t\t\t\t\t\toptionalEnvVars: result.optionalEnvVars || [],\n\t\t\t\t\t\terror: result.error ? new Error(result.error) : undefined,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// JSON parse failed\n\t\t\t}\n\n\t\t\t// If we couldn't parse the output, return empty with error info\n\t\t\tresolvePromise({\n\t\t\t\tenvVars: [],\n\t\t\t\toptionalEnvVars: [],\n\t\t\t\terror: new Error(\n\t\t\t\t\t`Failed to sniff entry file (exit code ${code}): ${stderr || stdout || 'No output'}`,\n\t\t\t\t),\n\t\t\t});\n\t\t});\n\n\t\tchild.on('error', (err) => {\n\t\t\tresolvePromise({\n\t\t\t\tenvVars: [],\n\t\t\t\toptionalEnvVars: [],\n\t\t\t\terror: err,\n\t\t\t});\n\t\t});\n\t});\n}\n\n/**\n * Sniff route files by loading constructs and calling getEnvironment().\n *\n * Route-based apps have endpoints, functions, crons, and subscribers that\n * use services. Each service's register() method accesses environment variables.\n *\n * This runs in a subprocess with tsx loader to properly handle TypeScript\n * compilation and path alias resolution (e.g., `src/...` imports).\n *\n * @param routes - Glob pattern(s) for route files\n * @param appPath - The app's path relative to workspace (e.g., 'apps/api')\n * @param workspacePath - Absolute path to workspace root\n * @returns EntrySniffResult with env vars and optional error\n */\nasync function sniffRouteFiles(\n\troutes: string | string[],\n\tappPath: string,\n\tworkspacePath: string,\n): Promise<EntrySniffResult> {\n\tconst fullAppPath = resolve(workspacePath, appPath);\n\tconst workerPath = resolveSnifferFile('sniffer-routes-worker');\n\tconst tsxPath = resolveTsxPath();\n\n\t// Convert array of patterns to first pattern (worker handles glob internally)\n\tconst routesArray = Array.isArray(routes) ? routes : [routes];\n\tconst pattern = routesArray[0];\n\tif (!pattern) {\n\t\treturn {\n\t\t\tenvVars: [],\n\t\t\toptionalEnvVars: [],\n\t\t\terror: new Error('No route patterns provided'),\n\t\t};\n\t}\n\n\treturn new Promise((resolvePromise) => {\n\t\tconst child = spawn(\n\t\t\t'node',\n\t\t\t['--import', tsxPath, workerPath, fullAppPath, pattern],\n\t\t\t{\n\t\t\t\tcwd: fullAppPath,\n\t\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tlet stdout = '';\n\t\tlet stderr = '';\n\n\t\tchild.stdout.on('data', (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tchild.stderr.on('data', (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tchild.on('close', (code) => {\n\t\t\t// Log any stderr output (import errors, etc.)\n\t\t\tif (stderr) {\n\t\t\t\tstderr\n\t\t\t\t\t.split('\\n')\n\t\t\t\t\t.filter((line) => line.trim())\n\t\t\t\t\t.forEach((line) => console.warn(line));\n\t\t\t}\n\n\t\t\t// Try to parse the JSON output from the worker\n\t\t\ttry {\n\t\t\t\t// Find the last JSON object in stdout (worker may emit other output)\n\t\t\t\tconst jsonMatch = stdout.match(/\\{[^{}]*\"envVars\"[^{}]*\\}[^{]*$/);\n\t\t\t\tif (jsonMatch) {\n\t\t\t\t\tconst result = JSON.parse(jsonMatch[0]);\n\t\t\t\t\tresolvePromise({\n\t\t\t\t\t\tenvVars: result.envVars || [],\n\t\t\t\t\t\t// Routes worker uses getEnvironment() which doesn't track\n\t\t\t\t\t\t// optionality yet — populated when service register() is sniffed\n\t\t\t\t\t\toptionalEnvVars: result.optionalEnvVars || [],\n\t\t\t\t\t\terror: result.error ? new Error(result.error) : undefined,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// JSON parse failed\n\t\t\t}\n\n\t\t\t// If we couldn't parse the output, return empty with error info\n\t\t\tresolvePromise({\n\t\t\t\tenvVars: [],\n\t\t\t\toptionalEnvVars: [],\n\t\t\t\terror: new Error(\n\t\t\t\t\t`Failed to sniff route files (exit code ${code}): ${stderr || stdout || 'No output'}`,\n\t\t\t\t),\n\t\t\t});\n\t\t});\n\n\t\tchild.on('error', (err) => {\n\t\t\tresolvePromise({\n\t\t\t\tenvVars: [],\n\t\t\t\toptionalEnvVars: [],\n\t\t\t\terror: err,\n\t\t\t});\n\t\t});\n\t});\n}\n\n/**\n * Run the SnifferEnvironmentParser on an envParser module to detect\n * which environment variables it accesses.\n *\n * This function handles \"fire and forget\" async operations by using\n * the shared sniffWithFireAndForget utility from @geekmidas/envkit.\n *\n * @param envParserPath - The envParser config (e.g., './src/config/env#envParser')\n * @param appPath - The app's path relative to workspace\n * @param workspacePath - Absolute path to workspace root\n * @returns SniffResult with env vars and any errors encountered\n */\nasync function sniffEnvParser(\n\tenvParserPath: string,\n\tappPath: string,\n\tworkspacePath: string,\n): Promise<SniffResult> {\n\t// Parse the envParser path: './src/config/env#envParser' or './src/config/env'\n\tconst [modulePath, exportName = 'default'] = envParserPath.split('#');\n\tif (!modulePath) {\n\t\treturn { envVars: [], optionalEnvVars: [], unhandledRejections: [] };\n\t}\n\n\t// Resolve the full path to the module\n\tconst fullPath = resolve(workspacePath, appPath, modulePath);\n\n\t// Dynamically import the sniffer utilities\n\tlet SnifferEnvironmentParser: any;\n\tlet sniffWithFireAndForget: any;\n\ttry {\n\t\tconst envkitModule = await import('@geekmidas/envkit/sniffer');\n\t\tSnifferEnvironmentParser = envkitModule.SnifferEnvironmentParser;\n\t\tsniffWithFireAndForget = envkitModule.sniffWithFireAndForget;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.warn(\n\t\t\t`[sniffer] Failed to import SnifferEnvironmentParser: ${message}`,\n\t\t);\n\t\treturn { envVars: [], optionalEnvVars: [], unhandledRejections: [] };\n\t}\n\n\tconst sniffer = new SnifferEnvironmentParser();\n\n\treturn sniffWithFireAndForget(sniffer, async () => {\n\t\t// Import the envParser module\n\t\tconst moduleUrl = pathToFileURL(fullPath).href;\n\t\tconst module = await import(moduleUrl);\n\n\t\t// Get the envParser function\n\t\tconst envParser = module[exportName];\n\t\tif (typeof envParser !== 'function') {\n\t\t\tconsole.warn(\n\t\t\t\t`[sniffer] Export \"${exportName}\" from \"${modulePath}\" is not a function`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// The envParser function typically creates and configures an EnvironmentParser.\n\t\t// We pass our sniffer which implements the same interface.\n\t\tconst result = envParser(sniffer);\n\n\t\t// If the result is a ConfigParser, call parse() to trigger env var access\n\t\tif (result && typeof result.parse === 'function') {\n\t\t\ttry {\n\t\t\t\tresult.parse();\n\t\t\t} catch {\n\t\t\t\t// Parsing may fail due to mock values, that's expected\n\t\t\t}\n\t\t}\n\t});\n}\n\n/**\n * Sniff environment requirements for multiple apps.\n *\n * @param apps - Map of app name to app config\n * @param workspacePath - Absolute path to workspace root\n * @param options - Optional configuration for sniffing behavior\n * @returns Map of app name to sniffed environment\n */\nexport async function sniffAllApps(\n\tapps: Record<string, NormalizedAppConfig>,\n\tworkspacePath: string,\n\toptions: SniffAppOptions = {},\n): Promise<Map<string, SniffedEnvironment>> {\n\tconst results = new Map<string, SniffedEnvironment>();\n\n\tfor (const [appName, app] of Object.entries(apps)) {\n\t\tconst sniffed = await sniffAppEnvironment(\n\t\t\tapp,\n\t\t\tappName,\n\t\t\tworkspacePath,\n\t\t\toptions,\n\t\t);\n\t\tresults.set(appName, sniffed);\n\t}\n\n\treturn results;\n}\n\n// Export for testing\nexport {\n\tsniffEnvParser as _sniffEnvParser,\n\tsniffEntryFile as _sniffEntryFile,\n\tsniffRouteFiles as _sniffRouteFiles,\n};\n","/**\n * Deploy Module\n *\n * Handles deployment of GKM workspaces to various providers (Docker, Dokploy).\n *\n * ## Per-App Database Credentials\n *\n * When deploying to Dokploy with Postgres, this module creates per-app database\n * users with isolated schemas. This follows the same pattern as local dev mode\n * (docker/postgres/init.sh).\n *\n * ### How It Works\n *\n * 1. **Provisioning**: Creates Postgres service with master credentials\n * 2. **User Creation**: For each backend app that needs DATABASE_URL:\n *    - Generates a unique password (stored in deploy state)\n *    - Creates a database user with that password\n *    - Assigns schema permissions based on app name\n * 3. **Schema Assignment**:\n *    - `api` app: Uses `public` schema (shared tables)\n *    - Other apps (e.g., `auth`): Get their own schema with `search_path` set\n * 4. **Environment Injection**: Each app receives its own DATABASE_URL\n *\n * ### Security\n *\n * - External Postgres port is enabled only during user creation, then disabled\n * - Each app can only access its own schema\n * - Credentials are stored in `.gkm/deploy-{stage}.json` (gitignored)\n * - Subsequent deploys reuse existing credentials from state\n *\n * ### Example Flow\n *\n * ```\n * gkm deploy --stage production\n *   ├─ Create Postgres (user: postgres, db: myproject)\n *   ├─ Enable external port temporarily\n *   ├─ Create user \"api\" → public schema\n *   ├─ Create user \"auth\" → auth schema (search_path=auth)\n *   ├─ Disable external port\n *   ├─ Deploy \"api\" with DATABASE_URL=postgresql://api:xxx@postgres:5432/myproject\n *   └─ Deploy \"auth\" with DATABASE_URL=postgresql://auth:yyy@postgres:5432/myproject\n * ```\n *\n * @module deploy\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { stdin as input, stdout as output } from 'node:process';\nimport * as readline from 'node:readline/promises';\nimport { Client as PgClient } from 'pg';\nimport {\n\tgetDokployCredentials,\n\tgetDokployRegistryId,\n\tstoreDokployCredentials,\n\tvalidateDokployToken,\n} from '../auth';\nimport { storeDokployRegistryId } from '../auth/credentials';\nimport { buildCommand } from '../build/index';\nimport { type GkmConfig, loadConfig, loadWorkspaceConfig } from '../config';\nimport { readStageSecrets } from '../secrets/storage.js';\nimport {\n\tgetAppBuildOrder,\n\tgetDeployTargetError,\n\tgetPublicEnvPrefix,\n\tisDeployTargetSupported,\n} from '../workspace/index.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { orchestrateDns, verifyDnsRecords } from './dns/index.js';\nimport { deployDocker, resolveDockerConfig } from './docker';\nimport { deployDokploy } from './dokploy';\nimport {\n\tDokployApi,\n\ttype DokployApplication,\n\ttype DokployPostgres,\n\ttype DokployRedis,\n} from './dokploy-api';\nimport { isMainFrontendApp, resolveHost } from './domain.js';\nimport {\n\ttype EnvResolverContext,\n\tformatMissingVarsError,\n\tvalidateEnvVars,\n} from './env-resolver.js';\nimport { updateConfig } from './init';\nimport { createStateProvider } from './StateProvider.js';\nimport { generateSecretsReport, prepareSecretsForAllApps } from './secrets.js';\nimport { sniffAllApps } from './sniffer.js';\nimport {\n\ttype AppDbCredentials,\n\tcreateEmptyState,\n\tgetAllAppCredentials,\n\tgetApplicationId,\n\tgetBackupState,\n\tgetPostgresId,\n\tgetRedisId,\n\tsetAppCredentials,\n\tsetApplicationId,\n\tsetBackupState,\n\tsetPostgresBackupId,\n\tsetPostgresId,\n\tsetRedisId,\n} from './state.js';\nimport type {\n\tAppDeployResult,\n\tDeployOptions,\n\tDeployProvider,\n\tDeployResult,\n\tDockerDeployConfig,\n\tDokployDeployConfig,\n\tWorkspaceDeployResult,\n} from './types';\n\nconst logger = console;\n\n/**\n * Prompt for input\n */\nasync function prompt(message: string, hidden = false): Promise<string> {\n\tif (!process.stdin.isTTY) {\n\t\tthrow new Error('Interactive input required. Please configure manually.');\n\t}\n\n\tif (hidden) {\n\t\tprocess.stdout.write(message);\n\t\treturn new Promise((resolve) => {\n\t\t\tlet value = '';\n\t\t\tconst onData = (char: Buffer) => {\n\t\t\t\tconst c = char.toString();\n\t\t\t\tif (c === '\\n' || c === '\\r') {\n\t\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\t\tprocess.stdin.pause();\n\t\t\t\t\tprocess.stdin.removeListener('data', onData);\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tresolve(value);\n\t\t\t\t} else if (c === '\\u0003') {\n\t\t\t\t\tprocess.stdin.setRawMode(false);\n\t\t\t\t\tprocess.stdin.pause();\n\t\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t} else if (c === '\\u007F' || c === '\\b') {\n\t\t\t\t\tif (value.length > 0) value = value.slice(0, -1);\n\t\t\t\t} else {\n\t\t\t\t\tvalue += c;\n\t\t\t\t}\n\t\t\t};\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t\tprocess.stdin.resume();\n\t\t\tprocess.stdin.on('data', onData);\n\t\t});\n\t}\n\n\tconst rl = readline.createInterface({ input, output });\n\ttry {\n\t\treturn await rl.question(message);\n\t} finally {\n\t\trl.close();\n\t}\n}\n\n/**\n * Docker compose services that can be provisioned\n */\ninterface DockerComposeServices {\n\tpostgres?: boolean;\n\tredis?: boolean;\n\trabbitmq?: boolean;\n}\n\n/**\n * Service URLs including both connection URLs and individual parameters\n */\ninterface ServiceUrls {\n\tDATABASE_URL?: string;\n\tDATABASE_HOST?: string;\n\tDATABASE_PORT?: string;\n\tDATABASE_NAME?: string;\n\tDATABASE_USER?: string;\n\tDATABASE_PASSWORD?: string;\n\tREDIS_URL?: string;\n\tREDIS_HOST?: string;\n\tREDIS_PORT?: string;\n\tREDIS_PASSWORD?: string;\n}\n\n/**\n * Result of Dokploy setup including provisioned service URLs\n */\ninterface DokploySetupResult {\n\tconfig: DokployDeployConfig;\n\tserviceUrls?: ServiceUrls;\n}\n\n/**\n * Result from provisioning services\n */\nexport interface ProvisionServicesResult {\n\tserviceUrls: ServiceUrls;\n\tserviceIds: {\n\t\tpostgresId?: string;\n\t\tredisId?: string;\n\t};\n}\n\n/**\n * Configuration for a database user to create during Dokploy deployment.\n *\n * @property name - The database username (typically matches the app name)\n * @property password - The generated password for this user\n * @property usePublicSchema - If true, user gets access to public schema (for api app).\n *                             If false, user gets their own schema with search_path set.\n */\ninterface DbUserConfig {\n\tname: string;\n\tpassword: string;\n\tusePublicSchema: boolean;\n}\n\n/**\n * Wait for Postgres to be ready to accept connections.\n *\n * Polls the Postgres server until it accepts a connection or max retries reached.\n * Used after enabling the external port to ensure the database is accessible\n * before creating users.\n *\n * @param host - The Postgres server hostname\n * @param port - The external port (typically 5432)\n * @param user - Master database user (postgres)\n * @param password - Master database password\n * @param database - Database name to connect to\n * @param maxRetries - Maximum number of connection attempts (default: 30)\n * @param retryIntervalMs - Milliseconds between retries (default: 2000)\n * @throws Error if Postgres is not ready after maxRetries\n */\nasync function waitForPostgres(\n\thost: string,\n\tport: number,\n\tuser: string,\n\tpassword: string,\n\tdatabase: string,\n\tmaxRetries = 30,\n\tretryIntervalMs = 2000,\n): Promise<void> {\n\tfor (let i = 0; i < maxRetries; i++) {\n\t\ttry {\n\t\t\tconst client = new PgClient({ host, port, user, password, database });\n\t\t\tawait client.connect();\n\t\t\tawait client.end();\n\t\t\treturn;\n\t\t} catch {\n\t\t\tif (i < maxRetries - 1) {\n\t\t\t\tlogger.log(`   Waiting for Postgres... (${i + 1}/${maxRetries})`);\n\t\t\t\tawait new Promise((r) => setTimeout(r, retryIntervalMs));\n\t\t\t}\n\t\t}\n\t}\n\tthrow new Error(`Postgres not ready after ${maxRetries} retries`);\n}\n\n/**\n * Initialize Postgres with per-app users and schemas.\n *\n * This function implements the same user/schema isolation pattern used in local\n * dev mode (see docker/postgres/init.sh). It:\n *\n * 1. Temporarily enables the external Postgres port\n * 2. Connects using master credentials\n * 3. Creates each user with appropriate schema permissions\n * 4. Disables the external port for security\n *\n * Schema assignment follows this pattern:\n * - `api` app: Uses `public` schema (shared tables, migrations run here)\n * - Other apps: Get their own schema with `search_path` configured\n *\n * @param api - The Dokploy API client\n * @param postgres - The provisioned Postgres service details\n * @param serverHostname - The Dokploy server hostname (for external connection)\n * @param users - Array of users to create with their schema configuration\n *\n * @example\n * ```ts\n * await initializePostgresUsers(api, postgres, 'dokploy.example.com', [\n *   { name: 'api', password: 'xxx', usePublicSchema: true },\n *   { name: 'auth', password: 'yyy', usePublicSchema: false },\n * ]);\n * ```\n */\nasync function initializePostgresUsers(\n\tapi: DokployApi,\n\tpostgres: DokployPostgres,\n\tserverHostname: string,\n\tusers: DbUserConfig[],\n): Promise<void> {\n\tlogger.log('\\n🔧 Initializing database users...');\n\n\t// Enable external port temporarily\n\tconst externalPort = 5432;\n\tlogger.log(`   Enabling external port ${externalPort}...`);\n\tawait api.savePostgresExternalPort(postgres.postgresId, externalPort);\n\n\t// Redeploy to apply external port change\n\tawait api.deployPostgres(postgres.postgresId);\n\n\t// Wait for Postgres to be ready with external port\n\tlogger.log(\n\t\t`   Waiting for Postgres to be accessible at ${serverHostname}:${externalPort}...`,\n\t);\n\tawait waitForPostgres(\n\t\tserverHostname,\n\t\texternalPort,\n\t\tpostgres.databaseUser,\n\t\tpostgres.databasePassword,\n\t\tpostgres.databaseName,\n\t);\n\n\t// Connect and create users\n\tconst client = new PgClient({\n\t\thost: serverHostname,\n\t\tport: externalPort,\n\t\tuser: postgres.databaseUser,\n\t\tpassword: postgres.databasePassword,\n\t\tdatabase: postgres.databaseName,\n\t});\n\n\ttry {\n\t\tawait client.connect();\n\n\t\tfor (const user of users) {\n\t\t\tconst schemaName = user.usePublicSchema ? 'public' : user.name;\n\t\t\tlogger.log(\n\t\t\t\t`   Creating user \"${user.name}\" with schema \"${schemaName}\"...`,\n\t\t\t);\n\n\t\t\t// Create or update user with all settings in one DO block\n\t\t\t// This avoids \"tuple already updated by self\" errors from multiple ALTER USER calls\n\t\t\tif (user.usePublicSchema) {\n\t\t\t\t// API uses public schema\n\t\t\t\tawait client.query(`\n\t\t\t\t\tDO $$ BEGIN\n\t\t\t\t\t\tIF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${user.name}') THEN\n\t\t\t\t\t\t\tCREATE USER \"${user.name}\" WITH PASSWORD '${user.password}';\n\t\t\t\t\t\tELSE\n\t\t\t\t\t\t\tALTER USER \"${user.name}\" WITH PASSWORD '${user.password}';\n\t\t\t\t\t\tEND IF;\n\t\t\t\t\tEND $$;\n\t\t\t\t`);\n\t\t\t\tawait client.query(`\n\t\t\t\t\tGRANT ALL ON SCHEMA public TO \"${user.name}\";\n\t\t\t\t\tALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO \"${user.name}\";\n\t\t\t\t\tALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO \"${user.name}\";\n\t\t\t\t`);\n\t\t\t} else {\n\t\t\t\t// Other apps get their own schema - combine user creation and search_path in one block\n\t\t\t\tawait client.query(`\n\t\t\t\t\tDO $$ BEGIN\n\t\t\t\t\t\tIF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${user.name}') THEN\n\t\t\t\t\t\t\tCREATE USER \"${user.name}\" WITH PASSWORD '${user.password}';\n\t\t\t\t\t\tELSE\n\t\t\t\t\t\t\tALTER USER \"${user.name}\" WITH PASSWORD '${user.password}';\n\t\t\t\t\t\tEND IF;\n\t\t\t\t\t\t-- Set search_path in same transaction to avoid tuple conflict\n\t\t\t\t\t\tALTER USER \"${user.name}\" SET search_path TO \"${schemaName}\";\n\t\t\t\t\tEND $$;\n\t\t\t\t`);\n\t\t\t\tawait client.query(`\n\t\t\t\t\tCREATE SCHEMA IF NOT EXISTS \"${schemaName}\" AUTHORIZATION \"${user.name}\";\n\t\t\t\t\tGRANT USAGE ON SCHEMA \"${schemaName}\" TO \"${user.name}\";\n\t\t\t\t\tGRANT ALL ON ALL TABLES IN SCHEMA \"${schemaName}\" TO \"${user.name}\";\n\t\t\t\t\tALTER DEFAULT PRIVILEGES IN SCHEMA \"${schemaName}\" GRANT ALL ON TABLES TO \"${user.name}\";\n\t\t\t\t`);\n\t\t\t}\n\n\t\t\tlogger.log(`   ✓ User \"${user.name}\" configured`);\n\t\t}\n\t} finally {\n\t\tawait client.end();\n\t}\n\n\t// Disable external port for security\n\tlogger.log('   Disabling external port...');\n\tawait api.savePostgresExternalPort(postgres.postgresId, null);\n\tawait api.deployPostgres(postgres.postgresId);\n\n\tlogger.log('   ✓ Database users initialized');\n}\n\n/**\n * Get the server hostname from the Dokploy endpoint URL\n */\nfunction getServerHostname(endpoint: string): string {\n\tconst url = new URL(endpoint);\n\treturn url.hostname;\n}\n\n/**\n * Build per-app DATABASE_URL for internal Docker network communication.\n *\n * The URL uses the Postgres container name (postgresAppName) as the host,\n * which resolves via Docker's internal DNS when apps are in the same network.\n *\n * @param appName - The database username (matches the app name)\n * @param appPassword - The app's database password\n * @param postgresAppName - The Postgres container/service name in Dokploy\n * @param databaseName - The database name (typically the project name)\n * @returns A properly encoded PostgreSQL connection URL\n *\n * @example\n * ```ts\n * const url = buildPerAppDatabaseUrl('api', 'secret123', 'postgres-abc', 'myproject');\n * // Returns: postgresql://api:secret123@postgres-abc:5432/myproject\n * ```\n */\nfunction _buildPerAppDatabaseUrl(\n\tappName: string,\n\tappPassword: string,\n\tpostgresAppName: string,\n\tdatabaseName: string,\n): string {\n\treturn `postgresql://${appName}:${encodeURIComponent(appPassword)}@${postgresAppName}:5432/${databaseName}`;\n}\n\n/**\n * Provision docker compose services in Dokploy\n * @internal Exported for testing\n */\nexport async function provisionServices(\n\tapi: DokployApi,\n\tprojectId: string,\n\tenvironmentId: string | undefined,\n\tprojectName: string,\n\tservices?: DockerComposeServices,\n\texistingServiceIds?: { postgresId?: string; redisId?: string },\n): Promise<ProvisionServicesResult | undefined> {\n\tlogger.log(\n\t\t`\\n🔍 provisionServices called: services=${JSON.stringify(services)}, envId=${environmentId}`,\n\t);\n\tif (!services || !environmentId) {\n\t\tlogger.log('   Skipping: no services or no environmentId');\n\t\treturn undefined;\n\t}\n\n\tconst serviceUrls: ServiceUrls = {};\n\tconst serviceIds: { postgresId?: string; redisId?: string } = {};\n\n\tif (services.postgres) {\n\t\tlogger.log('\\n🐘 Checking PostgreSQL...');\n\t\tconst postgresName = 'db';\n\n\t\ttry {\n\t\t\tlet postgres: DokployPostgres | null = null;\n\t\t\tlet created = false;\n\n\t\t\t// Check if we have an existing ID from state\n\t\t\tif (existingServiceIds?.postgresId) {\n\t\t\t\tlogger.log(`   Using cached ID: ${existingServiceIds.postgresId}`);\n\t\t\t\tpostgres = await api.getPostgres(existingServiceIds.postgresId);\n\t\t\t\tif (postgres) {\n\t\t\t\t\tlogger.log(`   ✓ PostgreSQL found: ${postgres.postgresId}`);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`   ⚠ Cached ID invalid, will create new`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If not found by ID, use findOrCreate\n\t\t\tif (!postgres) {\n\t\t\t\tconst databasePassword = randomBytes(16).toString('hex');\n\t\t\t\t// Use project name as database name (replace hyphens with underscores for PostgreSQL)\n\t\t\t\tconst databaseName = projectName.replace(/-/g, '_');\n\n\t\t\t\tconst result = await api.findOrCreatePostgres(\n\t\t\t\t\tpostgresName,\n\t\t\t\t\tprojectId,\n\t\t\t\t\tenvironmentId,\n\t\t\t\t\t{ databaseName, databasePassword },\n\t\t\t\t);\n\t\t\t\tpostgres = result.postgres;\n\t\t\t\tcreated = result.created;\n\n\t\t\t\tif (created) {\n\t\t\t\t\tlogger.log(`   ✓ Created PostgreSQL: ${postgres.postgresId}`);\n\n\t\t\t\t\t// Deploy the database (only for new instances)\n\t\t\t\t\tawait api.deployPostgres(postgres.postgresId);\n\t\t\t\t\tlogger.log('   ✓ PostgreSQL deployed');\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`   ✓ PostgreSQL already exists: ${postgres.postgresId}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Store the ID for state\n\t\t\tserviceIds.postgresId = postgres.postgresId;\n\n\t\t\t// Store individual connection parameters\n\t\t\tserviceUrls.DATABASE_HOST = postgres.appName;\n\t\t\tserviceUrls.DATABASE_PORT = '5432';\n\t\t\tserviceUrls.DATABASE_NAME = postgres.databaseName;\n\t\t\tserviceUrls.DATABASE_USER = postgres.databaseUser;\n\t\t\tserviceUrls.DATABASE_PASSWORD = postgres.databasePassword;\n\n\t\t\t// Construct connection URL using internal docker network hostname\n\t\t\tserviceUrls.DATABASE_URL = `postgresql://${postgres.databaseUser}:${postgres.databasePassword}@${postgres.appName}:5432/${postgres.databaseName}`;\n\t\t\tlogger.log(`   ✓ Database credentials configured`);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\t\tlogger.log(`   ⚠ Failed to provision PostgreSQL: ${message}`);\n\t\t}\n\t}\n\n\tif (services.redis) {\n\t\tlogger.log('\\n🔴 Checking Redis...');\n\t\tconst redisName = 'cache';\n\n\t\ttry {\n\t\t\tlet redis: DokployRedis | null = null;\n\t\t\tlet created = false;\n\n\t\t\t// Check if we have an existing ID from state\n\t\t\tif (existingServiceIds?.redisId) {\n\t\t\t\tlogger.log(`   Using cached ID: ${existingServiceIds.redisId}`);\n\t\t\t\tredis = await api.getRedis(existingServiceIds.redisId);\n\t\t\t\tif (redis) {\n\t\t\t\t\tlogger.log(`   ✓ Redis found: ${redis.redisId}`);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`   ⚠ Cached ID invalid, will create new`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If not found by ID, use findOrCreate\n\t\t\tif (!redis) {\n\t\t\t\tconst { randomBytes } = await import('node:crypto');\n\t\t\t\tconst databasePassword = randomBytes(16).toString('hex');\n\n\t\t\t\tconst result = await api.findOrCreateRedis(\n\t\t\t\t\tredisName,\n\t\t\t\t\tprojectId,\n\t\t\t\t\tenvironmentId,\n\t\t\t\t\t{ databasePassword },\n\t\t\t\t);\n\t\t\t\tredis = result.redis;\n\t\t\t\tcreated = result.created;\n\n\t\t\t\tif (created) {\n\t\t\t\t\tlogger.log(`   ✓ Created Redis: ${redis.redisId}`);\n\n\t\t\t\t\t// Deploy the redis instance (only for new instances)\n\t\t\t\t\tawait api.deployRedis(redis.redisId);\n\t\t\t\t\tlogger.log('   ✓ Redis deployed');\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(`   ✓ Redis already exists: ${redis.redisId}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Store the ID for state\n\t\t\tserviceIds.redisId = redis.redisId;\n\n\t\t\t// Store individual connection parameters\n\t\t\tserviceUrls.REDIS_HOST = redis.appName;\n\t\t\tserviceUrls.REDIS_PORT = '6379';\n\t\t\tif (redis.databasePassword) {\n\t\t\t\tserviceUrls.REDIS_PASSWORD = redis.databasePassword;\n\t\t\t}\n\n\t\t\t// Construct connection URL\n\t\t\tconst password = redis.databasePassword\n\t\t\t\t? `:${redis.databasePassword}@`\n\t\t\t\t: '';\n\t\t\tserviceUrls.REDIS_URL = `redis://${password}${redis.appName}:6379`;\n\t\t\tlogger.log(`   ✓ Redis credentials configured`);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error';\n\t\t\tlogger.log(`   ⚠ Failed to provision Redis: ${message}`);\n\t\t}\n\t}\n\n\treturn Object.keys(serviceUrls).length > 0\n\t\t? { serviceUrls, serviceIds }\n\t\t: undefined;\n}\n\n/**\n * Ensure Dokploy is fully configured, recovering/creating resources as needed\n */\nasync function ensureDokploySetup(\n\tconfig: GkmConfig,\n\tdockerConfig: DockerDeployConfig,\n\tstage: string,\n\tservices?: DockerComposeServices,\n): Promise<DokploySetupResult> {\n\tlogger.log('\\n🔧 Checking Dokploy setup...');\n\n\t// Step 1: Ensure we have Dokploy credentials\n\tlet creds = await getDokployCredentials();\n\n\tif (!creds) {\n\t\tlogger.log(\"\\n📋 Dokploy credentials not found. Let's set them up.\");\n\t\tconst endpoint = await prompt(\n\t\t\t'Dokploy URL (e.g., https://dokploy.example.com): ',\n\t\t);\n\t\tconst normalizedEndpoint = endpoint.replace(/\\/$/, '');\n\n\t\ttry {\n\t\t\tnew URL(normalizedEndpoint);\n\t\t} catch {\n\t\t\tthrow new Error('Invalid URL format');\n\t\t}\n\n\t\tlogger.log(\n\t\t\t`\\nGenerate a token at: ${normalizedEndpoint}/settings/profile\\n`,\n\t\t);\n\t\tconst token = await prompt('API Token: ', true);\n\n\t\tlogger.log('\\nValidating credentials...');\n\t\tconst isValid = await validateDokployToken(normalizedEndpoint, token);\n\t\tif (!isValid) {\n\t\t\tthrow new Error('Invalid credentials. Please check your token.');\n\t\t}\n\n\t\tawait storeDokployCredentials(token, normalizedEndpoint);\n\t\tcreds = { token, endpoint: normalizedEndpoint };\n\t\tlogger.log('✓ Credentials saved');\n\t}\n\n\tconst api = new DokployApi({ baseUrl: creds.endpoint, token: creds.token });\n\n\t// Step 2: Check if we have config in gkm.config.ts\n\tconst existingConfig = config.providers?.dokploy;\n\tif (\n\t\texistingConfig &&\n\t\ttypeof existingConfig !== 'boolean' &&\n\t\texistingConfig.applicationId &&\n\t\texistingConfig.projectId\n\t) {\n\t\tlogger.log('✓ Dokploy config found in gkm.config.ts');\n\n\t\t// Verify the application still exists\n\t\ttry {\n\t\t\tconst projectDetails = await api.getProject(existingConfig.projectId);\n\t\t\tlogger.log('✓ Project verified');\n\n\t\t\t// Get registry ID from config first, then from local storage\n\t\t\tconst storedRegistryId =\n\t\t\t\texistingConfig.registryId ?? (await getDokployRegistryId());\n\n\t\t\t// Get environment ID for service provisioning (match by stage name)\n\t\t\tconst environments = projectDetails.environments ?? [];\n\t\t\tlet environment = environments.find(\n\t\t\t\t(e) => e.name.toLowerCase() === stage.toLowerCase(),\n\t\t\t);\n\n\t\t\t// Create environment if it doesn't exist for this stage\n\t\t\tif (!environment) {\n\t\t\t\tlogger.log(`   Creating \"${stage}\" environment...`);\n\t\t\t\tenvironment = await api.createEnvironment(\n\t\t\t\t\texistingConfig.projectId,\n\t\t\t\t\tstage,\n\t\t\t\t);\n\t\t\t\tlogger.log(`   ✓ Created environment: ${environment.environmentId}`);\n\t\t\t}\n\n\t\t\tconst environmentId = environment.environmentId;\n\n\t\t\t// Provision services if configured\n\t\t\tlogger.log(\n\t\t\t\t`   Services config: ${JSON.stringify(services)}, envId: ${environmentId}`,\n\t\t\t);\n\t\t\t// For single-app mode, we don't have state persistence yet, so pass undefined\n\t\t\tconst provisionResult = await provisionServices(\n\t\t\t\tapi,\n\t\t\t\texistingConfig.projectId,\n\t\t\t\tenvironmentId,\n\t\t\t\tdockerConfig.appName!,\n\t\t\t\tservices,\n\t\t\t\tundefined, // No state in single-app mode\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tconfig: {\n\t\t\t\t\tendpoint: existingConfig.endpoint,\n\t\t\t\t\tprojectId: existingConfig.projectId,\n\t\t\t\t\tapplicationId: existingConfig.applicationId,\n\t\t\t\t\tregistry: existingConfig.registry,\n\t\t\t\t\tregistryId: storedRegistryId ?? undefined,\n\t\t\t\t},\n\t\t\t\tserviceUrls: provisionResult?.serviceUrls,\n\t\t\t};\n\t\t} catch {\n\t\t\tlogger.log('⚠ Project not found, will recover...');\n\t\t}\n\t}\n\n\t// Step 3: Find or create project\n\tlogger.log('\\n📁 Looking for project...');\n\tconst projectName = dockerConfig.projectName!;\n\tconst projects = await api.listProjects();\n\tlet project = projects.find(\n\t\t(p) => p.name.toLowerCase() === projectName.toLowerCase(),\n\t);\n\n\tlet environmentId: string;\n\n\tif (project) {\n\t\tlogger.log(\n\t\t\t`   Found existing project: ${project.name} (${project.projectId})`,\n\t\t);\n\n\t\t// Step 4: Get or create environment for existing project (match by stage)\n\t\tconst projectDetails = await api.getProject(project.projectId);\n\t\tconst environments = projectDetails.environments ?? [];\n\t\tconst matchingEnv = environments.find(\n\t\t\t(e) => e.name.toLowerCase() === stage.toLowerCase(),\n\t\t);\n\t\tif (matchingEnv) {\n\t\t\tenvironmentId = matchingEnv.environmentId;\n\t\t\tlogger.log(`   Using environment: ${matchingEnv.name}`);\n\t\t} else {\n\t\t\tlogger.log(`   Creating \"${stage}\" environment...`);\n\t\t\tconst env = await api.createEnvironment(project.projectId, stage);\n\t\t\tenvironmentId = env.environmentId;\n\t\t\tlogger.log(`   ✓ Created environment: ${stage}`);\n\t\t}\n\t} else {\n\t\tlogger.log(`   Creating project: ${projectName}`);\n\t\tconst result = await api.createProject(projectName);\n\t\tproject = result.project;\n\t\t// Rename the default environment to match stage if different\n\t\tif (result.environment.name.toLowerCase() !== stage.toLowerCase()) {\n\t\t\tlogger.log(`   Creating \"${stage}\" environment...`);\n\t\t\tconst env = await api.createEnvironment(project.projectId, stage);\n\t\t\tenvironmentId = env.environmentId;\n\t\t} else {\n\t\t\tenvironmentId = result.environment.environmentId;\n\t\t}\n\t\tlogger.log(`   ✓ Created project: ${project.projectId}`);\n\t\tlogger.log(`   ✓ Using environment: ${stage}`);\n\t}\n\n\t// Step 5: Find or create application\n\tlogger.log('\\n📦 Looking for application...');\n\tconst appName = dockerConfig.appName!;\n\n\tlet applicationId: string;\n\n\t// Try to find existing app from config\n\tif (\n\t\texistingConfig &&\n\t\ttypeof existingConfig !== 'boolean' &&\n\t\texistingConfig.applicationId\n\t) {\n\t\tapplicationId = existingConfig.applicationId;\n\t\tlogger.log(`   Using application from config: ${applicationId}`);\n\t} else {\n\t\t// Create new application\n\t\tlogger.log(`   Creating application: ${appName}`);\n\t\tconst app = await api.createApplication(\n\t\t\tappName,\n\t\t\tproject.projectId,\n\t\t\tenvironmentId,\n\t\t);\n\t\tapplicationId = app.applicationId;\n\t\tlogger.log(`   ✓ Created application: ${applicationId}`);\n\t}\n\n\t// Step 6: Ensure registry is set up\n\tlogger.log('\\n🐳 Checking registry...');\n\tlet registryId = await getDokployRegistryId();\n\n\tif (registryId) {\n\t\t// Verify stored registry still exists\n\t\ttry {\n\t\t\tconst registry = await api.getRegistry(registryId);\n\t\t\tlogger.log(`   Using registry: ${registry.registryName}`);\n\t\t} catch {\n\t\t\tlogger.log('   ⚠ Stored registry not found, clearing...');\n\t\t\tregistryId = undefined;\n\t\t\tawait storeDokployRegistryId('');\n\t\t}\n\t}\n\n\tif (!registryId) {\n\t\tconst registries = await api.listRegistries();\n\n\t\tif (registries.length === 0) {\n\t\t\t// No registries exist\n\t\t\tif (dockerConfig.registry) {\n\t\t\t\tlogger.log(\"   No registries found in Dokploy. Let's create one.\");\n\t\t\t\tlogger.log(`   Registry URL: ${dockerConfig.registry}`);\n\n\t\t\t\tconst username = await prompt('Registry username: ');\n\t\t\t\tconst password = await prompt('Registry password/token: ', true);\n\n\t\t\t\tconst registry = await api.createRegistry(\n\t\t\t\t\t'Default Registry',\n\t\t\t\t\tdockerConfig.registry,\n\t\t\t\t\tusername,\n\t\t\t\t\tpassword,\n\t\t\t\t);\n\t\t\t\tregistryId = registry.registryId;\n\t\t\t\tawait storeDokployRegistryId(registryId);\n\t\t\t\tlogger.log(`   ✓ Registry created: ${registryId}`);\n\t\t\t} else {\n\t\t\t\tlogger.log(\n\t\t\t\t\t'   ⚠ No registry configured. Set docker.registry in gkm.config.ts',\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\t// Show available registries and let user select or create new\n\t\t\tlogger.log('   Available registries:');\n\t\t\tregistries.forEach((reg, i) => {\n\t\t\t\tlogger.log(`     ${i + 1}. ${reg.registryName} (${reg.registryUrl})`);\n\t\t\t});\n\t\t\tif (dockerConfig.registry) {\n\t\t\t\tlogger.log(`     ${registries.length + 1}. Create new registry`);\n\t\t\t}\n\n\t\t\tconst maxOption = dockerConfig.registry\n\t\t\t\t? registries.length + 1\n\t\t\t\t: registries.length;\n\t\t\tconst selection = await prompt(`   Select registry (1-${maxOption}): `);\n\t\t\tconst index = parseInt(selection, 10) - 1;\n\n\t\t\tif (index >= 0 && index < registries.length) {\n\t\t\t\t// Selected existing registry\n\t\t\t\tregistryId = registries[index]!.registryId;\n\t\t\t\tawait storeDokployRegistryId(registryId);\n\t\t\t\tlogger.log(`   ✓ Selected: ${registries[index]!.registryName}`);\n\t\t\t} else if (dockerConfig.registry && index === registries.length) {\n\t\t\t\t// Create new registry\n\t\t\t\tlogger.log(`\\n   Creating new registry...`);\n\t\t\t\tlogger.log(`   Registry URL: ${dockerConfig.registry}`);\n\n\t\t\t\tconst username = await prompt('   Registry username: ');\n\t\t\t\tconst password = await prompt('   Registry password/token: ', true);\n\n\t\t\t\tconst registry = await api.createRegistry(\n\t\t\t\t\tdockerConfig.registry.replace(/^https?:\\/\\//, ''),\n\t\t\t\t\tdockerConfig.registry,\n\t\t\t\t\tusername,\n\t\t\t\t\tpassword,\n\t\t\t\t);\n\t\t\t\tregistryId = registry.registryId;\n\t\t\t\tawait storeDokployRegistryId(registryId);\n\t\t\t\tlogger.log(`   ✓ Registry created: ${registryId}`);\n\t\t\t} else {\n\t\t\t\tlogger.log('   ⚠ Invalid selection, skipping registry setup');\n\t\t\t}\n\t\t}\n\t}\n\n\t// Step 7: Build and save config\n\tconst dokployConfig: DokployDeployConfig = {\n\t\tendpoint: creds.endpoint,\n\t\tprojectId: project.projectId,\n\t\tapplicationId,\n\t\tregistryId: registryId ?? undefined,\n\t};\n\n\t// Update gkm.config.ts\n\tawait updateConfig(dokployConfig);\n\n\tlogger.log('\\n✅ Dokploy setup complete!');\n\tlogger.log(`   Project: ${project.projectId}`);\n\tlogger.log(`   Application: ${applicationId}`);\n\tif (registryId) {\n\t\tlogger.log(`   Registry: ${registryId}`);\n\t}\n\n\t// Step 8: Provision docker compose services if configured\n\t// For single-app mode, we don't have state persistence yet, so pass undefined\n\tconst provisionResult = await provisionServices(\n\t\tapi,\n\t\tproject.projectId,\n\t\tenvironmentId,\n\t\tdockerConfig.appName!,\n\t\tservices,\n\t\tundefined, // No state in single-app mode\n\t);\n\n\treturn {\n\t\tconfig: dokployConfig,\n\t\tserviceUrls: provisionResult?.serviceUrls,\n\t};\n}\n\n/**\n * Generate image tag from stage and timestamp\n */\nexport function generateTag(stage: string): string {\n\tconst timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n\treturn `${stage}-${timestamp}`;\n}\n\n/**\n * Deploy all apps in a workspace to Dokploy.\n *\n * Two-phase orchestration:\n * - PHASE 1: Deploy backend apps (with encrypted secrets)\n * - PHASE 2: Deploy frontend apps (with public URLs from backends)\n *\n * Security model:\n * - Backend apps get encrypted secrets embedded at build time\n * - Only GKM_MASTER_KEY is injected as Dokploy env var\n * - Frontend apps get public URLs baked in at build time (no secrets)\n *\n * @internal Exported for testing\n */\nexport async function workspaceDeployCommand(\n\tworkspace: NormalizedWorkspace,\n\toptions: DeployOptions,\n): Promise<WorkspaceDeployResult> {\n\tconst { provider, stage, tag, apps: selectedApps } = options;\n\n\tif (provider !== 'dokploy') {\n\t\tthrow new Error(\n\t\t\t`Workspace deployment only supports Dokploy. Got: ${provider}`,\n\t\t);\n\t}\n\n\tlogger.log(`\\n🚀 Deploying workspace \"${workspace.name}\" to Dokploy...`);\n\tlogger.log(`   Stage: ${stage}`);\n\n\t// Generate tag if not provided\n\tconst imageTag = tag ?? generateTag(stage);\n\tlogger.log(`   Tag: ${imageTag}`);\n\n\t// Get apps to deploy in dependency order\n\tconst buildOrder = getAppBuildOrder(workspace);\n\n\t// Filter to selected apps if specified\n\tlet appsToDeployNames = buildOrder;\n\tif (selectedApps && selectedApps.length > 0) {\n\t\t// Validate selected apps exist\n\t\tconst invalidApps = selectedApps.filter((name) => !workspace.apps[name]);\n\t\tif (invalidApps.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown apps: ${invalidApps.join(', ')}\\n` +\n\t\t\t\t\t`Available apps: ${Object.keys(workspace.apps).join(', ')}`,\n\t\t\t);\n\t\t}\n\t\t// Keep only selected apps, but maintain dependency order\n\t\tappsToDeployNames = buildOrder.filter((name) =>\n\t\t\tselectedApps.includes(name),\n\t\t);\n\t\tlogger.log(`   Deploying apps: ${appsToDeployNames.join(', ')}`);\n\t} else {\n\t\tlogger.log(`   Deploying all apps: ${appsToDeployNames.join(', ')}`);\n\t}\n\n\t// Filter apps by deploy target\n\tconst dokployApps = appsToDeployNames.filter((name) => {\n\t\tconst app = workspace.apps[name]!;\n\t\tconst target = app.resolvedDeployTarget;\n\t\tif (!isDeployTargetSupported(target)) {\n\t\t\tlogger.log(\n\t\t\t\t`   ⚠️  Skipping ${name}: ${getDeployTargetError(target, name)}`,\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\tif (dokployApps.length === 0) {\n\t\tthrow new Error(\n\t\t\t'No apps to deploy. All selected apps have unsupported deploy targets.',\n\t\t);\n\t}\n\n\tappsToDeployNames = dokployApps;\n\n\t// ==================================================================\n\t// PREFLIGHT: Load secrets and sniff environment requirements\n\t// ==================================================================\n\tlogger.log('\\n🔐 Loading secrets and analyzing environment requirements...');\n\n\t// Load secrets for this stage\n\tconst stageSecrets = await readStageSecrets(stage, workspace.root);\n\tif (!stageSecrets) {\n\t\tlogger.log(`   ⚠️  No secrets found for stage \"${stage}\"`);\n\t\tlogger.log(\n\t\t\t`      Run \"gkm secrets:init --stage ${stage}\" to create secrets`,\n\t\t);\n\t}\n\n\t// Sniff environment variables for all apps\n\tconst sniffedApps = await sniffAllApps(workspace.apps, workspace.root);\n\n\t// Prepare encrypted secrets for backend apps\n\tconst encryptedSecrets = stageSecrets\n\t\t? prepareSecretsForAllApps(stageSecrets, sniffedApps)\n\t\t: new Map();\n\n\t// Report on secrets preparation\n\tif (stageSecrets) {\n\t\tconst report = generateSecretsReport(encryptedSecrets, sniffedApps);\n\t\tif (report.appsWithSecrets.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t`   ✓ Encrypted secrets for: ${report.appsWithSecrets.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tif (report.appsWithMissingSecrets.length > 0) {\n\t\t\tfor (const { appName, missing } of report.appsWithMissingSecrets) {\n\t\t\t\tlogger.log(`   ⚠️  ${appName}: Missing secrets: ${missing.join(', ')}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// SETUP: Credentials, Project, Registry\n\t// ==================================================================\n\tlet creds = await getDokployCredentials();\n\tif (!creds) {\n\t\tlogger.log(\"\\n📋 Dokploy credentials not found. Let's set them up.\");\n\t\tconst endpoint = await prompt(\n\t\t\t'Dokploy URL (e.g., https://dokploy.example.com): ',\n\t\t);\n\t\tconst normalizedEndpoint = endpoint.replace(/\\/$/, '');\n\n\t\ttry {\n\t\t\tnew URL(normalizedEndpoint);\n\t\t} catch {\n\t\t\tthrow new Error('Invalid URL format');\n\t\t}\n\n\t\tlogger.log(\n\t\t\t`\\nGenerate a token at: ${normalizedEndpoint}/settings/profile\\n`,\n\t\t);\n\t\tconst token = await prompt('API Token: ', true);\n\n\t\tlogger.log('\\nValidating credentials...');\n\t\tconst isValid = await validateDokployToken(normalizedEndpoint, token);\n\t\tif (!isValid) {\n\t\t\tthrow new Error('Invalid credentials. Please check your token.');\n\t\t}\n\n\t\tawait storeDokployCredentials(token, normalizedEndpoint);\n\t\tcreds = { token, endpoint: normalizedEndpoint };\n\t\tlogger.log('✓ Credentials saved');\n\t}\n\n\tconst api = new DokployApi({ baseUrl: creds.endpoint, token: creds.token });\n\n\t// Find or create project for the workspace\n\tlogger.log('\\n📁 Setting up Dokploy project...');\n\tconst projectName = workspace.name;\n\tconst projects = await api.listProjects();\n\tlet project = projects.find(\n\t\t(p) => p.name.toLowerCase() === projectName.toLowerCase(),\n\t);\n\n\tlet environmentId: string;\n\n\tif (project) {\n\t\tlogger.log(`   Found existing project: ${project.name}`);\n\t\tconst projectDetails = await api.getProject(project.projectId);\n\t\tconst environments = projectDetails.environments ?? [];\n\t\tconst matchingEnv = environments.find(\n\t\t\t(e) => e.name.toLowerCase() === stage.toLowerCase(),\n\t\t);\n\t\tif (matchingEnv) {\n\t\t\tenvironmentId = matchingEnv.environmentId;\n\t\t\tlogger.log(`   Using environment: ${matchingEnv.name}`);\n\t\t} else {\n\t\t\tlogger.log(`   Creating \"${stage}\" environment...`);\n\t\t\tconst env = await api.createEnvironment(project.projectId, stage);\n\t\t\tenvironmentId = env.environmentId;\n\t\t\tlogger.log(`   ✓ Created environment: ${stage}`);\n\t\t}\n\t} else {\n\t\tlogger.log(`   Creating project: ${projectName}`);\n\t\tconst result = await api.createProject(projectName);\n\t\tproject = result.project;\n\t\tif (result.environment.name.toLowerCase() !== stage.toLowerCase()) {\n\t\t\tlogger.log(`   Creating \"${stage}\" environment...`);\n\t\t\tconst env = await api.createEnvironment(project.projectId, stage);\n\t\t\tenvironmentId = env.environmentId;\n\t\t} else {\n\t\t\tenvironmentId = result.environment.environmentId;\n\t\t}\n\t\tlogger.log(`   ✓ Created project: ${project.projectId}`);\n\t}\n\n\t// ==================================================================\n\t// STATE: Create state provider and load deploy state\n\t// ==================================================================\n\tlogger.log('\\n📋 Loading deploy state...');\n\n\t// Create state provider based on workspace config\n\tconst stateProvider = await createStateProvider({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tlet state = await stateProvider.read(stage);\n\n\tif (state) {\n\t\tlogger.log(`   Found existing state for stage \"${stage}\"`);\n\t\t// Verify project ID matches (in case of recreation)\n\t\tif (state.projectId !== project.projectId) {\n\t\t\tlogger.log(`   ⚠ Project ID changed, updating state`);\n\t\t\tstate.projectId = project.projectId;\n\t\t}\n\t\t// Verify environment ID matches (in case of recreation)\n\t\tif (state.environmentId !== environmentId) {\n\t\t\tlogger.log(`   ⚠ Environment ID changed, updating state`);\n\t\t\tstate.environmentId = environmentId;\n\t\t}\n\t} else {\n\t\tlogger.log(`   Creating new state for stage \"${stage}\"`);\n\t\tstate = createEmptyState(stage, project.projectId, environmentId);\n\t}\n\n\t// Get or set up registry\n\tlogger.log('\\n🐳 Checking registry...');\n\tlet registryId = await getDokployRegistryId();\n\tconst registry = workspace.deploy.dokploy?.registry;\n\n\tif (registryId) {\n\t\ttry {\n\t\t\tconst reg = await api.getRegistry(registryId);\n\t\t\tlogger.log(`   Using registry: ${reg.registryName}`);\n\t\t} catch {\n\t\t\tlogger.log('   ⚠ Stored registry not found, clearing...');\n\t\t\tregistryId = undefined;\n\t\t\tawait storeDokployRegistryId('');\n\t\t}\n\t}\n\n\tif (!registryId) {\n\t\tconst registries = await api.listRegistries();\n\t\tif (registries.length > 0) {\n\t\t\tregistryId = registries[0]!.registryId;\n\t\t\tawait storeDokployRegistryId(registryId);\n\t\t\tlogger.log(`   Using registry: ${registries[0]!.registryName}`);\n\t\t} else if (registry) {\n\t\t\tlogger.log(\"   No registries found in Dokploy. Let's create one.\");\n\t\t\tlogger.log(`   Registry URL: ${registry}`);\n\n\t\t\tconst username = await prompt('Registry username: ');\n\t\t\tconst password = await prompt('Registry password/token: ', true);\n\n\t\t\tconst reg = await api.createRegistry(\n\t\t\t\t'Default Registry',\n\t\t\t\tregistry,\n\t\t\t\tusername,\n\t\t\t\tpassword,\n\t\t\t);\n\t\t\tregistryId = reg.registryId;\n\t\t\tawait storeDokployRegistryId(registryId);\n\t\t\tlogger.log(`   ✓ Registry created: ${registryId}`);\n\t\t} else {\n\t\t\tlogger.log(\n\t\t\t\t'   ⚠ No registry configured. Set deploy.dokploy.registry in workspace config',\n\t\t\t);\n\t\t}\n\t}\n\n\t// Provision infrastructure services if configured\n\tconst services = workspace.services;\n\tconst dockerServices = {\n\t\tpostgres: services.db !== undefined && services.db !== false,\n\t\tredis: services.cache !== undefined && services.cache !== false,\n\t};\n\n\t// Track provisioned postgres info for per-app DATABASE_URL\n\tlet provisionedPostgres: DokployPostgres | null = null;\n\tlet provisionedRedis: DokployRedis | null = null;\n\n\tif (dockerServices.postgres || dockerServices.redis) {\n\t\tlogger.log('\\n🔧 Provisioning infrastructure services...');\n\t\t// Pass existing service IDs from state (prefer state over URL sniffing)\n\t\tconst existingServiceIds = {\n\t\t\tpostgresId: getPostgresId(state),\n\t\t\tredisId: getRedisId(state),\n\t\t};\n\n\t\tconst provisionResult = await provisionServices(\n\t\t\tapi,\n\t\t\tproject.projectId,\n\t\t\tenvironmentId,\n\t\t\tworkspace.name,\n\t\t\tdockerServices,\n\t\t\texistingServiceIds,\n\t\t);\n\n\t\t// Update state with returned service IDs\n\t\tif (provisionResult?.serviceIds) {\n\t\t\tif (provisionResult.serviceIds.postgresId) {\n\t\t\t\tsetPostgresId(state, provisionResult.serviceIds.postgresId);\n\t\t\t\t// Fetch full postgres info for later use\n\t\t\t\tprovisionedPostgres = await api.getPostgres(\n\t\t\t\t\tprovisionResult.serviceIds.postgresId,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (provisionResult.serviceIds.redisId) {\n\t\t\t\tsetRedisId(state, provisionResult.serviceIds.redisId);\n\t\t\t\t// Fetch full redis info for later use\n\t\t\t\tprovisionedRedis = await api.getRedis(\n\t\t\t\t\tprovisionResult.serviceIds.redisId,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// Separate apps by type for two-phase deployment\n\t// ==================================================================\n\t// Mobile apps deploy via their own toolchain (e.g. EAS Build for Expo)\n\t// — skip them in the Dokploy deploy phases.\n\tconst skippedMobileApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'mobile',\n\t);\n\tif (skippedMobileApps.length > 0) {\n\t\tlogger.log(\n\t\t\t`\\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(', ')}`,\n\t\t);\n\t}\n\n\tconst backendApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'backend',\n\t);\n\tconst frontendApps = appsToDeployNames.filter(\n\t\t(name) => workspace.apps[name]!.type === 'web',\n\t);\n\n\t// ==================================================================\n\t// Initialize per-app database users if Postgres is provisioned\n\t// ==================================================================\n\tconst perAppDbCredentials = new Map<string, AppDbCredentials>();\n\n\tif (provisionedPostgres && backendApps.length > 0) {\n\t\t// Determine which backend apps need DATABASE_URL\n\t\tconst appsNeedingDb = backendApps.filter((appName) => {\n\t\t\tconst requirements = sniffedApps.get(appName);\n\t\t\treturn requirements?.requiredEnvVars.includes('DATABASE_URL');\n\t\t});\n\n\t\tif (appsNeedingDb.length > 0) {\n\t\t\tlogger.log(`\\n🔐 Setting up per-app database credentials...`);\n\t\t\tlogger.log(`   Apps needing DATABASE_URL: ${appsNeedingDb.join(', ')}`);\n\n\t\t\t// Get or generate credentials for each app\n\t\t\tconst existingCredentials = getAllAppCredentials(state);\n\t\t\tconst usersToCreate: DbUserConfig[] = [];\n\n\t\t\tfor (const appName of appsNeedingDb) {\n\t\t\t\tlet credentials = existingCredentials[appName];\n\n\t\t\t\tif (credentials) {\n\t\t\t\t\tlogger.log(`   ${appName}: Using existing credentials from state`);\n\t\t\t\t} else {\n\t\t\t\t\t// Generate new credentials\n\t\t\t\t\tconst password = randomBytes(16).toString('hex');\n\t\t\t\t\tcredentials = { dbUser: appName, dbPassword: password };\n\t\t\t\t\tsetAppCredentials(state, appName, credentials);\n\t\t\t\t\tlogger.log(`   ${appName}: Generated new credentials`);\n\t\t\t\t}\n\n\t\t\t\tperAppDbCredentials.set(appName, credentials);\n\n\t\t\t\t// Always add to users to create (idempotent - will update if exists)\n\t\t\t\tusersToCreate.push({\n\t\t\t\t\tname: appName,\n\t\t\t\t\tpassword: credentials.dbPassword,\n\t\t\t\t\tusePublicSchema: appName === 'api', // API uses public schema, others get their own\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Initialize database users\n\t\t\tconst serverHostname = getServerHostname(creds.endpoint);\n\t\t\tawait initializePostgresUsers(\n\t\t\t\tapi,\n\t\t\t\tprovisionedPostgres,\n\t\t\t\tserverHostname,\n\t\t\t\tusersToCreate,\n\t\t\t);\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// Provision backup destination if configured\n\t// ==================================================================\n\tif (workspace.deploy?.backups && provisionedPostgres) {\n\t\tlogger.log('\\n💾 Provisioning backup destination...');\n\n\t\tconst { provisionBackupDestination } = await import(\n\t\t\t'./backup-provisioner.js'\n\t\t);\n\n\t\tconst backupState = await provisionBackupDestination({\n\t\t\tapi,\n\t\t\tprojectId: project.projectId,\n\t\t\tprojectName: workspace.name,\n\t\t\tstage,\n\t\t\tconfig: workspace.deploy.backups,\n\t\t\texistingState: getBackupState(state),\n\t\t\tlogger,\n\t\t});\n\n\t\t// Save backup state\n\t\tsetBackupState(state, backupState);\n\n\t\t// Create backup schedule for postgres if not already configured\n\t\tif (!backupState.postgresBackupId) {\n\t\t\tconst backupSchedule = workspace.deploy.backups.schedule ?? '0 2 * * *';\n\t\t\tconst backupRetention = workspace.deploy.backups.retention ?? 30;\n\n\t\t\tlogger.log('   Creating postgres backup schedule...');\n\t\t\tconst backup = await api.createPostgresBackup({\n\t\t\t\tschedule: backupSchedule,\n\t\t\t\tprefix: `${stage}/postgres`,\n\t\t\t\tdestinationId: backupState.destinationId,\n\t\t\t\tdatabase: provisionedPostgres.databaseName,\n\t\t\t\tpostgresId: provisionedPostgres.postgresId,\n\t\t\t\tenabled: true,\n\t\t\t\tkeepLatestCount: backupRetention,\n\t\t\t});\n\t\t\tsetPostgresBackupId(state, backup.backupId);\n\t\t\tlogger.log(`   ✓ Postgres backup schedule created (${backupSchedule})`);\n\t\t} else {\n\t\t\tlogger.log('   ✓ Using existing postgres backup schedule');\n\t\t}\n\t}\n\n\t// Track deployed app public URLs for frontend builds\n\tconst publicUrls: Record<string, string> = {};\n\tconst results: AppDeployResult[] = [];\n\tconst dokployConfig = workspace.deploy.dokploy;\n\n\t// Track domain IDs and hostnames for DNS orchestration\n\tconst appHostnames = new Map<string, string>(); // appName -> hostname\n\tconst appDomainIds = new Map<string, string>(); // appName -> domainId\n\n\t// ==================================================================\n\t// PRE-COMPUTE: Frontend URLs for BETTER_AUTH_TRUSTED_ORIGINS\n\t// ==================================================================\n\tconst frontendUrls: string[] = [];\n\tfor (const appName of frontendApps) {\n\t\tconst app = workspace.apps[appName]!;\n\t\tconst isMainFrontend = isMainFrontendApp(appName, app, workspace.apps);\n\t\tconst hostname = resolveHost(\n\t\t\tappName,\n\t\t\tapp,\n\t\t\tstage,\n\t\t\tdokployConfig,\n\t\t\tisMainFrontend,\n\t\t);\n\t\tfrontendUrls.push(`https://${hostname}`);\n\t}\n\n\t// ==================================================================\n\t// PHASE 1: Deploy backend apps (with encrypted secrets)\n\t// ==================================================================\n\tif (backendApps.length > 0) {\n\t\tlogger.log('\\n📦 PHASE 1: Deploying backend applications...');\n\n\t\tfor (const appName of backendApps) {\n\t\t\tconst app = workspace.apps[appName]!;\n\n\t\t\tlogger.log(`\\n   ⚙️  Deploying ${appName}...`);\n\n\t\t\ttry {\n\t\t\t\t// Use simple app name - project already provides namespace\n\t\t\t\tconst dokployAppName = appName;\n\n\t\t\t\t// Check state for cached application ID\n\t\t\t\tlet application: DokployApplication | null = null;\n\t\t\t\tconst cachedAppId = getApplicationId(state, appName);\n\n\t\t\t\tif (cachedAppId) {\n\t\t\t\t\tlogger.log(`      Using cached ID: ${cachedAppId}`);\n\t\t\t\t\tapplication = await api.getApplication(cachedAppId);\n\t\t\t\t\tif (application) {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      ✓ Application found: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.log(`      ⚠ Cached ID invalid, will create new`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If not found by ID, use findOrCreate\n\t\t\t\tif (!application) {\n\t\t\t\t\tconst result = await api.findOrCreateApplication(\n\t\t\t\t\t\tdokployAppName,\n\t\t\t\t\t\tproject.projectId,\n\t\t\t\t\t\tenvironmentId,\n\t\t\t\t\t);\n\t\t\t\t\tapplication = result.application;\n\n\t\t\t\t\tif (result.created) {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      Created application: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      Found existing application: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Store application ID in state\n\t\t\t\tsetApplicationId(state, appName, application.applicationId);\n\n\t\t\t\t// Get encrypted secrets for this app\n\t\t\t\tconst appSecrets = encryptedSecrets.get(appName);\n\t\t\t\tconst buildArgs: string[] = [];\n\n\t\t\t\tif (appSecrets && appSecrets.secretCount > 0) {\n\t\t\t\t\tbuildArgs.push(\n\t\t\t\t\t\t`GKM_ENCRYPTED_CREDENTIALS=${appSecrets.payload.encrypted}`,\n\t\t\t\t\t);\n\t\t\t\t\tbuildArgs.push(`GKM_CREDENTIALS_IV=${appSecrets.payload.iv}`);\n\t\t\t\t\tlogger.log(`      Encrypted ${appSecrets.secretCount} secrets`);\n\t\t\t\t}\n\n\t\t\t\t// Build Docker image with encrypted secrets\n\t\t\t\tconst imageName = `${workspace.name}-${appName}`;\n\t\t\t\tconst imageRef = registry\n\t\t\t\t\t? `${registry}/${imageName}:${imageTag}`\n\t\t\t\t\t: `${imageName}:${imageTag}`;\n\n\t\t\t\tlogger.log(`      Building Docker image: ${imageRef}`);\n\n\t\t\t\tawait deployDocker({\n\t\t\t\t\tstage,\n\t\t\t\t\ttag: imageTag,\n\t\t\t\t\tskipPush: false,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\timageName,\n\t\t\t\t\t\tappName,\n\t\t\t\t\t},\n\t\t\t\t\tbuildArgs,\n\t\t\t\t});\n\n\t\t\t\t// Compute hostname first (needed for BETTER_AUTH_URL)\n\t\t\t\tconst backendHost = resolveHost(\n\t\t\t\t\tappName,\n\t\t\t\t\tapp,\n\t\t\t\t\tstage,\n\t\t\t\t\tdokployConfig,\n\t\t\t\t\tfalse, // Backend apps are not main frontend\n\t\t\t\t);\n\n\t\t\t\t// Build dependency URLs from already-deployed apps\n\t\t\t\tconst dependencyUrls: Record<string, string> = {};\n\t\t\t\tif (app.dependencies) {\n\t\t\t\t\tfor (const dep of app.dependencies) {\n\t\t\t\t\t\tif (publicUrls[dep]) {\n\t\t\t\t\t\t\tdependencyUrls[dep] = publicUrls[dep];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Build env resolver context\n\t\t\t\tconst envContext: EnvResolverContext = {\n\t\t\t\t\tapp,\n\t\t\t\t\tappName,\n\t\t\t\t\tstage,\n\t\t\t\t\tstate,\n\t\t\t\t\tappCredentials: perAppDbCredentials.get(appName),\n\t\t\t\t\tpostgres: provisionedPostgres\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\thost: provisionedPostgres.appName,\n\t\t\t\t\t\t\t\tport: 5432,\n\t\t\t\t\t\t\t\tdatabase: provisionedPostgres.databaseName,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tredis: provisionedRedis\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\thost: provisionedRedis.appName,\n\t\t\t\t\t\t\t\tport: 6379,\n\t\t\t\t\t\t\t\tpassword: provisionedRedis.databasePassword,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tappHostname: backendHost,\n\t\t\t\t\tfrontendUrls,\n\t\t\t\t\tuserSecrets: stageSecrets ?? undefined,\n\t\t\t\t\tmasterKey: appSecrets?.masterKey,\n\t\t\t\t\tdependencyUrls,\n\t\t\t\t};\n\n\t\t\t\t// Resolve all required environment variables\n\t\t\t\t// Always include PORT, NODE_ENV, STAGE even if not explicitly required\n\t\t\t\tconst appRequirements = sniffedApps.get(appName);\n\t\t\t\tconst sniffedVars = appRequirements?.requiredEnvVars ?? [];\n\t\t\t\tconst requiredVars = [\n\t\t\t\t\t...new Set(['PORT', 'NODE_ENV', 'STAGE', ...sniffedVars]),\n\t\t\t\t];\n\t\t\t\tconst { valid, missing, resolved } = validateEnvVars(\n\t\t\t\t\trequiredVars,\n\t\t\t\t\tenvContext,\n\t\t\t\t);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tthrow new Error(formatMissingVarsError(appName, missing, stage));\n\t\t\t\t}\n\n\t\t\t\t// Build env vars string for Dokploy\n\t\t\t\tconst envVars: string[] = Object.entries(resolved).map(\n\t\t\t\t\t([key, value]) => `${key}=${value}`,\n\t\t\t\t);\n\n\t\t\t\tif (Object.keys(resolved).length > 0) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t`      Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(', ')}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Configure and deploy application in Dokploy\n\t\t\t\tawait api.saveDockerProvider(application.applicationId, imageRef, {\n\t\t\t\t\tregistryId,\n\t\t\t\t});\n\n\t\t\t\tawait api.saveApplicationEnv(\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t\tenvVars.join('\\n'),\n\t\t\t\t);\n\n\t\t\t\tlogger.log(`      Deploying to Dokploy...`);\n\t\t\t\tawait api.deployApplication(application.applicationId);\n\n\t\t\t\t// Check if domain already exists (backendHost computed above)\n\t\t\t\tconst existingDomains = await api.getDomainsByApplicationId(\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t);\n\t\t\t\tconst existingDomain = existingDomains.find(\n\t\t\t\t\t(d) => d.host === backendHost,\n\t\t\t\t);\n\n\t\t\t\tif (existingDomain) {\n\t\t\t\t\t// Domain already exists\n\t\t\t\t\tappHostnames.set(appName, backendHost);\n\t\t\t\t\tappDomainIds.set(appName, existingDomain.domainId);\n\t\t\t\t\tpublicUrls[appName] = `https://${backendHost}`;\n\t\t\t\t\tlogger.log(`      ✓ Domain: https://${backendHost} (existing)`);\n\t\t\t\t} else {\n\t\t\t\t\t// Create new domain\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst domain = await api.createDomain({\n\t\t\t\t\t\t\thost: backendHost,\n\t\t\t\t\t\t\tport: app.port,\n\t\t\t\t\t\t\thttps: true,\n\t\t\t\t\t\t\tcertificateType: 'letsencrypt',\n\t\t\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tappHostnames.set(appName, backendHost);\n\t\t\t\t\t\tappDomainIds.set(appName, domain.domainId);\n\t\t\t\t\t\tpublicUrls[appName] = `https://${backendHost}`;\n\t\t\t\t\t\tlogger.log(`      ✓ Domain: https://${backendHost} (created)`);\n\t\t\t\t\t} catch (domainError) {\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\tdomainError instanceof Error\n\t\t\t\t\t\t\t\t? domainError.message\n\t\t\t\t\t\t\t\t: 'Unknown error';\n\t\t\t\t\t\tlogger.log(`      ⚠ Domain creation failed: ${message}`);\n\t\t\t\t\t\tappHostnames.set(appName, backendHost);\n\t\t\t\t\t\tpublicUrls[appName] = `https://${backendHost}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresults.push({\n\t\t\t\t\tappName,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\timageRef,\n\t\t\t\t});\n\n\t\t\t\tlogger.log(`      ✓ ${appName} deployed successfully`);\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\tlogger.log(`      ✗ Failed to deploy ${appName}: ${message}`);\n\n\t\t\t\tresults.push({\n\t\t\t\t\tappName,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: message,\n\t\t\t\t});\n\n\t\t\t\t// Abort on backend failure to prevent incomplete deployment\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Backend deployment failed for ${appName}. Aborting to prevent partial deployment.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// PHASE 2: Deploy frontend apps (with public URLs from backends)\n\t// ==================================================================\n\tif (frontendApps.length > 0) {\n\t\tlogger.log('\\n🌐 PHASE 2: Deploying frontend applications...');\n\n\t\tfor (const appName of frontendApps) {\n\t\t\tconst app = workspace.apps[appName]!;\n\n\t\t\tlogger.log(`\\n   🌐 Deploying ${appName}...`);\n\n\t\t\ttry {\n\t\t\t\t// Use simple app name - project already provides namespace\n\t\t\t\tconst dokployAppName = appName;\n\n\t\t\t\t// Check state for cached application ID\n\t\t\t\tlet application: DokployApplication | null = null;\n\t\t\t\tconst cachedAppId = getApplicationId(state, appName);\n\n\t\t\t\tif (cachedAppId) {\n\t\t\t\t\tlogger.log(`      Using cached ID: ${cachedAppId}`);\n\t\t\t\t\tapplication = await api.getApplication(cachedAppId);\n\t\t\t\t\tif (application) {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      ✓ Application found: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.log(`      ⚠ Cached ID invalid, will create new`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If not found by ID, use findOrCreate\n\t\t\t\tif (!application) {\n\t\t\t\t\tconst result = await api.findOrCreateApplication(\n\t\t\t\t\t\tdokployAppName,\n\t\t\t\t\t\tproject.projectId,\n\t\t\t\t\t\tenvironmentId,\n\t\t\t\t\t);\n\t\t\t\t\tapplication = result.application;\n\n\t\t\t\t\tif (result.created) {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      Created application: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t`      Found existing application: ${application.applicationId}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Store application ID in state\n\t\t\t\tsetApplicationId(state, appName, application.applicationId);\n\n\t\t\t\t// Build dependency URLs for frontend (same pattern as backend)\n\t\t\t\tconst dependencyUrls: Record<string, string> = {};\n\t\t\t\tif (app.dependencies) {\n\t\t\t\t\tfor (const dep of app.dependencies) {\n\t\t\t\t\t\tif (publicUrls[dep]) {\n\t\t\t\t\t\t\tdependencyUrls[dep] = publicUrls[dep];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Compute hostname for this frontend app\n\t\t\t\tconst isMainFrontend = isMainFrontendApp(appName, app, workspace.apps);\n\t\t\t\tconst frontendHost = resolveHost(\n\t\t\t\t\tappName,\n\t\t\t\t\tapp,\n\t\t\t\t\tstage,\n\t\t\t\t\tdokployConfig,\n\t\t\t\t\tisMainFrontend,\n\t\t\t\t);\n\n\t\t\t\t// Build env context for frontend\n\t\t\t\tconst envContext: EnvResolverContext = {\n\t\t\t\t\tapp,\n\t\t\t\t\tappName,\n\t\t\t\t\tstage,\n\t\t\t\t\tstate,\n\t\t\t\t\tappHostname: frontendHost,\n\t\t\t\t\tfrontendUrls: [],\n\t\t\t\t\tuserSecrets: stageSecrets ?? undefined,\n\t\t\t\t\tdependencyUrls,\n\t\t\t\t};\n\n\t\t\t\t// Resolve all env vars BEFORE Docker build (public-prefixed vars\n\t\t\t\t// must be present at bundler build time so they get inlined).\n\t\t\t\tconst sniffedVars = sniffedApps.get(appName)?.requiredEnvVars ?? [];\n\t\t\t\tconst { valid, missing, resolved } = validateEnvVars(\n\t\t\t\t\tsniffedVars,\n\t\t\t\t\tenvContext,\n\t\t\t\t);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tthrow new Error(formatMissingVarsError(appName, missing, stage));\n\t\t\t\t}\n\n\t\t\t\tif (Object.keys(resolved).length > 0) {\n\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t`      Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(', ')}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Build args: only the framework's public-prefixed vars get baked\n\t\t\t\t// into the bundle. Server-only vars stay as runtime env.\n\t\t\t\tconst publicPrefix = getPublicEnvPrefix(app.framework);\n\t\t\t\tconst buildArgs: string[] = [];\n\t\t\t\tconst publicUrlArgNames: string[] = [];\n\n\t\t\t\tif (publicPrefix) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\t\tif (key.startsWith(publicPrefix)) {\n\t\t\t\t\t\t\tbuildArgs.push(`${key}=${value}`);\n\t\t\t\t\t\t\tpublicUrlArgNames.push(key);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (buildArgs.length > 0) {\n\t\t\t\t\tlogger.log(`      Build args: ${publicUrlArgNames.join(', ')}`);\n\t\t\t\t}\n\n\t\t\t\t// Build Docker image with public-prefixed vars as build args\n\t\t\t\tconst imageName = `${workspace.name}-${appName}`;\n\t\t\t\tconst imageRef = registry\n\t\t\t\t\t? `${registry}/${imageName}:${imageTag}`\n\t\t\t\t\t: `${imageName}:${imageTag}`;\n\n\t\t\t\tlogger.log(`      Building Docker image: ${imageRef}`);\n\n\t\t\t\tawait deployDocker({\n\t\t\t\t\tstage,\n\t\t\t\t\ttag: imageTag,\n\t\t\t\t\tskipPush: false,\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\timageName,\n\t\t\t\t\t\tappName,\n\t\t\t\t\t},\n\t\t\t\t\tbuildArgs,\n\t\t\t\t\t// Pass arg names for Dockerfile ARG generation\n\t\t\t\t\tpublicUrlArgs: publicUrlArgNames,\n\t\t\t\t});\n\n\t\t\t\t// Prepare runtime environment variables\n\t\t\t\tconst envVars: string[] = [\n\t\t\t\t\t`NODE_ENV=production`,\n\t\t\t\t\t`PORT=${app.port}`,\n\t\t\t\t\t`STAGE=${stage}`,\n\t\t\t\t];\n\n\t\t\t\t// Add all resolved vars as runtime env (for SSR and server components)\n\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\tenvVars.push(`${key}=${value}`);\n\t\t\t\t}\n\n\t\t\t\t// Configure and deploy application in Dokploy\n\t\t\t\tawait api.saveDockerProvider(application.applicationId, imageRef, {\n\t\t\t\t\tregistryId,\n\t\t\t\t});\n\n\t\t\t\tawait api.saveApplicationEnv(\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t\tenvVars.join('\\n'),\n\t\t\t\t);\n\n\t\t\t\tlogger.log(`      Deploying to Dokploy...`);\n\t\t\t\tawait api.deployApplication(application.applicationId);\n\n\t\t\t\t// Check if domain already exists (frontendHost computed earlier for env context)\n\t\t\t\tconst existingFrontendDomains = await api.getDomainsByApplicationId(\n\t\t\t\t\tapplication.applicationId,\n\t\t\t\t);\n\t\t\t\tconst existingFrontendDomain = existingFrontendDomains.find(\n\t\t\t\t\t(d) => d.host === frontendHost,\n\t\t\t\t);\n\n\t\t\t\tif (existingFrontendDomain) {\n\t\t\t\t\t// Domain already exists\n\t\t\t\t\tappHostnames.set(appName, frontendHost);\n\t\t\t\t\tappDomainIds.set(appName, existingFrontendDomain.domainId);\n\t\t\t\t\tpublicUrls[appName] = `https://${frontendHost}`;\n\t\t\t\t\tlogger.log(`      ✓ Domain: https://${frontendHost} (existing)`);\n\t\t\t\t} else {\n\t\t\t\t\t// Create new domain\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst domain = await api.createDomain({\n\t\t\t\t\t\t\thost: frontendHost,\n\t\t\t\t\t\t\tport: app.port,\n\t\t\t\t\t\t\thttps: true,\n\t\t\t\t\t\t\tcertificateType: 'letsencrypt',\n\t\t\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tappHostnames.set(appName, frontendHost);\n\t\t\t\t\t\tappDomainIds.set(appName, domain.domainId);\n\t\t\t\t\t\tpublicUrls[appName] = `https://${frontendHost}`;\n\t\t\t\t\t\tlogger.log(`      ✓ Domain: https://${frontendHost} (created)`);\n\t\t\t\t\t} catch (domainError) {\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\tdomainError instanceof Error\n\t\t\t\t\t\t\t\t? domainError.message\n\t\t\t\t\t\t\t\t: 'Unknown error';\n\t\t\t\t\t\tlogger.log(`      ⚠ Domain creation failed: ${message}`);\n\t\t\t\t\t\tappHostnames.set(appName, frontendHost);\n\t\t\t\t\t\tpublicUrls[appName] = `https://${frontendHost}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresults.push({\n\t\t\t\t\tappName,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tapplicationId: application.applicationId,\n\t\t\t\t\timageRef,\n\t\t\t\t});\n\n\t\t\t\tlogger.log(`      ✓ ${appName} deployed successfully`);\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error';\n\t\t\t\tlogger.log(`      ✗ Failed to deploy ${appName}: ${message}`);\n\n\t\t\t\tresults.push({\n\t\t\t\t\tappName,\n\t\t\t\t\ttype: app.type,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: message,\n\t\t\t\t});\n\t\t\t\t// Don't abort on frontend failures - continue with other frontends\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// STATE: Save deploy state\n\t// ==================================================================\n\tlogger.log('\\n📋 Saving deploy state...');\n\tawait stateProvider.write(stage, state);\n\tlogger.log('   ✓ State saved');\n\n\t// ==================================================================\n\t// DNS: Create DNS records, verify propagation, and validate for SSL\n\t// ==================================================================\n\tconst dnsConfig = workspace.deploy.dns;\n\tif (dnsConfig && appHostnames.size > 0) {\n\t\tconst dnsResult = await orchestrateDns(\n\t\t\tappHostnames,\n\t\t\tdnsConfig,\n\t\t\tcreds.endpoint,\n\t\t);\n\n\t\t// Verify DNS records resolve correctly (with state caching)\n\t\tif (dnsResult?.serverIp && appHostnames.size > 0) {\n\t\t\tawait verifyDnsRecords(appHostnames, dnsResult.serverIp, state);\n\n\t\t\t// Save state again to persist DNS verification results\n\t\t\tawait stateProvider.write(stage, state);\n\t\t}\n\n\t\t// Validate domains to trigger SSL certificate generation\n\t\tif (dnsResult?.success && appHostnames.size > 0) {\n\t\t\tlogger.log('\\n🔒 Validating domains for SSL certificates...');\n\t\t\tfor (const [appName, hostname] of appHostnames) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await api.validateDomain(hostname);\n\t\t\t\t\tif (result.isValid) {\n\t\t\t\t\t\tlogger.log(`   ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.log(`   ⚠ ${appName}: ${hostname} not valid`);\n\t\t\t\t\t}\n\t\t\t\t} catch (validationError) {\n\t\t\t\t\tconst message =\n\t\t\t\t\t\tvalidationError instanceof Error\n\t\t\t\t\t\t\t? validationError.message\n\t\t\t\t\t\t\t: 'Unknown error';\n\t\t\t\t\tlogger.log(`   ⚠ ${appName}: validation failed - ${message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ==================================================================\n\t// Summary\n\t// ==================================================================\n\tconst successCount = results.filter((r) => r.success).length;\n\tconst failedCount = results.filter((r) => !r.success).length;\n\n\tlogger.log(`\\n${'─'.repeat(50)}`);\n\tlogger.log(`\\n✅ Workspace deployment complete!`);\n\tlogger.log(`   Project: ${project.projectId}`);\n\tlogger.log(`   Successful: ${successCount}`);\n\tif (failedCount > 0) {\n\t\tlogger.log(`   Failed: ${failedCount}`);\n\t}\n\n\t// Print deployed URLs\n\tif (Object.keys(publicUrls).length > 0) {\n\t\tlogger.log('\\n   📡 Deployed URLs:');\n\t\tfor (const [name, url] of Object.entries(publicUrls)) {\n\t\t\tlogger.log(`      ${name}: ${url}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tapps: results,\n\t\tprojectId: project.projectId,\n\t\tsuccessCount,\n\t\tfailedCount,\n\t};\n}\n\n/**\n * Main deploy command\n */\nexport async function deployCommand(\n\toptions: DeployOptions,\n): Promise<DeployResult | WorkspaceDeployResult> {\n\tconst { provider, stage, tag, skipPush, skipBuild } = options;\n\n\t// Load config with workspace detection\n\tconst loadedConfig = await loadWorkspaceConfig();\n\n\t// Route to workspace deploy mode for multi-app workspaces\n\tif (loadedConfig.type === 'workspace') {\n\t\tlogger.log('📦 Detected workspace configuration');\n\t\treturn workspaceDeployCommand(loadedConfig.workspace, options);\n\t}\n\n\tlogger.log(`\\n🚀 Deploying to ${provider}...`);\n\tlogger.log(`   Stage: ${stage}`);\n\n\t// Single-app mode - use existing logic\n\tconst config = await loadConfig();\n\n\t// Generate tag if not provided\n\tconst imageTag = tag ?? generateTag(stage);\n\tlogger.log(`   Tag: ${imageTag}`);\n\n\t// Resolve docker config for image reference\n\tconst dockerConfig = resolveDockerConfig(config);\n\tconst imageName = dockerConfig.imageName!;\n\tconst registry = dockerConfig.registry;\n\tconst imageRef = registry\n\t\t? `${registry}/${imageName}:${imageTag}`\n\t\t: `${imageName}:${imageTag}`;\n\n\t// For Dokploy, set up services BEFORE build so URLs are available\n\tlet dokployConfig: DokployDeployConfig | undefined;\n\tlet finalRegistry = registry;\n\n\tif (provider === 'dokploy') {\n\t\t// Extract docker compose services config\n\t\tconst composeServices = config.docker?.compose?.services;\n\t\tlogger.log(\n\t\t\t`\\n🔍 Docker compose config: ${JSON.stringify(config.docker?.compose)}`,\n\t\t);\n\t\tconst dockerServices: DockerComposeServices | undefined = composeServices\n\t\t\t? Array.isArray(composeServices)\n\t\t\t\t? {\n\t\t\t\t\t\tpostgres: composeServices.includes('postgres'),\n\t\t\t\t\t\tredis: composeServices.includes('redis'),\n\t\t\t\t\t\trabbitmq: composeServices.includes('rabbitmq'),\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tpostgres: Boolean(composeServices.postgres),\n\t\t\t\t\t\tredis: Boolean(composeServices.redis),\n\t\t\t\t\t\trabbitmq: Boolean(composeServices.rabbitmq),\n\t\t\t\t\t}\n\t\t\t: undefined;\n\n\t\t// Ensure Dokploy is fully set up (credentials, project, app, registry, services)\n\t\tconst setupResult = await ensureDokploySetup(\n\t\t\tconfig,\n\t\t\tdockerConfig,\n\t\t\tstage,\n\t\t\tdockerServices,\n\t\t);\n\t\tdokployConfig = setupResult.config;\n\t\tfinalRegistry = dokployConfig.registry ?? dockerConfig.registry;\n\n\t\t// Save provisioned service URLs to secrets before build\n\t\tif (setupResult.serviceUrls) {\n\t\t\tconst { readStageSecrets, writeStageSecrets, initStageSecrets } =\n\t\t\t\tawait import('../secrets/storage');\n\t\t\tlet secrets = await readStageSecrets(stage);\n\n\t\t\t// Create secrets file if it doesn't exist\n\t\t\tif (!secrets) {\n\t\t\t\tlogger.log(`   Creating secrets file for stage \"${stage}\"...`);\n\t\t\t\tsecrets = initStageSecrets(stage);\n\t\t\t}\n\n\t\t\tlet updated = false;\n\t\t\t// URL fields go to secrets.urls, individual params go to secrets.custom\n\t\t\tconst urlFields = ['DATABASE_URL', 'REDIS_URL', 'RABBITMQ_URL'] as const;\n\n\t\t\tfor (const [key, value] of Object.entries(setupResult.serviceUrls)) {\n\t\t\t\tif (!value) continue;\n\n\t\t\t\tif (urlFields.includes(key as (typeof urlFields)[number])) {\n\t\t\t\t\t// URL fields\n\t\t\t\t\tconst urlKey = key as keyof typeof secrets.urls;\n\t\t\t\t\tif (!secrets.urls[urlKey]) {\n\t\t\t\t\t\tsecrets.urls[urlKey] = value;\n\t\t\t\t\t\tlogger.log(`   Saved ${key} to secrets.urls`);\n\t\t\t\t\t\tupdated = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Individual parameters (HOST, PORT, NAME, USER, PASSWORD)\n\t\t\t\t\tif (!secrets.custom[key]) {\n\t\t\t\t\t\tsecrets.custom[key] = value;\n\t\t\t\t\t\tlogger.log(`   Saved ${key} to secrets.custom`);\n\t\t\t\t\t\tupdated = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (updated) {\n\t\t\t\tawait writeStageSecrets(secrets);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Build for production with secrets injection (unless skipped)\n\tlet masterKey: string | undefined;\n\tif (!skipBuild) {\n\t\tlogger.log(`\\n📦 Building for production...`);\n\t\tconst buildResult = await buildCommand({\n\t\t\tprovider: 'server',\n\t\t\tproduction: true,\n\t\t\tstage,\n\t\t});\n\t\tmasterKey = buildResult.masterKey;\n\t} else {\n\t\tlogger.log(`\\n⏭️  Skipping build (--skip-build)`);\n\t}\n\n\t// Deploy based on provider\n\tlet result: DeployResult;\n\n\tswitch (provider) {\n\t\tcase 'docker': {\n\t\t\tresult = await deployDocker({\n\t\t\t\tstage,\n\t\t\t\ttag: imageTag,\n\t\t\t\tskipPush,\n\t\t\t\tmasterKey,\n\t\t\t\tconfig: dockerConfig,\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'dokploy': {\n\t\t\tif (!dokployConfig) {\n\t\t\t\tthrow new Error('Dokploy config not initialized');\n\t\t\t}\n\t\t\tconst finalImageRef = finalRegistry\n\t\t\t\t? `${finalRegistry}/${imageName}:${imageTag}`\n\t\t\t\t: `${imageName}:${imageTag}`;\n\n\t\t\t// First build and push the Docker image\n\t\t\tawait deployDocker({\n\t\t\t\tstage,\n\t\t\t\ttag: imageTag,\n\t\t\t\tskipPush: false, // Dokploy needs the image in registry\n\t\t\t\tmasterKey,\n\t\t\t\tconfig: {\n\t\t\t\t\tregistry: finalRegistry,\n\t\t\t\t\timageName: dockerConfig.imageName,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// Then trigger Dokploy deployment\n\t\t\tresult = await deployDokploy({\n\t\t\t\tstage,\n\t\t\t\ttag: imageTag,\n\t\t\t\timageRef: finalImageRef,\n\t\t\t\tmasterKey,\n\t\t\t\tconfig: dokployConfig,\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'aws-lambda': {\n\t\t\tlogger.log('\\n⚠️  AWS Lambda deployment is not yet implemented.');\n\t\t\tlogger.log('   Use SST or AWS CDK for Lambda deployments.');\n\t\t\tresult = { imageRef, masterKey };\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault: {\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown deploy provider: ${provider}\\n` +\n\t\t\t\t\t'Supported providers: docker, dokploy, aws-lambda',\n\t\t\t);\n\t\t}\n\t}\n\n\tlogger.log('\\n✅ Deployment complete!');\n\n\treturn result;\n}\n\nexport type { DeployOptions, DeployProvider, DeployResult };\n","/**\n * State Management CLI Commands\n *\n * Commands for managing deployment state across local and remote providers.\n */\n\nimport { loadWorkspaceConfig } from '../config';\nimport { CachedStateProvider } from './CachedStateProvider';\nimport { createStateProvider } from './StateProvider';\nimport type { DokployStageState } from './state';\n\nexport interface StateCommandOptions {\n\tstage: string;\n}\n\n/**\n * Pull state from remote to local.\n * `gkm state:pull --stage=<stage>`\n */\nexport async function statePullCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tif (!workspace.state || workspace.state.provider === 'local') {\n\t\tconsole.error('No remote state provider configured.');\n\t\tconsole.error('Add a remote provider in gkm.config.ts:');\n\t\tconsole.error('  state: { provider: \"ssm\", region: \"us-east-1\" }');\n\t\tprocess.exit(1);\n\t}\n\n\tconst provider = await createStateProvider({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tif (!(provider instanceof CachedStateProvider)) {\n\t\tconsole.error('State provider does not support pull operation.');\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(`Pulling state for stage: ${options.stage}...`);\n\tconst state = await provider.pull(options.stage);\n\n\tif (state) {\n\t\tconsole.log('State pulled successfully.');\n\t\tprintStateSummary(state);\n\t} else {\n\t\tconsole.log('No remote state found for this stage.');\n\t}\n}\n\n/**\n * Push local state to remote.\n * `gkm state:push --stage=<stage>`\n */\nexport async function statePushCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tif (!workspace.state || workspace.state.provider === 'local') {\n\t\tconsole.error('No remote state provider configured.');\n\t\tconsole.error('Add a remote provider in gkm.config.ts:');\n\t\tconsole.error('  state: { provider: \"ssm\", region: \"us-east-1\" }');\n\t\tprocess.exit(1);\n\t}\n\n\tconst provider = await createStateProvider({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tif (!(provider instanceof CachedStateProvider)) {\n\t\tconsole.error('State provider does not support push operation.');\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(`Pushing state for stage: ${options.stage}...`);\n\tconst state = await provider.push(options.stage);\n\n\tif (state) {\n\t\tconsole.log('State pushed successfully.');\n\t\tprintStateSummary(state);\n\t} else {\n\t\tconsole.log('No local state found for this stage.');\n\t}\n}\n\n/**\n * Show current state.\n * `gkm state:show --stage=<stage>`\n */\nexport async function stateShowCommand(\n\toptions: StateCommandOptions & { json?: boolean },\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tconst provider = await createStateProvider({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tconst state = await provider.read(options.stage);\n\n\tif (!state) {\n\t\tconsole.log(`No state found for stage: ${options.stage}`);\n\t\treturn;\n\t}\n\n\tif (options.json) {\n\t\tconsole.log(JSON.stringify(state, null, 2));\n\t} else {\n\t\tprintStateDetails(state);\n\t}\n}\n\n/**\n * Compare local and remote state.\n * `gkm state:diff --stage=<stage>`\n */\nexport async function stateDiffCommand(\n\toptions: StateCommandOptions,\n): Promise<void> {\n\tconst { workspace } = await loadWorkspaceConfig();\n\n\tif (!workspace.state || workspace.state.provider === 'local') {\n\t\tconsole.error('No remote state provider configured.');\n\t\tconsole.error('Diff requires a remote provider to compare against.');\n\t\tprocess.exit(1);\n\t}\n\n\tconst provider = await createStateProvider({\n\t\tconfig: workspace.state,\n\t\tworkspaceRoot: workspace.root,\n\t\tworkspaceName: workspace.name,\n\t});\n\n\tif (!(provider instanceof CachedStateProvider)) {\n\t\tconsole.error('State provider does not support diff operation.');\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(`Comparing state for stage: ${options.stage}...\\n`);\n\tconst { local, remote } = await provider.diff(options.stage);\n\n\tif (!local && !remote) {\n\t\tconsole.log('No state found (local or remote).');\n\t\treturn;\n\t}\n\n\tif (!local) {\n\t\tconsole.log('Local:  (none)');\n\t} else {\n\t\tconsole.log(`Local:  Last deployed ${local.lastDeployedAt}`);\n\t}\n\n\tif (!remote) {\n\t\tconsole.log('Remote: (none)');\n\t} else {\n\t\tconsole.log(`Remote: Last deployed ${remote.lastDeployedAt}`);\n\t}\n\n\tconsole.log('');\n\n\t// Compare applications\n\tconst localApps = local?.applications ?? {};\n\tconst remoteApps = remote?.applications ?? {};\n\tconst allApps = new Set([\n\t\t...Object.keys(localApps),\n\t\t...Object.keys(remoteApps),\n\t]);\n\n\tif (allApps.size > 0) {\n\t\tconsole.log('Applications:');\n\t\tfor (const app of allApps) {\n\t\t\tconst localId = localApps[app];\n\t\t\tconst remoteId = remoteApps[app];\n\n\t\t\tif (localId === remoteId) {\n\t\t\t\tconsole.log(`  ${app}: ${localId ?? '(none)'}`);\n\t\t\t} else if (!localId) {\n\t\t\t\tconsole.log(`  ${app}: (none) -> ${remoteId} [REMOTE ONLY]`);\n\t\t\t} else if (!remoteId) {\n\t\t\t\tconsole.log(`  ${app}: ${localId} -> (none) [LOCAL ONLY]`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`  ${app}: ${localId} (local) != ${remoteId} (remote) [MISMATCH]`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compare services\n\tconst localServices = local?.services ?? {};\n\tconst remoteServices = remote?.services ?? {};\n\n\tif (\n\t\tObject.keys(localServices).length > 0 ||\n\t\tObject.keys(remoteServices).length > 0\n\t) {\n\t\tconsole.log('\\nServices:');\n\t\tconst serviceKeys = new Set([\n\t\t\t...Object.keys(localServices),\n\t\t\t...Object.keys(remoteServices),\n\t\t]);\n\n\t\tfor (const key of serviceKeys) {\n\t\t\tconst localVal = localServices[key as keyof typeof localServices];\n\t\t\tconst remoteVal = remoteServices[key as keyof typeof remoteServices];\n\n\t\t\tif (localVal === remoteVal) {\n\t\t\t\tconsole.log(`  ${key}: ${localVal ?? '(none)'}`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`  ${key}: ${localVal ?? '(none)'} (local) != ${remoteVal ?? '(none)'} (remote)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction printStateSummary(state: DokployStageState): void {\n\tconst appCount = Object.keys(state.applications).length;\n\tconst hasPostgres = !!state.services.postgresId;\n\tconst hasRedis = !!state.services.redisId;\n\n\tconsole.log(`  Stage: ${state.stage}`);\n\tconsole.log(`  Applications: ${appCount}`);\n\tconsole.log(`  Postgres: ${hasPostgres ? 'configured' : 'none'}`);\n\tconsole.log(`  Redis: ${hasRedis ? 'configured' : 'none'}`);\n\tconsole.log(`  Last deployed: ${state.lastDeployedAt}`);\n}\n\nfunction printStateDetails(state: DokployStageState): void {\n\tconsole.log(`Stage: ${state.stage}`);\n\tconsole.log(`Environment ID: ${state.environmentId}`);\n\tconsole.log(`Last Deployed: ${state.lastDeployedAt}`);\n\tconsole.log('');\n\n\tconsole.log('Applications:');\n\tconst apps = Object.entries(state.applications);\n\tif (apps.length === 0) {\n\t\tconsole.log('  (none)');\n\t} else {\n\t\tfor (const [name, id] of apps) {\n\t\t\tconsole.log(`  ${name}: ${id}`);\n\t\t}\n\t}\n\tconsole.log('');\n\n\tconsole.log('Services:');\n\tif (!state.services.postgresId && !state.services.redisId) {\n\t\tconsole.log('  (none)');\n\t} else {\n\t\tif (state.services.postgresId) {\n\t\t\tconsole.log(`  Postgres: ${state.services.postgresId}`);\n\t\t}\n\t\tif (state.services.redisId) {\n\t\t\tconsole.log(`  Redis: ${state.services.redisId}`);\n\t\t}\n\t}\n\n\tif (state.dnsVerified && Object.keys(state.dnsVerified).length > 0) {\n\t\tconsole.log('');\n\t\tconsole.log('DNS Verified:');\n\t\tfor (const [hostname, info] of Object.entries(state.dnsVerified)) {\n\t\t\tconsole.log(`  ${hostname}: ${info.serverIp} (${info.verifiedAt})`);\n\t\t}\n\t}\n}\n","import { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n// Load package.json - handles both bundled (flat dist/) and source (nested src/init/)\nfunction loadPackageJson(): { version: string } {\n\ttry {\n\t\t// Try flat dist path first (../package.json from dist/)\n\t\treturn require('../package.json');\n\t} catch {\n\t\t// Fall back to nested source path (../../package.json from src/init/)\n\t\treturn require('../../package.json');\n\t}\n}\n\nconst pkg = loadPackageJson();\n\n/**\n * CLI version resolved from package.json at runtime\n */\nexport const CLI_VERSION = `~${pkg.version}`;\n\n/**\n * Package versions for @geekmidas packages\n *\n * AUTO-GENERATED (except CLI) - Do not edit manually\n * Run: pnpm --filter @geekmidas/cli sync-versions\n */\nexport const GEEKMIDAS_VERSIONS = {\n\t'@geekmidas/audit': '~2.0.1',\n\t'@geekmidas/auth': '~2.0.1',\n\t'@geekmidas/cache': '~1.1.1',\n\t'@geekmidas/client': '~6.0.0',\n\t'@geekmidas/cloud': '~1.0.1',\n\t'@geekmidas/constructs': '~4.0.1',\n\t'@geekmidas/db': '~1.0.2',\n\t'@geekmidas/emailkit': '~1.0.1',\n\t'@geekmidas/envkit': '~1.0.7',\n\t'@geekmidas/errors': '~1.0.1',\n\t'@geekmidas/events': '~1.1.4',\n\t'@geekmidas/logger': '~1.0.2',\n\t'@geekmidas/rate-limit': '~3.0.0',\n\t'@geekmidas/schema': '~1.0.3',\n\t'@geekmidas/services': '~1.1.1',\n\t'@geekmidas/storage': '~2.0.3',\n\t'@geekmidas/studio': '~1.0.1',\n\t'@geekmidas/telescope': '~1.0.1',\n\t'@geekmidas/testkit': '~2.0.0',\n\t'@geekmidas/cli': CLI_VERSION,\n} as const;\n\nexport type GeekmidasPackage = keyof typeof GEEKMIDAS_VERSIONS;\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate auth app files for fullstack template\n * Uses better-auth with magic link authentication\n */\nexport function generateAuthAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/auth`;\n\tconst modelsPackage = `@${options.name}/models`;\n\n\t// package.json for auth app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm dev --entry ./src/index.ts',\n\t\t\tbuild: 'tsc',\n\t\t\tstart: 'node dist/index.js',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t\t'db:migrate': 'gkm exec -- npx @better-auth/cli migrate',\n\t\t\t'db:generate': 'gkm exec -- npx @better-auth/cli generate',\n\t\t},\n\t\tdependencies: {\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t\t'@hono/node-server': '~1.13.0',\n\t\t\t'better-auth': '~1.2.0',\n\t\t\thono: '~4.8.0',\n\t\t\tkysely: '~0.27.0',\n\t\t\tpg: '~8.13.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@types/node': '~22.0.0',\n\t\t\t'@types/pg': '~8.11.0',\n\t\t\ttsx: '~4.20.0',\n\t\t\ttypescript: '~5.8.2',\n\t\t},\n\t};\n\n\t// tsconfig.json for auth app\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tbaseUrl: '.',\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[`@${options.name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// src/config/env.ts\n\tconst envTs = `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed where needed\nexport const config = envParser\n  .create((get) => ({\n    nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n    stage: get('STAGE').enum(['development', 'staging', 'production']).default('development'),\n  }))\n  .parse();\n`;\n\n\t// src/config/logger.ts\n\tconst loggerTs = `import { createLogger } from '@geekmidas/logger/${options.loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t// src/auth.ts - better-auth instance with magic link\n\tconst authTs = `import { betterAuth } from 'better-auth';\nimport { magicLink } from 'better-auth/plugins';\nimport pg from 'pg';\nimport { envParser } from './config/env.ts';\nimport { logger } from './config/logger.ts';\n\n// Parse auth-specific config (no defaults - values from secrets)\nconst authConfig = envParser\n  .create((get) => ({\n    databaseUrl: get('DATABASE_URL').string(),\n    baseUrl: get('BETTER_AUTH_URL').string(),\n    trustedOrigins: get('BETTER_AUTH_TRUSTED_ORIGINS').string(),\n    secret: get('BETTER_AUTH_SECRET').string(),\n  }))\n  .parse();\n\nexport const auth = betterAuth({\n  database: new pg.Pool({\n    connectionString: authConfig.databaseUrl,\n  }),\n  baseURL: authConfig.baseUrl,\n  trustedOrigins: authConfig.trustedOrigins.split(','),\n  secret: authConfig.secret,\n  plugins: [\n    magicLink({\n      sendMagicLink: async ({ email, url }) => {\n        // TODO: Implement email sending using @geekmidas/emailkit\n        // For development, log the magic link\n        logger.info({ email, url }, 'Magic link generated');\n        console.log('\\\\n================================');\n        console.log('MAGIC LINK FOR:', email);\n        console.log(url);\n        console.log('================================\\\\n');\n      },\n      expiresIn: 300, // 5 minutes\n    }),\n  ],\n  emailAndPassword: {\n    enabled: false, // Only magic link for now\n  },\n});\n\nexport type Auth = typeof auth;\n`;\n\n\t// src/index.ts - Hono app entry point\n\tconst indexTs = `import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { serve } from '@hono/node-server';\nimport { auth } from './auth.ts';\nimport { envParser } from './config/env.ts';\nimport { logger } from './config/logger.ts';\n\n// Parse server config (no defaults - values from secrets)\nconst serverConfig = envParser\n  .create((get) => ({\n    port: get('PORT').string().transform(Number),\n    trustedOrigins: get('BETTER_AUTH_TRUSTED_ORIGINS').string(),\n  }))\n  .parse();\n\nconst app = new Hono();\n\n// CORS must be registered before routes\napp.use(\n  '/api/auth/*',\n  cors({\n    origin: serverConfig.trustedOrigins.split(','),\n    allowHeaders: ['Content-Type', 'Authorization'],\n    allowMethods: ['POST', 'GET', 'OPTIONS'],\n    credentials: true,\n  }),\n);\n\n// Health check endpoint\napp.get('/health', (c) => {\n  return c.json({\n    status: 'ok',\n    service: 'auth',\n    timestamp: new Date().toISOString(),\n  });\n});\n\n// Mount better-auth handler\napp.on(['POST', 'GET'], '/api/auth/*', (c) => {\n  return auth.handler(c.req.raw);\n});\n\nlogger.info({ port: serverConfig.port }, 'Starting auth server');\n\nserve({\n  fetch: app.fetch,\n  port: serverConfig.port,\n}, (info) => {\n  logger.info({ port: info.port }, 'Auth server running');\n});\n`;\n\n\t// .gitignore for auth app\n\tconst gitignore = `node_modules/\ndist/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/auth/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/src/config/env.ts',\n\t\t\tcontent: envTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/src/config/logger.ts',\n\t\t\tcontent: loggerTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/src/auth.ts',\n\t\t\tcontent: authTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/src/index.ts',\n\t\t\tcontent: indexTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/auth/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Vitest config content with globalSetup for database-enabled apps\n */\nconst vitestConfigContent = `import { defineConfig } from 'vitest/config';\nimport tsconfigPaths from 'vite-tsconfig-paths';\n\nexport default defineConfig({\n  plugins: [tsconfigPaths()],\n  test: {\n    environment: 'node',\n    globalSetup: './test/globalSetup.ts',\n  },\n});\n`;\n\n/**\n * Generate configuration files (gkm.config.ts, tsconfig.json, biome.json, turbo.json)\n */\nexport function generateConfigFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { telescope, studio, routesStructure } = options;\n\tconst isServerless = template.name === 'serverless';\n\tconst hasWorker = template.name === 'worker';\n\tconst isFullstack = options.template === 'fullstack';\n\n\t// Get routes glob pattern based on structure\n\tconst getRoutesGlob = () => {\n\t\tswitch (routesStructure) {\n\t\t\tcase 'centralized-endpoints':\n\t\t\t\treturn './src/endpoints/**/*.ts';\n\t\t\tcase 'centralized-routes':\n\t\t\t\treturn './src/routes/**/*.ts';\n\t\t\tcase 'domain-based':\n\t\t\t\treturn './src/**/routes/*.ts';\n\t\t}\n\t};\n\n\t// For fullstack template, generate workspace config at root\n\t// Single app config is still generated for non-fullstack monorepo setups\n\tif (isFullstack) {\n\t\t// Workspace config is generated in monorepo.ts for fullstack\n\t\treturn generateSingleAppConfigFiles(options, template, {\n\t\t\ttelescope,\n\t\t\tstudio,\n\t\t\troutesStructure,\n\t\t\tisServerless,\n\t\t\thasWorker,\n\t\t\tgetRoutesGlob,\n\t\t});\n\t}\n\n\t// Build gkm.config.ts for single-app\n\tlet gkmConfig = `import { defineConfig } from '@geekmidas/cli/config';\n\nexport default defineConfig({\n  routes: '${getRoutesGlob()}',\n  envParser: './src/config/env#envParser',\n  logger: './src/config/logger#logger',`;\n\n\tif (isServerless || hasWorker) {\n\t\tgkmConfig += `\n  functions: './src/functions/**/*.ts',`;\n\t}\n\n\tif (hasWorker) {\n\t\tgkmConfig += `\n  crons: './src/crons/**/*.ts',\n  subscribers: './src/subscribers/**/*.ts',`;\n\t}\n\n\tif (telescope) {\n\t\tgkmConfig += `\n  telescope: {\n    enabled: true,\n    path: '/__telescope',\n  },`;\n\t}\n\n\tif (studio) {\n\t\tgkmConfig += `\n  studio: './src/config/studio#studio',`;\n\t}\n\n\t// Always add openapi config (output path is fixed to .gkm/openapi.ts)\n\tgkmConfig += `\n  openapi: {\n    enabled: true,\n  },`;\n\n\tgkmConfig += `\n});\n`;\n\n\t// Build tsconfig.json - extends root for monorepo, standalone for non-monorepo\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = options.monorepo\n\t\t? {\n\t\t\t\textends: '../../tsconfig.json',\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\tnoEmit: true,\n\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\tbaseUrl: '.',\n\t\t\t\t\tpaths: {\n\t\t\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t\t\t[`@${options.name}/*`]: ['../../packages/*/src'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tinclude: ['src/**/*.ts'],\n\t\t\t\texclude: ['node_modules', 'dist'],\n\t\t\t}\n\t\t: {\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\ttarget: 'ES2022',\n\t\t\t\t\tmodule: 'NodeNext',\n\t\t\t\t\tmoduleResolution: 'NodeNext',\n\t\t\t\t\tlib: ['ES2022'],\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tesModuleInterop: true,\n\t\t\t\t\tskipLibCheck: true,\n\t\t\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\t\t\tresolveJsonModule: true,\n\t\t\t\t\tnoEmit: true,\n\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t},\n\t\t\t\tinclude: ['src/**/*.ts'],\n\t\t\t\texclude: ['node_modules', 'dist'],\n\t\t\t};\n\n\t// Skip biome.json and turbo.json for monorepo (they're at root)\n\tif (options.monorepo) {\n\t\tconst files: GeneratedFile[] = [\n\t\t\t{\n\t\t\t\tpath: 'gkm.config.ts',\n\t\t\t\tcontent: gkmConfig,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: 'tsconfig.json',\n\t\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t\t},\n\t\t];\n\n\t\tif (options.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'vitest.config.ts',\n\t\t\t\tcontent: vitestConfigContent,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t}\n\n\t// Build biome.json\n\tconst biomeConfig = {\n\t\t$schema: 'https://biomejs.dev/schemas/2.3.0/schema.json',\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\torganizeImports: {\n\t\t\tenabled: true,\n\t\t},\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tfiles: {\n\t\t\tignore: ['node_modules', 'dist', '.gkm', 'coverage'],\n\t\t},\n\t};\n\n\t// Build turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['dist/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: gkmConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigContent,\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * Helper to generate config files for API app in fullstack template\n * (workspace config is at root, so no gkm.config.ts for app)\n */\ninterface ConfigHelperOptions {\n\ttelescope: boolean;\n\tstudio: boolean;\n\troutesStructure: string;\n\tisServerless: boolean;\n\thasWorker: boolean;\n\tgetRoutesGlob: () => string;\n}\n\nfunction generateSingleAppConfigFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n\t_helpers: ConfigHelperOptions,\n): GeneratedFile[] {\n\t// For fullstack, only generate tsconfig.json for the API app\n\t// The workspace gkm.config.ts is generated in monorepo.ts\n\t// Using noEmit: true since typecheck is done via turbo\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tbaseUrl: '.',\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t\t[`@${options.name}/*`]: ['../../packages/*/src'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t];\n\n\tif (options.database) {\n\t\tfiles.push({\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfigContent,\n\t\t});\n\t}\n\n\treturn files;\n}\n","import type { EventsBackend } from '../../types.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\nexport interface DatabaseAppConfig {\n\tname: string;\n\tpassword: string;\n}\n\n/**\n * Generate docker-compose.yml based on template and options\n */\nexport function generateDockerFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n\tdbApps?: DatabaseAppConfig[],\n): GeneratedFile[] {\n\tconst { database } = options;\n\tconst isServerless = template.name === 'serverless';\n\tconst hasWorker = template.name === 'worker';\n\tconst isFullstack = options.template === 'fullstack';\n\n\tconst services: string[] = [];\n\tconst volumes: string[] = [];\n\tconst files: GeneratedFile[] = [];\n\n\t// PostgreSQL database\n\tif (database) {\n\t\tconst initVolume =\n\t\t\tisFullstack && dbApps?.length\n\t\t\t\t? `\n      - ./docker/postgres/init.sh:/docker-entrypoint-initdb.d/init.sh:ro`\n\t\t\t\t: '';\n\n\t\tconst envFile =\n\t\t\tisFullstack && dbApps?.length\n\t\t\t\t? `\n    env_file:\n      - ./docker/.env`\n\t\t\t\t: '';\n\n\t\tservices.push(`  postgres:\n    image: postgres:18-alpine\n    container_name: ${options.name}-postgres\n    restart: unless-stopped${envFile}\n    environment:\n      POSTGRES_USER: \\${POSTGRES_USER:-postgres}\n      POSTGRES_PASSWORD: \\${POSTGRES_PASSWORD:-postgres}\n      POSTGRES_DB: \\${POSTGRES_DB:-${options.name.replace(/-/g, '_')}_dev}\n    ports:\n      - '\\${POSTGRES_HOST_PORT:-5432}:5432'\n    volumes:\n      - dbdata:/var/lib/postgresql/18/data${initVolume}\n    healthcheck:\n      test: ['CMD-SHELL', 'pg_isready -U $$POSTGRES_USER']\n      interval: 5s\n      timeout: 5s\n      retries: 5`);\n\t\tvolumes.push('  dbdata:');\n\n\t\t// Generate PostgreSQL init script and .env for fullstack template\n\t\tif (isFullstack && dbApps?.length) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'docker/postgres/init.sh',\n\t\t\t\tcontent: generatePostgresInitScript(dbApps, options.services?.events),\n\t\t\t});\n\n\t\t\t// Generate .env file for docker-compose (contains db passwords)\n\t\t\tfiles.push({\n\t\t\t\tpath: 'docker/.env',\n\t\t\t\tcontent: generateDockerEnv(dbApps, options.services?.events),\n\t\t\t});\n\t\t}\n\t}\n\n\t// Redis - different setup for serverless vs standard\n\tif (isServerless) {\n\t\t// Use serverless-redis-http for Lambda compatibility\n\t\tservices.push(`  redis:\n    image: redis:7-alpine\n    container_name: ${options.name}-redis\n    restart: unless-stopped\n    ports:\n      - '\\${REDIS_HOST_PORT:-6379}:6379'\n    volumes:\n      - redis_data:/data\n    healthcheck:\n      test: ['CMD', 'redis-cli', 'ping']\n      interval: 5s\n      timeout: 5s\n      retries: 5\n\n  serverless-redis:\n    image: hiett/serverless-redis-http:latest\n    container_name: ${options.name}-serverless-redis\n    restart: unless-stopped\n    ports:\n      - '\\${SRH_HOST_PORT:-8079}:80'\n    environment:\n      SRH_MODE: env\n      SRH_TOKEN: local_dev_token\n      SRH_CONNECTION_STRING: redis://redis:6379\n    depends_on:\n      redis:\n        condition: service_healthy`);\n\t\tvolumes.push('  redis_data:');\n\t} else {\n\t\t// Standard Redis for non-serverless templates\n\t\tservices.push(`  redis:\n    image: redis:7-alpine\n    container_name: ${options.name}-redis\n    restart: unless-stopped\n    ports:\n      - '\\${REDIS_HOST_PORT:-6379}:6379'\n    volumes:\n      - redis_data:/data\n    healthcheck:\n      test: ['CMD', 'redis-cli', 'ping']\n      interval: 5s\n      timeout: 5s\n      retries: 5`);\n\t\tvolumes.push('  redis_data:');\n\t}\n\n\t// RabbitMQ for worker template\n\tif (hasWorker) {\n\t\tservices.push(`  rabbitmq:\n    image: rabbitmq:3-management-alpine\n    container_name: ${options.name}-rabbitmq\n    restart: unless-stopped\n    ports:\n      - '\\${RABBITMQ_HOST_PORT:-5672}:5672'\n      - '\\${RABBITMQ_MGMT_HOST_PORT:-15672}:15672'\n    environment:\n      RABBITMQ_DEFAULT_USER: guest\n      RABBITMQ_DEFAULT_PASS: guest\n    volumes:\n      - rabbitmq_data:/var/lib/rabbitmq\n    healthcheck:\n      test: ['CMD', 'rabbitmq-diagnostics', 'check_running']\n      interval: 10s\n      timeout: 5s\n      retries: 5`);\n\t\tvolumes.push('  rabbitmq_data:');\n\t}\n\n\t// Mailpit for email testing\n\tif (options.services?.mail) {\n\t\tservices.push(`  mailpit:\n    image: axllent/mailpit:latest\n    container_name: ${options.name}-mailpit\n    restart: unless-stopped\n    ports:\n      - '\\${SMTP_PORT:-1025}:1025'\n      - '\\${MAILPIT_PORT:-8025}:8025'\n    environment:\n      MP_SMTP_AUTH: \\${SMTP_USER:-${options.name}}:\\${SMTP_PASS:-${options.name}}`);\n\t}\n\n\t// MinIO for S3-compatible object storage\n\tif (options.services?.storage) {\n\t\tservices.push(`  minio:\n    image: minio/minio:latest\n    container_name: ${options.name}-minio\n    restart: unless-stopped\n    entrypoint: sh\n    command: -c 'mkdir -p /data/\\${STORAGE_BUCKET:-${options.name}} && /usr/bin/docker-entrypoint.sh server --console-address \":9001\" /data'\n    environment:\n      MINIO_ROOT_USER: \\${STORAGE_ACCESS_KEY_ID:-${options.name}}\n      MINIO_ROOT_PASSWORD: \\${STORAGE_SECRET_ACCESS_KEY:-${options.name}}\n    ports:\n      - '\\${MINIO_API_HOST_PORT:-9000}:9000'\n      - '\\${MINIO_CONSOLE_HOST_PORT:-9001}:9001'\n    volumes:\n      - minio_data:/data\n    healthcheck:\n      test: ['CMD', 'mc', 'ready', 'local']\n      interval: 10s\n      timeout: 5s\n      retries: 5`);\n\t\tvolumes.push('  minio_data:');\n\t}\n\n\t// LocalStack for SNS events\n\tif (options.services?.events === 'sns') {\n\t\tservices.push(`  localstack:\n    image: localstack/localstack:latest\n    container_name: ${options.name}-localstack\n    restart: unless-stopped\n    environment:\n      SERVICES: sns,sqs\n      AWS_DEFAULT_REGION: \\${AWS_REGION:-us-east-1}\n      AWS_ACCESS_KEY_ID: \\${AWS_ACCESS_KEY_ID:-localstack}\n      AWS_SECRET_ACCESS_KEY: \\${AWS_SECRET_ACCESS_KEY:-localstack}\n    ports:\n      - '\\${LOCALSTACK_PORT:-4566}:4566'\n    volumes:\n      - localstack_data:/var/lib/localstack\n    healthcheck:\n      test: ['CMD', 'curl', '-f', 'http://localhost:4566/_localstack/health']\n      interval: 10s\n      timeout: 5s\n      retries: 5`);\n\t\tvolumes.push('  localstack_data:');\n\t}\n\n\t// RabbitMQ for rabbitmq events (when not already added by worker template)\n\tif (options.services?.events === 'rabbitmq' && !hasWorker) {\n\t\tservices.push(`  rabbitmq:\n    image: rabbitmq:3-management-alpine\n    container_name: ${options.name}-rabbitmq\n    restart: unless-stopped\n    ports:\n      - '\\${RABBITMQ_HOST_PORT:-5672}:5672'\n      - '\\${RABBITMQ_MGMT_HOST_PORT:-15672}:15672'\n    environment:\n      RABBITMQ_DEFAULT_USER: guest\n      RABBITMQ_DEFAULT_PASS: guest\n    volumes:\n      - rabbitmq_data:/var/lib/rabbitmq\n    healthcheck:\n      test: ['CMD', 'rabbitmq-diagnostics', 'check_running']\n      interval: 10s\n      timeout: 5s\n      retries: 5`);\n\t\tif (!volumes.includes('  rabbitmq_data:')) {\n\t\t\tvolumes.push('  rabbitmq_data:');\n\t\t}\n\t}\n\n\t// Build docker-compose.yml\n\tlet dockerCompose = `# Use \"gkm dev\" or \"gkm test\" to start services.\n# Running \"docker compose up\" directly will not inject secrets or resolve ports.\nservices:\n${services.join('\\n\\n')}\n`;\n\n\tif (volumes.length > 0) {\n\t\tdockerCompose += `\nvolumes:\n${volumes.join('\\n')}\n`;\n\t}\n\n\t// Add docker-compose.yml to files\n\tfiles.push({\n\t\tpath: 'docker-compose.yml',\n\t\tcontent: dockerCompose,\n\t});\n\n\treturn files;\n}\n\n/**\n * Generate .env file for docker-compose with database passwords\n */\nfunction generateDockerEnv(\n\tapps: DatabaseAppConfig[],\n\t_eventsBackend?: EventsBackend,\n): string {\n\tconst envVars = apps.map((app) => {\n\t\tconst envVar = `${app.name.toUpperCase()}_DB_PASSWORD`;\n\t\treturn `${envVar}=${app.password}`;\n\t});\n\n\t// Always include pgboss password for the dedicated pgboss user\n\tenvVars.push(`PGBOSS_DB_PASSWORD=pgboss-dev-password`);\n\n\treturn `# Auto-generated docker environment file\n# Contains database passwords for docker-compose postgres init\n# This file is gitignored - do not commit to version control\n${envVars.join('\\n')}\n`;\n}\n\n/**\n * Generate PostgreSQL init shell script that creates per-app users with separate schemas.\n * Uses idempotent DO blocks so the script can be re-run safely.\n * - api user: uses public schema\n * - auth user: uses auth schema with search_path=auth\n * - pgboss user: uses pgboss schema (when events === 'pgboss')\n */\nfunction generatePostgresInitScript(\n\tapps: DatabaseAppConfig[],\n\t_eventsBackend?: EventsBackend,\n): string {\n\tconst userCreations = apps.map((app) => {\n\t\tconst userName = app.name.replace(/-/g, '_');\n\t\tconst envVar = `${app.name.toUpperCase()}_DB_PASSWORD`;\n\t\tconst isApi = app.name === 'api';\n\t\tconst schemaName = isApi ? 'public' : userName;\n\n\t\tif (isApi) {\n\t\t\treturn `\n# Create ${app.name} user (uses public schema) - idempotent\necho \"Creating user ${userName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n    DO \\\\$\\\\$\n    BEGIN\n        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${userName}') THEN\n            CREATE USER ${userName} WITH PASSWORD '$${envVar}';\n        ELSE\n            ALTER USER ${userName} WITH PASSWORD '$${envVar}';\n        END IF;\n    END\n    \\\\$\\\\$;\n    GRANT ALL ON SCHEMA public TO ${userName};\n    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ${userName};\n    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO ${userName};\nEOSQL\n`;\n\t\t}\n\t\treturn `\n# Create ${app.name} user with dedicated schema - idempotent\necho \"Creating user ${userName} with schema ${schemaName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n    DO \\\\$\\\\$\n    BEGIN\n        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${userName}') THEN\n            CREATE USER ${userName} WITH PASSWORD '$${envVar}';\n        ELSE\n            ALTER USER ${userName} WITH PASSWORD '$${envVar}';\n        END IF;\n    END\n    \\\\$\\\\$;\n    CREATE SCHEMA IF NOT EXISTS ${schemaName} AUTHORIZATION ${userName};\n    ALTER USER ${userName} SET search_path TO ${schemaName};\n    GRANT USAGE ON SCHEMA ${schemaName} TO ${userName};\n    GRANT ALL ON ALL TABLES IN SCHEMA ${schemaName} TO ${userName};\n    GRANT ALL ON ALL SEQUENCES IN SCHEMA ${schemaName} TO ${userName};\n    ALTER DEFAULT PRIVILEGES IN SCHEMA ${schemaName} GRANT ALL ON TABLES TO ${userName};\n    ALTER DEFAULT PRIVILEGES IN SCHEMA ${schemaName} GRANT ALL ON SEQUENCES TO ${userName};\nEOSQL\n`;\n\t});\n\n\t// Always add pgboss user and schema.\n\t// pgboss reuses the same database with a dedicated user/schema,\n\t// so subscribers work out of the box without explicit events config.\n\tconst pgbossBlock = `\n# Create pgboss user with dedicated schema - idempotent\necho \"Creating pgboss user and schema...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n    DO \\\\$\\\\$\n    BEGIN\n        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgboss') THEN\n            CREATE USER pgboss WITH PASSWORD '$PGBOSS_DB_PASSWORD';\n        ELSE\n            ALTER USER pgboss WITH PASSWORD '$PGBOSS_DB_PASSWORD';\n        END IF;\n    END\n    \\\\$\\\\$;\n    CREATE SCHEMA IF NOT EXISTS pgboss AUTHORIZATION pgboss;\n    ALTER USER pgboss SET search_path TO pgboss;\n    GRANT USAGE ON SCHEMA pgboss TO pgboss;\n    GRANT ALL ON ALL TABLES IN SCHEMA pgboss TO pgboss;\n    GRANT ALL ON ALL SEQUENCES IN SCHEMA pgboss TO pgboss;\n    ALTER DEFAULT PRIVILEGES IN SCHEMA pgboss GRANT ALL ON TABLES TO pgboss;\n    ALTER DEFAULT PRIVILEGES IN SCHEMA pgboss GRANT ALL ON SEQUENCES TO pgboss;\nEOSQL\n`;\n\n\t// Add extensions\n\tconst extensions = `\n# Create extensions\necho \"Creating extensions...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n    CREATE EXTENSION IF NOT EXISTS pg_trgm;\n    CREATE EXTENSION IF NOT EXISTS citext;\nEOSQL\n`;\n\n\treturn `#!/bin/bash\nset -e\n\n# Auto-generated PostgreSQL init script (idempotent - safe to re-run)\n# Creates per-app users with separate schemas in a single database\n# - api: uses public schema\n# - auth: uses auth schema (search_path=auth)\n# - pgboss: uses pgboss schema for event processing\n${extensions}\n${userCreations.join('\\n')}${pgbossBlock}\necho \"Database initialization complete!\"\n`;\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate environment-related files (.gitignore only).\n * Note: .env files are no longer generated. Use `gkm secrets:init` to initialize\n * encrypted secrets stored in `.gkm/secrets/{stage}.json` with keys stored at\n * `~/.gkm/{project-name}/{stage}.key`.\n */\nexport function generateEnvFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tconst files: GeneratedFile[] = [];\n\n\t// Only add .gitignore for non-monorepo (monorepo has it at root)\n\tif (!options.monorepo) {\n\t\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Environment (legacy - use gkm secrets instead)\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n`;\n\t\tfiles.push({\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t});\n\t}\n\n\treturn files;\n}\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate an Expo mobile app for the fullstack template.\n *\n * Mirrors the structure of rezgo/apps/app: NativeWind for styling,\n * expo-router for navigation, better-auth + magic link, React Query\n * for data, all wired into the toolbox's typed API client.\n */\nexport function generateExpoAppFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/app`;\n\tconst apiPackage = `@${options.name}/api`;\n\tconst modelsPackage = `@${options.name}/models`;\n\t// Expo bundle id / scheme — kept simple; the user can rename later.\n\tconst slug = options.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\tconst scheme = slug.replace(/-/g, '');\n\tconst bundleId = `com.${scheme}.app`;\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tmain: 'expo-router/entry',\n\t\tprivate: true,\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- expo start -c',\n\t\t\tios: 'expo start --ios',\n\t\t\tandroid: 'expo start --android',\n\t\t\tweb: 'expo start --web',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[apiPackage]: 'workspace:*',\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t'@better-auth/expo': '~1.2.0',\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@react-navigation/native': '^7.1.0',\n\t\t\t'@tanstack/react-query': '~5.80.0',\n\t\t\t'better-auth': '~1.2.0',\n\t\t\texpo: '~55.0.0',\n\t\t\t'expo-constants': '~55.0.0',\n\t\t\t'expo-dev-client': '~55.0.0',\n\t\t\t'expo-linking': '~55.0.0',\n\t\t\t'expo-router': '~55.0.0',\n\t\t\t'expo-secure-store': '~14.2.0',\n\t\t\t'expo-splash-screen': '~55.0.0',\n\t\t\t'expo-status-bar': '~55.0.0',\n\t\t\tnativewind: '~4.2.0',\n\t\t\treact: '19.2.0',\n\t\t\t'react-dom': '19.2.0',\n\t\t\t'react-native': '0.83.6',\n\t\t\t'react-native-gesture-handler': '~2.30.0',\n\t\t\t'react-native-reanimated': '~4.2.0',\n\t\t\t'react-native-safe-area-context': '~5.6.0',\n\t\t\t'react-native-screens': '~4.23.0',\n\t\t\t'react-native-web': '~0.21.0',\n\t\t\ttailwindcss: '~3.4.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@babel/core': '^7.25.0',\n\t\t\t'@types/react': '~19.0.0',\n\t\t\ttypescript: '~5.8.2',\n\t\t},\n\t};\n\n\tconst appConfig = `import type { ConfigContext, ExpoConfig } from '@expo/config';\n\n/**\n * Expo runtime config. Public env vars (\\`EXPO_PUBLIC_*\\`) are inlined\n * at build time; everything else is read at runtime from \\`extra\\`.\n */\nexport default function config(_context: ConfigContext): ExpoConfig {\n  return {\n    name: '${options.name}',\n    slug: '${slug}',\n    version: '0.0.1',\n    orientation: 'portrait',\n    icon: './assets/icon.png',\n    scheme: '${scheme}',\n    userInterfaceStyle: 'automatic',\n    newArchEnabled: true,\n    ios: {\n      supportsTablet: true,\n      bundleIdentifier: '${bundleId}',\n    },\n    android: {\n      package: '${bundleId}',\n      adaptiveIcon: {\n        foregroundImage: './assets/adaptive-icon.png',\n        backgroundColor: '#ffffff',\n      },\n      edgeToEdgeEnabled: true,\n    },\n    web: {\n      output: 'static',\n    },\n    plugins: [\n      'expo-router',\n      'expo-secure-store',\n      [\n        'expo-splash-screen',\n        {\n          image: './assets/splash.png',\n          imageWidth: 200,\n          resizeMode: 'contain',\n          backgroundColor: '#ffffff',\n        },\n      ],\n    ],\n    experiments: {\n      typedRoutes: true,\n    },\n  };\n}\n`;\n\n\tconst easJson = {\n\t\tcli: {\n\t\t\tversion: '>= 10.2.1',\n\t\t\tappVersionSource: 'remote',\n\t\t},\n\t\tbuild: {\n\t\t\tdev: {\n\t\t\t\tdevelopmentClient: true,\n\t\t\t\tdistribution: 'internal',\n\t\t\t\tenvironment: 'development',\n\t\t\t\tenv: {\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'http://localhost:3000',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'http://localhost:3002',\n\t\t\t\t},\n\t\t\t},\n\t\t\tpreview: {\n\t\t\t\tdistribution: 'internal',\n\t\t\t\tenvironment: 'preview',\n\t\t\t\tenv: {\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t\tproduction: {\n\t\t\t\tautoIncrement: true,\n\t\t\t\tenvironment: 'production',\n\t\t\t\tenv: {\n\t\t\t\t\tEXPO_PUBLIC_API_URL: 'https://api.example.com',\n\t\t\t\t\tEXPO_PUBLIC_AUTH_URL: 'https://auth.example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n\n\tconst babelConfig = `module.exports = function (api) {\n  api.cache(true);\n  return {\n    presets: [\n      ['babel-preset-expo', { jsxImportSource: 'nativewind' }],\n      'nativewind/babel',\n    ],\n  };\n};\n`;\n\n\tconst metroConfig = `const { getDefaultConfig } = require('expo/metro-config');\nconst { withNativeWind } = require('nativewind/metro');\n\nconst config = getDefaultConfig(__dirname);\n\nmodule.exports = withNativeWind(config, { input: './global.css' });\n`;\n\n\tconst tsConfig = {\n\t\textends: 'expo/tsconfig.base',\n\t\tcompilerOptions: {\n\t\t\tstrict: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\ttypes: ['nativewind/types'],\n\t\t\tpaths: {\n\t\t\t\t'@/*': ['./*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t[`${apiPackage}/client`]: ['../../apps/api/.gkm/openapi.ts'],\n\t\t\t},\n\t\t},\n\t\tinclude: [\n\t\t\t'**/*.ts',\n\t\t\t'**/*.tsx',\n\t\t\t'.expo/types/**/*.ts',\n\t\t\t'expo-env.d.ts',\n\t\t\t'nativewind-env.d.ts',\n\t\t],\n\t};\n\n\tconst tailwindConfig = `import type { Config } from 'tailwindcss';\n\nexport default {\n  content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],\n  presets: [require('nativewind/preset')],\n  theme: {\n    extend: {},\n  },\n  plugins: [],\n} satisfies Config;\n`;\n\n\tconst globalCss = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`;\n\n\tconst expoEnvDts = `/// <reference types=\"expo/types\" />\\n`;\n\n\tconst nativewindEnvDts = `/// <reference types=\"nativewind/types\" />\\n`;\n\n\tconst configTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n/**\n * Public app config. EXPO_PUBLIC_* vars are inlined into the bundle at\n * build time, so they're safe to read in client code.\n */\nconst envParser = new EnvironmentParser({\n  EXPO_PUBLIC_API_URL: process.env.EXPO_PUBLIC_API_URL,\n  EXPO_PUBLIC_AUTH_URL: process.env.EXPO_PUBLIC_AUTH_URL,\n});\n\nexport const config = envParser\n  .create((get) => ({\n    apiUrl: get('EXPO_PUBLIC_API_URL').string(),\n    authUrl: get('EXPO_PUBLIC_AUTH_URL').string(),\n  }))\n  .parse();\n`;\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nexport const queryClient = new QueryClient({\n  defaultOptions: {\n    queries: {\n      staleTime: 60 * 1000,\n    },\n  },\n});\n`;\n\n\tconst authClientTs = `import { expoClient } from '@better-auth/expo/client';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport * as SecureStore from 'expo-secure-store';\n\nimport { config } from '@/config.ts';\n\nexport const STORAGE_PREFIX = '${scheme}';\nexport const COOKIE_STORE_KEY = \\`\\${STORAGE_PREFIX}_cookie\\`;\n\nexport const authClient = createAuthClient({\n  baseURL: config.authUrl,\n  plugins: [\n    expoClient({\n      scheme: '${scheme}',\n      storagePrefix: STORAGE_PREFIX,\n      storage: SecureStore,\n    }),\n    magicLinkClient(),\n  ],\n});\n\nexport const { signIn, useSession } = authClient;\n\nexport async function signOut() {\n  try {\n    await authClient.signOut();\n  } finally {\n    await SecureStore.deleteItemAsync(COOKIE_STORE_KEY);\n  }\n}\n`;\n\n\tconst apiTs = `import { createApi } from '${apiPackage}/client';\n\nimport { config } from '@/config.ts';\nimport { authClient } from './auth-client.ts';\nimport { queryClient } from './query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n  return createApi({\n    baseURL: config.apiUrl,\n    queryClient,\n    headers: options?.headers,\n    onRequest: (cfg) => {\n      const cookie = authClient.getCookie();\n      const next = { ...cfg, credentials: 'omit' as const };\n      if (cookie) {\n        return {\n          ...next,\n          headers: { ...(next.headers ?? {}), Cookie: cookie },\n        };\n      }\n      return next;\n    },\n  });\n}\n`;\n\n\tconst apiContextTsx = `import { createContext, type ReactNode, use } from 'react';\nimport type { createAppApi } from './api.ts';\n\nexport type Api = ReturnType<typeof createAppApi>;\n\nconst ApiContext = createContext<Api | null>(null);\n\nexport function ApiProvider({\n  api,\n  children,\n}: {\n  api: Api;\n  children: ReactNode;\n}) {\n  return <ApiContext.Provider value={api}>{children}</ApiContext.Provider>;\n}\n\nexport function useApi(): Api {\n  const api = use(ApiContext);\n  if (!api) {\n    throw new Error('useApi must be used within an ApiProvider');\n  }\n  return api;\n}\n`;\n\n\tconst layoutTsx = `import '../global.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { Stack, useRouter, useSegments } from 'expo-router';\nimport { StatusBar } from 'expo-status-bar';\nimport { useEffect, useMemo } from 'react';\nimport 'react-native-reanimated';\n\nimport { authClient } from '@/lib/auth-client.ts';\nimport { ApiProvider } from '@/lib/api-context.tsx';\nimport { createAppApi } from '@/lib/api.ts';\nimport { queryClient } from '@/lib/query-client.ts';\n\nfunction AuthGate({ children }: { children: React.ReactNode }) {\n  const router = useRouter();\n  const segments = useSegments();\n  const { data: session, isPending } = authClient.useSession();\n\n  useEffect(() => {\n    if (isPending) return;\n    const onAuthRoute = segments[0] === 'login';\n    if (!session && !onAuthRoute) {\n      router.replace('/login');\n    } else if (session && onAuthRoute) {\n      router.replace('/');\n    }\n  }, [isPending, session, segments, router]);\n\n  return <>{children}</>;\n}\n\nexport default function RootLayout() {\n  const api = useMemo(() => createAppApi(), []);\n\n  return (\n    <QueryClientProvider client={queryClient}>\n      <ApiProvider api={api}>\n        <AuthGate>\n          <Stack screenOptions={{ headerShown: false }}>\n            <Stack.Screen name=\"index\" />\n            <Stack.Screen name=\"login\" />\n          </Stack>\n        </AuthGate>\n        <StatusBar style=\"auto\" />\n      </ApiProvider>\n    </QueryClientProvider>\n  );\n}\n`;\n\n\tconst indexTsx = `import { Pressable, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { signOut, useSession } from '@/lib/auth-client.ts';\nimport { useApi } from '@/lib/api-context.tsx';\n\nexport default function Home() {\n  const { data: session } = useSession();\n  const api = useApi();\n  const { data: health } = api.useQuery('GET /health', {});\n\n  return (\n    <SafeAreaView className=\"flex-1 bg-white\">\n      <View className=\"flex-1 items-center justify-center gap-4 px-6\">\n        <Text className=\"text-3xl font-bold text-slate-900\">\n          Welcome to ${options.name}\n        </Text>\n        {session ? (\n          <Text className=\"text-sm text-slate-500\">\n            Signed in as {session.user.email}\n          </Text>\n        ) : null}\n        {health ? (\n          <Text className=\"text-xs text-slate-400\">\n            API: {JSON.stringify(health)}\n          </Text>\n        ) : null}\n        <Pressable\n          onPress={signOut}\n          className=\"mt-4 rounded-lg bg-slate-900 px-6 py-3\"\n        >\n          <Text className=\"font-semibold text-white\">Sign out</Text>\n        </Pressable>\n      </View>\n    </SafeAreaView>\n  );\n}\n`;\n\n\tconst loginTsx = `import * as Linking from 'expo-linking';\nimport { useState } from 'react';\nimport {\n  KeyboardAvoidingView,\n  Platform,\n  Pressable,\n  Text,\n  TextInput,\n  View,\n} from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\n\nimport { authClient } from '@/lib/auth-client.ts';\n\nconst EMAIL_RE = /^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$/;\n\nexport default function LoginScreen() {\n  const [email, setEmail] = useState('');\n  const [submitting, setSubmitting] = useState(false);\n  const [sent, setSent] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  async function handleSubmit() {\n    if (!EMAIL_RE.test(email.trim())) {\n      setError('Enter a valid email address');\n      return;\n    }\n    setError(null);\n    setSubmitting(true);\n\n    const callbackURL = Linking.createURL('/').replace(/^(\\\\w+):\\\\/\\\\/\\\\//, '$1://');\n    try {\n      const result = await authClient.signIn.magicLink({\n        email: email.trim(),\n        callbackURL,\n      });\n      if (result.error) {\n        setError(result.error.message ?? 'Could not send magic link');\n        return;\n      }\n      setSent(true);\n    } catch (err) {\n      setError(err instanceof Error ? err.message : 'Something went wrong');\n    } finally {\n      setSubmitting(false);\n    }\n  }\n\n  if (sent) {\n    return (\n      <SafeAreaView className=\"flex-1 bg-white\">\n        <View className=\"flex-1 items-center justify-center px-6\">\n          <Text className=\"text-2xl font-bold text-slate-900\">\n            Check your inbox\n          </Text>\n          <Text className=\"mt-3 text-center text-slate-500\">\n            We sent a sign-in link to {email.trim()}\n          </Text>\n        </View>\n      </SafeAreaView>\n    );\n  }\n\n  return (\n    <SafeAreaView className=\"flex-1 bg-white\">\n      <KeyboardAvoidingView\n        behavior={Platform.OS === 'ios' ? 'padding' : undefined}\n        className=\"flex-1\"\n      >\n        <View className=\"flex-1 justify-center px-6\">\n          <Text className=\"text-3xl font-bold text-slate-900\">Sign in</Text>\n          <Text className=\"mt-1 text-sm text-slate-500\">\n            We'll email you a one-time sign-in link.\n          </Text>\n\n          <Text className=\"mt-6 text-xs font-semibold uppercase text-slate-500\">\n            Email\n          </Text>\n          <TextInput\n            value={email}\n            onChangeText={(v) => {\n              setEmail(v);\n              if (error) setError(null);\n            }}\n            autoCapitalize=\"none\"\n            autoCorrect={false}\n            keyboardType=\"email-address\"\n            placeholder=\"you@example.com\"\n            placeholderTextColor=\"#94a3b8\"\n            editable={!submitting}\n            className=\"mt-2 rounded-lg border border-slate-300 px-4 py-3\"\n          />\n          {error ? (\n            <Text className=\"mt-2 text-sm text-red-600\">{error}</Text>\n          ) : null}\n\n          <Pressable\n            onPress={handleSubmit}\n            disabled={submitting}\n            className=\"mt-6 items-center rounded-lg bg-slate-900 py-4 disabled:opacity-60\"\n          >\n            <Text className=\"font-semibold text-white\">\n              {submitting ? 'Sending…' : 'Email me a sign-in link'}\n            </Text>\n          </Pressable>\n        </View>\n      </KeyboardAvoidingView>\n    </SafeAreaView>\n  );\n}\n`;\n\n\tconst gitignore = `node_modules/\n.expo/\ndist/\n*.log\n.env*.local\nios/\nandroid/\n.eas/\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/app/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/app.config.ts', content: appConfig },\n\t\t{\n\t\t\tpath: 'apps/app/eas.json',\n\t\t\tcontent: `${JSON.stringify(easJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/babel.config.js', content: babelConfig },\n\t\t{ path: 'apps/app/metro.config.js', content: metroConfig },\n\t\t{\n\t\t\tpath: 'apps/app/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/app/tailwind.config.ts', content: tailwindConfig },\n\t\t{ path: 'apps/app/global.css', content: globalCss },\n\t\t{ path: 'apps/app/expo-env.d.ts', content: expoEnvDts },\n\t\t{ path: 'apps/app/nativewind-env.d.ts', content: nativewindEnvDts },\n\t\t{ path: 'apps/app/config.ts', content: configTs },\n\t\t{ path: 'apps/app/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/app/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/app/lib/api.ts', content: apiTs },\n\t\t{ path: 'apps/app/lib/api-context.tsx', content: apiContextTsx },\n\t\t{ path: 'apps/app/app/_layout.tsx', content: layoutTsx },\n\t\t{ path: 'apps/app/app/index.tsx', content: indexTsx },\n\t\t{ path: 'apps/app/app/login.tsx', content: loginTsx },\n\t\t{ path: 'apps/app/.gitignore', content: gitignore },\n\t];\n}\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/**\n * Generate packages/models for shared Zod schemas (monorepo only)\n */\nexport function generateModelsPackage(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\t// Package name based on project name\n\tconst packageName = `@${options.name}/models`;\n\n\t// package.json for models\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\texports: {\n\t\t\t'./*': './src/*.ts',\n\t\t},\n\t\tscripts: {\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {},\n\t\tdevDependencies: {\n\t\t\ttypescript: '~5.8.2',\n\t\t},\n\t};\n\n\t// tsconfig.json for models - extends root config\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t},\n\t\tinclude: ['src/**/*.ts'],\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// common.ts - shared utility schemas\n\tconst commonTs = `import { z } from 'zod';\n\n// ============================================\n// Common Schemas\n// ============================================\n\nexport const IdSchema = z.uuid();\n\nexport const IdParamsSchema = z.object({\n  id: IdSchema,\n});\n\nexport const TimestampsSchema = z.object({\n  createdAt: z.coerce.date(),\n  updatedAt: z.coerce.date(),\n});\n\nexport const PaginationSchema = z.object({\n  page: z.coerce.number().int().positive().default(1),\n  limit: z.coerce.number().int().positive().max(100).default(20),\n});\n\nexport const PaginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>\n  z.object({\n    items: z.array(itemSchema),\n    total: z.number(),\n    page: z.number(),\n    limit: z.number(),\n    totalPages: z.number(),\n  });\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type Id = z.infer<typeof IdSchema>;\nexport type IdParams = z.infer<typeof IdParamsSchema>;\nexport type Timestamps = z.infer<typeof TimestampsSchema>;\nexport type Pagination = z.infer<typeof PaginationSchema>;\n`;\n\n\t// user.ts - user-related schemas\n\tconst userTs = `import { z } from 'zod';\nimport { IdSchema, TimestampsSchema } from './common.ts';\n\n// ============================================\n// User Schemas\n// ============================================\n\nexport const UserSchema = z.object({\n  id: IdSchema,\n  email: z.string().email(),\n  name: z.string().min(1).max(100),\n  ...TimestampsSchema.shape,\n});\n\nexport const CreateUserSchema = UserSchema.omit({\n  id: true,\n  createdAt: true,\n  updatedAt: true,\n});\n\nexport const UpdateUserSchema = CreateUserSchema.partial();\n\n// ============================================\n// Response Schemas\n// ============================================\n\nexport const UserResponseSchema = UserSchema.pick({\n  id: true,\n  name: true,\n  email: true,\n});\n\nexport const ListUsersResponseSchema = z.object({\n  users: z.array(UserSchema.pick({ id: true, name: true })),\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\nexport type User = z.infer<typeof UserSchema>;\nexport type CreateUser = z.infer<typeof CreateUserSchema>;\nexport type UpdateUser = z.infer<typeof UpdateUserSchema>;\nexport type UserResponse = z.infer<typeof UserResponseSchema>;\nexport type ListUsersResponse = z.infer<typeof ListUsersResponseSchema>;\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'packages/models/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/common.ts',\n\t\t\tcontent: commonTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/models/src/user.ts',\n\t\t\tcontent: userTs,\n\t\t},\n\t];\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate monorepo root files (pnpm-workspace.yaml, root package.json, etc.)\n */\nexport function generateMonorepoFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.monorepo) {\n\t\treturn [];\n\t}\n\n\tconst isFullstack = options.template === 'fullstack';\n\n\t// Root package.json for monorepo\n\tconst rootPackageJson = {\n\t\tname: options.name,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tpackageManager: 'pnpm@10.13.1',\n\t\tscripts: {\n\t\t\tdev: isFullstack ? 'gkm dev' : 'turbo dev',\n\t\t\tbuild: isFullstack ? 'gkm build' : 'turbo build',\n\t\t\ttest: isFullstack ? 'gkm test' : 'turbo test',\n\t\t\t'test:once': isFullstack ? 'gkm test --run' : 'turbo test:once',\n\t\t\ttypecheck: 'turbo typecheck',\n\t\t\tlint: 'biome lint .',\n\t\t\tfmt: 'biome format . --write',\n\t\t\t'fmt:check': 'biome format .',\n\t\t\t...(isFullstack\n\t\t\t\t? { storybook: 'pnpm --filter ./packages/ui storybook' }\n\t\t\t\t: {}),\n\t\t\t...(options.deployTarget === 'dokploy'\n\t\t\t\t? { deploy: 'gkm deploy --provider dokploy --stage production' }\n\t\t\t\t: {}),\n\t\t},\n\t\tdependencies: {\n\t\t\tzod: '~4.1.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@biomejs/biome': '~2.3.0',\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\tesbuild: '~0.27.0',\n\t\t\ttsx: '~4.20.0',\n\t\t\tturbo: '~2.3.0',\n\t\t\ttypescript: '~5.8.2',\n\t\t\tvitest: '~4.0.0',\n\t\t},\n\t};\n\n\t// pnpm-workspace.yaml - detect folder structure from apiPath\n\tconst apiPathParts = options.apiPath.split('/');\n\tconst appsFolder = apiPathParts[0] || 'apps';\n\n\tconst pnpmWorkspace = `packages:\n  - '${appsFolder}/*'\n  - 'packages/*'\n`;\n\n\t// Root biome.json\n\tconst biomeConfig = {\n\t\t$schema: 'https://biomejs.dev/schemas/2.3.0/schema.json',\n\t\tvcs: {\n\t\t\tenabled: true,\n\t\t\tclientKind: 'git',\n\t\t\tuseIgnoreFile: true,\n\t\t},\n\t\torganizeImports: {\n\t\t\tenabled: true,\n\t\t},\n\t\tformatter: {\n\t\t\tenabled: true,\n\t\t\tindentStyle: 'space',\n\t\t\tindentWidth: 2,\n\t\t\tlineWidth: 80,\n\t\t},\n\t\tjavascript: {\n\t\t\tformatter: {\n\t\t\t\tquoteStyle: 'single',\n\t\t\t\ttrailingCommas: 'all',\n\t\t\t\tsemicolons: 'always',\n\t\t\t\tarrowParentheses: 'always',\n\t\t\t},\n\t\t},\n\t\tlinter: {\n\t\t\tenabled: true,\n\t\t\trules: {\n\t\t\t\trecommended: true,\n\t\t\t\tcorrectness: {\n\t\t\t\t\tnoUnusedImports: 'error',\n\t\t\t\t\tnoUnusedVariables: 'error',\n\t\t\t\t},\n\t\t\t\tstyle: {\n\t\t\t\t\tnoNonNullAssertion: 'off',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tfiles: {\n\t\t\tignore: ['node_modules', 'dist', '.gkm', 'coverage'],\n\t\t},\n\t};\n\n\t// Root turbo.json\n\tconst turboConfig = {\n\t\t$schema: 'https://turbo.build/schema.json',\n\t\ttasks: {\n\t\t\tbuild: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['dist/**'],\n\t\t\t},\n\t\t\tdev: {\n\t\t\t\tcache: false,\n\t\t\t\tpersistent: true,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\tcache: false,\n\t\t\t},\n\t\t\t'test:once': {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: ['coverage/**'],\n\t\t\t},\n\t\t\ttypecheck: {\n\t\t\t\tdependsOn: ['^build'],\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tlint: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t\tfmt: {\n\t\t\t\toutputs: [],\n\t\t\t},\n\t\t},\n\t};\n\n\t// Root .gitignore\n\tconst gitignore = `# Dependencies\nnode_modules/\n\n# Build output\ndist/\n.gkm/\n\n# Environment\n.env\n.env.local\n.env.*.local\ndocker/.env\n\n# IDE\n.idea/\n*.swp\n*.swo\n\n# OS\n.DS_Store\nThumbs.db\n\n# Logs\n*.log\nnpm-debug.log*\nyarn-debug.log*\npnpm-debug.log*\n\n# Test coverage\ncoverage/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Turbo\n.turbo/\n`;\n\n\t// Root tsconfig.json - base config for all packages\n\t// Using turbo typecheck to run tsc --noEmit in each app/package\n\tconst tsConfig = {\n\t\tcompilerOptions: {\n\t\t\ttarget: 'ES2022',\n\t\t\tmodule: 'NodeNext',\n\t\t\tmoduleResolution: 'NodeNext',\n\t\t\tlib: ['ES2022'],\n\t\t\tstrict: true,\n\t\t\tesModuleInterop: true,\n\t\t\tskipLibCheck: true,\n\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\tresolveJsonModule: true,\n\t\t},\n\t\texclude: ['node_modules', 'dist'],\n\t};\n\n\t// Vitest config for workspace\n\tconst vitestConfig = `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: 'node',\n    include: ['apps/**/*.{test,spec}.ts', 'packages/**/*.{test,spec}.ts'],\n    exclude: ['**/node_modules/**', '**/dist/**'],\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'json', 'html'],\n      exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts'],\n    },\n  },\n});\n`;\n\n\t// VSCode settings for consistent development experience\n\tconst vscodeSettings = {\n\t\t'search.exclude': {\n\t\t\t'**/.sst': true,\n\t\t\t'**/.gkm': true,\n\t\t\t'**/.turbo': true,\n\t\t},\n\t\t'editor.formatOnSave': true,\n\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t'editor.codeActionsOnSave': {\n\t\t\t'source.fixAll.biome': 'always',\n\t\t\t'source.organizeImports.biome': 'always',\n\t\t\t'source.organizeImports': 'always',\n\t\t},\n\t\t'[typescriptreact]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[typescript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[javascript]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'[json]': {\n\t\t\t'editor.defaultFormatter': 'biomejs.biome',\n\t\t},\n\t\t'cSpell.words': [\n\t\t\t'betterauth',\n\t\t\t'dokploy',\n\t\t\t'envkit',\n\t\t\t'geekmidas',\n\t\t\t'healthcheck',\n\t\t\t'kysely',\n\t\t\t'testkit',\n\t\t\t'timestamptz',\n\t\t\t'turborepo',\n\t\t\toptions.name,\n\t\t],\n\t};\n\n\t// VSCode extensions recommendations\n\tconst vscodeExtensions = {\n\t\trecommendations: [\n\t\t\t'biomejs.biome',\n\t\t\t'streetsidesoftware.code-spell-checker',\n\t\t\t'dbaeumer.vscode-eslint',\n\t\t\t'ms-azuretools.vscode-docker',\n\t\t],\n\t};\n\n\tconst files: GeneratedFile[] = [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(rootPackageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'pnpm-workspace.yaml',\n\t\t\tcontent: pnpmWorkspace,\n\t\t},\n\t\t{\n\t\t\tpath: 'tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'biome.json',\n\t\t\tcontent: `${JSON.stringify(biomeConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'turbo.json',\n\t\t\tcontent: `${JSON.stringify(turboConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'vitest.config.ts',\n\t\t\tcontent: vitestConfig,\n\t\t},\n\t\t{\n\t\t\tpath: '.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/settings.json',\n\t\t\tcontent: `${JSON.stringify(vscodeSettings, null, '\\t')}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: '.vscode/extensions.json',\n\t\t\tcontent: `${JSON.stringify(vscodeExtensions, null, '\\t')}\\n`,\n\t\t},\n\t];\n\n\t// Add workspace config for fullstack template\n\tif (isFullstack) {\n\t\tfiles.push({\n\t\t\tpath: 'gkm.config.ts',\n\t\t\tcontent: generateWorkspaceConfig(options),\n\t\t});\n\t}\n\n\treturn files;\n}\n\n/**\n * Generate the frontend app entry for the workspace config based on the\n * selected `frontendFramework`. Defaults to Next.js for backwards compat.\n */\nfunction generateFrontendAppEntry(options: TemplateOptions): string {\n\tswitch (options.frontendFramework) {\n\t\tcase 'tanstack-start':\n\t\t\treturn `web: {\n      type: 'web',\n      framework: 'tanstack-start',\n      path: 'apps/web',\n      port: 3001,\n      dependencies: ['api', 'auth'],\n      config: {\n        client: './src/config/client.ts',\n        server: './src/config/server.ts',\n      },\n    },`;\n\t\tcase 'expo':\n\t\t\treturn `app: {\n      type: 'mobile',\n      framework: 'expo',\n      path: 'apps/app',\n      port: 8081,\n      dependencies: ['api', 'auth'],\n    },`;\n\t\tdefault:\n\t\t\treturn `web: {\n      type: 'web',\n      framework: 'nextjs',\n      path: 'apps/web',\n      port: 3001,\n      dependencies: ['api', 'auth'],\n      config: {\n        client: './src/config/client.ts',\n        server: './src/config/server.ts',\n      },\n    },`;\n\t}\n}\n\n/**\n * Generate gkm.config.ts with defineWorkspace for fullstack template\n */\nfunction generateWorkspaceConfig(options: TemplateOptions): string {\n\tconst { telescope, services, deployTarget, routesStructure } = options;\n\n\t// Get routes glob pattern\n\tconst getRoutesGlob = (): string => {\n\t\tswitch (routesStructure) {\n\t\t\tcase 'centralized-endpoints':\n\t\t\t\treturn './src/endpoints/**/*.ts';\n\t\t\tcase 'centralized-routes':\n\t\t\t\treturn './src/routes/**/*.ts';\n\t\t\tcase 'domain-based':\n\t\t\t\treturn './src/**/routes/*.ts';\n\t\t}\n\t};\n\n\tlet config = `import { defineWorkspace } from '@geekmidas/cli/config';\n\nexport default defineWorkspace({\n  name: '${options.name}',\n  apps: {\n    api: {\n      type: 'backend',\n      path: 'apps/api',\n      port: 3000,\n      routes: '${getRoutesGlob()}',\n      envParser: './src/config/env#envParser',\n      logger: './src/config/logger#logger',\n      dependencies: ['auth'],`;\n\n\tif (telescope) {\n\t\tconfig += `\n      telescope: {\n        enabled: true,\n        path: '/__telescope',\n      },`;\n\t}\n\n\tconfig += `\n      openapi: {\n        enabled: true,\n      },\n    },\n    auth: {\n      type: 'backend',\n      path: 'apps/auth',\n      port: 3002,\n      entry: './src/index.ts',\n      framework: 'better-auth',\n      envParser: './src/config/env#envParser',\n      logger: './src/config/logger#logger',\n    },\n    ${generateFrontendAppEntry(options)}\n  },\n  shared: {\n    packages: ['packages/*'],\n    models: {\n      path: 'packages/models',\n      schema: 'zod',\n    },\n  },`;\n\n\t// Add services if any are selected\n\tif (\n\t\tservices.db ||\n\t\tservices.cache ||\n\t\tservices.mail ||\n\t\tservices.storage ||\n\t\tservices.events\n\t) {\n\t\tconfig += `\n  services: {`;\n\t\tif (services.db) {\n\t\t\tconfig += `\n    db: true,`;\n\t\t}\n\t\tif (services.cache) {\n\t\t\tconfig += `\n    cache: true,`;\n\t\t}\n\t\tif (services.mail) {\n\t\t\tconfig += `\n    mail: true,`;\n\t\t}\n\t\tif (services.storage) {\n\t\t\tconfig += `\n    storage: true,`;\n\t\t}\n\t\tif (services.events) {\n\t\t\tconfig += `\n    events: '${services.events}',`;\n\t\t}\n\t\tconfig += `\n  },`;\n\t}\n\n\t// Add deploy config if dokploy is selected\n\tif (deployTarget === 'dokploy') {\n\t\tconfig += `\n  deploy: {\n    default: 'dokploy',\n  },`;\n\t}\n\n\t// Always enable secrets for workspace dev environment\n\tconfig += `\n  secrets: {\n    enabled: true,\n  },`;\n\n\tconfig += `\n});\n`;\n\n\treturn config;\n}\n","import { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const apiTemplate: TemplateConfig = {\n\tname: 'api',\n\tdescription: 'Full API with auth, database, services',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@geekmidas/services': GEEKMIDAS_VERSIONS['@geekmidas/services'],\n\t\t'@geekmidas/errors': GEEKMIDAS_VERSIONS['@geekmidas/errors'],\n\t\t'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],\n\t\t'@hono/node-server': '~1.14.1',\n\t\thono: '~4.8.2',\n\t\tpino: '~9.6.0',\n\t\tzod: '~4.1.0',\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': '~2.3.0',\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': '~22.0.0',\n\t\tesbuild: '~0.27.0',\n\t\ttsx: '~4.20.0',\n\t\tturbo: '~2.3.0',\n\t\ttypescript: '~5.8.2',\n\t\tvitest: '~4.0.0',\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure, monorepo, name } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Models package import path for monorepo\n\t\tconst modelsImport = monorepo ? `@${name}/models` : null;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based': {\n\t\t\t\t\tconst parts = file.split('/');\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t\t\t}\n\t\t\t\t\treturn `src/${parts[0]}/routes/${parts.slice(1).join('/')}`;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n  .create((get) => ({\n    nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n    stage: get('STAGE').enum(['development', 'staging', 'production']).default('development'),\n  }))\n  .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: monorepo\n\t\t\t\t\t? `import { z } from 'zod';\nimport { publicRouter } from '~/router.ts';\n\nexport const healthEndpoint = publicRouter\n  .get('/health')\n  .output(z.object({\n    status: z.string(),\n    timestamp: z.string(),\n  }))\n  .handle(async () => ({\n    status: 'ok',\n    timestamp: new Date().toISOString(),\n  }));\n`\n\t\t\t\t\t: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nexport const healthEndpoint = e\n  .get('/health')\n  .output(z.object({\n    status: z.string(),\n    timestamp: z.string(),\n  }))\n  .handle(async () => ({\n    status: 'ok',\n    timestamp: new Date().toISOString(),\n  }));\n`,\n\t\t\t},\n\n\t\t\t// users endpoints\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/list.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { e } from '@geekmidas/constructs/endpoints';\nimport { ListUsersResponseSchema } from '${modelsImport}/user';\n\nexport const listUsersEndpoint = e\n  .get('/users')\n  .output(ListUsersResponseSchema)\n  .handle(async () => ({\n    users: [\n      { id: '550e8400-e29b-41d4-a716-446655440001', name: 'Alice' },\n      { id: '550e8400-e29b-41d4-a716-446655440002', name: 'Bob' },\n    ],\n  }));\n`\n\t\t\t\t\t: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nconst UserSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n});\n\nexport const listUsersEndpoint = e\n  .get('/users')\n  .output(z.object({\n    users: z.array(UserSchema),\n  }))\n  .handle(async () => ({\n    users: [\n      { id: '1', name: 'Alice' },\n      { id: '2', name: 'Bob' },\n    ],\n  }));\n`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: getRoutePath('users/get.ts'),\n\t\t\t\tcontent: modelsImport\n\t\t\t\t\t? `import { e } from '@geekmidas/constructs/endpoints';\nimport { IdParamsSchema } from '${modelsImport}/common';\nimport { UserResponseSchema } from '${modelsImport}/user';\n\nexport const getUserEndpoint = e\n  .get('/users/:id')\n  .params(IdParamsSchema)\n  .output(UserResponseSchema)\n  .handle(async ({ params }) => ({\n    id: params.id,\n    name: 'Alice',\n    email: 'alice@example.com',\n  }));\n`\n\t\t\t\t\t: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nexport const getUserEndpoint = e\n  .get('/users/:id')\n  .params(z.object({ id: z.string() }))\n  .output(z.object({\n    id: z.string(),\n    name: z.string(),\n    email: z.string().email(),\n  }))\n  .handle(async ({ params }) => ({\n    id: params.id,\n    name: 'Alice',\n    email: 'alice@example.com',\n  }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// Add auth service for monorepo (calls auth app for session)\n\t\tif (options.monorepo) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/services/auth.ts',\n\t\t\t\tcontent: `import type { Service, ServiceRegisterOptions } from '@geekmidas/services';\n\nexport interface Session {\n  user: {\n    id: string;\n    email: string;\n    name: string;\n  };\n}\n\nexport interface AuthClient {\n  getSession: (cookie: string) => Promise<Session | null>;\n}\n\nexport const authService = {\n  serviceName: 'auth' as const,\n  async register({ envParser, context }: ServiceRegisterOptions) {\n    const logger = context.getLogger();\n\n    const config = envParser\n      .create((get) => ({\n        url: get('AUTH_URL').string(),\n      }))\n      .parse();\n\n    logger.info({ authUrl: config.url }, 'Auth service configured');\n\n    return {\n      getSession: async (cookie: string): Promise<Session | null> => {\n        const res = await fetch(\\`\\${config.url}/api/auth/get-session\\`, {\n          headers: { cookie },\n        });\n        if (!res.ok) return null;\n        return res.json();\n      },\n    };\n  },\n} satisfies Service<'auth', AuthClient>;\n`,\n\t\t\t});\n\n\t\t\t// Add router with session\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/router.ts',\n\t\t\t\tcontent: `import { e } from '@geekmidas/constructs/endpoints';\nimport { UnauthorizedError } from '@geekmidas/errors';\nimport { authService, type Session } from './services/auth.ts';\nimport { logger } from './config/logger.ts';\n\n// Public router - no auth required\nexport const publicRouter = e.logger(logger);\n\n// Router with auth service available (but session not enforced)\nexport const r = publicRouter.services([authService]);\n\n// Session router - requires active session, throws if not authenticated\nexport const sessionRouter = r.session<Session>(async ({ services, header }) => {\n  const cookie = header('cookie') || '';\n  const session = await services.auth.getSession(cookie);\n\n  if (!session?.user) {\n    throw new UnauthorizedError('No active session');\n  }\n\n  return session;\n});\n`,\n\t\t\t});\n\n\t\t\t// Add protected endpoint example\n\t\t\tfiles.push({\n\t\t\t\tpath: getRoutePath('profile.ts'),\n\t\t\t\tcontent: `import { z } from 'zod';\nimport { sessionRouter } from '~/router.ts';\n\nexport const profileEndpoint = sessionRouter\n  .get('/profile')\n  .output(z.object({\n    id: z.string(),\n    email: z.string(),\n    name: z.string(),\n  }))\n  .handle(async ({ session }) => session.user);\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add database service if enabled\n\t\tif (options.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/services/database.ts',\n\t\t\t\tcontent: `import type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\n\n// Define your database schema\nexport interface Database {\n  users: {\n    id: string;\n    name: string;\n    email: string;\n    created_at: Date;\n  };\n}\n\nexport const databaseService = {\n  serviceName: 'database' as const,\n  async register({ envParser, context }: ServiceRegisterOptions) {\n    const logger = context.getLogger();\n    logger.info('Connecting to database');\n\n    const config = envParser\n      .create((get) => ({\n        url: get('DATABASE_URL').string(),\n      }))\n      .parse();\n\n    const db = new Kysely<Database>({\n      dialect: new PostgresDialect({\n        pool: new pg.Pool({ connectionString: config.url }),\n      }),\n    });\n\n    logger.info('Database connection established');\n    return db;\n  },\n} satisfies Service<'database', Kysely<Database>>;\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n  storage: new InMemoryStorage({ maxEntries: 100 }),\n  enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Studio config if enabled (requires database)\n\t\tif (options.studio && options.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/studio.ts',\n\t\t\t\tcontent: `import { Direction, InMemoryMonitoringStorage, Studio } from '@geekmidas/studio';\nimport { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\nimport type { Database } from '~/services/database.ts';\nimport { envParser } from '~/config/env.ts';\n\n// Parse database config for Studio\nconst studioConfig = envParser\n  .create((get) => ({\n    databaseUrl: get('DATABASE_URL').string(),\n  }))\n  .parse();\n\n// Create a Kysely instance for Studio\nconst db = new Kysely<Database>({\n  dialect: new PostgresDialect({\n    pool: new pg.Pool({ connectionString: studioConfig.databaseUrl }),\n  }),\n});\n\nexport const studio = new Studio<Database>({\n  monitoring: {\n    storage: new InMemoryMonitoringStorage({ maxEntries: 100 }),\n  },\n  data: {\n    db,\n    cursor: { field: 'id', direction: Direction.Desc },\n  },\n  enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const minimalTemplate: TemplateConfig = {\n\tname: 'minimal',\n\tdescription: 'Basic health endpoint',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': '~1.14.1',\n\t\thono: '~4.8.2',\n\t\tpino: '~9.6.0',\n\t\tzod: '~4.1.0',\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': '~2.3.0',\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': '~22.0.0',\n\t\tesbuild: '~0.27.0',\n\t\ttsx: '~4.20.0',\n\t\tturbo: '~2.3.0',\n\t\ttypescript: '~5.8.2',\n\t\tvitest: '~4.0.0',\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n  .create((get) => ({\n    nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n    stage: get('STAGE').enum(['development', 'staging', 'production']).default('development'),\n  }))\n  .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nexport const healthEndpoint = e\n  .get('/health')\n  .output(z.object({\n    status: z.string(),\n    timestamp: z.string(),\n  }))\n  .handle(async () => ({\n    status: 'ok',\n    timestamp: new Date().toISOString(),\n  }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// Add database service if enabled\n\t\tif (options.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/services/database.ts',\n\t\t\t\tcontent: `import type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\n\n// Define your database schema\nexport interface Database {\n  // Add your tables here\n}\n\nexport const databaseService = {\n  serviceName: 'database' as const,\n  async register({ envParser, context }: ServiceRegisterOptions) {\n    const logger = context.getLogger();\n    logger.info('Connecting to database');\n\n    const config = envParser\n      .create((get) => ({\n        url: get('DATABASE_URL').string(),\n      }))\n      .parse();\n\n    const db = new Kysely<Database>({\n      dialect: new PostgresDialect({\n        pool: new pg.Pool({ connectionString: config.url }),\n      }),\n    });\n\n    logger.info('Database connection established');\n    return db;\n  },\n} satisfies Service<'database', Kysely<Database>>;\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n  storage: new InMemoryStorage({ maxEntries: 100 }),\n  enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\t// Add Studio config if enabled (requires database)\n\t\tif (options.studio && options.database) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/studio.ts',\n\t\t\t\tcontent: `import { Direction, InMemoryMonitoringStorage, Studio } from '@geekmidas/studio';\nimport { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\nimport type { Database } from '~/services/database.ts';\nimport { envParser } from '~/config/env.ts';\n\n// Parse database config for Studio\nconst studioConfig = envParser\n  .create((get) => ({\n    databaseUrl: get('DATABASE_URL').string(),\n  }))\n  .parse();\n\n// Create a Kysely instance for Studio\nconst db = new Kysely<Database>({\n  dialect: new PostgresDialect({\n    pool: new pg.Pool({ connectionString: studioConfig.databaseUrl }),\n  }),\n});\n\nexport const studio = new Studio<Database>({\n  monitoring: {\n    storage: new InMemoryMonitoringStorage({ maxEntries: 100 }),\n  },\n  data: {\n    db,\n    cursor: { field: 'id', direction: Direction.Desc },\n  },\n  enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const serverlessTemplate: TemplateConfig = {\n\tname: 'serverless',\n\tdescription: 'AWS Lambda handlers',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/cloud': GEEKMIDAS_VERSIONS['@geekmidas/cloud'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': '~1.14.1',\n\t\thono: '~4.8.2',\n\t\tpino: '~9.6.0',\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': '~2.3.0',\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/aws-lambda': '~8.10.92',\n\t\t'@types/node': '~22.0.0',\n\t\ttsx: '~4.20.0',\n\t\tturbo: '~2.3.0',\n\t\ttypescript: '~5.8.2',\n\t\tvitest: '~4.0.0',\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build --provider aws-apigatewayv2',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n  .create((get) => ({\n    nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n    stage: get('STAGE').enum(['dev', 'staging', 'prod']).default('dev'),\n  }))\n  .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nexport const healthEndpoint = e\n  .get('/health')\n  .output(z.object({\n    status: z.string(),\n    timestamp: z.string(),\n    region: z.string(),\n  }))\n  .handle(async () => ({\n    status: 'ok',\n    timestamp: new Date().toISOString(),\n    region: process.env.AWS_REGION || 'local',\n  }));\n`,\n\t\t\t},\n\n\t\t\t// src/functions/hello.ts\n\t\t\t{\n\t\t\t\tpath: 'src/functions/hello.ts',\n\t\t\t\tcontent: `import { f } from '@geekmidas/constructs/functions';\nimport { z } from 'zod';\n\nexport const helloFunction = f\n  .input(z.object({ name: z.string() }))\n  .output(z.object({ message: z.string() }))\n  .handle(async ({ input }) => ({\n    message: \\`Hello, \\${input.name}!\\`,\n  }));\n`,\n\t\t\t},\n\t\t];\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\n// Note: For production Lambda, consider using a persistent storage\nexport const telescope = new Telescope({\n  storage: new InMemoryStorage({ maxEntries: 50 }),\n  enabled: process.env.STAGE === 'dev',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { GEEKMIDAS_VERSIONS } from '../versions.js';\nimport type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from './index.js';\n\nexport const workerTemplate: TemplateConfig = {\n\tname: 'worker',\n\tdescription: 'Background job processing',\n\n\tdependencies: {\n\t\t'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],\n\t\t'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],\n\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],\n\t\t'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],\n\t\t'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],\n\t\t'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],\n\t\t'@hono/node-server': '~1.14.1',\n\t\thono: '~4.8.2',\n\t\tpino: '~9.6.0',\n\t},\n\n\tdevDependencies: {\n\t\t'@biomejs/biome': '~2.3.0',\n\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t'@types/node': '~22.0.0',\n\t\ttsx: '~4.20.0',\n\t\tturbo: '~2.3.0',\n\t\ttypescript: '~5.8.2',\n\t\tvitest: '~4.0.0',\n\t},\n\n\tscripts: {\n\t\tdev: 'gkm dev',\n\t\tbuild: 'gkm build',\n\t\ttest: 'vitest',\n\t\t'test:once': 'vitest run',\n\t\ttypecheck: 'tsc --noEmit',\n\t\tlint: 'biome lint .',\n\t\tfmt: 'biome format . --write',\n\t\t'fmt:check': 'biome format .',\n\t},\n\n\tfiles: (options: TemplateOptions): GeneratedFile[] => {\n\t\tconst { loggerType, routesStructure } = options;\n\n\t\tconst loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';\n\nexport const logger = createLogger();\n`;\n\n\t\t// Get route path based on structure\n\t\tconst getRoutePath = (file: string) => {\n\t\t\tswitch (routesStructure) {\n\t\t\t\tcase 'centralized-endpoints':\n\t\t\t\t\treturn `src/endpoints/${file}`;\n\t\t\t\tcase 'centralized-routes':\n\t\t\t\t\treturn `src/routes/${file}`;\n\t\t\t\tcase 'domain-based':\n\t\t\t\t\treturn `src/${file.replace('.ts', '')}/routes/index.ts`;\n\t\t\t}\n\t\t};\n\n\t\tconst files: GeneratedFile[] = [\n\t\t\t// src/config/env.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/env.ts',\n\t\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser({ ...process.env, ...Credentials });\n\n// Global config - only minimal shared values\n// Service-specific config should be parsed in each service\nexport const config = envParser\n  .create((get) => ({\n    nodeEnv: get('NODE_ENV').enum(['development', 'test', 'production']).default('development'),\n    stage: get('STAGE').enum(['development', 'staging', 'production']).default('development'),\n  }))\n  .parse();\n`,\n\t\t\t},\n\n\t\t\t// src/config/logger.ts\n\t\t\t{\n\t\t\t\tpath: 'src/config/logger.ts',\n\t\t\t\tcontent: loggerContent,\n\t\t\t},\n\n\t\t\t// health endpoint\n\t\t\t{\n\t\t\t\tpath: getRoutePath('health.ts'),\n\t\t\t\tcontent: `import { e } from '@geekmidas/constructs/endpoints';\nimport { z } from 'zod';\n\nexport const healthEndpoint = e\n  .get('/health')\n  .output(z.object({\n    status: z.string(),\n    timestamp: z.string(),\n  }))\n  .handle(async () => ({\n    status: 'ok',\n    timestamp: new Date().toISOString(),\n  }));\n`,\n\t\t\t},\n\n\t\t\t// src/events/types.ts\n\t\t\t{\n\t\t\t\tpath: 'src/events/types.ts',\n\t\t\t\tcontent: `import type { PublishableMessage } from '@geekmidas/events';\n\n// Define your event types here\nexport type AppEvents =\n  | PublishableMessage<'user.created', { userId: string; email: string }>\n  | PublishableMessage<'user.updated', { userId: string; changes: Record<string, unknown> }>\n  | PublishableMessage<'order.placed', { orderId: string; userId: string; total: number }>;\n`,\n\t\t\t},\n\n\t\t\t// src/events/publisher.ts\n\t\t\t{\n\t\t\t\tpath: 'src/events/publisher.ts',\n\t\t\t\tcontent: `import type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport { Publisher, type EventPublisher } from '@geekmidas/events';\nimport type { AppEvents } from './types.ts';\n\nexport const eventsPublisherService = {\n  serviceName: 'events' as const,\n  async register({ envParser, context }: ServiceRegisterOptions) {\n    const logger = context.getLogger();\n    logger.info('Connecting to message broker');\n\n    const config = envParser\n      .create((get) => ({\n        url: get('RABBITMQ_URL').string().default('amqp://localhost:5672'),\n      }))\n      .parse();\n\n    const publisher = await Publisher.fromConnectionString<AppEvents>(\n      \\`rabbitmq://\\${config.url.replace('amqp://', '')}?exchange=events\\`\n    );\n\n    logger.info('Message broker connection established');\n    return publisher;\n  },\n} satisfies Service<'events', EventPublisher<AppEvents>>;\n`,\n\t\t\t},\n\n\t\t\t// src/subscribers/user-events.ts\n\t\t\t{\n\t\t\t\tpath: 'src/subscribers/user-events.ts',\n\t\t\t\tcontent: `import { s } from '@geekmidas/constructs/subscribers';\nimport { eventsPublisherService } from '~/events/publisher.ts';\n\nexport const userEventsSubscriber = s\n  .publisher(eventsPublisherService)\n  .subscribe(['user.created', 'user.updated'])\n  .handle(async ({ event, logger }) => {\n    logger.info({ type: event.type, payload: event.payload }, 'Processing user event');\n\n    switch (event.type) {\n      case 'user.created':\n        // Handle user creation\n        logger.info({ userId: event.payload.userId }, 'New user created');\n        break;\n      case 'user.updated':\n        // Handle user update\n        logger.info({ userId: event.payload.userId }, 'User updated');\n        break;\n    }\n  });\n`,\n\t\t\t},\n\n\t\t\t// src/crons/cleanup.ts\n\t\t\t{\n\t\t\t\tpath: 'src/crons/cleanup.ts',\n\t\t\t\tcontent: `import { cron } from '@geekmidas/constructs/crons';\n\n// Run every day at midnight\nexport const cleanupCron = cron('0 0 * * *')\n  .handle(async ({ logger }) => {\n    logger.info('Running cleanup job');\n\n    // Add your cleanup logic here\n    // e.g., delete old sessions, clean up temp files, etc.\n\n    logger.info('Cleanup job completed');\n  });\n`,\n\t\t\t},\n\t\t];\n\n\t\t// Add Telescope config if enabled\n\t\tif (options.telescope) {\n\t\t\tfiles.push({\n\t\t\t\tpath: 'src/config/telescope.ts',\n\t\t\t\tcontent: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n  storage: new InMemoryStorage({ maxEntries: 100 }),\n  enabled: process.env.NODE_ENV === 'development',\n});\n`,\n\t\t\t});\n\t\t}\n\n\t\treturn files;\n\t},\n};\n","import { apiTemplate } from './api.js';\nimport { minimalTemplate } from './minimal.js';\nimport { serverlessTemplate } from './serverless.js';\nimport { workerTemplate } from './worker.js';\n\n/**\n * OpenAPI output path (fixed, not configurable)\n */\nexport const OPENAPI_OUTPUT_PATH = './.gkm/openapi.ts';\n\n/**\n * Endpoints output path (generated by gkm dev/build)\n */\nexport const ENDPOINTS_OUTPUT_PATH = './.gkm/server/endpoints.ts';\n\n/**\n * Logger implementation type\n */\nexport type LoggerType = 'pino' | 'console';\n\n/**\n * Routes structure pattern\n */\nexport type RoutesStructure =\n\t| 'centralized-endpoints'\n\t| 'centralized-routes'\n\t| 'domain-based';\n\n/**\n * Package manager type\n */\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\n/**\n * Deploy target type\n */\nexport type DeployTarget = 'dokploy' | 'none';\n\n/**\n * Services selection\n */\nexport interface ServicesSelection {\n\tdb: boolean;\n\tcache: boolean;\n\tmail: boolean;\n\tstorage: boolean;\n\tevents?: import('../../types.js').EventsBackend;\n}\n\n/**\n * Frontend framework for the fullstack template's client app.\n * Limited to the three with first-class scaffolds; the wider\n * `FrontendFramework` type also covers `vite` and `remix` which\n * users can configure manually after init.\n */\nexport type FullstackFrontendFramework = 'nextjs' | 'tanstack-start' | 'expo';\n\n/**\n * Options collected from user prompts\n */\nexport interface TemplateOptions {\n\tname: string;\n\ttemplate: TemplateName;\n\ttelescope: boolean;\n\tdatabase: boolean;\n\tstudio: boolean;\n\tloggerType: LoggerType;\n\troutesStructure: RoutesStructure;\n\tmonorepo: boolean;\n\t/** Path for the API app in monorepo (e.g., 'apps/api') */\n\tapiPath: string;\n\t/** Selected package manager */\n\tpackageManager: PackageManager;\n\t/** Deploy target */\n\tdeployTarget: DeployTarget;\n\t/** Services selection */\n\tservices: ServicesSelection;\n\t/** Frontend framework (fullstack template only) */\n\tfrontendFramework?: FullstackFrontendFramework;\n}\n\n/**\n * A file to be generated\n */\nexport interface GeneratedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/**\n * Template configuration\n */\nexport interface TemplateConfig {\n\tname: TemplateName;\n\tdescription: string;\n\tdependencies: Record<string, string>;\n\tdevDependencies: Record<string, string>;\n\tscripts: Record<string, string>;\n\tfiles: (options: TemplateOptions) => GeneratedFile[];\n}\n\nexport type TemplateName =\n\t| 'minimal'\n\t| 'api'\n\t| 'serverless'\n\t| 'worker'\n\t| 'fullstack';\n\n/**\n * All available templates\n */\nexport const templates: Record<\n\tExclude<TemplateName, 'fullstack'>,\n\tTemplateConfig\n> = {\n\tminimal: minimalTemplate,\n\tapi: apiTemplate,\n\tserverless: serverlessTemplate,\n\tworker: workerTemplate,\n};\n\n/**\n * Template choices for prompts (Story 1.11 simplified to api + fullstack)\n */\nexport const templateChoices = [\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Single backend API with endpoints',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n];\n\n/**\n * All template choices (includes advanced options)\n */\nexport const allTemplateChoices = [\n\t{\n\t\ttitle: 'Minimal',\n\t\tvalue: 'minimal' as TemplateName,\n\t\tdescription: 'Basic health endpoint',\n\t},\n\t{\n\t\ttitle: 'API',\n\t\tvalue: 'api' as TemplateName,\n\t\tdescription: 'Full API with auth, database, services',\n\t},\n\t{\n\t\ttitle: 'Fullstack',\n\t\tvalue: 'fullstack' as TemplateName,\n\t\tdescription: 'Monorepo with API + Next.js + shared models',\n\t},\n\t{\n\t\ttitle: 'Serverless',\n\t\tvalue: 'serverless' as TemplateName,\n\t\tdescription: 'AWS Lambda handlers',\n\t},\n\t{\n\t\ttitle: 'Worker',\n\t\tvalue: 'worker' as TemplateName,\n\t\tdescription: 'Background job processing',\n\t},\n];\n\n/**\n * Frontend framework choices for the fullstack template prompt.\n */\nexport const frontendFrameworkChoices = [\n\t{\n\t\ttitle: 'Next.js',\n\t\tvalue: 'nextjs' as FullstackFrontendFramework,\n\t\tdescription: 'React server components, app router (default)',\n\t},\n\t{\n\t\ttitle: 'TanStack Start',\n\t\tvalue: 'tanstack-start' as FullstackFrontendFramework,\n\t\tdescription: 'File-based router on Vite + Nitro',\n\t},\n\t{\n\t\ttitle: 'Expo',\n\t\tvalue: 'expo' as FullstackFrontendFramework,\n\t\tdescription: 'React Native mobile app (iOS + Android)',\n\t},\n];\n\n/**\n * Logger type choices for prompts\n */\nexport const loggerTypeChoices = [\n\t{\n\t\ttitle: 'Pino',\n\t\tvalue: 'pino' as LoggerType,\n\t\tdescription: 'Fast JSON logger for production (recommended)',\n\t},\n\t{\n\t\ttitle: 'Console',\n\t\tvalue: 'console' as LoggerType,\n\t\tdescription: 'Simple console logger for development',\n\t},\n];\n\n/**\n * Routes structure choices for prompts\n */\nexport const routesStructureChoices = [\n\t{\n\t\ttitle: 'Centralized (endpoints)',\n\t\tvalue: 'centralized-endpoints' as RoutesStructure,\n\t\tdescription: 'src/endpoints/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Centralized (routes)',\n\t\tvalue: 'centralized-routes' as RoutesStructure,\n\t\tdescription: 'src/routes/**/*.ts',\n\t},\n\t{\n\t\ttitle: 'Domain-based',\n\t\tvalue: 'domain-based' as RoutesStructure,\n\t\tdescription: 'src/**/routes/*.ts (e.g., src/users/routes/list.ts)',\n\t},\n];\n\n/**\n * Package manager choices for prompts\n */\nexport const packageManagerChoices = [\n\t{\n\t\ttitle: 'pnpm',\n\t\tvalue: 'pnpm' as PackageManager,\n\t\tdescription: 'Fast, disk space efficient (recommended)',\n\t},\n\t{\n\t\ttitle: 'npm',\n\t\tvalue: 'npm' as PackageManager,\n\t\tdescription: 'Node.js default package manager',\n\t},\n\t{\n\t\ttitle: 'yarn',\n\t\tvalue: 'yarn' as PackageManager,\n\t\tdescription: 'Yarn package manager',\n\t},\n\t{\n\t\ttitle: 'bun',\n\t\tvalue: 'bun' as PackageManager,\n\t\tdescription: 'Fast JavaScript runtime and package manager',\n\t},\n];\n\n/**\n * Deploy target choices for prompts\n */\nexport const deployTargetChoices = [\n\t{\n\t\ttitle: 'Dokploy',\n\t\tvalue: 'dokploy' as DeployTarget,\n\t\tdescription: 'Deploy to Dokploy (Docker-based hosting)',\n\t},\n\t{\n\t\ttitle: 'Configure later',\n\t\tvalue: 'none' as DeployTarget,\n\t\tdescription: 'Skip deployment setup for now',\n\t},\n];\n\n/**\n * Services choices for multi-select prompt\n */\nexport const servicesChoices = [\n\t{\n\t\ttitle: 'PostgreSQL',\n\t\tvalue: 'db',\n\t\tdescription: 'PostgreSQL database',\n\t},\n\t{\n\t\ttitle: 'Redis',\n\t\tvalue: 'cache',\n\t\tdescription: 'Redis cache',\n\t},\n\t{\n\t\ttitle: 'Mailpit',\n\t\tvalue: 'mail',\n\t\tdescription: 'Email testing service (dev only)',\n\t},\n\t{\n\t\ttitle: 'MinIO',\n\t\tvalue: 'storage',\n\t\tdescription: 'S3-compatible object storage (dev only)',\n\t},\n];\n\n/**\n * Event backend choices for prompts\n */\nexport const eventsBackendChoices = [\n\t{\n\t\ttitle: 'pg-boss',\n\t\tvalue: 'pgboss' as const,\n\t\tdescription:\n\t\t\t'PostgreSQL-based job queue (reuses postgres, no extra container)',\n\t},\n\t{\n\t\ttitle: 'SNS/SQS',\n\t\tvalue: 'sns' as const,\n\t\tdescription: 'AWS SNS+SQS via LocalStack for local dev',\n\t},\n\t{\n\t\ttitle: 'RabbitMQ',\n\t\tvalue: 'rabbitmq' as const,\n\t\tdescription: 'AMQP message broker',\n\t},\n\t{\n\t\ttitle: 'None',\n\t\tvalue: undefined,\n\t\tdescription: 'Skip event backend',\n\t},\n];\n\n/**\n * Get a template by name\n */\nexport function getTemplate(name: TemplateName): TemplateConfig | null {\n\tif (name === 'fullstack') {\n\t\t// Fullstack template is handled specially, uses api template as base\n\t\treturn templates.api;\n\t}\n\tconst template = templates[name];\n\tif (!template) {\n\t\tthrow new Error(`Unknown template: ${name}`);\n\t}\n\treturn template;\n}\n\n/**\n * Check if a template is the fullstack monorepo template\n */\nexport function isFullstackTemplate(name: TemplateName): boolean {\n\treturn name === 'fullstack';\n}\n","import {\n\tENDPOINTS_OUTPUT_PATH,\n\ttype GeneratedFile,\n\tOPENAPI_OUTPUT_PATH,\n\ttype TemplateConfig,\n\ttype TemplateOptions,\n} from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate package.json with dependencies based on template and options\n */\nexport function generatePackageJson(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\tconst { name, telescope, database, studio, monorepo } = options;\n\n\t// Start with template dependencies\n\tconst dependencies = { ...template.dependencies };\n\tconst devDependencies = { ...template.devDependencies };\n\tconst scripts = { ...template.scripts };\n\n\t// Add optional dependencies based on user choices\n\tif (telescope) {\n\t\tdependencies['@geekmidas/telescope'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/telescope'];\n\t}\n\n\tif (studio) {\n\t\tdependencies['@geekmidas/studio'] = GEEKMIDAS_VERSIONS['@geekmidas/studio'];\n\t}\n\n\tif (database) {\n\t\tdependencies['@geekmidas/db'] = GEEKMIDAS_VERSIONS['@geekmidas/db'];\n\t\tdependencies.kysely = '~0.28.2';\n\t\tdependencies.pg = '~8.16.0';\n\t\tdevDependencies['@types/pg'] = '~8.15.0';\n\t\tdevDependencies['@geekmidas/testkit'] =\n\t\t\tGEEKMIDAS_VERSIONS['@geekmidas/testkit'];\n\t\tdevDependencies['@faker-js/faker'] = '~9.8.0';\n\t\tdevDependencies['kysely-ctl'] = '~0.10.0';\n\t\tdevDependencies['vite-tsconfig-paths'] = '~5.1.0';\n\t}\n\n\t// For monorepo apps, remove biome/turbo/esbuild (they're at root) and lint/fmt scripts\n\t// zod is at root level for monorepos\n\tif (monorepo) {\n\t\tdelete devDependencies['@biomejs/biome'];\n\t\tdelete devDependencies.turbo;\n\t\tdelete devDependencies.esbuild;\n\t\tdelete dependencies.zod;\n\t\tdelete scripts.lint;\n\t\tdelete scripts.fmt;\n\t\tdelete scripts['fmt:check'];\n\n\t\t// Add models package as dependency\n\t\tdependencies[`@${name}/models`] = 'workspace:*';\n\t}\n\n\t// Sort dependencies alphabetically\n\tconst sortObject = (obj: Record<string, string>) =>\n\t\tObject.fromEntries(\n\t\t\tObject.entries(obj).sort(([a], [b]) => a.localeCompare(b)),\n\t\t);\n\n\t// For monorepo, derive package name from apiPath (e.g., apps/api -> @name/api)\n\tlet packageName = name;\n\tif (monorepo && options.apiPath) {\n\t\tconst pathParts = options.apiPath.split('/');\n\t\tconst appName = pathParts[pathParts.length - 1] || 'api';\n\t\tpackageName = `@${name}/${appName}`;\n\t}\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\texports: {\n\t\t\t'./client': OPENAPI_OUTPUT_PATH,\n\t\t\t'./endpoints': ENDPOINTS_OUTPUT_PATH,\n\t\t},\n\t\tscripts,\n\t\tdependencies: sortObject(dependencies),\n\t\tdevDependencies: sortObject(devDependencies),\n\t};\n\n\treturn [\n\t\t{\n\t\t\tpath: 'package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t];\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate source files from template\n */\nexport function generateSourceFiles(\n\toptions: TemplateOptions,\n\ttemplate: TemplateConfig,\n): GeneratedFile[] {\n\treturn template.files(options);\n}\n","import type {\n\tGeneratedFile,\n\tTemplateConfig,\n\tTemplateOptions,\n} from '../templates/index.js';\n\n/**\n * Generate test infrastructure files when database is enabled.\n * Includes transaction-isolated test config, global setup with migrations,\n * factory system with builders/seeds, and an example spec.\n */\nexport function generateTestFiles(\n\toptions: TemplateOptions,\n\t_template: TemplateConfig,\n): GeneratedFile[] {\n\tif (!options.database) {\n\t\treturn [];\n\t}\n\n\treturn [\n\t\t// kysely.config.ts - Kysely CLI configuration for migrations\n\t\t{\n\t\t\tpath: 'kysely.config.ts',\n\t\t\tcontent: `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { PostgresDialect } from 'kysely';\nimport { defineConfig } from 'kysely-ctl';\nimport pg from 'pg';\n\nexport default defineConfig({\n  dialect: new PostgresDialect({\n    pool: new pg.Pool({\n      password: Credentials.POSTGRES_PASSWORD,\n      user: Credentials.POSTGRES_USER,\n      database: Credentials.POSTGRES_DB,\n      port: Number(Credentials.POSTGRES_PORT),\n      host: Credentials.POSTGRES_HOST,\n    }),\n  }),\n  migrations: {\n    migrationFolder: './src/db/migrations',\n  },\n});\n`,\n\t\t},\n\n\t\t// test/config.ts - Wraps vitest `it` with transaction auto-rollback\n\t\t{\n\t\t\tpath: 'test/config.ts',\n\t\t\tcontent: `import { it as itVitest } from 'vitest';\nimport { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\nimport { wrapVitestKyselyTransaction } from '@geekmidas/testkit/kysely';\nimport type { Database } from '~/services/database.ts';\n\nconst connection = new Kysely<Database>({\n  dialect: new PostgresDialect({\n    pool: new pg.Pool({ connectionString: process.env.DATABASE_URL }),\n  }),\n});\n\nexport const it = wrapVitestKyselyTransaction<Database>(itVitest, {\n  connection,\n});\n`,\n\t\t},\n\n\t\t// test/globalSetup.ts - Creates test database, provisions users, runs migrations\n\t\t{\n\t\t\tpath: 'test/globalSetup.ts',\n\t\t\tcontent: `import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { Credentials } from '@geekmidas/envkit/credentials';\nimport { PostgresKyselyMigrator } from '@geekmidas/testkit/kysely';\nimport { runInitScript } from '@geekmidas/testkit/postgres';\nimport { FileMigrationProvider, Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\n\nexport default async function globalSetup() {\n  const databaseUrl = Credentials.DATABASE_URL!;\n  const migrationFolder = path.resolve(import.meta.dirname, '../db/migrations');\n\n  const db = new Kysely({\n    dialect: new PostgresDialect({\n      pool: new pg.Pool({ connectionString: databaseUrl }),\n    }),\n  });\n\n  const migrator = new PostgresKyselyMigrator({\n    uri: databaseUrl,\n    db,\n    afterCreate: async (uri) => {\n      const initScriptPath = path.resolve(process.cwd(), 'docker/postgres/init.sh');\n      const dbUrl = new URL(Credentials.DATABASE_URL!);\n      const apiUrl = new URL(Credentials.API_DATABASE_URL!);\n      const authUrl = new URL(Credentials.AUTH_DATABASE_URL!);\n\n      const env = {\n        POSTGRES_USER: dbUrl.username,\n        POSTGRES_DB: dbUrl.pathname.slice(1),\n        API_DB_PASSWORD: decodeURIComponent(apiUrl.password),\n        AUTH_DB_PASSWORD: decodeURIComponent(authUrl.password),\n        PGBOSS_DB_PASSWORD: Credentials.PGBOSS_DB_PASSWORD ?? 'pgboss-dev-password',\n      };\n\n      await runInitScript(initScriptPath, uri, env);\n    },\n    provider: new FileMigrationProvider({\n      fs,\n      path,\n      migrationFolder,\n    }),\n  });\n\n  const teardown = await migrator.start();\n  return teardown;\n}\n`,\n\t\t},\n\n\t\t// test/factory/index.ts - Factory aggregator\n\t\t{\n\t\t\tpath: 'test/factory/index.ts',\n\t\t\tcontent: `import type { Kysely } from 'kysely';\nimport { KyselyFactory } from '@geekmidas/testkit/kysely';\nimport type { Database } from '~/services/database.ts';\nimport { usersBuilder } from './users.ts';\n\nconst builders = { users: usersBuilder };\nconst seeds = {};\n\nexport function createFactory(db: Kysely<Database>) {\n  return new KyselyFactory<Database, typeof builders, typeof seeds>(\n    builders,\n    seeds,\n    db,\n  );\n}\n\nexport type Factory = ReturnType<typeof createFactory>;\n`,\n\t\t},\n\n\t\t// test/factory/users.ts - Example builder\n\t\t{\n\t\t\tpath: 'test/factory/users.ts',\n\t\t\tcontent: `import { KyselyFactory } from '@geekmidas/testkit/kysely';\nimport type { Database } from '~/services/database.ts';\n\nexport const usersBuilder = KyselyFactory.createBuilder<Database, 'users'>(\n  'users',\n  ({ faker }) => ({\n    id: faker.string.uuid(),\n    name: faker.person.fullName(),\n    email: faker.internet.email(),\n    created_at: new Date(),\n  }),\n);\n`,\n\t\t},\n\n\t\t// test/example.spec.ts - Example test showing usage\n\t\t{\n\t\t\tpath: 'test/example.spec.ts',\n\t\t\tcontent: `import { describe, expect } from 'vitest';\nimport { it } from './config.ts';\n\ndescribe('example', () => {\n  it('should have a working test setup', async ({ db }) => {\n    // db is a transaction-wrapped Kysely instance\n    // All changes are automatically rolled back after the test\n    expect(db).toBeDefined();\n  });\n});\n`,\n\t\t},\n\t];\n}\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\n\n/**\n * Generate UI package files for fullstack template\n * Based on @geekmidas/ui with shadcn/ui, Tailwind CSS v4, and Storybook\n */\nexport function generateUiPackageFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/ui`;\n\n\t// package.json for UI package\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\texports: {\n\t\t\t'.': './src/index.ts',\n\t\t\t'./components': './src/components/index.ts',\n\t\t\t'./lib/utils': './src/lib/utils.ts',\n\t\t\t'./styles': './src/styles/globals.css',\n\t\t},\n\t\tscripts: {\n\t\t\t'ts:check': 'tsc --noEmit',\n\t\t\tstorybook: 'storybook dev -p 6006',\n\t\t\t'build:storybook': 'storybook build -o dist/storybook',\n\t\t},\n\t\tdependencies: {\n\t\t\t'@radix-ui/react-dialog': '~1.1.4',\n\t\t\t'@radix-ui/react-label': '~2.1.2',\n\t\t\t'@radix-ui/react-separator': '~1.1.2',\n\t\t\t'@radix-ui/react-slot': '~1.2.4',\n\t\t\t'@radix-ui/react-tabs': '~1.1.2',\n\t\t\t'@radix-ui/react-tooltip': '~1.1.6',\n\t\t\t'class-variance-authority': '~0.7.1',\n\t\t\tclsx: '^2.1.1',\n\t\t\t'lucide-react': '~0.562.0',\n\t\t\t'tailwind-merge': '~3.4.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@storybook/addon-a11y': '^8.4.7',\n\t\t\t'@storybook/addon-essentials': '^8.4.7',\n\t\t\t'@storybook/addon-interactions': '^8.4.7',\n\t\t\t'@storybook/react': '^8.4.7',\n\t\t\t'@storybook/react-vite': '^8.4.7',\n\t\t\t'@tailwindcss/vite': '^4.0.0',\n\t\t\t'@types/react': '^19.0.0',\n\t\t\t'@types/react-dom': '^19.0.0',\n\t\t\treact: '^19.0.0',\n\t\t\t'react-dom': '^19.0.0',\n\t\t\tstorybook: '^8.4.7',\n\t\t\ttailwindcss: '^4.0.0',\n\t\t\ttypescript: '^5.8.2',\n\t\t\tvite: '^6.0.0',\n\t\t},\n\t\tpeerDependencies: {\n\t\t\treact: '>=18.0.0',\n\t\t\t'react-dom': '>=18.0.0',\n\t\t\ttailwindcss: '>=4.0.0',\n\t\t},\n\t};\n\n\t// tsconfig.json for UI package\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tjsx: 'react-jsx',\n\t\t\tlib: ['ES2023', 'DOM', 'DOM.Iterable'],\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tbaseUrl: '.',\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['src/**/*'],\n\t\texclude: ['node_modules', 'dist', '**/*.stories.tsx'],\n\t};\n\n\t// components.json (shadcn config)\n\tconst componentsJson = {\n\t\t$schema: 'https://ui.shadcn.com/schema.json',\n\t\tstyle: 'new-york',\n\t\trsc: false,\n\t\ttsx: true,\n\t\ttailwind: {\n\t\t\tconfig: '',\n\t\t\tcss: 'src/styles/globals.css',\n\t\t\tbaseColor: 'neutral',\n\t\t\tcssVariables: true,\n\t\t\tprefix: '',\n\t\t},\n\t\taliases: {\n\t\t\tcomponents: '~/components',\n\t\t\tutils: '~/lib/utils',\n\t\t\tui: '~/components/ui',\n\t\t\tlib: '~/lib',\n\t\t\thooks: '~/hooks',\n\t\t},\n\t\ticonLibrary: 'lucide',\n\t};\n\n\t// .storybook/main.ts\n\tconst storybookMain = `import type { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.stories.@(ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n    '@storybook/addon-interactions',\n    '@storybook/addon-a11y',\n  ],\n  framework: {\n    name: '@storybook/react-vite',\n    options: {},\n  },\n  docs: {\n    autodocs: 'tag',\n  },\n  viteFinal: async (config) => {\n    // Add Tailwind CSS v4 plugin\n    const tailwindcss = await import('@tailwindcss/vite');\n    config.plugins = config.plugins || [];\n    config.plugins.push(tailwindcss.default());\n    return config;\n  },\n};\n\nexport default config;\n`;\n\n\t// .storybook/preview.ts\n\tconst storybookPreview = `import type { Preview } from '@storybook/react';\nimport '../src/styles/globals.css';\n\nconst preview: Preview = {\n  parameters: {\n    backgrounds: {\n      default: 'dark',\n      values: [\n        { name: 'dark', value: '#171717' },\n        { name: 'surface', value: '#1c1c1c' },\n        { name: 'light', value: '#fafafa' },\n      ],\n    },\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/i,\n      },\n    },\n    layout: 'centered',\n  },\n};\n\nexport default preview;\n`;\n\n\t// src/styles/globals.css (Tailwind v4 format)\n\tconst globalsCss = `@import \"tailwindcss\";\n\n@theme {\n  --color-background: hsl(var(--background));\n  --color-foreground: hsl(var(--foreground));\n  --color-card: hsl(var(--card));\n  --color-card-foreground: hsl(var(--card-foreground));\n  --color-popover: hsl(var(--popover));\n  --color-popover-foreground: hsl(var(--popover-foreground));\n  --color-primary: hsl(var(--primary));\n  --color-primary-foreground: hsl(var(--primary-foreground));\n  --color-secondary: hsl(var(--secondary));\n  --color-secondary-foreground: hsl(var(--secondary-foreground));\n  --color-muted: hsl(var(--muted));\n  --color-muted-foreground: hsl(var(--muted-foreground));\n  --color-accent: hsl(var(--accent));\n  --color-accent-foreground: hsl(var(--accent-foreground));\n  --color-destructive: hsl(var(--destructive));\n  --color-destructive-foreground: hsl(var(--destructive-foreground));\n  --color-border: hsl(var(--border));\n  --color-input: hsl(var(--input));\n  --color-ring: hsl(var(--ring));\n  --radius-sm: calc(var(--radius) - 4px);\n  --radius-md: calc(var(--radius) - 2px);\n  --radius-lg: var(--radius);\n  --radius-xl: calc(var(--radius) + 4px);\n}\n\n@layer base {\n  :root {\n    --background: 0 0% 100%;\n    --foreground: 0 0% 3.9%;\n    --card: 0 0% 100%;\n    --card-foreground: 0 0% 3.9%;\n    --popover: 0 0% 100%;\n    --popover-foreground: 0 0% 3.9%;\n    --primary: 160 84% 39%;\n    --primary-foreground: 0 0% 98%;\n    --secondary: 0 0% 96.1%;\n    --secondary-foreground: 0 0% 9%;\n    --muted: 0 0% 96.1%;\n    --muted-foreground: 0 0% 45.1%;\n    --accent: 0 0% 96.1%;\n    --accent-foreground: 0 0% 9%;\n    --destructive: 0 84.2% 60.2%;\n    --destructive-foreground: 0 0% 98%;\n    --border: 0 0% 89.8%;\n    --input: 0 0% 89.8%;\n    --ring: 160 84% 39%;\n    --radius: 0.5rem;\n  }\n\n  .dark {\n    --background: 0 0% 9%;\n    --foreground: 0 0% 98%;\n    --card: 0 0% 11%;\n    --card-foreground: 0 0% 98%;\n    --popover: 0 0% 11%;\n    --popover-foreground: 0 0% 98%;\n    --primary: 160 84% 52%;\n    --primary-foreground: 0 0% 9%;\n    --secondary: 0 0% 15%;\n    --secondary-foreground: 0 0% 98%;\n    --muted: 0 0% 15%;\n    --muted-foreground: 0 0% 64%;\n    --accent: 0 0% 15%;\n    --accent-foreground: 0 0% 98%;\n    --destructive: 0 62.8% 50.6%;\n    --destructive-foreground: 0 0% 98%;\n    --border: 0 0% 18%;\n    --input: 0 0% 18%;\n    --ring: 160 84% 52%;\n  }\n}\n\n@layer base {\n  * {\n    @apply border-border;\n  }\n  body {\n    @apply bg-background text-foreground;\n  }\n}\n`;\n\n\t// src/lib/utils.ts\n\tconst utilsTs = `import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n`;\n\n\t// src/components/ui/button.tsx\n\tconst buttonTsx = `import { Slot } from '@radix-ui/react-slot';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst buttonVariants = cva(\n  'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',\n  {\n    variants: {\n      variant: {\n        default:\n          'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n        destructive:\n          'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',\n        outline:\n          'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n        secondary:\n          'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n        ghost: 'hover:bg-accent hover:text-accent-foreground',\n        link: 'text-primary underline-offset-4 hover:underline',\n      },\n      size: {\n        default: 'h-9 px-4 py-2',\n        sm: 'h-8 rounded-md px-3 text-xs',\n        lg: 'h-10 rounded-md px-8',\n        icon: 'h-9 w-9',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'default',\n    },\n  },\n);\n\nexport interface ButtonProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n    VariantProps<typeof buttonVariants> {\n  asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n  ({ className, variant, size, asChild = false, ...props }, ref) => {\n    const Comp = asChild ? Slot : 'button';\n    return (\n      <Comp\n        className={cn(buttonVariants({ variant, size, className }))}\n        ref={ref}\n        {...props}\n      />\n    );\n  },\n);\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n`;\n\n\t// src/components/ui/button/button.stories.tsx\n\tconst buttonStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Button } from '~/components/ui/button';\n\nconst meta: Meta<typeof Button> = {\n  title: 'Components/Button',\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    variant: {\n      control: 'select',\n      options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'],\n    },\n    size: {\n      control: 'select',\n      options: ['default', 'sm', 'lg', 'icon'],\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Button>;\n\nexport const Default: Story = {\n  args: {\n    children: 'Button',\n    variant: 'default',\n    size: 'default',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Secondary',\n    variant: 'secondary',\n  },\n};\n\nexport const Destructive: Story = {\n  args: {\n    children: 'Destructive',\n    variant: 'destructive',\n  },\n};\n\nexport const Outline: Story = {\n  args: {\n    children: 'Outline',\n    variant: 'outline',\n  },\n};\n\nexport const Ghost: Story = {\n  args: {\n    children: 'Ghost',\n    variant: 'ghost',\n  },\n};\n\nexport const Link: Story = {\n  args: {\n    children: 'Link',\n    variant: 'link',\n  },\n};\n`;\n\n\t// src/components/ui/input.tsx\n\tconst inputTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(\n  ({ className, type, ...props }, ref) => {\n    return (\n      <input\n        type={type}\n        className={cn(\n          'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n          className,\n        )}\n        ref={ref}\n        {...props}\n      />\n    );\n  },\n);\nInput.displayName = 'Input';\n\nexport { Input };\n`;\n\n\t// src/components/ui/card.tsx\n\tconst cardTsx = `import * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Card = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div\n    ref={ref}\n    className={cn(\n      'rounded-xl border bg-card text-card-foreground shadow',\n      className,\n    )}\n    {...props}\n  />\n));\nCard.displayName = 'Card';\n\nconst CardHeader = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div\n    ref={ref}\n    className={cn('flex flex-col space-y-1.5 p-6', className)}\n    {...props}\n  />\n));\nCardHeader.displayName = 'CardHeader';\n\nconst CardTitle = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div\n    ref={ref}\n    className={cn('font-semibold leading-none tracking-tight', className)}\n    {...props}\n  />\n));\nCardTitle.displayName = 'CardTitle';\n\nconst CardDescription = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div\n    ref={ref}\n    className={cn('text-sm text-muted-foreground', className)}\n    {...props}\n  />\n));\nCardDescription.displayName = 'CardDescription';\n\nconst CardContent = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />\n));\nCardContent.displayName = 'CardContent';\n\nconst CardFooter = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n  <div\n    ref={ref}\n    className={cn('flex items-center p-6 pt-0', className)}\n    {...props}\n  />\n));\nCardFooter.displayName = 'CardFooter';\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };\n`;\n\n\t// src/components/ui/input/input.stories.tsx\n\tconst inputStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Input } from '~/components/ui/input';\n\nconst meta: Meta<typeof Input> = {\n  title: 'Components/Input',\n  component: Input,\n  tags: ['autodocs'],\n  argTypes: {\n    type: {\n      control: 'select',\n      options: ['text', 'email', 'password', 'number', 'search', 'tel', 'url'],\n    },\n    disabled: {\n      control: 'boolean',\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Input>;\n\nexport const Default: Story = {\n  args: {\n    placeholder: 'Enter text...',\n  },\n};\n\nexport const Email: Story = {\n  args: {\n    type: 'email',\n    placeholder: 'Enter email...',\n  },\n};\n\nexport const Password: Story = {\n  args: {\n    type: 'password',\n    placeholder: 'Enter password...',\n  },\n};\n\nexport const Disabled: Story = {\n  args: {\n    placeholder: 'Disabled input',\n    disabled: true,\n  },\n};\n\nexport const WithValue: Story = {\n  args: {\n    defaultValue: 'Hello World',\n  },\n};\n`;\n\n\t// src/components/ui/card/card.stories.tsx\n\tconst cardStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Button } from '~/components/ui/button';\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from '~/components/ui/card';\nimport { Input } from '~/components/ui/input';\n\nconst meta: Meta<typeof Card> = {\n  title: 'Components/Card',\n  component: Card,\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Card>;\n\nexport const Default: Story = {\n  render: () => (\n    <Card className=\"w-[350px]\">\n      <CardHeader>\n        <CardTitle>Card Title</CardTitle>\n        <CardDescription>Card description goes here.</CardDescription>\n      </CardHeader>\n      <CardContent>\n        <p>Card content goes here.</p>\n      </CardContent>\n    </Card>\n  ),\n};\n\nexport const WithFooter: Story = {\n  render: () => (\n    <Card className=\"w-[350px]\">\n      <CardHeader>\n        <CardTitle>Create Account</CardTitle>\n        <CardDescription>Enter your details below.</CardDescription>\n      </CardHeader>\n      <CardContent className=\"space-y-4\">\n        <Input placeholder=\"Email\" type=\"email\" />\n        <Input placeholder=\"Password\" type=\"password\" />\n      </CardContent>\n      <CardFooter className=\"flex justify-between\">\n        <Button variant=\"outline\">Cancel</Button>\n        <Button>Create</Button>\n      </CardFooter>\n    </Card>\n  ),\n};\n\nexport const Simple: Story = {\n  render: () => (\n    <Card className=\"w-[350px] p-6\">\n      <p>Simple card with just content.</p>\n    </Card>\n  ),\n};\n`;\n\n\t// src/components/ui/label/index.tsx\n\tconst labelTsx = `import * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst labelVariants = cva(\n  'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nconst Label = React.forwardRef<\n  React.ElementRef<typeof LabelPrimitive.Root>,\n  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n    VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n  <LabelPrimitive.Root\n    ref={ref}\n    className={cn(labelVariants(), className)}\n    {...props}\n  />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n`;\n\n\t// src/components/ui/label/label.stories.tsx\n\tconst labelStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Input } from '~/components/ui/input';\nimport { Label } from '~/components/ui/label';\n\nconst meta: Meta<typeof Label> = {\n  title: 'Components/Label',\n  component: Label,\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Label>;\n\nexport const Default: Story = {\n  args: {\n    children: 'Label',\n  },\n};\n\nexport const WithInput: Story = {\n  render: () => (\n    <div className=\"grid w-full max-w-sm items-center gap-1.5\">\n      <Label htmlFor=\"email\">Email</Label>\n      <Input type=\"email\" id=\"email\" placeholder=\"Email\" />\n    </div>\n  ),\n};\n\nexport const Disabled: Story = {\n  render: () => (\n    <div className=\"grid w-full max-w-sm items-center gap-1.5\">\n      <Label htmlFor=\"disabled\" className=\"peer-disabled:cursor-not-allowed peer-disabled:opacity-70\">\n        Disabled\n      </Label>\n      <Input type=\"text\" id=\"disabled\" placeholder=\"Disabled\" disabled className=\"peer\" />\n    </div>\n  ),\n};\n`;\n\n\t// src/components/ui/badge/index.tsx\n\tconst badgeTsx = `import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst badgeVariants = cva(\n  'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',\n  {\n    variants: {\n      variant: {\n        default:\n          'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',\n        secondary:\n          'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',\n        destructive:\n          'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',\n        outline: 'text-foreground',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n    },\n  },\n);\n\nexport interface BadgeProps\n  extends React.HTMLAttributes<HTMLDivElement>,\n    VariantProps<typeof badgeVariants> {}\n\nfunction Badge({ className, variant, ...props }: BadgeProps) {\n  return (\n    <div className={cn(badgeVariants({ variant }), className)} {...props} />\n  );\n}\n\nexport { Badge, badgeVariants };\n`;\n\n\t// src/components/ui/badge/badge.stories.tsx\n\tconst badgeStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Badge } from '~/components/ui/badge';\n\nconst meta: Meta<typeof Badge> = {\n  title: 'Components/Badge',\n  component: Badge,\n  tags: ['autodocs'],\n  argTypes: {\n    variant: {\n      control: 'select',\n      options: ['default', 'secondary', 'destructive', 'outline'],\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Badge>;\n\nexport const Default: Story = {\n  args: {\n    children: 'Badge',\n    variant: 'default',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Secondary',\n    variant: 'secondary',\n  },\n};\n\nexport const Destructive: Story = {\n  args: {\n    children: 'Destructive',\n    variant: 'destructive',\n  },\n};\n\nexport const Outline: Story = {\n  args: {\n    children: 'Outline',\n    variant: 'outline',\n  },\n};\n`;\n\n\t// src/components/ui/separator/index.tsx\n\tconst separatorTsx = `import * as SeparatorPrimitive from '@radix-ui/react-separator';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Separator = React.forwardRef<\n  React.ElementRef<typeof SeparatorPrimitive.Root>,\n  React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(\n  (\n    { className, orientation = 'horizontal', decorative = true, ...props },\n    ref,\n  ) => (\n    <SeparatorPrimitive.Root\n      ref={ref}\n      decorative={decorative}\n      orientation={orientation}\n      className={cn(\n        'shrink-0 bg-border',\n        orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n        className,\n      )}\n      {...props}\n    />\n  ),\n);\nSeparator.displayName = SeparatorPrimitive.Root.displayName;\n\nexport { Separator };\n`;\n\n\t// src/components/ui/separator/separator.stories.tsx\n\tconst separatorStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Separator } from '~/components/ui/separator';\n\nconst meta: Meta<typeof Separator> = {\n  title: 'Components/Separator',\n  component: Separator,\n  tags: ['autodocs'],\n  argTypes: {\n    orientation: {\n      control: 'select',\n      options: ['horizontal', 'vertical'],\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Separator>;\n\nexport const Horizontal: Story = {\n  render: () => (\n    <div className=\"w-[300px]\">\n      <div className=\"space-y-1\">\n        <h4 className=\"text-sm font-medium leading-none\">Radix Primitives</h4>\n        <p className=\"text-sm text-muted-foreground\">\n          An open-source UI component library.\n        </p>\n      </div>\n      <Separator className=\"my-4\" />\n      <div className=\"flex h-5 items-center space-x-4 text-sm\">\n        <div>Blog</div>\n        <Separator orientation=\"vertical\" />\n        <div>Docs</div>\n        <Separator orientation=\"vertical\" />\n        <div>Source</div>\n      </div>\n    </div>\n  ),\n};\n\nexport const Vertical: Story = {\n  render: () => (\n    <div className=\"flex h-5 items-center space-x-4 text-sm\">\n      <div>Blog</div>\n      <Separator orientation=\"vertical\" />\n      <div>Docs</div>\n      <Separator orientation=\"vertical\" />\n      <div>Source</div>\n    </div>\n  ),\n};\n`;\n\n\t// src/components/ui/tabs/index.tsx\n\tconst tabsTsx = `import * as TabsPrimitive from '@radix-ui/react-tabs';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Tabs = TabsPrimitive.Root;\n\nconst TabsList = React.forwardRef<\n  React.ElementRef<typeof TabsPrimitive.List>,\n  React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n  <TabsPrimitive.List\n    ref={ref}\n    className={cn(\n      'inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',\n      className,\n    )}\n    {...props}\n  />\n));\nTabsList.displayName = TabsPrimitive.List.displayName;\n\nconst TabsTrigger = React.forwardRef<\n  React.ElementRef<typeof TabsPrimitive.Trigger>,\n  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n  <TabsPrimitive.Trigger\n    ref={ref}\n    className={cn(\n      'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',\n      className,\n    )}\n    {...props}\n  />\n));\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\nconst TabsContent = React.forwardRef<\n  React.ElementRef<typeof TabsPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n  <TabsPrimitive.Content\n    ref={ref}\n    className={cn(\n      'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n      className,\n    )}\n    {...props}\n  />\n));\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n`;\n\n\t// src/components/ui/tabs/tabs.stories.tsx\n\tconst tabsStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '~/components/ui/tabs';\nimport { Button } from '~/components/ui/button';\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '~/components/ui/card';\nimport { Input } from '~/components/ui/input';\nimport { Label } from '~/components/ui/label';\n\nconst meta: Meta<typeof Tabs> = {\n  title: 'Components/Tabs',\n  component: Tabs,\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Tabs>;\n\nexport const Default: Story = {\n  render: () => (\n    <Tabs defaultValue=\"account\" className=\"w-[400px]\">\n      <TabsList>\n        <TabsTrigger value=\"account\">Account</TabsTrigger>\n        <TabsTrigger value=\"password\">Password</TabsTrigger>\n      </TabsList>\n      <TabsContent value=\"account\">\n        <Card>\n          <CardHeader>\n            <CardTitle>Account</CardTitle>\n            <CardDescription>\n              Make changes to your account here. Click save when you're done.\n            </CardDescription>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div className=\"space-y-1\">\n              <Label htmlFor=\"name\">Name</Label>\n              <Input id=\"name\" defaultValue=\"Pedro Duarte\" />\n            </div>\n            <div className=\"space-y-1\">\n              <Label htmlFor=\"username\">Username</Label>\n              <Input id=\"username\" defaultValue=\"@peduarte\" />\n            </div>\n          </CardContent>\n          <CardFooter>\n            <Button>Save changes</Button>\n          </CardFooter>\n        </Card>\n      </TabsContent>\n      <TabsContent value=\"password\">\n        <Card>\n          <CardHeader>\n            <CardTitle>Password</CardTitle>\n            <CardDescription>\n              Change your password here. After saving, you'll be logged out.\n            </CardDescription>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div className=\"space-y-1\">\n              <Label htmlFor=\"current\">Current password</Label>\n              <Input id=\"current\" type=\"password\" />\n            </div>\n            <div className=\"space-y-1\">\n              <Label htmlFor=\"new\">New password</Label>\n              <Input id=\"new\" type=\"password\" />\n            </div>\n          </CardContent>\n          <CardFooter>\n            <Button>Save password</Button>\n          </CardFooter>\n        </Card>\n      </TabsContent>\n    </Tabs>\n  ),\n};\n`;\n\n\t// src/components/ui/tooltip/index.tsx\n\tconst tooltipTsx = `import * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst TooltipProvider = TooltipPrimitive.Provider;\n\nconst Tooltip = TooltipPrimitive.Root;\n\nconst TooltipTrigger = TooltipPrimitive.Trigger;\n\nconst TooltipContent = React.forwardRef<\n  React.ElementRef<typeof TooltipPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n  <TooltipPrimitive.Portal>\n    <TooltipPrimitive.Content\n      ref={ref}\n      sideOffset={sideOffset}\n      className={cn(\n        'z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n        className,\n      )}\n      {...props}\n    />\n  </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n`;\n\n\t// src/components/ui/tooltip/tooltip.stories.tsx\n\tconst tooltipStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '~/components/ui/tooltip';\nimport { Button } from '~/components/ui/button';\n\nconst meta: Meta<typeof Tooltip> = {\n  title: 'Components/Tooltip',\n  component: Tooltip,\n  tags: ['autodocs'],\n  decorators: [\n    (Story) => (\n      <TooltipProvider>\n        <Story />\n      </TooltipProvider>\n    ),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Tooltip>;\n\nexport const Default: Story = {\n  render: () => (\n    <Tooltip>\n      <TooltipTrigger asChild>\n        <Button variant=\"outline\">Hover me</Button>\n      </TooltipTrigger>\n      <TooltipContent>\n        <p>Add to library</p>\n      </TooltipContent>\n    </Tooltip>\n  ),\n};\n\nexport const Positions: Story = {\n  render: () => (\n    <div className=\"flex gap-4\">\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button variant=\"outline\">Top</Button>\n        </TooltipTrigger>\n        <TooltipContent side=\"top\">\n          <p>Top tooltip</p>\n        </TooltipContent>\n      </Tooltip>\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button variant=\"outline\">Bottom</Button>\n        </TooltipTrigger>\n        <TooltipContent side=\"bottom\">\n          <p>Bottom tooltip</p>\n        </TooltipContent>\n      </Tooltip>\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button variant=\"outline\">Left</Button>\n        </TooltipTrigger>\n        <TooltipContent side=\"left\">\n          <p>Left tooltip</p>\n        </TooltipContent>\n      </Tooltip>\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button variant=\"outline\">Right</Button>\n        </TooltipTrigger>\n        <TooltipContent side=\"right\">\n          <p>Right tooltip</p>\n        </TooltipContent>\n      </Tooltip>\n    </div>\n  ),\n};\n`;\n\n\t// src/components/ui/dialog/index.tsx\n\tconst dialogTsx = `import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { X } from 'lucide-react';\nimport * as React from 'react';\n\nimport { cn } from '~/lib/utils';\n\nconst Dialog = DialogPrimitive.Root;\n\nconst DialogTrigger = DialogPrimitive.Trigger;\n\nconst DialogPortal = DialogPrimitive.Portal;\n\nconst DialogClose = DialogPrimitive.Close;\n\nconst DialogOverlay = React.forwardRef<\n  React.ElementRef<typeof DialogPrimitive.Overlay>,\n  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n  <DialogPrimitive.Overlay\n    ref={ref}\n    className={cn(\n      'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n      className,\n    )}\n    {...props}\n  />\n));\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n  React.ElementRef<typeof DialogPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n  <DialogPortal>\n    <DialogOverlay />\n    <DialogPrimitive.Content\n      ref={ref}\n      className={cn(\n        'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground\">\n        <X className=\"h-4 w-4\" />\n        <span className=\"sr-only\">Close</span>\n      </DialogPrimitive.Close>\n    </DialogPrimitive.Content>\n  </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      'flex flex-col space-y-1.5 text-center sm:text-left',\n      className,\n    )}\n    {...props}\n  />\n);\nDialogHeader.displayName = 'DialogHeader';\n\nconst DialogFooter = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n  <div\n    className={cn(\n      'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n      className,\n    )}\n    {...props}\n  />\n);\nDialogFooter.displayName = 'DialogFooter';\n\nconst DialogTitle = React.forwardRef<\n  React.ElementRef<typeof DialogPrimitive.Title>,\n  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n  <DialogPrimitive.Title\n    ref={ref}\n    className={cn(\n      'text-lg font-semibold leading-none tracking-tight',\n      className,\n    )}\n    {...props}\n  />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n  React.ElementRef<typeof DialogPrimitive.Description>,\n  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n  <DialogPrimitive.Description\n    ref={ref}\n    className={cn('text-sm text-muted-foreground', className)}\n    {...props}\n  />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n  Dialog,\n  DialogPortal,\n  DialogOverlay,\n  DialogTrigger,\n  DialogClose,\n  DialogContent,\n  DialogHeader,\n  DialogFooter,\n  DialogTitle,\n  DialogDescription,\n};\n`;\n\n\t// src/components/ui/dialog/dialog.stories.tsx\n\tconst dialogStories = `import type { Meta, StoryObj } from '@storybook/react';\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from '~/components/ui/dialog';\nimport { Button } from '~/components/ui/button';\nimport { Input } from '~/components/ui/input';\nimport { Label } from '~/components/ui/label';\n\nconst meta: Meta<typeof Dialog> = {\n  title: 'Components/Dialog',\n  component: Dialog,\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof Dialog>;\n\nexport const Default: Story = {\n  render: () => (\n    <Dialog>\n      <DialogTrigger asChild>\n        <Button variant=\"outline\">Edit Profile</Button>\n      </DialogTrigger>\n      <DialogContent className=\"sm:max-w-[425px]\">\n        <DialogHeader>\n          <DialogTitle>Edit profile</DialogTitle>\n          <DialogDescription>\n            Make changes to your profile here. Click save when you're done.\n          </DialogDescription>\n        </DialogHeader>\n        <div className=\"grid gap-4 py-4\">\n          <div className=\"grid grid-cols-4 items-center gap-4\">\n            <Label htmlFor=\"name\" className=\"text-right\">\n              Name\n            </Label>\n            <Input id=\"name\" defaultValue=\"Pedro Duarte\" className=\"col-span-3\" />\n          </div>\n          <div className=\"grid grid-cols-4 items-center gap-4\">\n            <Label htmlFor=\"username\" className=\"text-right\">\n              Username\n            </Label>\n            <Input id=\"username\" defaultValue=\"@peduarte\" className=\"col-span-3\" />\n          </div>\n        </div>\n        <DialogFooter>\n          <Button type=\"submit\">Save changes</Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  ),\n};\n\nexport const Alert: Story = {\n  render: () => (\n    <Dialog>\n      <DialogTrigger asChild>\n        <Button variant=\"destructive\">Delete Account</Button>\n      </DialogTrigger>\n      <DialogContent>\n        <DialogHeader>\n          <DialogTitle>Are you absolutely sure?</DialogTitle>\n          <DialogDescription>\n            This action cannot be undone. This will permanently delete your\n            account and remove your data from our servers.\n          </DialogDescription>\n        </DialogHeader>\n        <DialogFooter>\n          <Button variant=\"outline\">Cancel</Button>\n          <Button variant=\"destructive\">Delete</Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  ),\n};\n`;\n\n\t// src/components/ui/index.ts\n\tconst componentsUiIndex = `export { Button, type ButtonProps, buttonVariants } from './button.tsx';\nexport { Input } from './input.tsx';\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardDescription,\n  CardContent,\n} from './card.tsx';\nexport { Label } from './label.tsx';\nexport { Badge, type BadgeProps, badgeVariants } from './badge.tsx';\nexport { Separator } from './separator.tsx';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs.tsx';\nexport {\n  Tooltip,\n  TooltipTrigger,\n  TooltipContent,\n  TooltipProvider,\n} from './tooltip.tsx';\nexport {\n  Dialog,\n  DialogPortal,\n  DialogOverlay,\n  DialogTrigger,\n  DialogClose,\n  DialogContent,\n  DialogHeader,\n  DialogFooter,\n  DialogTitle,\n  DialogDescription,\n} from './dialog.tsx';\n`;\n\n\t// Rename component files to index.tsx (same content)\n\tconst buttonIndexTsx = buttonTsx;\n\tconst inputIndexTsx = inputTsx;\n\tconst cardIndexTsx = cardTsx;\n\n\t// src/components/index.ts\n\tconst componentsIndex = `export * from './ui/index.ts';\n`;\n\n\t// src/index.ts\n\tconst indexTs = `// @${options.name}/ui - Shared UI component library\n\n// shadcn/ui components\nexport * from './components/index.ts';\n\n// Utilities\nexport { cn } from './lib/utils.ts';\n`;\n\n\t// .gitignore for UI package\n\tconst gitignore = `node_modules/\ndist/\nstorybook-static/\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'packages/ui/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/components.json',\n\t\t\tcontent: `${JSON.stringify(componentsJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/.storybook/main.ts',\n\t\t\tcontent: storybookMain,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/.storybook/preview.ts',\n\t\t\tcontent: storybookPreview,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/styles/globals.css',\n\t\t\tcontent: globalsCss,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/lib/utils.ts',\n\t\t\tcontent: utilsTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/button/index.tsx',\n\t\t\tcontent: buttonIndexTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/button/button.stories.tsx',\n\t\t\tcontent: buttonStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/input/index.tsx',\n\t\t\tcontent: inputIndexTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/input/input.stories.tsx',\n\t\t\tcontent: inputStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/card/index.tsx',\n\t\t\tcontent: cardIndexTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/card/card.stories.tsx',\n\t\t\tcontent: cardStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/label/index.tsx',\n\t\t\tcontent: labelTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/label/label.stories.tsx',\n\t\t\tcontent: labelStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/badge/index.tsx',\n\t\t\tcontent: badgeTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/badge/badge.stories.tsx',\n\t\t\tcontent: badgeStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/separator/index.tsx',\n\t\t\tcontent: separatorTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/separator/separator.stories.tsx',\n\t\t\tcontent: separatorStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/tabs/index.tsx',\n\t\t\tcontent: tabsTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/tabs/tabs.stories.tsx',\n\t\t\tcontent: tabsStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/tooltip/index.tsx',\n\t\t\tcontent: tooltipTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/tooltip/tooltip.stories.tsx',\n\t\t\tcontent: tooltipStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/dialog/index.tsx',\n\t\t\tcontent: dialogTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/dialog/dialog.stories.tsx',\n\t\t\tcontent: dialogStories,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/ui/index.ts',\n\t\t\tcontent: componentsUiIndex,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/components/index.ts',\n\t\t\tcontent: componentsIndex,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/src/index.ts',\n\t\t\tcontent: indexTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'packages/ui/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate Next.js web app files for fullstack template\n */\nexport function generateWebAppFiles(options: TemplateOptions): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst apiPackage = `@${options.name}/api`;\n\tconst modelsPackage = `@${options.name}/models`;\n\tconst uiPackage = `@${options.name}/ui`;\n\n\t// package.json for web app\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- next dev --turbopack',\n\t\t\tbuild: 'gkm exec -- next build',\n\t\t\tstart: 'next start',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[apiPackage]: 'workspace:*',\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t[uiPackage]: 'workspace:*',\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': '~5.80.0',\n\t\t\t'better-auth': '~1.2.0',\n\t\t\tnext: '~16.1.0',\n\t\t\treact: '~19.2.0',\n\t\t\t'react-dom': '~19.2.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/postcss': '^4.0.0',\n\t\t\t'@types/node': '~22.0.0',\n\t\t\t'@types/react': '~19.0.0',\n\t\t\t'@types/react-dom': '~19.0.0',\n\t\t\ttailwindcss: '^4.0.0',\n\t\t\ttsx: '~4.20.0',\n\t\t\ttypescript: '~5.8.2',\n\t\t},\n\t};\n\n\t// next.config.ts\n\tconst nextConfig = `import type { NextConfig } from 'next';\n\nconst nextConfig: NextConfig = {\n  output: 'standalone',\n  reactStrictMode: true,\n  transpilePackages: ['${apiPackage}', '${modelsPackage}', '${uiPackage}'],\n};\n\nexport default nextConfig;\n`;\n\n\t// postcss.config.mjs for Tailwind v4\n\tconst postcssConfig = `export default {\n  plugins: {\n    '@tailwindcss/postcss': {},\n  },\n};\n`;\n\n\t// tsconfig.json for Next.js\n\t// Note: Next.js handles compilation, so noEmit: true\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\tplugins: [\n\t\t\t\t{\n\t\t\t\t\tname: 'next',\n\t\t\t\t},\n\t\t\t],\n\t\t\tbaseUrl: '.',\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*', '../../packages/ui/src/*'],\n\t\t\t\t[`${apiPackage}/client`]: ['../../apps/api/.gkm/openapi.ts'],\n\t\t\t\t[`${modelsPackage}`]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t[`${uiPackage}`]: ['../../packages/ui/src'],\n\t\t\t\t[`${uiPackage}/*`]: ['../../packages/ui/src/*'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],\n\t\texclude: ['node_modules'],\n\t\treferences: [\n\t\t\t{ path: '../../apps/api' },\n\t\t\t{ path: '../../packages/ui' },\n\t\t\t{ path: '../../packages/models' },\n\t\t],\n\t};\n\n\t// Query client singleton for browser, fresh instance for server\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n  return new QueryClient({\n    defaultOptions: {\n      queries: {\n        staleTime: 60 * 1000,\n      },\n    },\n  });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n  if (typeof window === 'undefined') {\n    // Server: always make a new query client\n    return makeQueryClient();\n  }\n  // Browser: reuse existing query client\n  if (!browserQueryClient) browserQueryClient = makeQueryClient();\n  return browserQueryClient;\n}\n`;\n\n\t// Client config - NEXT_PUBLIC_* vars (available in browser)\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - only NEXT_PUBLIC_* vars (available in browser)\n// These values are inlined at build time by Next.js\nconst envParser = new EnvironmentParser({\n  NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,\n  NEXT_PUBLIC_AUTH_URL: process.env.NEXT_PUBLIC_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n  .create((get) => ({\n    apiUrl: get('NEXT_PUBLIC_API_URL').string(),\n    authUrl: get('NEXT_PUBLIC_AUTH_URL').string(),\n  }))\n  .parse();\n`;\n\n\t// Server config - server-only vars (not available in browser)\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser)\n// Access these only in Server Components, Route Handlers, or Server Actions\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n  .create((get) => ({\n    // Add server-only secrets here\n    // Example: stripeSecretKey: get('STRIPE_SECRET_KEY').string(),\n  }))\n  .parse();\n`;\n\n\t// Auth client for better-auth\n\tconst authClientTs = `import { createAuthClient } from 'better-auth/react';\nimport { magicLinkClient } from 'better-auth/client/plugins';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n  baseURL: clientConfig.authUrl,\n  plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\t// Providers using shared QueryClient\n\tconst providersTsx = `'use client';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n  const queryClient = getQueryClient();\n\n  return (\n    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n  );\n}\n`;\n\n\t// API client setup - imports directly from the API package export\n\tconst apiIndexTs = `import { createApi } from '${apiPackage}/client';\nimport { getQueryClient } from '~/lib/query-client.ts';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const api = createApi({\n  baseURL: clientConfig.apiUrl,\n  queryClient: getQueryClient(),\n});\n`;\n\n\t// globals.css that imports UI package styles\n\tconst globalsCss = `@import '${uiPackage}/styles';\n`;\n\n\t// App layout\n\tconst layoutTsx = `import type { Metadata } from 'next';\nimport { Providers } from './providers.tsx';\nimport './globals.css';\n\nexport const metadata: Metadata = {\n  title: '${options.name}',\n  description: 'Created with gkm init',\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <html lang=\"en\">\n      <body>\n        <Providers>{children}</Providers>\n      </body>\n    </html>\n  );\n}\n`;\n\n\t// Home page with API example using UI components\n\tconst pageTsx = `import { api } from '~/api/index.ts';\nimport { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from '${uiPackage}/components';\n\nexport default async function Home() {\n  // Type-safe API call using the generated client\n  const health = await api('GET /health').catch(() => null);\n\n  return (\n    <main className=\"min-h-screen bg-background p-8\">\n      <div className=\"mx-auto max-w-4xl space-y-8\">\n        <div className=\"space-y-2\">\n          <h1 className=\"text-4xl font-bold tracking-tight\">Welcome to ${options.name}</h1>\n          <p className=\"text-muted-foreground\">Your fullstack application is ready.</p>\n        </div>\n\n        <Card>\n          <CardHeader>\n            <CardTitle>API Status</CardTitle>\n            <CardDescription>Connection to your backend API</CardDescription>\n          </CardHeader>\n          <CardContent>\n            {health ? (\n              <pre className=\"rounded-lg bg-muted p-4 text-sm\">\n                {JSON.stringify(health, null, 2)}\n              </pre>\n            ) : (\n              <p className=\"text-destructive\">Unable to connect to API</p>\n            )}\n          </CardContent>\n        </Card>\n\n        <Card>\n          <CardHeader>\n            <CardTitle>Next Steps</CardTitle>\n            <CardDescription>Get started with your project</CardDescription>\n          </CardHeader>\n          <CardContent className=\"space-y-4\">\n            <ul className=\"list-inside list-disc space-y-2 text-muted-foreground\">\n              <li>Run <code className=\"rounded bg-muted px-1\">gkm openapi</code> to generate typed API client</li>\n              <li>Edit <code className=\"rounded bg-muted px-1\">apps/web/src/app/page.tsx</code> to customize this page</li>\n              <li>Add API routes in <code className=\"rounded bg-muted px-1\">apps/api/src/endpoints/</code></li>\n              <li>Add UI components with <code className=\"rounded bg-muted px-1\">npx shadcn@latest add</code> in packages/ui</li>\n            </ul>\n            <div className=\"flex gap-4\">\n              <Button>Get Started</Button>\n              <Button variant=\"outline\">Documentation</Button>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n    </main>\n  );\n}\n`;\n\n\t// .gitignore for Next.js\n\tconst gitignore = `.next/\nnode_modules/\n.env.local\n*.log\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/next.config.ts',\n\t\t\tcontent: nextConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/postcss.config.mjs',\n\t\t\tcontent: postcssConfig,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/globals.css',\n\t\t\tcontent: globalsCss,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/layout.tsx',\n\t\t\tcontent: layoutTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/providers.tsx',\n\t\t\tcontent: providersTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/app/page.tsx',\n\t\t\tcontent: pageTsx,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/client.ts',\n\t\t\tcontent: clientConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/config/server.ts',\n\t\t\tcontent: serverConfigTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/query-client.ts',\n\t\t\tcontent: queryClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/lib/auth-client.ts',\n\t\t\tcontent: authClientTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/src/api/index.ts',\n\t\t\tcontent: apiIndexTs,\n\t\t},\n\t\t{\n\t\t\tpath: 'apps/web/.gitignore',\n\t\t\tcontent: gitignore,\n\t\t},\n\t];\n}\n","import type { GeneratedFile, TemplateOptions } from '../templates/index.js';\nimport { GEEKMIDAS_VERSIONS } from '../versions.js';\n\n/**\n * Generate TanStack Start web app files for the fullstack template.\n *\n * Mirrors the Next.js scaffold (apps/web) but on Vite + TanStack Start +\n * TanStack Router with the `VITE_` env-var convention.\n */\nexport function generateTanStackWebFiles(\n\toptions: TemplateOptions,\n): GeneratedFile[] {\n\tif (!options.monorepo || options.template !== 'fullstack') {\n\t\treturn [];\n\t}\n\n\tconst packageName = `@${options.name}/web`;\n\tconst apiPackage = `@${options.name}/api`;\n\tconst modelsPackage = `@${options.name}/models`;\n\tconst uiPackage = `@${options.name}/ui`;\n\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.0.1',\n\t\tprivate: true,\n\t\ttype: 'module',\n\t\tscripts: {\n\t\t\tdev: 'gkm exec -- vite dev',\n\t\t\tbuild: 'gkm exec -- vite build',\n\t\t\tstart: 'node .output/server/index.mjs',\n\t\t\ttypecheck: 'tsc --noEmit',\n\t\t},\n\t\tdependencies: {\n\t\t\t[apiPackage]: 'workspace:*',\n\t\t\t[modelsPackage]: 'workspace:*',\n\t\t\t[uiPackage]: 'workspace:*',\n\t\t\t'@geekmidas/client': GEEKMIDAS_VERSIONS['@geekmidas/client'],\n\t\t\t'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],\n\t\t\t'@tanstack/react-query': '~5.80.0',\n\t\t\t'@tanstack/react-router': '^1.87.0',\n\t\t\t'@tanstack/react-start': '^1.87.0',\n\t\t\t'better-auth': '~1.2.0',\n\t\t\treact: '~19.2.0',\n\t\t\t'react-dom': '~19.2.0',\n\t\t},\n\t\tdevDependencies: {\n\t\t\t'@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],\n\t\t\t'@tailwindcss/vite': '^4.0.0',\n\t\t\t'@tanstack/router-plugin': '^1.87.0',\n\t\t\t'@types/node': '~22.0.0',\n\t\t\t'@types/react': '~19.0.0',\n\t\t\t'@types/react-dom': '~19.0.0',\n\t\t\t'@vitejs/plugin-react': '^4.3.4',\n\t\t\ttailwindcss: '^4.0.0',\n\t\t\ttsx: '~4.20.0',\n\t\t\ttypescript: '~5.8.2',\n\t\t\tvite: '^7.0.0',\n\t\t\t'vite-tsconfig-paths': '~5.1.0',\n\t\t},\n\t};\n\n\tconst viteConfig = `import { Credentials } from '@geekmidas/envkit/credentials';\nimport tailwindcss from '@tailwindcss/vite';\nimport { tanstackStart } from '@tanstack/react-start/plugin/vite';\nimport viteReact from '@vitejs/plugin-react';\nimport { defineConfig } from 'vite';\nimport tsconfigPaths from 'vite-tsconfig-paths';\n\nexport default defineConfig({\n  server: {\n    port: Number(Credentials.PORT ?? 3001),\n  },\n  // VITE_* vars are inlined automatically; no manual loadEnv needed.\n  envPrefix: 'VITE_',\n  plugins: [\n    tsconfigPaths({ root: import.meta.dirname }),\n    tailwindcss(),\n    tanstackStart(),\n    viteReact(),\n  ],\n});\n`;\n\n\tconst tsConfig = {\n\t\textends: '../../tsconfig.json',\n\t\tcompilerOptions: {\n\t\t\tlib: ['dom', 'dom.iterable', 'ES2022'],\n\t\t\tallowJs: true,\n\t\t\tskipLibCheck: true,\n\t\t\tstrict: true,\n\t\t\tnoEmit: true,\n\t\t\tallowImportingTsExtensions: true,\n\t\t\tesModuleInterop: true,\n\t\t\tmodule: 'ESNext',\n\t\t\tmoduleResolution: 'bundler',\n\t\t\tresolveJsonModule: true,\n\t\t\tisolatedModules: true,\n\t\t\tjsx: 'preserve',\n\t\t\tincremental: true,\n\t\t\tbaseUrl: '.',\n\t\t\ttypes: ['vite/client'],\n\t\t\tpaths: {\n\t\t\t\t'~/*': ['./src/*', '../../packages/ui/src/*'],\n\t\t\t\t[modelsPackage]: ['../../packages/models/src'],\n\t\t\t\t[`${modelsPackage}/*`]: ['../../packages/models/src/*'],\n\t\t\t\t[uiPackage]: ['../../packages/ui/src'],\n\t\t\t\t[`${uiPackage}/*`]: ['../../packages/ui/src/*'],\n\t\t\t\t[`${apiPackage}/client`]: ['../../apps/api/.gkm/openapi.ts'],\n\t\t\t},\n\t\t},\n\t\tinclude: ['**/*.ts', '**/*.tsx', 'src/routeTree.gen.ts'],\n\t\texclude: ['node_modules', '.output', '.vinxi', 'dist'],\n\t};\n\n\tconst queryClientTs = `import { QueryClient } from '@tanstack/react-query';\n\nfunction makeQueryClient() {\n  return new QueryClient({\n    defaultOptions: {\n      queries: {\n        staleTime: 60 * 1000,\n      },\n    },\n  });\n}\n\nlet browserQueryClient: QueryClient | undefined = undefined;\n\nexport function getQueryClient() {\n  if (typeof window === 'undefined') {\n    return makeQueryClient();\n  }\n  if (!browserQueryClient) browserQueryClient = makeQueryClient();\n  return browserQueryClient;\n}\n`;\n\n\tconst clientConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Client config - VITE_* vars are inlined at build time.\nconst envParser = new EnvironmentParser({\n  VITE_API_URL: import.meta.env.VITE_API_URL,\n  VITE_AUTH_URL: import.meta.env.VITE_AUTH_URL,\n});\n\nexport const clientConfig = envParser\n  .create((get) => ({\n    apiUrl: get('VITE_API_URL').string(),\n    authUrl: get('VITE_AUTH_URL').string(),\n  }))\n  .parse();\n`;\n\n\tconst serverConfigTs = `import { EnvironmentParser } from '@geekmidas/envkit';\n\n// Server config - all env vars (server-side only, not exposed to browser).\n// Access these only in TanStack Start server functions / server routes.\nconst envParser = new EnvironmentParser({ ...process.env });\n\nexport const serverConfig = envParser\n  .create((_get) => ({\n    // Add server-only secrets here\n    // Example: stripeSecretKey: _get('STRIPE_SECRET_KEY').string(),\n  }))\n  .parse();\n`;\n\n\tconst authClientTs = `import { magicLinkClient } from 'better-auth/client/plugins';\nimport { createAuthClient } from 'better-auth/react';\nimport { clientConfig } from '~/config/client.ts';\n\nexport const authClient = createAuthClient({\n  baseURL: clientConfig.authUrl,\n  plugins: [magicLinkClient()],\n});\n\nexport const { signIn, signUp, signOut, useSession, magicLink } = authClient;\n`;\n\n\tconst apiIndexTs = `import { createApi } from '${apiPackage}/client';\nimport { clientConfig } from '~/config/client.ts';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport function createAppApi(options?: { headers?: Record<string, string> }) {\n  return createApi({\n    baseURL: clientConfig.apiUrl,\n    queryClient: getQueryClient(),\n    headers: options?.headers,\n    onRequest: (config) => ({ ...config, credentials: 'include' }),\n  });\n}\n\nexport const api = createAppApi();\n`;\n\n\tconst routerTs = `import { createRouter } from '@tanstack/react-router';\nimport { routeTree } from './routeTree.gen.ts';\n\nexport function getRouter() {\n  return createRouter({\n    routeTree,\n    scrollRestoration: true,\n    defaultPreload: 'intent',\n  });\n}\n\ndeclare module '@tanstack/react-router' {\n  interface Register {\n    router: ReturnType<typeof getRouter>;\n  }\n}\n`;\n\n\t// Placeholder routeTree.gen — TanStack's plugin regenerates this on dev.\n\tconst routeTreeGen = `// This file is auto-generated by @tanstack/router-plugin.\n// It will be overwritten on the next \\`vite dev\\` run.\nimport { rootRouteWithContext } from '@tanstack/react-router';\n\nexport const routeTree = rootRouteWithContext()({\n  // Routes are populated by the plugin from src/routes/**.tsx\n} as never);\n`;\n\n\tconst rootRouteTsx = `/// <reference types=\"vite/client\" />\nimport '~/styles/globals.css';\n\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport {\n  HeadContent,\n  Outlet,\n  Scripts,\n  createRootRoute,\n} from '@tanstack/react-router';\nimport type { ReactNode } from 'react';\nimport { getQueryClient } from '~/lib/query-client.ts';\n\nexport const Route = createRootRoute({\n  head: () => ({\n    meta: [\n      { charSet: 'utf-8' },\n      { name: 'viewport', content: 'width=device-width, initial-scale=1' },\n      { title: '${options.name}' },\n    ],\n  }),\n  component: RootComponent,\n});\n\nfunction RootComponent() {\n  const queryClient = getQueryClient();\n  return (\n    <RootDocument>\n      <QueryClientProvider client={queryClient}>\n        <Outlet />\n      </QueryClientProvider>\n    </RootDocument>\n  );\n}\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <head>\n        <HeadContent />\n      </head>\n      <body>\n        {children}\n        <Scripts />\n      </body>\n    </html>\n  );\n}\n`;\n\n\tconst indexRouteTsx = `import { createFileRoute } from '@tanstack/react-router';\nimport { api } from '~/api/index.ts';\n\nexport const Route = createFileRoute('/')({\n  component: HomeComponent,\n});\n\nfunction HomeComponent() {\n  const { data: health } = api.useQuery('GET /health', {});\n\n  return (\n    <main className=\"min-h-screen bg-background p-8\">\n      <div className=\"mx-auto max-w-4xl space-y-8\">\n        <div className=\"space-y-2\">\n          <h1 className=\"text-4xl font-bold tracking-tight\">\n            Welcome to ${options.name}\n          </h1>\n          <p className=\"text-muted-foreground\">\n            Your TanStack Start app is ready.\n          </p>\n        </div>\n\n        <section className=\"rounded-lg border p-6\">\n          <h2 className=\"text-xl font-semibold\">API Status</h2>\n          {health ? (\n            <pre className=\"mt-4 rounded bg-muted p-4 text-sm\">\n              {JSON.stringify(health, null, 2)}\n            </pre>\n          ) : (\n            <p className=\"mt-2 text-muted-foreground\">Connecting…</p>\n          )}\n        </section>\n      </div>\n    </main>\n  );\n}\n`;\n\n\tconst globalsCss = `@import '${uiPackage}/styles';\n\n@source \"../..\";\n@source \"../../../../packages/ui/src\";\n`;\n\n\tconst gitignore = `.output/\n.vinxi/\nnode_modules/\n.env.local\n*.log\nsrc/routeTree.gen.ts\n`;\n\n\treturn [\n\t\t{\n\t\t\tpath: 'apps/web/package.json',\n\t\t\tcontent: `${JSON.stringify(packageJson, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/vite.config.ts', content: viteConfig },\n\t\t{\n\t\t\tpath: 'apps/web/tsconfig.json',\n\t\t\tcontent: `${JSON.stringify(tsConfig, null, 2)}\\n`,\n\t\t},\n\t\t{ path: 'apps/web/src/lib/query-client.ts', content: queryClientTs },\n\t\t{ path: 'apps/web/src/lib/auth-client.ts', content: authClientTs },\n\t\t{ path: 'apps/web/src/config/client.ts', content: clientConfigTs },\n\t\t{ path: 'apps/web/src/config/server.ts', content: serverConfigTs },\n\t\t{ path: 'apps/web/src/api/index.ts', content: apiIndexTs },\n\t\t{ path: 'apps/web/src/router.tsx', content: routerTs },\n\t\t{ path: 'apps/web/src/routeTree.gen.ts', content: routeTreeGen },\n\t\t{ path: 'apps/web/src/routes/__root.tsx', content: rootRouteTsx },\n\t\t{ path: 'apps/web/src/routes/index.tsx', content: indexRouteTsx },\n\t\t{ path: 'apps/web/src/styles/globals.css', content: globalsCss },\n\t\t{ path: 'apps/web/.gitignore', content: gitignore },\n\t];\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport fg from 'fast-glob';\nimport { parse as parseYaml } from 'yaml';\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\n/**\n * Detect the package manager being used based on lockfiles or npm_config_user_agent\n */\nexport function detectPackageManager(\n\tcwd: string = process.cwd(),\n): PackageManager {\n\t// Check for lockfiles in cwd\n\tif (existsSync(join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n\tif (existsSync(join(cwd, 'yarn.lock'))) return 'yarn';\n\tif (existsSync(join(cwd, 'bun.lockb'))) return 'bun';\n\tif (existsSync(join(cwd, 'package-lock.json'))) return 'npm';\n\n\t// Check npm_config_user_agent (set when running via npx/pnpm dlx/etc)\n\tconst userAgent = process.env.npm_config_user_agent || '';\n\tif (userAgent.includes('pnpm')) return 'pnpm';\n\tif (userAgent.includes('yarn')) return 'yarn';\n\tif (userAgent.includes('bun')) return 'bun';\n\n\treturn 'npm';\n}\n\n/**\n * Validate project name for npm package naming conventions\n */\nexport function validateProjectName(name: string): boolean | string {\n\tif (!name) {\n\t\treturn 'Project name is required';\n\t}\n\n\t// Check for valid npm package name characters\n\tif (!/^[a-z0-9-_@/.]+$/i.test(name)) {\n\t\treturn 'Project name can only contain letters, numbers, hyphens, underscores, @, /, and .';\n\t}\n\n\t// Check for reserved names\n\tconst reserved = ['node_modules', '.git', 'package.json', 'src'];\n\tif (reserved.includes(name.toLowerCase())) {\n\t\treturn `\"${name}\" is a reserved name`;\n\t}\n\n\treturn true;\n}\n\n/**\n * Check if a directory already exists at the target path\n */\nexport function checkDirectoryExists(\n\tname: string,\n\tcwd: string = process.cwd(),\n): boolean | string {\n\tconst targetPath = join(cwd, name);\n\tif (existsSync(targetPath)) {\n\t\treturn `Directory \"${name}\" already exists`;\n\t}\n\treturn true;\n}\n\n/**\n * Get the install command for a package manager\n */\nexport function getInstallCommand(pkgManager: PackageManager): string {\n\tswitch (pkgManager) {\n\t\tcase 'pnpm':\n\t\t\treturn 'pnpm install';\n\t\tcase 'yarn':\n\t\t\treturn 'yarn';\n\t\tcase 'bun':\n\t\t\treturn 'bun install';\n\t\tdefault:\n\t\t\treturn 'npm install';\n\t}\n}\n\n/**\n * Get the dev command for a package manager\n */\nexport function getRunCommand(\n\tpkgManager: PackageManager,\n\tscript: string,\n): string {\n\tswitch (pkgManager) {\n\t\tcase 'pnpm':\n\t\t\treturn `pnpm ${script}`;\n\t\tcase 'yarn':\n\t\t\treturn `yarn ${script}`;\n\t\tcase 'bun':\n\t\t\treturn `bun run ${script}`;\n\t\tdefault:\n\t\t\treturn `npm run ${script}`;\n\t}\n}\n\nconst lockfileByPm: Record<PackageManager, string> = {\n\tpnpm: 'pnpm-lock.yaml',\n\tyarn: 'yarn.lock',\n\tnpm: 'package-lock.json',\n\tbun: 'bun.lockb',\n};\n\n/**\n * Find the workspace/project root by walking up from cwd.\n * Checks for PM-specific workspace config, package.json#workspaces,\n * and lockfiles.\n */\nexport function findWorkspaceRoot(cwd: string, pm: PackageManager): string {\n\tlet dir = cwd;\n\tconst root = parse(dir).root;\n\tconst lockfile = lockfileByPm[pm];\n\n\twhile (dir !== root) {\n\t\tif (pm === 'pnpm' && existsSync(join(dir, 'pnpm-workspace.yaml'))) {\n\t\t\treturn dir;\n\t\t}\n\n\t\tconst pkgJsonPath = join(dir, 'package.json');\n\t\tif (existsSync(pkgJsonPath)) {\n\t\t\ttry {\n\t\t\t\tconst pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n\t\t\t\tif (pkg.workspaces) return dir;\n\t\t\t} catch {\n\t\t\t\t// ignore malformed package.json\n\t\t\t}\n\t\t}\n\n\t\tif (existsSync(join(dir, lockfile))) {\n\t\t\treturn dir;\n\t\t}\n\n\t\tdir = dirname(dir);\n\t}\n\n\treturn cwd;\n}\n\n/**\n * Get workspace package glob patterns from pnpm-workspace.yaml\n * or package.json#workspaces.\n */\nexport function getWorkspaceGlobs(root: string): string[] {\n\tconst pnpmWorkspacePath = join(root, 'pnpm-workspace.yaml');\n\tif (existsSync(pnpmWorkspacePath)) {\n\t\tconst content = readFileSync(pnpmWorkspacePath, 'utf-8');\n\t\tconst parsed = parseYaml(content);\n\t\treturn parsed?.packages ?? [];\n\t}\n\n\tconst rootPkgJsonPath = join(root, 'package.json');\n\tif (existsSync(rootPkgJsonPath)) {\n\t\tconst pkg = JSON.parse(readFileSync(rootPkgJsonPath, 'utf-8'));\n\t\tif (Array.isArray(pkg.workspaces)) {\n\t\t\treturn pkg.workspaces;\n\t\t}\n\t\tif (pkg.workspaces?.packages) {\n\t\t\treturn pkg.workspaces.packages;\n\t\t}\n\t}\n\n\treturn [];\n}\n\n/**\n * Find all package.json files across a workspace.\n * Returns the root package.json plus all workspace member package.json paths.\n */\nexport function findWorkspacePackages(\n\tcwd: string,\n\tpm: PackageManager,\n): string[] {\n\tconst workspaceRoot = findWorkspaceRoot(cwd, pm);\n\tconst results: string[] = [];\n\n\tconst rootPkgJson = join(workspaceRoot, 'package.json');\n\tif (existsSync(rootPkgJson)) {\n\t\tresults.push(rootPkgJson);\n\t}\n\n\tconst globs = getWorkspaceGlobs(workspaceRoot);\n\n\tfor (const glob of globs) {\n\t\tconst pattern = `${glob}/package.json`;\n\t\tconst matches = fg.sync(pattern, {\n\t\t\tcwd: workspaceRoot,\n\t\t\tabsolute: true,\n\t\t\tignore: ['**/node_modules/**'],\n\t\t});\n\t\tresults.push(...matches);\n\t}\n\n\treturn [...new Set(results)];\n}\n","import { execSync } from 'node:child_process';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport prompts from 'prompts';\nimport { createStageSecrets } from '../secrets/generator.js';\nimport { getKeyPath } from '../secrets/keystore.js';\nimport { writeStageSecrets } from '../secrets/storage.js';\nimport {\n\tgenerateDbPassword,\n\tgenerateDbUrl,\n} from '../setup/fullstack-secrets.js';\nimport type { ComposeServiceName, EventsBackend } from '../types.js';\nimport { generateAuthAppFiles } from './generators/auth.js';\nimport { generateConfigFiles } from './generators/config.js';\nimport {\n\ttype DatabaseAppConfig,\n\tgenerateDockerFiles,\n} from './generators/docker.js';\nimport { generateEnvFiles } from './generators/env.js';\nimport { generateExpoAppFiles } from './generators/mobile-expo.js';\nimport { generateModelsPackage } from './generators/models.js';\nimport { generateMonorepoFiles } from './generators/monorepo.js';\nimport { generatePackageJson } from './generators/package.js';\nimport { generateSourceFiles } from './generators/source.js';\nimport { generateTestFiles } from './generators/test.js';\nimport { generateUiPackageFiles } from './generators/ui.js';\nimport { generateWebAppFiles } from './generators/web.js';\nimport { generateTanStackWebFiles } from './generators/web-tanstack.js';\nimport {\n\ttype DeployTarget,\n\tdeployTargetChoices,\n\teventsBackendChoices,\n\ttype FullstackFrontendFramework,\n\tfrontendFrameworkChoices,\n\tgetTemplate,\n\tisFullstackTemplate,\n\tloggerTypeChoices,\n\ttype PackageManager,\n\tpackageManagerChoices,\n\troutesStructureChoices,\n\ttype ServicesSelection,\n\tservicesChoices,\n\ttype TemplateName,\n\ttype TemplateOptions,\n\ttemplateChoices,\n} from './templates/index.js';\nimport {\n\tcheckDirectoryExists,\n\tdetectPackageManager,\n\tgetInstallCommand,\n\tgetRunCommand,\n\tvalidateProjectName,\n} from './utils.js';\n\nexport interface InitOptions {\n\t/** Project name */\n\tname?: string;\n\t/** Template to use */\n\ttemplate?: TemplateName;\n\t/** Skip dependency installation */\n\tskipInstall?: boolean;\n\t/** Use defaults for all prompts */\n\tyes?: boolean;\n\t/** Force monorepo setup (deprecated, use fullstack template) */\n\tmonorepo?: boolean;\n\t/** API app path in monorepo */\n\tapiPath?: string;\n\t/** Package manager to use */\n\tpm?: PackageManager;\n}\n\n/**\n * Main init command - scaffolds a new project\n */\nexport async function initCommand(\n\tprojectName?: string,\n\toptions: InitOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst detectedPkgManager = detectPackageManager(cwd);\n\n\t// Handle Ctrl+C gracefully\n\tprompts.override({});\n\tconst onCancel = () => {\n\t\tprocess.exit(0);\n\t};\n\n\t// Gather answers via prompts\n\tconst answers = await prompts(\n\t\t[\n\t\t\t{\n\t\t\t\ttype: projectName || options.name ? null : 'text',\n\t\t\t\tname: 'name',\n\t\t\t\tmessage: 'Project name:',\n\t\t\t\tinitial: 'my-app',\n\t\t\t\tvalidate: (value: string) => {\n\t\t\t\t\tconst nameValid = validateProjectName(value);\n\t\t\t\t\tif (nameValid !== true) return nameValid;\n\t\t\t\t\tconst dirValid = checkDirectoryExists(value, cwd);\n\t\t\t\t\tif (dirValid !== true) return dirValid;\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.template || options.yes ? null : 'select',\n\t\t\t\tname: 'template',\n\t\t\t\tmessage: 'Template:',\n\t\t\t\tchoices: templateChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'multiselect',\n\t\t\t\tname: 'services',\n\t\t\t\tmessage: 'Services (space to select, enter to confirm):',\n\t\t\t\tchoices: servicesChoices.map((c) => ({ ...c, selected: true })),\n\t\t\t\thint: '- Space to select. Return to submit',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'eventsBackend',\n\t\t\t\tmessage: 'Event backend:',\n\t\t\t\tchoices: eventsBackendChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'packageManager',\n\t\t\t\tmessage: 'Package manager:',\n\t\t\t\tchoices: packageManagerChoices,\n\t\t\t\tinitial: packageManagerChoices.findIndex(\n\t\t\t\t\t(c) => c.value === detectedPkgManager,\n\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'deployTarget',\n\t\t\t\tmessage: 'Deployment target:',\n\t\t\t\tchoices: deployTargetChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'confirm',\n\t\t\t\tname: 'telescope',\n\t\t\t\tmessage: 'Include Telescope (debugging dashboard)?',\n\t\t\t\tinitial: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'loggerType',\n\t\t\t\tmessage: 'Logger:',\n\t\t\t\tchoices: loggerTypeChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: options.yes ? null : 'select',\n\t\t\t\tname: 'routesStructure',\n\t\t\t\tmessage: 'Routes structure:',\n\t\t\t\tchoices: routesStructureChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Only prompt for frontend framework on the fullstack template.\n\t\t\t\ttype: (_prev, values) =>\n\t\t\t\t\t!options.yes &&\n\t\t\t\t\t(options.template === 'fullstack' || values.template === 'fullstack')\n\t\t\t\t\t\t? 'select'\n\t\t\t\t\t\t: null,\n\t\t\t\tname: 'frontendFramework',\n\t\t\t\tmessage: 'Frontend framework:',\n\t\t\t\tchoices: frontendFrameworkChoices,\n\t\t\t\tinitial: 0,\n\t\t\t},\n\t\t],\n\t\t{ onCancel },\n\t);\n\n\t// Build final options\n\tconst name = projectName || options.name || answers.name;\n\tif (!name) {\n\t\tconsole.error('Project name is required');\n\t\tprocess.exit(1);\n\t}\n\n\t// Validate name if provided via argument\n\tif (projectName || options.name) {\n\t\tconst nameToValidate = projectName || options.name!;\n\t\tconst nameValid = validateProjectName(nameToValidate);\n\t\tif (nameValid !== true) {\n\t\t\tconsole.error(nameValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconst dirValid = checkDirectoryExists(nameToValidate, cwd);\n\t\tif (dirValid !== true) {\n\t\t\tconsole.error(dirValid);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst template: TemplateName = options.template || answers.template || 'api';\n\tconst isFullstack = isFullstackTemplate(template);\n\n\t// For fullstack, force monorepo mode\n\t// For api template, monorepo is optional (via --monorepo flag)\n\tconst monorepo = isFullstack || options.monorepo || false;\n\n\t// Parse services selection\n\tconst servicesArray: string[] = options.yes\n\t\t? ['db', 'cache', 'mail', 'storage']\n\t\t: answers.services || [];\n\n\t// Determine events backend (default to pgboss for all templates with --yes)\n\tconst eventsBackend: EventsBackend | undefined = options.yes\n\t\t? 'pgboss'\n\t\t: answers.eventsBackend;\n\n\tconst services: ServicesSelection = {\n\t\tdb: servicesArray.includes('db'),\n\t\tcache: servicesArray.includes('cache'),\n\t\tmail: servicesArray.includes('mail'),\n\t\tstorage: servicesArray.includes('storage'),\n\t\tevents: eventsBackend,\n\t};\n\n\t// pgboss requires postgres\n\tif (services.events === 'pgboss') {\n\t\tservices.db = true;\n\t}\n\n\tconst pkgManager: PackageManager = options.pm\n\t\t? options.pm\n\t\t: options.yes\n\t\t\t? 'pnpm'\n\t\t\t: (answers.packageManager ?? detectedPkgManager);\n\n\tconst deployTarget: DeployTarget = options.yes\n\t\t? 'dokploy'\n\t\t: (answers.deployTarget ?? 'dokploy');\n\n\tconst database = services.db;\n\tconst frontendFramework: FullstackFrontendFramework | undefined = isFullstack\n\t\t? options.yes\n\t\t\t? 'nextjs'\n\t\t\t: (answers.frontendFramework ?? 'nextjs')\n\t\t: undefined;\n\tconst templateOptions: TemplateOptions = {\n\t\tname,\n\t\ttemplate,\n\t\ttelescope: options.yes ? true : (answers.telescope ?? true),\n\t\tdatabase,\n\t\tstudio: database,\n\t\tloggerType: options.yes ? 'pino' : (answers.loggerType ?? 'pino'),\n\t\troutesStructure: options.yes\n\t\t\t? 'centralized-endpoints'\n\t\t\t: (answers.routesStructure ?? 'centralized-endpoints'),\n\t\tmonorepo,\n\t\tapiPath: monorepo ? (options.apiPath ?? 'apps/api') : '',\n\t\tpackageManager: pkgManager,\n\t\tdeployTarget,\n\t\tservices,\n\t\tfrontendFramework,\n\t};\n\n\tconst targetDir = join(cwd, name);\n\tconst baseTemplate = getTemplate(templateOptions.template);\n\n\tconst isMonorepo = templateOptions.monorepo;\n\tconst apiPath = templateOptions.apiPath;\n\n\tconsole.log('\\n🚀 Creating your project...\\n');\n\n\t// Create project directory\n\tawait mkdir(targetDir, { recursive: true });\n\n\t// For monorepo, app files go in the specified apiPath (e.g., apps/api)\n\tconst appDir = isMonorepo ? join(targetDir, apiPath) : targetDir;\n\tif (isMonorepo) {\n\t\tawait mkdir(appDir, { recursive: true });\n\t}\n\n\t// Generate per-app database configs for fullstack template\n\tconst dbApps: DatabaseAppConfig[] = [];\n\tif (isFullstack && services.db) {\n\t\tdbApps.push(\n\t\t\t{ name: 'api', password: generateDbPassword() },\n\t\t\t{ name: 'auth', password: generateDbPassword() },\n\t\t);\n\t}\n\n\t// Collect app files (backend/api)\n\t// Note: Docker files go to root for monorepo, so exclude them here\n\tconst appFiles = baseTemplate\n\t\t? [\n\t\t\t\t...generatePackageJson(templateOptions, baseTemplate),\n\t\t\t\t...generateConfigFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateEnvFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateSourceFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateTestFiles(templateOptions, baseTemplate),\n\t\t\t\t...(isMonorepo\n\t\t\t\t\t? []\n\t\t\t\t\t: generateDockerFiles(templateOptions, baseTemplate, dbApps)),\n\t\t\t]\n\t\t: [];\n\n\t// For monorepo, docker files go at root level\n\tconst dockerFiles =\n\t\tisMonorepo && baseTemplate\n\t\t\t? generateDockerFiles(templateOptions, baseTemplate, dbApps)\n\t\t\t: [];\n\n\t// Collect root monorepo files (includes packages/models)\n\tconst rootFiles = baseTemplate\n\t\t? [\n\t\t\t\t...generateMonorepoFiles(templateOptions, baseTemplate),\n\t\t\t\t...generateModelsPackage(templateOptions),\n\t\t\t]\n\t\t: [];\n\n\t// Collect frontend app files for fullstack template, dispatched by framework\n\tconst webAppFiles = isFullstack\n\t\t? frontendFramework === 'tanstack-start'\n\t\t\t? generateTanStackWebFiles(templateOptions)\n\t\t\t: frontendFramework === 'expo'\n\t\t\t\t? generateExpoAppFiles(templateOptions)\n\t\t\t\t: generateWebAppFiles(templateOptions)\n\t\t: [];\n\n\t// Collect auth app files for fullstack template\n\tconst authAppFiles = isFullstack ? generateAuthAppFiles(templateOptions) : [];\n\n\t// Collect UI package files for fullstack template\n\tconst uiPackageFiles = isFullstack\n\t\t? generateUiPackageFiles(templateOptions)\n\t\t: [];\n\n\t// Write root files (for monorepo)\n\tfor (const { path, content } of rootFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write docker files at root for monorepo\n\tfor (const { path, content } of dockerFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write app files (backend)\n\tfor (const { path, content } of appFiles) {\n\t\tconst fullPath = join(appDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write web app files (frontend)\n\tfor (const { path, content } of webAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write auth app files (authentication service)\n\tfor (const { path, content } of authAppFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Write UI package files (shared components)\n\tfor (const { path, content } of uiPackageFiles) {\n\t\tconst fullPath = join(targetDir, path);\n\t\tawait mkdir(dirname(fullPath), { recursive: true });\n\t\tawait writeFile(fullPath, content);\n\t}\n\n\t// Initialize encrypted secrets for development stage\n\tconsole.log('🔐 Initializing encrypted secrets...\\n');\n\tconst secretServices: ComposeServiceName[] = [];\n\tif (services.db) secretServices.push('postgres');\n\tif (services.cache) secretServices.push('redis');\n\tif (services.storage) secretServices.push('minio');\n\tif (services.mail) secretServices.push('mailpit');\n\tif (services.events === 'sns') secretServices.push('localstack');\n\tif (services.events === 'rabbitmq') secretServices.push('rabbitmq');\n\n\tconst devSecrets = createStageSecrets('development', secretServices, {\n\t\tprojectName: name,\n\t\teventsBackend: services.events,\n\t});\n\n\t// Add common custom secrets\n\tconst customSecrets: Record<string, string> = {\n\t\tNODE_ENV: 'development',\n\t\tPORT: '3000',\n\t\tLOG_LEVEL: 'debug',\n\t\tJWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n\t};\n\n\t// Add per-app database URLs and passwords for fullstack template\n\tif (isFullstack && dbApps.length > 0) {\n\t\tfor (const app of dbApps) {\n\t\t\t// Database URL for the app to use (all apps use same database, different users/schemas)\n\t\t\tconst urlKey = `${app.name.toUpperCase()}_DATABASE_URL`;\n\t\t\tcustomSecrets[urlKey] = generateDbUrl(app.name, app.password, name);\n\n\t\t\t// Database password for docker-compose init script\n\t\t\tconst passwordKey = `${app.name.toUpperCase()}_DB_PASSWORD`;\n\t\t\tcustomSecrets[passwordKey] = app.password;\n\t\t}\n\n\t\t// Auth service secrets (better-auth)\n\t\tcustomSecrets.AUTH_PORT = '3002';\n\t\tcustomSecrets.AUTH_URL = 'http://localhost:3002'; // For API app to call auth service\n\t\tcustomSecrets.BETTER_AUTH_SECRET = `better-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\t\tcustomSecrets.BETTER_AUTH_URL = 'http://localhost:3002';\n\t\tcustomSecrets.BETTER_AUTH_TRUSTED_ORIGINS =\n\t\t\t'http://localhost:3000,http://localhost:3001';\n\t}\n\n\tdevSecrets.custom = customSecrets;\n\n\tawait writeStageSecrets(devSecrets, targetDir);\n\tconst keyPath = getKeyPath('development', name);\n\tconsole.log(`  Secrets: .gkm/secrets/development.json (encrypted)`);\n\tconsole.log(`  Key: ${keyPath}\\n`);\n\n\t// Install dependencies\n\tif (!options.skipInstall) {\n\t\tconsole.log('\\n📦 Installing dependencies...\\n');\n\t\ttry {\n\t\t\texecSync(getInstallCommand(pkgManager), {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\tconsole.error('Failed to install dependencies');\n\t\t}\n\n\t\t// Format generated files with biome\n\t\ttry {\n\t\t\texecSync('npx @biomejs/biome format --write --unsafe .', {\n\t\t\t\tcwd: targetDir,\n\t\t\t\tstdio: 'inherit',\n\t\t\t});\n\t\t} catch {\n\t\t\t// Silently ignore format errors\n\t\t}\n\t}\n\n\t// Initialize git repository\n\tconsole.log('\\n📦 Initializing git repository...\\n');\n\ttry {\n\t\texecSync('git init', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git branch -M main', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git add .', { cwd: targetDir, stdio: 'pipe' });\n\t\texecSync('git commit -m \"🎉 Project created with @geekmidas/toolbox\"', {\n\t\t\tcwd: targetDir,\n\t\t\tstdio: 'pipe',\n\t\t});\n\t\tconsole.log('  Initialized git repository on branch main');\n\t} catch {\n\t\tconsole.log(\n\t\t\t'  Could not initialize git repository (git may not be installed)',\n\t\t);\n\t}\n\n\t// Print success message with next steps\n\tprintNextSteps(name, templateOptions, pkgManager);\n}\n\n/**\n * Print success message with next steps\n */\nfunction printNextSteps(\n\tprojectName: string,\n\toptions: TemplateOptions,\n\tpkgManager: PackageManager,\n): void {\n\tconst devCommand = getRunCommand(pkgManager, 'dev');\n\tconst cdCommand = `cd ${projectName}`;\n\n\tconsole.log(`\\n${'─'.repeat(50)}`);\n\tconsole.log('\\n✅ Project created successfully!\\n');\n\n\tconsole.log('Next steps:\\n');\n\tconsole.log(`  ${cdCommand}`);\n\n\tif (options.services.db) {\n\t\tconsole.log(`  # Start PostgreSQL (if not running)`);\n\t\tconsole.log(`  docker compose up -d postgres`);\n\t}\n\n\tconsole.log(`  ${devCommand}`);\n\tconsole.log('');\n\n\tif (options.monorepo) {\n\t\tconsole.log('📁 Project structure:');\n\t\tconsole.log(`  ${projectName}/`);\n\t\tconsole.log(`  ├── apps/`);\n\t\tconsole.log(`  │   ├── api/          # Backend API`);\n\t\tif (isFullstackTemplate(options.template)) {\n\t\t\tconsole.log(`  │   ├── auth/         # Auth service (better-auth)`);\n\t\t\tswitch (options.frontendFramework) {\n\t\t\t\tcase 'tanstack-start':\n\t\t\t\t\tconsole.log(`  │   └── web/          # TanStack Start frontend`);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'expo':\n\t\t\t\t\tconsole.log(`  │   └── app/          # Expo (React Native) app`);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(`  │   └── web/          # Next.js frontend`);\n\t\t\t}\n\t\t}\n\t\tconsole.log(`  ├── packages/`);\n\t\tconsole.log(`  │   ├── models/       # Shared Zod schemas`);\n\t\tif (isFullstackTemplate(options.template)) {\n\t\t\tconsole.log(`  │   └── ui/           # Shared UI components`);\n\t\t}\n\t\tconsole.log(`  ├── .gkm/secrets/     # Encrypted secrets`);\n\t\tconsole.log(`  ├── gkm.config.ts     # Workspace config`);\n\t\tconsole.log(`  └── turbo.json        # Turbo config`);\n\t\tconsole.log('');\n\t}\n\n\tconsole.log('🔐 Secrets management:');\n\tconsole.log(`  gkm secrets:show --stage development  # View secrets`);\n\tconsole.log(`  gkm secrets:set KEY VALUE --stage development  # Add secret`);\n\tconsole.log(\n\t\t`  gkm secrets:init --stage production  # Create production secrets`,\n\t);\n\tconsole.log('');\n\n\tif (options.deployTarget === 'dokploy') {\n\t\tconsole.log('🚀 Deployment:');\n\t\tconsole.log(`  ${getRunCommand(pkgManager, 'deploy')}`);\n\t\tconsole.log('');\n\t}\n\n\tconsole.log('📚 Documentation: https://geekmidas.github.io/toolbox/');\n\tconsole.log('');\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { loadConfig, loadWorkspaceConfig } from '../config';\nimport { generateFullstackCustomSecrets } from '../setup/fullstack-secrets';\nimport type { ComposeServiceName, ComposeServicesConfig } from '../types';\nimport { createStageSecrets, rotateServicePassword } from './generator';\nimport {\n\tmaskPassword,\n\treadStageSecrets,\n\tsecretsExist,\n\tsetCustomSecret,\n\twriteStageSecrets,\n} from './storage';\n\nconst logger = console;\n\nexport interface SecretsInitOptions {\n\tstage: string;\n\tforce?: boolean;\n}\n\nexport interface SecretsSetOptions {\n\tstage: string;\n}\n\nexport interface SecretsShowOptions {\n\tstage: string;\n\treveal?: boolean;\n}\n\nexport interface SecretsRotateOptions {\n\tstage: string;\n\tservice?: ComposeServiceName;\n}\n\nexport interface SecretsImportOptions {\n\tstage: string;\n\t/** Merge with existing secrets (default: true) */\n\tmerge?: boolean;\n}\n\n/**\n * Extract service names from compose config.\n */\nexport function getServicesFromConfig(\n\tservices: ComposeServicesConfig | ComposeServiceName[] | undefined,\n): ComposeServiceName[] {\n\tif (!services) {\n\t\treturn [];\n\t}\n\n\tif (Array.isArray(services)) {\n\t\treturn services;\n\t}\n\n\t// Object format - get keys where value is truthy\n\treturn (Object.entries(services) as [ComposeServiceName, unknown][])\n\t\t.filter(([, config]) => config)\n\t\t.map(([name]) => name);\n}\n\n/**\n * Initialize secrets for a stage.\n * Generates secure random passwords for configured services.\n */\nexport async function secretsInitCommand(\n\toptions: SecretsInitOptions,\n): Promise<void> {\n\tconst { stage, force } = options;\n\n\t// Check if secrets already exist\n\tif (!force && secretsExist(stage)) {\n\t\tlogger.error(\n\t\t\t`Secrets already exist for stage \"${stage}\". Use --force to overwrite.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Load config to get services\n\tconst config = await loadConfig();\n\tconst services = getServicesFromConfig(config.docker?.compose?.services);\n\n\tif (services.length === 0) {\n\t\tlogger.warn(\n\t\t\t'No services configured in docker.compose.services. Creating secrets with empty services.',\n\t\t);\n\t}\n\n\t// Detect workspace mode for project name and fullstack secrets\n\tlet projectName: string | undefined;\n\tlet workspaceSecrets: Record<string, string> | undefined;\n\ttry {\n\t\tconst loaded = await loadWorkspaceConfig();\n\t\tprojectName = loaded.workspace.name;\n\t\tconst isMultiApp = Object.keys(loaded.workspace.apps).length > 1;\n\n\t\tif (isMultiApp) {\n\t\t\tworkspaceSecrets = generateFullstackCustomSecrets(loaded.workspace);\n\t\t\tlogger.log('  Detected workspace mode — generating per-app secrets');\n\t\t}\n\t} catch {\n\t\t// Not a workspace — single-app mode, skip custom secrets\n\t}\n\n\t// Generate secrets (with project name so DATABASE_URL matches app-specific URLs)\n\tconst secrets = createStageSecrets(stage, services, { projectName });\n\n\tif (workspaceSecrets) {\n\t\tsecrets.custom = workspaceSecrets;\n\t}\n\n\t// Write to file\n\tawait writeStageSecrets(secrets);\n\n\tlogger.log(`\\n✓ Secrets initialized for stage \"${stage}\"`);\n\tlogger.log(`  Location: .gkm/secrets/${stage}.json`);\n\tlogger.log('\\n  Generated credentials for:');\n\n\tfor (const service of services) {\n\t\tlogger.log(`    - ${service}`);\n\t}\n\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(`\\n  DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(`  REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);\n\t}\n\tif (secrets.urls.RABBITMQ_URL) {\n\t\tlogger.log(`  RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(`  STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\tif (Object.keys(secrets.custom).length > 0) {\n\t\tlogger.log(`\\n  Custom secrets: ${Object.keys(secrets.custom).length}`);\n\t}\n\n\tlogger.log(`\\n  Use \"gkm secrets:show --stage ${stage}\" to view secrets`);\n\tlogger.log(\n\t\t'  Use \"gkm secrets:set <KEY> <VALUE> --stage ' +\n\t\t\tstage +\n\t\t\t'\" to add custom secrets',\n\t);\n}\n\n/**\n * Read all data from stdin.\n */\nasync function readStdin(): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\n\tfor await (const chunk of process.stdin) {\n\t\tchunks.push(chunk);\n\t}\n\n\treturn Buffer.concat(chunks).toString('utf-8').trim();\n}\n\n/**\n * Set a custom secret.\n * If value is not provided, reads from stdin.\n */\nexport async function secretsSetCommand(\n\tkey: string,\n\tvalue: string | undefined,\n\toptions: SecretsSetOptions,\n): Promise<void> {\n\tconst { stage } = options;\n\n\t// Read from stdin if value not provided\n\tlet secretValue = value;\n\tif (!secretValue) {\n\t\tif (process.stdin.isTTY) {\n\t\t\tlogger.error(\n\t\t\t\t'No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>',\n\t\t\t);\n\t\t\tlogger.error(\n\t\t\t\t'Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>',\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsecretValue = await readStdin();\n\t\tif (!secretValue) {\n\t\t\tlogger.error('No value received from stdin');\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\ttry {\n\t\tawait setCustomSecret(stage, key, secretValue);\n\t\tlogger.log(`\\n✓ Secret \"${key}\" set for stage \"${stage}\"`);\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\terror instanceof Error ? error.message : 'Failed to set secret',\n\t\t);\n\t\tprocess.exit(1);\n\t}\n}\n\n/**\n * Show secrets for a stage.\n */\nexport async function secretsShowCommand(\n\toptions: SecretsShowOptions,\n): Promise<void> {\n\tconst { stage, reveal } = options;\n\n\tconst secrets = await readStageSecrets(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tlogger.log(`\\nSecrets for stage \"${stage}\":`);\n\tlogger.log(`  Created: ${secrets.createdAt}`);\n\tlogger.log(`  Updated: ${secrets.updatedAt}`);\n\n\t// Show service credentials\n\tlogger.log('\\nService Credentials:');\n\tfor (const [service, creds] of Object.entries(secrets.services)) {\n\t\tif (creds) {\n\t\t\tlogger.log(`\\n  ${service}:`);\n\t\t\tlogger.log(`    host: ${creds.host}`);\n\t\t\tlogger.log(`    port: ${creds.port}`);\n\t\t\tlogger.log(`    username: ${creds.username}`);\n\t\t\tlogger.log(\n\t\t\t\t`    password: ${reveal ? creds.password : maskPassword(creds.password)}`,\n\t\t\t);\n\t\t\tif (creds.database) {\n\t\t\t\tlogger.log(`    database: ${creds.database}`);\n\t\t\t}\n\t\t\tif (creds.vhost) {\n\t\t\t\tlogger.log(`    vhost: ${creds.vhost}`);\n\t\t\t}\n\t\t\tif (creds.bucket) {\n\t\t\t\tlogger.log(`    bucket: ${creds.bucket}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Show URLs\n\tlogger.log('\\nConnection URLs:');\n\tif (secrets.urls.DATABASE_URL) {\n\t\tlogger.log(\n\t\t\t`  DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.REDIS_URL) {\n\t\tlogger.log(\n\t\t\t`  REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.RABBITMQ_URL) {\n\t\tlogger.log(\n\t\t\t`  RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`,\n\t\t);\n\t}\n\tif (secrets.urls.STORAGE_ENDPOINT) {\n\t\tlogger.log(`  STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);\n\t}\n\n\t// Show custom secrets\n\tconst customKeys = Object.keys(secrets.custom);\n\tif (customKeys.length > 0) {\n\t\tlogger.log('\\nCustom Secrets:');\n\t\tfor (const [key, value] of Object.entries(secrets.custom)) {\n\t\t\tlogger.log(`  ${key}: ${reveal ? value : maskPassword(value)}`);\n\t\t}\n\t}\n\n\tif (!reveal) {\n\t\tlogger.log('\\nUse --reveal to show actual values');\n\t}\n}\n\n/**\n * Rotate passwords for services.\n */\nexport async function secretsRotateCommand(\n\toptions: SecretsRotateOptions,\n): Promise<void> {\n\tconst { stage, service } = options;\n\n\tconst secrets = await readStageSecrets(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tif (service) {\n\t\t// Rotate specific service\n\t\tif (!secrets.services[service]) {\n\t\t\tlogger.error(`Service \"${service}\" not configured in stage \"${stage}\"`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst updated = rotateServicePassword(secrets, service);\n\t\tawait writeStageSecrets(updated);\n\t\tlogger.log(`\\n✓ Password rotated for ${service} in stage \"${stage}\"`);\n\t} else {\n\t\t// Rotate all services\n\t\tlet updated = secrets;\n\t\tconst services = Object.keys(secrets.services) as ComposeServiceName[];\n\n\t\tfor (const svc of services) {\n\t\t\tupdated = rotateServicePassword(updated, svc);\n\t\t}\n\n\t\tawait writeStageSecrets(updated);\n\t\tlogger.log(\n\t\t\t`\\n✓ Passwords rotated for all services in stage \"${stage}\": ${services.join(', ')}`,\n\t\t);\n\t}\n\n\tlogger.log(`\\nUse \"gkm secrets:show --stage ${stage}\" to view new values`);\n}\n\n/**\n * Import secrets from a JSON file.\n */\nexport async function secretsImportCommand(\n\tfile: string,\n\toptions: SecretsImportOptions,\n): Promise<void> {\n\tconst { stage, merge = true } = options;\n\n\t// Check if file exists\n\tif (!existsSync(file)) {\n\t\tlogger.error(`File not found: ${file}`);\n\t\tprocess.exit(1);\n\t}\n\n\t// Read and parse JSON file\n\tlet importedSecrets: Record<string, string>;\n\ttry {\n\t\tconst content = await readFile(file, 'utf-8');\n\t\timportedSecrets = JSON.parse(content);\n\n\t\t// Validate it's a flat object with string values\n\t\tif (typeof importedSecrets !== 'object' || importedSecrets === null) {\n\t\t\tthrow new Error('JSON must be an object');\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(importedSecrets)) {\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Value for \"${key}\" must be a string, got ${typeof value}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tlogger.error(\n\t\t\t`Failed to parse JSON file: ${error instanceof Error ? error.message : 'Invalid JSON'}`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Check if secrets exist for stage\n\tconst secrets = await readStageSecrets(stage);\n\n\tif (!secrets) {\n\t\tlogger.error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Merge or replace custom secrets\n\tconst updatedCustom = merge\n\t\t? { ...secrets.custom, ...importedSecrets }\n\t\t: importedSecrets;\n\n\tconst updated = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: updatedCustom,\n\t};\n\n\tawait writeStageSecrets(updated);\n\n\tconst importedCount = Object.keys(importedSecrets).length;\n\tconst totalCount = Object.keys(updatedCustom).length;\n\n\tlogger.log(`\\n✓ Imported ${importedCount} secrets for stage \"${stage}\"`);\n\n\tif (merge && totalCount > importedCount) {\n\t\tlogger.log(`  Total custom secrets: ${totalCount}`);\n\t}\n\n\tlogger.log('\\n  Imported keys:');\n\tfor (const key of Object.keys(importedSecrets)) {\n\t\tlogger.log(`    - ${key}`);\n\t}\n}\n\n/**\n * Mask password in a URL for display.\n */\nexport function maskUrl(url: string): string {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tif (parsed.password) {\n\t\t\tparsed.password = maskPassword(parsed.password);\n\t\t}\n\t\treturn parsed.toString();\n\t} catch {\n\t\treturn url;\n\t}\n}\n","import { spawn } from 'node:child_process';\nimport { writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcreateCredentialsPreload,\n\tloadEnvFiles,\n\tprepareEntryCredentials,\n} from '../credentials';\nimport { sniffAppEnvironment } from '../deploy/sniffer';\n\nexport interface TestOptions {\n\t/** Stage to load secrets from (default: development) */\n\tstage?: string;\n\t/** Run tests once without watch mode */\n\trun?: boolean;\n\t/** Enable watch mode */\n\twatch?: boolean;\n\t/** Generate coverage report */\n\tcoverage?: boolean;\n\t/** Open Vitest UI */\n\tui?: boolean;\n\t/** Pattern to filter tests */\n\tpattern?: string;\n\t/**\n\t * Generate a fresh stage (secrets + encryption key) from the workspace config\n\t * when none exists, instead of requiring committed secrets / a shared key.\n\t * Intended for CI. Also enabled by the GKM_AUTO_SETUP env var.\n\t */\n\tautoSetup?: boolean;\n}\n\n/**\n * Run tests with secrets, dependency URLs, and .env files loaded.\n * Environment variables are sniffed to inject only what the app needs.\n */\nexport async function testCommand(options: TestOptions = {}): Promise<void> {\n\tconst stage = options.stage ?? 'development';\n\tconst cwd = process.cwd();\n\n\tconsole.log(`\\n🧪 Running tests with ${stage} environment...\\n`);\n\n\t// 0. Auto-setup (CI): regenerate a fresh stage from the workspace config when\n\t//    none exists, so tests run without committed secrets or a shared key.\n\tconst autoSetup = options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP);\n\tif (autoSetup) {\n\t\tconst { ensureStageSecrets } = await import('../setup/index.js');\n\t\tconst generated = await ensureStageSecrets(stage, cwd);\n\t\tif (generated) {\n\t\t\tconsole.log(`  🔐 Generated fresh ${stage} secrets (auto-setup)`);\n\t\t}\n\t}\n\n\t// 1. Load .env files\n\tconst defaultEnv = loadEnvFiles('.env');\n\tif (defaultEnv.loaded.length > 0) {\n\t\tconsole.log(`  📦 Loaded env: ${defaultEnv.loaded.join(', ')}`);\n\t}\n\n\t// 2. Prepare credentials: loads secrets, resolves Docker ports,\n\t//    starts services, rewrites URLs, injects dependency URLs\n\tconst result = await prepareEntryCredentials({\n\t\tstages: [stage],\n\t\tstartDocker: true,\n\t\tsecretsFileName: 'test-secrets.json',\n\t\tresolveDockerPorts: 'full',\n\t});\n\n\tlet finalCredentials = { ...result.credentials };\n\n\t// 3. Sniff env vars to filter only what the app needs (workspace only)\n\tif (result.appInfo) {\n\t\tconst sniffed = await sniffAppEnvironment(\n\t\t\tresult.appInfo.app,\n\t\t\tresult.appInfo.appName,\n\t\t\tresult.appInfo.workspaceRoot,\n\t\t\t{ logWarnings: false },\n\t\t);\n\n\t\tif (sniffed.requiredEnvVars.length > 0) {\n\t\t\tconst needed = new Set(sniffed.requiredEnvVars);\n\t\t\tconst filtered: Record<string, string> = {};\n\t\t\tfor (const [key, value] of Object.entries(finalCredentials)) {\n\t\t\t\tif (needed.has(key)) {\n\t\t\t\t\tfiltered[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinalCredentials = filtered;\n\t\t\tconsole.log(\n\t\t\t\t`  🔍 Sniffed ${sniffed.requiredEnvVars.length} required env var(s)`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// 4. Rewrite DATABASE_URL for test isolation (append _test suffix)\n\tfinalCredentials = rewriteDatabaseUrlForTests(finalCredentials);\n\n\tconsole.log('');\n\n\t// 5. Write final credentials and create preload script\n\tawait writeFile(\n\t\tresult.secretsJsonPath,\n\t\tJSON.stringify(finalCredentials, null, 2),\n\t);\n\n\tconst gkmDir = join(cwd, '.gkm');\n\tconst preloadPath = join(gkmDir, 'test-credentials-preload.ts');\n\tawait createCredentialsPreload(preloadPath, result.secretsJsonPath);\n\n\t// Merge NODE_OPTIONS with existing value (if any)\n\tconst existingNodeOptions = process.env.NODE_OPTIONS ?? '';\n\tconst tsxImport = '--import=tsx';\n\tconst preloadImport = `--import=${preloadPath}`;\n\tconst nodeOptions = [existingNodeOptions, tsxImport, preloadImport]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\t// Build vitest args\n\tconst args: string[] = [];\n\n\tif (options.run) {\n\t\targs.push('run');\n\t} else if (options.watch) {\n\t\targs.push('--watch');\n\t}\n\n\tif (options.coverage) {\n\t\targs.push('--coverage');\n\t}\n\n\tif (options.ui) {\n\t\targs.push('--ui');\n\t}\n\n\tif (options.pattern) {\n\t\targs.push(options.pattern);\n\t}\n\n\t// Run vitest with combined environment and credentials preload\n\tconst vitestProcess = spawn('npx', ['vitest', ...args], {\n\t\tcwd,\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...finalCredentials,\n\t\t\tNODE_ENV: 'test',\n\t\t\tNODE_OPTIONS: nodeOptions,\n\t\t},\n\t});\n\n\t// Wait for vitest to complete\n\treturn new Promise((resolve, reject) => {\n\t\tvitestProcess.on('close', (code) => {\n\t\t\tif (code === 0) {\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(new Error(`Tests failed with exit code ${code}`));\n\t\t\t}\n\t\t});\n\n\t\tvitestProcess.on('error', (error) => {\n\t\t\treject(error);\n\t\t});\n\t});\n}\n\nconst TEST_DB_SUFFIX = '_test';\n\n/**\n * Rewrite DATABASE_URL to point to a separate test database.\n * Appends `_test` to the database name (e.g., `app` -> `app_test`).\n * @internal Exported for testing\n */\nexport function rewriteDatabaseUrlForTests(\n\tenv: Record<string, string>,\n): Record<string, string> {\n\tconst result = { ...env };\n\n\tfor (const key of Object.keys(result)) {\n\t\tif (!key.includes('DATABASE_URL')) continue;\n\n\t\tconst value = result[key] as string;\n\t\ttry {\n\t\t\tconst url = new URL(value);\n\t\t\tconst dbName = url.pathname.slice(1);\n\t\t\tif (dbName && !dbName.endsWith(TEST_DB_SUFFIX)) {\n\t\t\t\turl.pathname = `/${dbName}${TEST_DB_SUFFIX}`;\n\t\t\t\tresult[key] = url.toString();\n\t\t\t\tconsole.log(\n\t\t\t\t\t`  🧪 ${key}: using test database \"${dbName}${TEST_DB_SUFFIX}\"`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not a valid URL, skip\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport {\n\tdetectPackageManager,\n\tfindWorkspacePackages,\n\ttype PackageManager,\n} from '../init/utils.js';\n\nconst logger = console;\n\nexport interface UpgradeOptions {\n\tdryRun?: boolean;\n}\n\ninterface FoundDependency {\n\tpackageName: string;\n\tcurrentVersion: string;\n\tdepType: 'dependencies' | 'devDependencies' | 'peerDependencies';\n\tpackageJsonPath: string;\n\tworkspaceName: string;\n}\n\ninterface UpgradeInfo extends FoundDependency {\n\tlatestVersion: string;\n\tisWorkspaceRef: boolean;\n\tneedsUpgrade: boolean;\n}\n\nexport async function upgradeCommand(\n\toptions: UpgradeOptions = {},\n): Promise<void> {\n\tconst cwd = process.cwd();\n\n\tlogger.log('\\n📦 Scanning workspace for @geekmidas packages...\\n');\n\n\tconst pm = detectPackageManager(cwd);\n\tlogger.log(`  Package manager: ${pm}`);\n\n\tconst packageJsonPaths = findWorkspacePackages(cwd, pm);\n\tlogger.log(`  Found ${packageJsonPaths.length} package(s) in workspace\\n`);\n\n\tconst dependencies = scanForGeekmidasDeps(packageJsonPaths);\n\n\tif (dependencies.length === 0) {\n\t\tlogger.log('  No @geekmidas packages found.\\n');\n\t\treturn;\n\t}\n\n\tconst uniquePackages = [...new Set(dependencies.map((d) => d.packageName))];\n\tlogger.log(\n\t\t`  Checking ${uniquePackages.length} unique @geekmidas package(s) on npm...\\n`,\n\t);\n\n\tconst latestVersions = await fetchLatestVersions(uniquePackages);\n\n\tconst upgradeInfos = dependencies.map((dep) =>\n\t\tresolveUpgradeInfo(dep, latestVersions),\n\t);\n\n\tprintUpgradeTable(upgradeInfos);\n\n\tconst upgradable = upgradeInfos.filter(\n\t\t(info) => info.needsUpgrade && !info.isWorkspaceRef,\n\t);\n\n\tif (upgradable.length === 0) {\n\t\tlogger.log('\\n  All @geekmidas packages are up to date!\\n');\n\t\treturn;\n\t}\n\n\tlogger.log(`\\n  ${upgradable.length} package(s) can be upgraded.\\n`);\n\n\tif (options.dryRun) {\n\t\tlogger.log('  --dry-run: No changes made.\\n');\n\t\tprintUpgradeCommands(upgradable, pm);\n\t\treturn;\n\t}\n\n\texecuteUpgrade(upgradable, pm, cwd);\n\n\tlogger.log('\\n  ✅ Upgrade complete! Run your tests to verify.\\n');\n}\n\nfunction scanForGeekmidasDeps(packageJsonPaths: string[]): FoundDependency[] {\n\tconst results: FoundDependency[] = [];\n\tconst depTypes = [\n\t\t'dependencies',\n\t\t'devDependencies',\n\t\t'peerDependencies',\n\t] as const;\n\n\tfor (const pkgJsonPath of packageJsonPaths) {\n\t\tconst pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n\t\tconst workspaceName = pkg.name ?? pkgJsonPath;\n\n\t\tfor (const depType of depTypes) {\n\t\t\tconst deps = pkg[depType];\n\t\t\tif (!deps) continue;\n\n\t\t\tfor (const [name, version] of Object.entries(deps)) {\n\t\t\t\tif (!name.startsWith('@geekmidas/')) continue;\n\n\t\t\t\tresults.push({\n\t\t\t\t\tpackageName: name,\n\t\t\t\t\tcurrentVersion: version as string,\n\t\t\t\t\tdepType,\n\t\t\t\t\tpackageJsonPath: pkgJsonPath,\n\t\t\t\t\tworkspaceName,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n\nasync function fetchLatestVersions(\n\tpackageNames: string[],\n): Promise<Map<string, string>> {\n\tconst versions = new Map<string, string>();\n\n\tconst results = await Promise.allSettled(\n\t\tpackageNames.map(async (name) => {\n\t\t\tconst res = await fetch(`https://registry.npmjs.org/${name}/latest`);\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst data = (await res.json()) as { version: string };\n\t\t\treturn { name, version: data.version };\n\t\t}),\n\t);\n\n\tfor (const result of results) {\n\t\tif (result.status === 'fulfilled') {\n\t\t\tversions.set(result.value.name, result.value.version);\n\t\t}\n\t}\n\n\treturn versions;\n}\n\nfunction resolveUpgradeInfo(\n\tdep: FoundDependency,\n\tlatestVersions: Map<string, string>,\n): UpgradeInfo {\n\tconst isWorkspaceRef = dep.currentVersion.startsWith('workspace:');\n\tconst latestVersion = latestVersions.get(dep.packageName) ?? 'unknown';\n\n\tconst currentBare = dep.currentVersion.replace(/^[\\^~>=<]*/g, '');\n\tconst needsUpgrade =\n\t\t!isWorkspaceRef &&\n\t\tlatestVersion !== 'unknown' &&\n\t\tcurrentBare !== latestVersion;\n\n\treturn {\n\t\t...dep,\n\t\tlatestVersion,\n\t\tisWorkspaceRef,\n\t\tneedsUpgrade,\n\t};\n}\n\nfunction printUpgradeTable(infos: UpgradeInfo[]): void {\n\tconst byPackage = new Map<string, UpgradeInfo>();\n\tfor (const info of infos) {\n\t\tif (!byPackage.has(info.packageName)) {\n\t\t\tbyPackage.set(info.packageName, info);\n\t\t}\n\t}\n\n\tconst nameWidth = 33;\n\tconst verWidth = 14;\n\tconst statusWidth = 14;\n\n\tconst hr = `  ${'─'.repeat(nameWidth + verWidth * 2 + statusWidth + 5)}`;\n\n\tlogger.log(hr);\n\tlogger.log(\n\t\t`  ${'Package'.padEnd(nameWidth)} ${'Current'.padEnd(verWidth)} ${'Latest'.padEnd(verWidth)} ${'Status'.padEnd(statusWidth)}`,\n\t);\n\tlogger.log(hr);\n\n\tfor (const [, info] of byPackage) {\n\t\tconst name = info.packageName.padEnd(nameWidth);\n\t\tconst current = info.currentVersion.padEnd(verWidth);\n\t\tconst latest = info.latestVersion.padEnd(verWidth);\n\n\t\tlet status: string;\n\t\tif (info.isWorkspaceRef) {\n\t\t\tstatus = 'workspace';\n\t\t} else if (info.needsUpgrade) {\n\t\t\tstatus = '⬆ upgrade';\n\t\t} else {\n\t\t\tstatus = '✓ up-to-date';\n\t\t}\n\n\t\tlogger.log(`  ${name} ${current} ${latest} ${status}`);\n\t}\n\n\tlogger.log(hr);\n}\n\nfunction printUpgradeCommands(\n\tupgradable: UpgradeInfo[],\n\tpm: PackageManager,\n): void {\n\tlogger.log('  Commands that would be run:\\n');\n\n\tconst uniquePackages = [...new Set(upgradable.map((i) => i.packageName))];\n\tconst cmd = getWorkspaceUpgradeCommand(pm, uniquePackages);\n\tlogger.log(`    ${cmd}\\n`);\n}\n\nfunction getWorkspaceUpgradeCommand(\n\tpm: PackageManager,\n\tpackages: string[],\n): string {\n\tconst pkgList = packages.join(' ');\n\n\tswitch (pm) {\n\t\tcase 'pnpm':\n\t\t\treturn `pnpm update -r ${pkgList} --latest`;\n\t\tcase 'yarn':\n\t\t\treturn `yarn upgrade ${pkgList}`;\n\t\tcase 'bun':\n\t\t\treturn `bun update ${pkgList}`;\n\t\tcase 'npm':\n\t\t\treturn `npm update ${pkgList} --workspaces`;\n\t\tdefault:\n\t\t\treturn `npm update ${pkgList}`;\n\t}\n}\n\nfunction executeUpgrade(\n\tupgradable: UpgradeInfo[],\n\tpm: PackageManager,\n\tcwd: string,\n): void {\n\tconst uniquePackages = [...new Set(upgradable.map((i) => i.packageName))];\n\n\tconst cmd = getWorkspaceUpgradeCommand(pm, uniquePackages);\n\tlogger.log(`  Running: ${cmd}\\n`);\n\n\ttry {\n\t\texecSync(cmd, {\n\t\t\tcwd,\n\t\t\tstdio: 'inherit',\n\t\t\ttimeout: 120_000,\n\t\t});\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'Package upgrade failed. Check the output above for details.',\n\t\t);\n\t}\n}\n","#!/usr/bin/env -S npx tsx\n\nimport { Command } from 'commander';\nimport pkg from '../package.json';\nimport { loginCommand, logoutCommand, whoamiCommand } from './auth';\nimport { buildCommand } from './build/index';\nimport { enableDebug, formatError } from './debug';\nimport { type DeployProvider, deployCommand } from './deploy/index';\nimport { deployInitCommand, deployListCommand } from './deploy/init';\nimport {\n\tstateDiffCommand,\n\tstatePullCommand,\n\tstatePushCommand,\n\tstateShowCommand,\n} from './deploy/state-commands';\nimport { devCommand, execCommand } from './dev/index';\nimport { type DockerOptions, dockerCommand } from './docker/index';\nimport { type InitOptions, initCommand } from './init/index';\nimport { openapiCommand } from './openapi';\nimport { generateReactQueryCommand } from './openapi-react-query';\nimport {\n\tsecretsImportCommand,\n\tsecretsInitCommand,\n\tsecretsRotateCommand,\n\tsecretsSetCommand,\n\tsecretsShowCommand,\n} from './secrets';\nimport { type SetupOptions, setupCommand } from './setup/index';\nimport { type TestOptions, testCommand } from './test/index';\nimport type { ComposeServiceName, LegacyProvider, MainProvider } from './types';\nimport { type UpgradeOptions, upgradeCommand } from './upgrade/index';\n\nconst program = new Command();\n\nprogram\n\t.name('gkm')\n\t.description('GeekMidas backend framework CLI')\n\t.version(pkg.version)\n\t.option('--cwd <path>', 'Change working directory')\n\t.option('--debug', 'Enable debug mode (verbose errors with stack traces)')\n\t.hook('preAction', () => {\n\t\tconst opts = program.opts();\n\t\tif (opts.debug) enableDebug();\n\t});\n\nprogram\n\t.command('init')\n\t.description('Scaffold a new project')\n\t.argument('[name]', 'Project name')\n\t.option(\n\t\t'--template <template>',\n\t\t'Project template (minimal, api, serverless, worker)',\n\t)\n\t.option('--skip-install', 'Skip dependency installation', false)\n\t.option('-y, --yes', 'Skip prompts, use defaults', false)\n\t.option('--monorepo', 'Setup as monorepo with packages/models', false)\n\t.option('--api-path <path>', 'API app path in monorepo (default: apps/api)')\n\t.option('--pm <manager>', 'Package manager (pnpm, npm, yarn, bun)')\n\t.action(async (name: string | undefined, options: InitOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait initCommand(name, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('setup')\n\t.description('Setup development environment (secrets, Docker, database)')\n\t.option('--stage <stage>', 'Stage name', 'development')\n\t.option('--force', 'Regenerate secrets even if they exist')\n\t.option('--skip-docker', 'Skip starting Docker services')\n\t.option('-y, --yes', 'Skip prompts')\n\t.action(async (options: SetupOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait setupCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('build')\n\t.description('Build handlers from endpoints, functions, and crons')\n\t.option(\n\t\t'--provider <provider>',\n\t\t'Target provider for generated handlers (aws, server)',\n\t)\n\t.option(\n\t\t'--providers <providers>',\n\t\t'[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)',\n\t)\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation generation for server builds',\n\t)\n\t.option('--production', 'Build for production (no dev tools, bundled output)')\n\t.option('--skip-bundle', 'Skip bundling step in production build')\n\t.option('--stage <stage>', 'Inject encrypted secrets for deployment stage')\n\t.option(\n\t\t'--mark-optional',\n\t\t'Suffix optional env vars with ? in manifest envVars field (e.g. PORT?)',\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider?: string;\n\t\t\tproviders?: string;\n\t\t\tenableOpenapi?: boolean;\n\t\t\tproduction?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tstage?: string;\n\t\t\tmarkOptional?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\t// Handle new single provider option\n\t\t\t\tif (options.provider) {\n\t\t\t\t\tif (!['aws', 'server'].includes(options.provider)) {\n\t\t\t\t\t\tprocess.exit(1);\n\t\t\t\t\t}\n\t\t\t\t\tawait buildCommand({\n\t\t\t\t\t\tprovider: options.provider as MainProvider,\n\t\t\t\t\t\tenableOpenApi: options.enableOpenapi || false,\n\t\t\t\t\t\tproduction: options.production || false,\n\t\t\t\t\t\tskipBundle: options.skipBundle || false,\n\t\t\t\t\t\tstage: options.stage,\n\t\t\t\t\t\tmarkOptional: options.markOptional || false,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// Handle legacy providers option\n\t\t\t\telse if (options.providers) {\n\t\t\t\t\tconst providerList = [\n\t\t\t\t\t\t...new Set(options.providers.split(',').map((p) => p.trim())),\n\t\t\t\t\t] as LegacyProvider[];\n\t\t\t\t\tawait buildCommand({\n\t\t\t\t\t\tproviders: providerList,\n\t\t\t\t\t\tenableOpenApi: options.enableOpenapi || false,\n\t\t\t\t\t\tproduction: options.production || false,\n\t\t\t\t\t\tskipBundle: options.skipBundle || false,\n\t\t\t\t\t\tstage: options.stage,\n\t\t\t\t\t\tmarkOptional: options.markOptional || false,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// Default to config-driven build\n\t\t\t\telse {\n\t\t\t\t\tawait buildCommand({\n\t\t\t\t\t\tenableOpenApi: options.enableOpenapi || false,\n\t\t\t\t\t\tproduction: options.production || false,\n\t\t\t\t\t\tskipBundle: options.skipBundle || false,\n\t\t\t\t\t\tstage: options.stage,\n\t\t\t\t\t\tmarkOptional: options.markOptional || false,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('dev')\n\t.description('Start development server with automatic reload')\n\t.option('-p, --port <port>', 'Port to run the development server on')\n\t.option('--entry <file>', 'Entry file to run (bypasses gkm config)')\n\t.option('--watch', 'Watch for file changes (default: true with --entry)')\n\t.option('--no-watch', 'Disable file watching')\n\t.option(\n\t\t'--enable-openapi',\n\t\t'Enable OpenAPI documentation for development server',\n\t\ttrue,\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tport?: string;\n\t\t\tentry?: string;\n\t\t\twatch?: boolean;\n\t\t\tenableOpenapi?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait devCommand({\n\t\t\t\t\tport: options.port ? Number.parseInt(options.port, 10) : 3000,\n\t\t\t\t\tportExplicit: !!options.port,\n\t\t\t\t\tenableOpenApi: options.enableOpenapi ?? true,\n\t\t\t\t\tentry: options.entry,\n\t\t\t\t\twatch: options.watch,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('exec')\n\t.description('Run a command with secrets injected into Credentials')\n\t.argument('<command...>', 'Command to run (use -- before command)')\n\t.action(async (commandArgs: string[]) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait execCommand(commandArgs);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('test')\n\t.description('Run tests with secrets loaded from environment')\n\t.option('--stage <stage>', 'Stage to load secrets from', 'development')\n\t.option('--run', 'Run tests once without watch mode')\n\t.option('--watch', 'Enable watch mode')\n\t.option('--coverage', 'Generate coverage report')\n\t.option('--ui', 'Open Vitest UI')\n\t.option(\n\t\t'--auto-setup',\n\t\t'Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)',\n\t)\n\t.argument('[pattern]', 'Pattern to filter tests')\n\t.action(async (pattern: string | undefined, options: TestOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait testCommand({ ...options, pattern });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('cron')\n\t.description('Manage cron jobs')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Cron management - coming soon\\n');\n\t});\n\nprogram\n\t.command('function')\n\t.description('Manage serverless functions')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('Serverless function management - coming soon\\n');\n\t});\n\nprogram\n\t.command('api')\n\t.description('Manage REST API endpoints')\n\t.action(() => {\n\t\tconst globalOptions = program.opts();\n\t\tif (globalOptions.cwd) {\n\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t}\n\t\tprocess.stdout.write('REST API management - coming soon\\n');\n\t});\n\nprogram\n\t.command('openapi')\n\t.description('Generate OpenAPI specification from endpoints')\n\t.option(\n\t\t'--app <name>',\n\t\t'Workspace mode: generate for a single named backend app',\n\t)\n\t.action(async (options: { app?: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait openapiCommand({ app: options.app });\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('generate:react-query')\n\t.description('Generate React Query hooks from OpenAPI specification')\n\t.option('--input <path>', 'Input OpenAPI spec file path', 'openapi.json')\n\t.option(\n\t\t'--output <path>',\n\t\t'Output file path for generated hooks',\n\t\t'src/api/hooks.ts',\n\t)\n\t.option('--name <name>', 'API name prefix for generated code', 'API')\n\t.action(\n\t\tasync (options: { input?: string; output?: string; name?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tawait generateReactQueryCommand(options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('docker')\n\t.description('Generate Docker deployment files')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.option('--slim', 'Use slim Dockerfile (assumes pre-built bundle exists)')\n\t.option('--turbo', 'Use turbo prune for monorepo optimization')\n\t.option('--turbo-package <name>', 'Package name for turbo prune')\n\t.action(async (options: DockerOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait dockerCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('prepack')\n\t.description('Generate Docker files for production deployment')\n\t.option('--build', 'Build Docker image after generating files')\n\t.option('--push', 'Push image to registry after building')\n\t.option('--tag <tag>', 'Image tag', 'latest')\n\t.option('--registry <registry>', 'Container registry URL')\n\t.option('--slim', 'Build locally first, then use slim Dockerfile')\n\t.option('--skip-bundle', 'Skip bundling step (only with --slim)')\n\t.option('--turbo', 'Use turbo prune for monorepo optimization')\n\t.option('--turbo-package <name>', 'Package name for turbo prune')\n\t.action(\n\t\tasync (options: {\n\t\t\tbuild?: boolean;\n\t\t\tpush?: boolean;\n\t\t\ttag?: string;\n\t\t\tregistry?: string;\n\t\t\tslim?: boolean;\n\t\t\tskipBundle?: boolean;\n\t\t\tturbo?: boolean;\n\t\t\tturboPackage?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (options.slim) {\n\t\t\t\t\tawait buildCommand({\n\t\t\t\t\t\tprovider: 'server',\n\t\t\t\t\t\tproduction: true,\n\t\t\t\t\t\tskipBundle: options.skipBundle,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait dockerCommand({\n\t\t\t\t\tbuild: options.build,\n\t\t\t\t\tpush: options.push,\n\t\t\t\t\ttag: options.tag,\n\t\t\t\t\tregistry: options.registry,\n\t\t\t\t\tslim: options.slim,\n\t\t\t\t\tturbo: options.turbo,\n\t\t\t\t\tturboPackage: options.turboPackage,\n\t\t\t\t});\n\t\t\t\tif (options.slim) {\n\t\t\t\t} else {\n\t\t\t\t}\n\n\t\t\t\tif (options.build) {\n\t\t\t\t\tconst tag = options.tag ?? 'latest';\n\t\t\t\t\tconst registry = options.registry;\n\t\t\t\t\tconst _imageRef = registry ? `${registry}/api:${tag}` : `api:${tag}`;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Secrets management commands\nprogram\n\t.command('secrets:init')\n\t.description('Initialize secrets for a deployment stage')\n\t.requiredOption('--stage <stage>', 'Stage name (e.g., production, staging)')\n\t.option('--force', 'Overwrite existing secrets')\n\t.action(async (options: { stage: string; force?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsInitCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:set')\n\t.description('Set a custom secret for a stage')\n\t.argument('<key>', 'Secret key (e.g., API_KEY)')\n\t.argument('[value]', 'Secret value (reads from stdin if omitted)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(\n\t\tasync (\n\t\t\tkey: string,\n\t\t\tvalue: string | undefined,\n\t\t\toptions: { stage: string },\n\t\t) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\t\t\t\tawait secretsSetCommand(key, value, options);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nprogram\n\t.command('secrets:show')\n\t.description('Show secrets for a stage')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--reveal', 'Show actual secret values (not masked)')\n\t.action(async (options: { stage: string; reveal?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:rotate')\n\t.description('Rotate service passwords')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option(\n\t\t'--service <service>',\n\t\t'Specific service to rotate (postgres, redis, rabbitmq)',\n\t)\n\t.action(async (options: { stage: string; service?: ComposeServiceName }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsRotateCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:import')\n\t.description('Import secrets from a JSON file')\n\t.argument('<file>', 'JSON file path (e.g., secrets.json)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.option('--no-merge', 'Replace all custom secrets instead of merging')\n\t.action(async (file: string, options: { stage: string; merge?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait secretsImportCommand(file, options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:push')\n\t.description('Push secrets to remote provider (SSM)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tconst { loadWorkspaceConfig } = await import('./config');\n\t\t\tconst { pushSecrets } = await import('./secrets/sync');\n\t\t\tconst { reconcileMissingSecrets } = await import('./secrets/reconcile');\n\t\t\tconst { readStageSecrets, writeStageSecrets } = await import(\n\t\t\t\t'./secrets/storage'\n\t\t\t);\n\n\t\t\tconst { workspace } = await loadWorkspaceConfig();\n\n\t\t\tconst secrets = await readStageSecrets(options.stage, workspace.root);\n\t\t\tif (secrets) {\n\t\t\t\tconst result = reconcileMissingSecrets(secrets, workspace);\n\t\t\t\tif (result) {\n\t\t\t\t\tawait writeStageSecrets(result.secrets, workspace.root);\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`  Reconciled ${result.addedKeys.length} missing secret(s):`,\n\t\t\t\t\t);\n\t\t\t\t\tfor (const key of result.addedKeys) {\n\t\t\t\t\t\tconsole.log(`    + ${key}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait pushSecrets(options.stage, workspace);\n\t\t\tconsole.log(`\\n✓ Secrets pushed for stage \"${options.stage}\"`);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:pull')\n\t.description('Pull secrets from remote provider (SSM)')\n\t.requiredOption('--stage <stage>', 'Stage name')\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tconst { loadWorkspaceConfig } = await import('./config');\n\t\t\tconst { pullSecrets } = await import('./secrets/sync');\n\t\t\tconst { writeStageSecrets } = await import('./secrets/storage');\n\t\t\tconst { reconcileMissingSecrets } = await import('./secrets/reconcile');\n\n\t\t\tconst { workspace } = await loadWorkspaceConfig();\n\t\t\tlet secrets = await pullSecrets(options.stage, workspace);\n\n\t\t\tif (!secrets) {\n\t\t\t\tconsole.error(`No remote secrets found for stage \"${options.stage}\".`);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tconst result = reconcileMissingSecrets(secrets, workspace);\n\t\t\tif (result) {\n\t\t\t\tsecrets = result.secrets;\n\t\t\t\tconsole.log(\n\t\t\t\t\t`  Reconciled ${result.addedKeys.length} missing secret(s):`,\n\t\t\t\t);\n\t\t\t\tfor (const key of result.addedKeys) {\n\t\t\t\t\tconsole.log(`    + ${key}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait writeStageSecrets(secrets, workspace.root);\n\t\t\tconsole.log(`\\n✓ Secrets pulled for stage \"${options.stage}\"`);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('secrets:reconcile')\n\t.description('Backfill missing custom secrets from workspace config')\n\t.option('--stage <stage>', 'Stage name', 'development')\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tconst { loadWorkspaceConfig } = await import('./config');\n\t\t\tconst { reconcileMissingSecrets } = await import('./secrets/reconcile');\n\t\t\tconst { readStageSecrets, writeStageSecrets } = await import(\n\t\t\t\t'./secrets/storage'\n\t\t\t);\n\n\t\t\tconst { workspace } = await loadWorkspaceConfig();\n\t\t\tconst secrets = await readStageSecrets(options.stage, workspace.root);\n\n\t\t\tif (!secrets) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`No secrets found for stage \"${options.stage}\". Run \"gkm secrets:init --stage ${options.stage}\" first.`,\n\t\t\t\t);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\tconst result = reconcileMissingSecrets(secrets, workspace);\n\n\t\t\tif (!result) {\n\t\t\t\tconsole.log(`\\n✓ Secrets for stage \"${options.stage}\" are up-to-date`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait writeStageSecrets(result.secrets, workspace.root);\n\t\t\tconsole.log(\n\t\t\t\t`\\n✓ Reconciled ${result.addedKeys.length} missing secret(s) for stage \"${options.stage}\":`,\n\t\t\t);\n\t\t\tfor (const key of result.addedKeys) {\n\t\t\t\tconsole.log(`    + ${key}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// Deploy command\nprogram\n\t.command('deploy')\n\t.description('Deploy application to a provider')\n\t.requiredOption(\n\t\t'--provider <provider>',\n\t\t'Deploy provider (docker, dokploy, aws-lambda)',\n\t)\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option('--tag <tag>', 'Image tag (default: stage-timestamp)')\n\t.option('--skip-push', 'Skip pushing image to registry')\n\t.option('--skip-build', 'Skip build step (use existing build)')\n\t.action(\n\t\tasync (options: {\n\t\t\tprovider: string;\n\t\t\tstage: string;\n\t\t\ttag?: string;\n\t\t\tskipPush?: boolean;\n\t\t\tskipBuild?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tconst validProviders = ['docker', 'dokploy', 'aws-lambda'];\n\t\t\t\tif (!validProviders.includes(options.provider)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Invalid provider: ${options.provider}\\n` +\n\t\t\t\t\t\t\t`Valid providers: ${validProviders.join(', ')}`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\n\t\t\t\tawait deployCommand({\n\t\t\t\t\tprovider: options.provider as DeployProvider,\n\t\t\t\t\tstage: options.stage,\n\t\t\t\t\ttag: options.tag,\n\t\t\t\t\tskipPush: options.skipPush,\n\t\t\t\t\tskipBuild: options.skipBuild,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy init command - Initialize Dokploy project and application\nprogram\n\t.command('deploy:init')\n\t.description('Initialize Dokploy deployment (create project and application)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.requiredOption('--project <name>', 'Project name (creates if not exists)')\n\t.requiredOption('--app <name>', 'Application name')\n\t.option('--project-id <id>', 'Use existing project ID instead of creating')\n\t.option('--registry-id <id>', 'Configure registry for the application')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tproject: string;\n\t\t\tapp: string;\n\t\t\tprojectId?: string;\n\t\t\tregistryId?: string;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tawait deployInitCommand({\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\tprojectName: options.project,\n\t\t\t\t\tappName: options.app,\n\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\tregistryId: options.registryId,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Deploy list command - List Dokploy resources\nprogram\n\t.command('deploy:list')\n\t.description('List Dokploy resources (projects, registries)')\n\t.option(\n\t\t'--endpoint <url>',\n\t\t'Dokploy server URL (uses stored credentials if logged in)',\n\t)\n\t.option('--projects', 'List projects')\n\t.option('--registries', 'List registries')\n\t.action(\n\t\tasync (options: {\n\t\t\tendpoint?: string;\n\t\t\tprojects?: boolean;\n\t\t\tregistries?: boolean;\n\t\t}) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (options.projects) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (options.registries) {\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (!options.projects && !options.registries) {\n\t\t\t\t\t// Default to listing both\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'projects',\n\t\t\t\t\t});\n\t\t\t\t\tawait deployListCommand({\n\t\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t\t\tresource: 'registries',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Login command\nprogram\n\t.command('login')\n\t.description('Authenticate with a deployment service')\n\t.option('--service <service>', 'Service to login to (dokploy)', 'dokploy')\n\t.option('--token <token>', 'API token (will prompt if not provided)')\n\t.option('--endpoint <url>', 'Service endpoint URL')\n\t.action(\n\t\tasync (options: { service: string; token?: string; endpoint?: string }) => {\n\t\t\ttry {\n\t\t\t\tconst globalOptions = program.opts();\n\t\t\t\tif (globalOptions.cwd) {\n\t\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t\t}\n\n\t\t\t\tif (options.service !== 'dokploy') {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Unknown service: ${options.service}. Supported: dokploy`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\n\t\t\t\tawait loginCommand({\n\t\t\t\t\tservice: options.service as 'dokploy',\n\t\t\t\t\ttoken: options.token,\n\t\t\t\t\tendpoint: options.endpoint,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n// Logout command\nprogram\n\t.command('logout')\n\t.description('Remove stored credentials')\n\t.option(\n\t\t'--service <service>',\n\t\t'Service to logout from (dokploy, all)',\n\t\t'dokploy',\n\t)\n\t.action(async (options: { service: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait logoutCommand({\n\t\t\t\tservice: options.service as 'dokploy' | 'all',\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// Whoami command\nprogram\n\t.command('whoami')\n\t.description('Show current authentication status')\n\t.action(async () => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\n\t\t\tawait whoamiCommand();\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\n// State management commands\nprogram\n\t.command('state:pull')\n\t.description('Pull deployment state from remote to local')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePullCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:push')\n\t.description('Push deployment state from local to remote')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait statePushCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:show')\n\t.description('Show deployment state for a stage')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.option('--json', 'Output as JSON')\n\t.action(async (options: { stage: string; json?: boolean }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateShowCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('state:diff')\n\t.description('Compare local and remote deployment state')\n\t.requiredOption(\n\t\t'--stage <stage>',\n\t\t'Deployment stage (e.g., production, staging)',\n\t)\n\t.action(async (options: { stage: string }) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait stateDiffCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram\n\t.command('upgrade')\n\t.description('Upgrade all @geekmidas packages to their latest versions')\n\t.option('--dry-run', 'Show what would be upgraded without making changes')\n\t.action(async (options: UpgradeOptions) => {\n\t\ttry {\n\t\t\tconst globalOptions = program.opts();\n\t\t\tif (globalOptions.cwd) {\n\t\t\t\tprocess.chdir(globalOptions.cwd);\n\t\t\t}\n\t\t\tawait upgradeCommand(options);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram.parse();\n"],"mappings":"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AQ;AACR;;;;AAKD,MAAa,kBAAkB,CAC9B;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,GACD;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,CACD;;;;AAoCD,MAAa,2BAA2B;CACvC;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;AACD;;;;AAKD,MAAa,oBAAoB,CAChC;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,GACD;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,CACD;;;;AAKD,MAAa,yBAAyB;CACrC;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;AACD;;;;AAKD,MAAa,wBAAwB;CACpC;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;AACD;;;;AAKD,MAAa,sBAAsB,CAClC;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,GACD;CACC,OAAO;CACP,OAAO;CACP,aAAa;AACb,CACD;;;;AAKD,MAAa,kBAAkB;CAC9B;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;AACD;;;;AAKD,MAAa,uBAAuB;CACnC;EACC,OAAO;EACP,OAAO;EACP,aACC;CACD;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP,OAAO;EACP,aAAa;CACb;CACD;EACC,OAAO;EACP;EACA,aAAa;CACb;AACD;;;;AAKD,SAAgB,YAAYC,QAA2C;AA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MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;EACD;GACC,MAAM;GACN,SAAS;EACT;CACD;AACD;;;;;;;AC17CD,SAAgB,oBAAoBC,SAA2C;AAC9E,MAAK,QAAQ,YAAY,QAAQ,aAAa,YAC7C,QAAO,CAAE;CAGV,MAAM,eAAe,GAAG,QAAQ,KAAK;CACrC,MAAM,cAAc,GAAG,QAAQ,KAAK;CACpC,MAAM,iBAAiB,GAAG,QAAQ,KAAK;CACvC,MAAM,aAAa,GAAG,QAAQ,KAAK;CAGnC,MAAM,cAAc;EACnB,MAAM;EACN,SAAS;EACT,SAAS;EACT,MAAM;EACN,SAAS;GACR,KAAK;GACL,OAAO;GACP,OAAO;GACP,WAAW;EACX;EACD,cAAc;IACZ,aAAa;IACb,gBAAgB;IAChB,YAAY;GACb,qBAAqB,mBAAmB;GACxC,qBAAqB,mBAAmB;GACxC,yBAAyB;GACzB,eAAe;GACf,MAAM;GACN,OAAO;GACP,aAAa;EACb;EACD,iBAAiB;GAChB,kBAA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"}