@geekmidas/cli 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/{config-BYn5yUt5.cjs → config-6JHOwLCx.cjs} +30 -2
  3. package/dist/{config-dLNQIvDR.mjs.map → config-6JHOwLCx.cjs.map} +1 -1
  4. package/dist/{config-dLNQIvDR.mjs → config-DxASSNjr.mjs} +25 -3
  5. package/dist/{config-BYn5yUt5.cjs.map → config-DxASSNjr.mjs.map} +1 -1
  6. package/dist/config.cjs +3 -2
  7. package/dist/config.d.cts +14 -2
  8. package/dist/config.d.cts.map +1 -1
  9. package/dist/config.d.mts +14 -2
  10. package/dist/config.d.mts.map +1 -1
  11. package/dist/config.mjs +3 -3
  12. package/dist/{index-Bj5VNxEL.d.mts → index-C-KxSGGK.d.mts} +2 -2
  13. package/dist/{index-Ba21_lNt.d.cts.map → index-C-KxSGGK.d.mts.map} +1 -1
  14. package/dist/{index-Ba21_lNt.d.cts → index-Cyk2rTyj.d.cts} +2 -2
  15. package/dist/{index-Bj5VNxEL.d.mts.map → index-Cyk2rTyj.d.cts.map} +1 -1
  16. package/dist/index.cjs +549 -133
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +513 -97
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{openapi-CMTyaIJJ.mjs → openapi-BYlyAbH3.mjs} +6 -5
  21. package/dist/openapi-BYlyAbH3.mjs.map +1 -0
  22. package/dist/{openapi-CqblwJZ4.cjs → openapi-CnvwSRDU.cjs} +6 -5
  23. package/dist/openapi-CnvwSRDU.cjs.map +1 -0
  24. package/dist/openapi.cjs +3 -3
  25. package/dist/openapi.d.cts +1 -0
  26. package/dist/openapi.d.cts.map +1 -1
  27. package/dist/openapi.d.mts +1 -0
  28. package/dist/openapi.d.mts.map +1 -1
  29. package/dist/openapi.mjs +3 -3
  30. package/dist/workspace/index.cjs +1 -1
  31. package/dist/workspace/index.d.cts +1 -1
  32. package/dist/workspace/index.d.mts +1 -1
  33. package/dist/workspace/index.mjs +1 -1
  34. package/dist/{workspace-Dy8k7Wru.mjs → workspace-9IQIjwkQ.mjs} +5 -3
  35. package/dist/workspace-9IQIjwkQ.mjs.map +1 -0
  36. package/dist/{workspace-DIMnYaYt.cjs → workspace-D2ocAlpl.cjs} +5 -3
  37. package/dist/workspace-D2ocAlpl.cjs.map +1 -0
  38. package/package.json +6 -5
  39. package/src/config.ts +44 -0
  40. package/src/dev/__tests__/index.spec.ts +490 -0
  41. package/src/dev/index.ts +313 -18
  42. package/src/generators/Generator.ts +4 -1
  43. package/src/init/__tests__/generators.spec.ts +167 -18
  44. package/src/init/__tests__/init.spec.ts +66 -3
  45. package/src/init/generators/auth.ts +6 -5
  46. package/src/init/generators/config.ts +49 -7
  47. package/src/init/generators/docker.ts +8 -8
  48. package/src/init/generators/index.ts +1 -0
  49. package/src/init/generators/models.ts +3 -5
  50. package/src/init/generators/package.ts +4 -0
  51. package/src/init/generators/test.ts +133 -0
  52. package/src/init/generators/ui.ts +13 -12
  53. package/src/init/generators/web.ts +9 -8
  54. package/src/init/index.ts +2 -0
  55. package/src/init/templates/api.ts +6 -6
  56. package/src/init/templates/minimal.ts +2 -2
  57. package/src/init/templates/worker.ts +2 -2
  58. package/src/init/versions.ts +3 -3
  59. package/src/openapi.ts +6 -2
  60. package/src/test/__tests__/__fixtures__/workspace.ts +104 -0
  61. package/src/test/__tests__/api.spec.ts +199 -0
  62. package/src/test/__tests__/auth.spec.ts +162 -0
  63. package/src/test/__tests__/index.spec.ts +323 -0
  64. package/src/test/__tests__/web.spec.ts +210 -0
  65. package/src/test/index.ts +165 -14
  66. package/src/workspace/__tests__/index.spec.ts +3 -0
  67. package/src/workspace/index.ts +4 -2
  68. package/dist/openapi-CMTyaIJJ.mjs.map +0 -1
  69. package/dist/openapi-CqblwJZ4.cjs.map +0 -1
  70. package/dist/workspace-DIMnYaYt.cjs.map +0 -1
  71. package/dist/workspace-Dy8k7Wru.mjs.map +0 -1
@@ -1 +1 @@
1
- {"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<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","logger","workspace: NormalizedWorkspace","backendAppName: string","dependentApps: string[]","content: string","options: { silent?: boolean }","results: ClientCopyResult[]","result: ClientCopyResult","allResults: ClientCopyResult[]","logger","envConfig: string | string[] | undefined","cwd: string","loaded: string[]","missing: string[]","port: number","resolve","err: NodeJS.ErrnoException","preferredPort: number","config: GkmConfig['telescope']","isEnabled","telescopeConfig: TelescopeConfig","config: GkmConfig['studio']","studioConfig: StudioConfig","config: GkmConfig['hooks']","cliProduction: boolean","configProduction?: ProductionConfig","config: GkmConfig","options: DevOptions","appRoot: string","secretsRoot: string","workspaceAppName: string | undefined","workspaceAppPort: number | 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 }[]","appName: string","appPath: string","workspaceRoot: string","errors: string[]","warnings: string[]","pkg","results: FrontendValidationResult[]","appName?: string","secrets: Record<string, string>","servicesToStart: string[]","turboFilter: string[]","turboEnv: Record<string, string>","openApiWatcher: ReturnType<typeof chokidar.watch> | null","openApiPaths: { path: string; appName: string }[]","copyTimeout: NodeJS.Timeout | null","changedPath: string","config: any","context: BuildContext","provider: LegacyProvider","enableOpenApi: boolean","EndpointGenerator","startDir: string","secretsJsonPath: string","preloadPath: string","wrapperPath: string","entryPath: string","secretsJsonPath?: string","options: {\n\texplicitPort?: number;\n\tcwd?: string;\n}","appName: string | undefined","watch: boolean","restartTimeout: NodeJS.Timeout | null","requestedPort: number","portExplicit: boolean","telescope: NormalizedTelescopeConfig | undefined","studio: NormalizedStudioConfig | undefined","commandArgs: string[]","options: ExecOptions","code: number | null","error: Error","logger","outputDir: string","routes: RouteInfo[]","functions: FunctionInfo[]","crons: CronInfo[]","subscribers: SubscriberInfo[]","appInfo: ServerAppInfo","logger","options: BuildOptions","buildContext: BuildContext","EndpointGenerator","result: BuildResult","provider: LegacyProvider","context: BuildContext","rootOutputDir: string","endpointGenerator: EndpointGenerator","functionGenerator: FunctionGenerator","cronGenerator: CronGenerator","subscriberGenerator: SubscriberGenerator","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>>[]","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","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[]","DEFAULT_SERVICE_IMAGES: Record<ComposeServiceName, string>","DEFAULT_SERVICE_VERSIONS: Record<ComposeServiceName, string>","serviceName: ComposeServiceName","services: ComposeServicesConfig | ComposeServiceName[]","name","version","options: ComposeOptions","options: Omit<ComposeOptions, 'services'>","workspace: NormalizedWorkspace","options: WorkspaceComposeOptions","serviceName: 'postgres' | 'redis'","config: boolean | { version?: string; image?: string } | undefined","defaults: Record<'postgres' | 'redis', string>","appName: string","app: NormalizedAppConfig","allApps: [string, NormalizedAppConfig][]","options: {\n\t\tregistry?: string;\n\t\thasPostgres: boolean;\n\t\thasRedis: boolean;\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>","appName: string","app: NormalizedAppConfig","stage: string","dokployConfig: DokployWorkspaceConfig | undefined","isMainFrontend: boolean","allApps: Record<string, NormalizedAppConfig>","name","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","depName: string","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[]","configPaths: string[]","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","SERVICE_DEFAULTS: Record<\n\tComposeServiceName,\n\tOmit<ServiceCredentials, 'password'>\n>","service: ComposeServiceName","services: ComposeServiceName[]","result: StageSecrets['services']","creds: ServiceCredentials","services: StageSecrets['services']","urls: StageSecrets['urls']","stage: string","secrets: StageSecrets","newCreds: ServiceCredentials","require","options: TemplateOptions","options: TemplateOptions","template: TemplateConfig","_template: TemplateConfig","_helpers: ConfigHelperOptions","options: TemplateOptions","template: TemplateConfig","dbApps?: DatabaseAppConfig[]","services: string[]","volumes: string[]","files: GeneratedFile[]","apps: DatabaseAppConfig[]","options: TemplateOptions","_template: TemplateConfig","files: GeneratedFile[]","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","options: TemplateOptions","cwd: string","name: string","name","pkgManager: PackageManager","script: string","appName: string","password: string","projectName: string","projectName?: string","options: InitOptions","value: string","name","template: TemplateName","servicesArray: string[]","services: ServicesSelection","pkgManager: PackageManager","deployTarget: DeployTarget","templateOptions: TemplateOptions","isMonorepo","dbApps: DatabaseAppConfig[]","secretServices: ComposeServiceName[]","customSecrets: Record<string, string>","options: TemplateOptions","devCommand","services: ComposeServicesConfig | ComposeServiceName[] | undefined","name","options: SecretsInitOptions","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","envVars: Record<string, string>","args: string[]","resolve","Command","pkg","name: string | undefined","options: InitOptions","name","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}","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: { 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 }"],"sources":["../package.json","../src/auth/index.ts","../src/build/providerResolver.ts","../src/generators/CronGenerator.ts","../src/generators/FunctionGenerator.ts","../src/generators/SubscriberGenerator.ts","../src/workspace/client-generator.ts","../src/dev/index.ts","../src/build/manifests.ts","../src/build/index.ts","../src/deploy/state.ts","../src/deploy/dns/DnsProvider.ts","../src/deploy/dns/index.ts","../src/docker/compose.ts","../src/docker/templates.ts","../src/docker/index.ts","../src/deploy/docker.ts","../src/deploy/dokploy.ts","../src/deploy/domain.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/secrets/generator.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/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/ui.ts","../src/init/generators/web.ts","../src/init/utils.ts","../src/init/index.ts","../src/secrets/index.ts","../src/test/index.ts","../src/index.ts"],"sourcesContent":["{\n\t\"name\": \"@geekmidas/cli\",\n\t\"version\": \"1.5.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\"types\": \"./dist/index.d.ts\",\n\t\t\t\"import\": \"./dist/index.mjs\",\n\t\t\t\"require\": \"./dist/index.cjs\"\n\t\t},\n\t\t\"./config\": {\n\t\t\t\"types\": \"./dist/config.d.ts\",\n\t\t\t\"import\": \"./dist/config.mjs\",\n\t\t\t\"require\": \"./dist/config.cjs\"\n\t\t},\n\t\t\"./workspace\": {\n\t\t\t\"types\": \"./dist/workspace/index.d.ts\",\n\t\t\t\"import\": \"./dist/workspace/index.mjs\",\n\t\t\t\"require\": \"./dist/workspace/index.cjs\"\n\t\t},\n\t\t\"./openapi\": {\n\t\t\t\"types\": \"./dist/openapi.d.ts\",\n\t\t\t\"import\": \"./dist/openapi.mjs\",\n\t\t\t\"require\": \"./dist/openapi.cjs\"\n\t\t},\n\t\t\"./openapi-react-query\": {\n\t\t\t\"types\": \"./dist/openapi-react-query.d.ts\",\n\t\t\t\"import\": \"./dist/openapi-react-query.mjs\",\n\t\t\t\"require\": \"./dist/openapi-react-query.cjs\"\n\t\t}\n\t},\n\t\"bin\": {\n\t\t\"gkm\": \"./dist/index.cjs\"\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.971.0\",\n\t\t\"@aws-sdk/client-route-53\": \"~3.971.0\",\n\t\t\"@aws-sdk/client-s3\": \"~3.971.0\",\n\t\t\"@aws-sdk/client-ssm\": \"~3.971.0\",\n\t\t\"@aws-sdk/credential-providers\": \"~3.971.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/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},\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});\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});\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 { 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\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment(),\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 * - 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 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().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\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 { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport type { NormalizedWorkspace } from './types.js';\n\nconst logger = console;\n\n/**\n * Result of copying a client to a frontend app.\n */\nexport interface ClientCopyResult {\n\tfrontendApp: string;\n\tbackendApp: string;\n\toutputPath: string;\n\tendpointCount: number;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Normalize routes to an array of patterns.\n * @internal Exported for use in dev command\n */\nexport function normalizeRoutes(\n\troutes: string | string[] | undefined,\n): string[] {\n\tif (!routes) return [];\n\treturn Array.isArray(routes) ? routes : [routes];\n}\n\n/**\n * Get the first routes pattern as a string (for simple cases).\n * @internal Exported for use in dev command\n */\nexport function getFirstRoute(\n\troutes: string | string[] | undefined,\n): string | null {\n\tconst normalized = normalizeRoutes(routes);\n\treturn normalized[0] || null;\n}\n\n/**\n * Check if a file path matches endpoint patterns that could affect OpenAPI schema.\n * Returns true for changes that should trigger client regeneration.\n */\nexport function shouldRegenerateClient(\n\tfilePath: string,\n\troutesPattern: string,\n): boolean {\n\t// Normalize path separators\n\tconst normalizedPath = filePath.replace(/\\\\/g, '/');\n\tconst normalizedPattern = routesPattern.replace(/\\\\/g, '/');\n\n\t// Check if the file matches the routes pattern\n\t// This is a simple check - the file should be within the routes directory\n\tconst patternDir = normalizedPattern.split('*')[0] || '';\n\n\tif (!normalizedPath.includes(patternDir.replace('./', ''))) {\n\t\treturn false;\n\t}\n\n\t// Check file extension - only TypeScript endpoint files\n\tif (!normalizedPath.endsWith('.ts') && !normalizedPath.endsWith('.tsx')) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Get backend apps that a frontend depends on.\n */\nexport function getBackendDependencies(\n\tworkspace: NormalizedWorkspace,\n\tfrontendAppName: string,\n): string[] {\n\tconst frontendApp = workspace.apps[frontendAppName];\n\tif (!frontendApp || frontendApp.type !== 'frontend') {\n\t\treturn [];\n\t}\n\n\treturn frontendApp.dependencies.filter((dep) => {\n\t\tconst depApp = workspace.apps[dep];\n\t\treturn depApp?.type === 'backend' && depApp.routes;\n\t});\n}\n\n/**\n * Get frontend apps that depend on a backend app.\n */\nexport function getDependentFrontends(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n): string[] {\n\tconst dependentApps: string[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'frontend' && app.dependencies.includes(backendAppName)) {\n\t\t\tdependentApps.push(appName);\n\t\t}\n\t}\n\n\treturn dependentApps;\n}\n\n/**\n * Get the path to a backend's OpenAPI spec file.\n */\nexport function getBackendOpenApiPath(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n): string | null {\n\tconst app = workspace.apps[backendAppName];\n\tif (!app || app.type !== 'backend') {\n\t\treturn null;\n\t}\n\n\treturn join(workspace.root, app.path, '.gkm', 'openapi.ts');\n}\n\n/**\n * Count endpoints in an OpenAPI spec content.\n */\nfunction countEndpoints(content: string): number {\n\tconst endpointMatches = content.match(\n\t\t/'(GET|POST|PUT|PATCH|DELETE)\\s+\\/[^']+'/g,\n\t);\n\treturn endpointMatches?.length ?? 0;\n}\n\n/**\n * Copy the OpenAPI client from a backend to all dependent frontend apps.\n * Called when the backend's .gkm/openapi.ts file changes.\n */\nexport async function copyClientToFrontends(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n\toptions: { silent?: boolean } = {},\n): Promise<ClientCopyResult[]> {\n\tconst log = options.silent ? () => {} : logger.log.bind(logger);\n\tconst results: ClientCopyResult[] = [];\n\n\tconst backendApp = workspace.apps[backendAppName];\n\tif (!backendApp || backendApp.type !== 'backend') {\n\t\treturn results;\n\t}\n\n\t// Get the backend's OpenAPI spec\n\tconst openApiPath = join(\n\t\tworkspace.root,\n\t\tbackendApp.path,\n\t\t'.gkm',\n\t\t'openapi.ts',\n\t);\n\n\tif (!existsSync(openApiPath)) {\n\t\treturn results;\n\t}\n\n\tconst content = await readFile(openApiPath, 'utf-8');\n\tconst endpointCount = countEndpoints(content);\n\n\t// Get all frontends that depend on this backend\n\tconst dependentFrontends = getDependentFrontends(workspace, backendAppName);\n\n\tfor (const frontendAppName of dependentFrontends) {\n\t\tconst frontendApp = workspace.apps[frontendAppName];\n\t\tif (!frontendApp || frontendApp.type !== 'frontend') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if frontend has client output configured\n\t\tconst clientOutput = frontendApp.client?.output;\n\t\tif (!clientOutput) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst result: ClientCopyResult = {\n\t\t\tfrontendApp: frontendAppName,\n\t\t\tbackendApp: backendAppName,\n\t\t\toutputPath: '',\n\t\t\tendpointCount,\n\t\t\tsuccess: false,\n\t\t};\n\n\t\ttry {\n\t\t\tconst frontendPath = join(workspace.root, frontendApp.path);\n\t\t\tconst outputDir = join(frontendPath, clientOutput);\n\t\t\tawait mkdir(outputDir, { recursive: true });\n\n\t\t\t// Use backend app name as filename\n\t\t\tconst fileName = `${backendAppName}.ts`;\n\t\t\tconst outputPath = join(outputDir, fileName);\n\n\t\t\t// Add header comment with backend reference\n\t\t\tconst backendRelPath = relative(\n\t\t\t\tdirname(outputPath),\n\t\t\t\tjoin(workspace.root, backendApp.path),\n\t\t\t);\n\n\t\t\tconst clientContent = `/**\n * Auto-generated API client for ${backendAppName}\n * Generated from: ${backendRelPath}\n *\n * DO NOT EDIT - This file is automatically regenerated when backend schemas change.\n */\n\n${content}\n`;\n\n\t\t\tawait writeFile(outputPath, clientContent);\n\n\t\t\tresult.outputPath = outputPath;\n\t\t\tresult.success = true;\n\n\t\t\tlog(\n\t\t\t\t`📦 Copied client to ${frontendAppName} from ${backendAppName} (${endpointCount} endpoints)`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tresult.error = (error as Error).message;\n\t\t}\n\n\t\tresults.push(result);\n\t}\n\n\treturn results;\n}\n\n/**\n * Copy clients from all backends to their dependent frontends.\n * Useful for initial setup or force refresh.\n */\nexport async function copyAllClients(\n\tworkspace: NormalizedWorkspace,\n\toptions: { silent?: boolean } = {},\n): Promise<ClientCopyResult[]> {\n\tconst allResults: ClientCopyResult[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'backend' && app.routes) {\n\t\t\tconst results = await copyClientToFrontends(workspace, appName, options);\n\t\t\tallResults.push(...results);\n\t\t}\n\t}\n\n\treturn allResults;\n}\n","import { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { dirname, join, resolve } from 'node:path';\nimport chokidar from 'chokidar';\nimport { config as dotenvConfig } from 'dotenv';\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\tCronGenerator,\n\tEndpointGenerator,\n\tFunctionGenerator,\n\tSubscriberGenerator,\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\tcopyAllClients,\n\tcopyClientToFrontends,\n\tgetBackendOpenApiPath,\n} from '../workspace/client-generator.js';\nimport {\n\tgetAppBuildOrder,\n\tgetDependencyEnvVars,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\n\nconst logger = console;\n\n/**\n * Load environment files\n * @internal Exported for testing\n */\nexport function loadEnvFiles(\n\tenvConfig: string | string[] | undefined,\n\tcwd: string = process.cwd(),\n): { loaded: string[]; missing: string[] } {\n\tconst loaded: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Normalize to array\n\tconst envFiles = envConfig\n\t\t? Array.isArray(envConfig)\n\t\t\t? envConfig\n\t\t\t: [envConfig]\n\t\t: ['.env'];\n\n\t// Load each env file in order (later files override earlier)\n\tfor (const envFile of envFiles) {\n\t\tconst envPath = resolve(cwd, envFile);\n\t\tif (existsSync(envPath)) {\n\t\t\tdotenvConfig({ path: envPath, override: true, quiet: true });\n\t\t\tloaded.push(envFile);\n\t\t} else if (envConfig) {\n\t\t\t// Only report as missing if explicitly configured\n\t\t\tmissing.push(envFile);\n\t\t}\n\t}\n\n\treturn { loaded, missing };\n}\n\n/**\n * Check if a port is available\n * @internal Exported for testing\n */\nexport async function isPortAvailable(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst server = createServer();\n\n\t\tserver.once('error', (err: NodeJS.ErrnoException) => {\n\t\t\tif (err.code === 'EADDRINUSE') {\n\t\t\t\tresolve(false);\n\t\t\t} else {\n\t\t\t\tresolve(false);\n\t\t\t}\n\t\t});\n\n\t\tserver.once('listening', () => {\n\t\t\tserver.close();\n\t\t\tresolve(true);\n\t\t});\n\n\t\tserver.listen(port);\n\t});\n}\n\n/**\n * Find an available port starting from the preferred port\n * @internal Exported for testing\n */\nexport async function findAvailablePort(\n\tpreferredPort: number,\n\tmaxAttempts = 10,\n): Promise<number> {\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tconst port = preferredPort + i;\n\t\tif (await isPortAvailable(port)) {\n\t\t\treturn port;\n\t\t}\n\t\tlogger.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);\n\t}\n\n\tthrow new Error(\n\t\t`Could not find an available port after trying ${maxAttempts} ports starting from ${preferredPort}`,\n\t);\n}\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\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\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 and write to JSON file\n\tlet secretsJsonPath: string | undefined;\n\tconst appSecrets = await loadSecretsForApp(secretsRoot, workspaceAppName);\n\tif (Object.keys(appSecrets).length > 0) {\n\t\tconst secretsDir = join(secretsRoot, '.gkm');\n\t\tawait mkdir(secretsDir, { recursive: true });\n\t\tsecretsJsonPath = join(secretsDir, 'dev-secrets.json');\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);\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 });\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\tlogger.error('❌ Rebuild failed:', (error as Error).message);\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 * Next.js config file patterns to check.\n */\nconst NEXTJS_CONFIG_FILES = [\n\t'next.config.js',\n\t'next.config.ts',\n\t'next.config.mjs',\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 (Next.js) app configuration.\n * Checks for Next.js config file and dependency.\n * @internal Exported for testing\n */\nexport async function validateFrontendApp(\n\tappName: string,\n\tappPath: string,\n\tworkspaceRoot: string,\n): Promise<FrontendValidationResult> {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst fullPath = join(workspaceRoot, appPath);\n\n\t// Check for Next.js config file\n\tconst hasConfigFile = NEXTJS_CONFIG_FILES.some((file) =>\n\t\texistsSync(join(fullPath, file)),\n\t);\n\n\tif (!hasConfigFile) {\n\t\terrors.push(\n\t\t\t`Next.js config file not found. Expected one of: ${NEXTJS_CONFIG_FILES.join(', ')}`,\n\t\t);\n\t}\n\n\t// Check for package.json\n\tconst packageJsonPath = join(fullPath, 'package.json');\n\tif (existsSync(packageJsonPath)) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\t\tconst pkg = require(packageJsonPath);\n\t\t\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n\t\t\tif (!deps.next) {\n\t\t\t\terrors.push(\n\t\t\t\t\t'Next.js not found in dependencies. Run: pnpm add next react react-dom',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Check for dev script\n\t\t\tif (!pkg.scripts?.dev) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t'No \"dev\" script found in package.json. Turbo expects a \"dev\" script to run.',\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\terrors.push(`Failed to read package.json at ${packageJsonPath}`);\n\t\t}\n\t} else {\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}\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 === 'frontend') {\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);\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 secrets:init --stage dev\"',\n\t);\n\treturn {};\n}\n\n/**\n * Load secrets from a path for dev mode.\n * For single app: returns secrets as-is.\n * For workspace app: maps {APP}_DATABASE_URL → DATABASE_URL.\n * @internal Exported for testing\n */\nexport async function loadSecretsForApp(\n\tsecretsRoot: string,\n\tappName?: string,\n): Promise<Record<string, string>> {\n\t// Try 'dev' stage first, then 'development'\n\tconst stages = ['dev', 'development'];\n\n\tlet secrets: Record<string, string> = {};\n\n\tfor (const stage of stages) {\n\t\tif (secretsExist(stage, secretsRoot)) {\n\t\t\tconst stageSecrets = await readStageSecrets(stage, secretsRoot);\n\t\t\tif (stageSecrets) {\n\t\t\t\tlogger.log(`🔐 Loading secrets from stage: ${stage}`);\n\t\t\t\tsecrets = toEmbeddableSecrets(stageSecrets);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (Object.keys(secrets).length === 0) {\n\t\treturn {};\n\t}\n\n\t// Single app mode - no mapping needed\n\tif (!appName) {\n\t\treturn secrets;\n\t}\n\n\t// Workspace app mode - map {APP}_* to generic names\n\tconst prefix = appName.toUpperCase();\n\tconst mapped = { ...secrets };\n\n\t// Map {APP}_DATABASE_URL → DATABASE_URL\n\tconst appDbUrl = secrets[`${prefix}_DATABASE_URL`];\n\tif (appDbUrl) {\n\t\tmapped.DATABASE_URL = appDbUrl;\n\t}\n\n\treturn mapped;\n}\n\n/**\n * Start docker-compose services for the workspace.\n * @internal Exported for testing\n */\nexport async function startWorkspaceServices(\n\tworkspace: NormalizedWorkspace,\n): Promise<void> {\n\tconst services = workspace.services;\n\tif (!services.db && !services.cache && !services.mail) {\n\t\treturn;\n\t}\n\n\tconst servicesToStart: string[] = [];\n\n\tif (services.db) {\n\t\tservicesToStart.push('postgres');\n\t}\n\tif (services.cache) {\n\t\tservicesToStart.push('redis');\n\t}\n\tif (services.mail) {\n\t\tservicesToStart.push('mailpit');\n\t}\n\n\tif (servicesToStart.length === 0) {\n\t\treturn;\n\t}\n\n\tlogger.log(`🐳 Starting services: ${servicesToStart.join(', ')}`);\n\n\ttry {\n\t\t// Check if docker-compose.yml exists\n\t\tconst composeFile = join(workspace.root, 'docker-compose.yml');\n\t\tif (!existsSync(composeFile)) {\n\t\t\tlogger.warn(\n\t\t\t\t'⚠️ No docker-compose.yml found. Services will not be started.',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Start services with docker-compose\n\t\texecSync(`docker compose up -d ${servicesToStart.join(' ')}`, {\n\t\t\tcwd: workspace.root,\n\t\t\tstdio: 'inherit',\n\t\t});\n\n\t\tlogger.log('✅ Services started');\n\t} catch (error) {\n\t\tlogger.error('❌ Failed to start services:', (error as Error).message);\n\t\tthrow error;\n\t}\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 === 'frontend',\n\t);\n\n\tlogger.log(`\\n🚀 Starting workspace: ${workspace.name}`);\n\tlogger.log(\n\t\t` ${backendApps.length} backend app(s), ${frontendApps.length} frontend app(s)`,\n\t);\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// Copy initial clients from backends to frontends\n\tif (frontendApps.length > 0 && backendApps.length > 0) {\n\t\tconst clientResults = await copyAllClients(workspace);\n\t\tconst copiedCount = clientResults.filter((r) => r.success).length;\n\t\tif (copiedCount > 0) {\n\t\t\tlogger.log(`\\n📦 Copied ${copiedCount} API client(s)`);\n\t\t}\n\t}\n\n\t// Start docker-compose services\n\tawait startWorkspaceServices(workspace);\n\n\t// Load secrets if enabled\n\tconst secretsEnv = await loadDevSecrets(workspace);\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\tlogger.log(\n\t\t\t` ${app.type === 'backend' ? '🔧' : '🌐'} ${appName} → http://localhost:${app.port}${deps}`,\n\t\t);\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});\n\n\t// Set up file watcher for backend .gkm/openapi.ts changes (auto-copy to frontends)\n\tlet openApiWatcher: ReturnType<typeof chokidar.watch> | null = null;\n\n\tif (frontendApps.length > 0 && backendApps.length > 0) {\n\t\t// Collect all backend openapi.ts file paths to watch\n\t\tconst openApiPaths: { path: string; appName: string }[] = [];\n\n\t\tfor (const [appName] of backendApps) {\n\t\t\tconst openApiPath = getBackendOpenApiPath(workspace, appName);\n\t\t\tif (openApiPath) {\n\t\t\t\topenApiPaths.push({ path: openApiPath, appName });\n\t\t\t}\n\t\t}\n\n\t\tif (openApiPaths.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t`\\n👀 Watching ${openApiPaths.length} backend OpenAPI spec(s) for changes`,\n\t\t\t);\n\n\t\t\t// Create a map for quick lookup of app name from path\n\t\t\tconst pathToApp = new Map(openApiPaths.map((p) => [p.path, p.appName]));\n\n\t\t\topenApiWatcher = chokidar.watch(\n\t\t\t\topenApiPaths.map((p) => p.path),\n\t\t\t\t{\n\t\t\t\t\tpersistent: true,\n\t\t\t\t\tignoreInitial: true,\n\t\t\t\t\t// Watch parent directory too since file may not exist yet\n\t\t\t\t\tdepth: 0,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tlet copyTimeout: NodeJS.Timeout | null = null;\n\n\t\t\tconst handleChange = async (changedPath: string) => {\n\t\t\t\t// Debounce to handle rapid changes\n\t\t\t\tif (copyTimeout) {\n\t\t\t\t\tclearTimeout(copyTimeout);\n\t\t\t\t}\n\n\t\t\t\tcopyTimeout = setTimeout(async () => {\n\t\t\t\t\tconst backendAppName = pathToApp.get(changedPath);\n\t\t\t\t\tif (!backendAppName) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlogger.log(`\\n🔄 OpenAPI spec changed for ${backendAppName}`);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst results = await copyClientToFrontends(\n\t\t\t\t\t\t\tworkspace,\n\t\t\t\t\t\t\tbackendAppName,\n\t\t\t\t\t\t\t{ silent: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\t\tif (result.success) {\n\t\t\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t\t\t` 📦 Copied client to ${result.frontendApp} (${result.endpointCount} endpoints)`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (result.error) {\n\t\t\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t\t\t` ❌ Failed to copy client to ${result.frontendApp}: ${result.error}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t` ❌ Failed to copy clients: ${(error as Error).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}, 200); // 200ms debounce\n\t\t\t};\n\n\t\t\topenApiWatcher.on('change', handleChange);\n\t\t\topenApiWatcher.on('add', handleChange);\n\t\t}\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 workspace...');\n\n\t\t// Close OpenAPI watcher\n\t\tif (openApiWatcher) {\n\t\t\topenApiWatcher.close().catch(() => {});\n\t\t}\n\n\t\t// Kill turbo process\n\t\tif (turboProcess.pid) {\n\t\t\ttry {\n\t\t\t\t// Try to kill the process group\n\t\t\t\tprocess.kill(-turboProcess.pid, 'SIGTERM');\n\t\t\t} catch {\n\t\t\t\t// Fall back to killing just the process\n\t\t\t\tturboProcess.kill('SIGTERM');\n\t\t\t}\n\t\t}\n\n\t\t// Give processes time to clean up\n\t\tsetTimeout(() => {\n\t\t\tprocess.exit(0);\n\t\t}, 2000);\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\t// Close watcher on exit\n\t\t\tif (openApiWatcher) {\n\t\t\t\topenApiWatcher.close().catch(() => {});\n\t\t\t}\n\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): 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\n\t// Load all constructs (resolve paths relative to appRoot)\n\tconst [allEndpoints, allFunctions, allCrons, allSubscribers] =\n\t\tawait Promise.all([\n\t\t\tendpointGenerator.load(config.routes, appRoot),\n\t\t\tconfig.functions ? functionGenerator.load(config.functions, appRoot) : [],\n\t\t\tconfig.crons ? cronGenerator.load(config.crons, appRoot) : [],\n\t\t\tconfig.subscribers\n\t\t\t\t? subscriberGenerator.load(config.subscribers, appRoot)\n\t\t\t\t: [],\n\t\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]);\n}\n\n/**\n * Find the directory containing .gkm/secrets/.\n * Walks up from cwd until it finds one, or returns cwd.\n * @internal Exported for testing\n */\nexport function findSecretsRoot(startDir: string): string {\n\tlet dir = startDir;\n\twhile (dir !== '/') {\n\t\tif (existsSync(join(dir, '.gkm', 'secrets'))) {\n\t\t\treturn dir;\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn startDir;\n}\n\n/**\n * Generate the credentials injection code snippet.\n * This is the common logic used by both entry wrapper and exec preload.\n * @internal\n */\nfunction generateCredentialsInjection(secretsJsonPath: string): string {\n\treturn `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets into Credentials and process.env\nconst secretsPath = '${secretsJsonPath}';\nif (existsSync(secretsPath)) {\n const secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));\n Object.assign(Credentials, secrets);\n Object.assign(process.env, secrets);\n // Debug: uncomment to verify preload is running\n // console.log('[gkm preload] Injected', Object.keys(secrets).length, 'credentials');\n}\n`;\n}\n\n/**\n * Create a preload script that injects secrets into Credentials.\n * Used by `gkm exec` to inject secrets before running any command.\n * @internal Exported for testing\n */\nexport async function createCredentialsPreload(\n\tpreloadPath: string,\n\tsecretsJsonPath: string,\n): Promise<void> {\n\tconst content = `/**\n * Credentials preload generated by 'gkm exec'\n * This file is loaded via NODE_OPTIONS=\"--import <path>\"\n */\n${generateCredentialsInjection(secretsJsonPath)}`;\n\n\tawait writeFile(preloadPath, content);\n}\n\n/**\n * Create a wrapper script that injects secrets before importing the entry file.\n * @internal Exported for testing\n */\nexport async function createEntryWrapper(\n\twrapperPath: string,\n\tentryPath: string,\n\tsecretsJsonPath?: string,\n): Promise<void> {\n\tconst credentialsInjection = secretsJsonPath\n\t\t? `${generateCredentialsInjection(secretsJsonPath)}\n`\n\t\t: '';\n\n\t// Use dynamic import() to ensure secrets are assigned before the entry file loads\n\t// Static imports are hoisted, so Object.assign would run after the entry file is loaded\n\tconst content = `#!/usr/bin/env node\n/**\n * Entry wrapper generated by 'gkm dev --entry'\n */\n${credentialsInjection}// Import and run the user's entry file (dynamic import ensures secrets load first)\nawait import('${entryPath}');\n`;\n\n\tawait writeFile(wrapperPath, content);\n}\n\n/**\n * Result of preparing entry credentials for dev mode.\n */\nexport interface EntryCredentialsResult {\n\t/** Credentials to inject (secrets + PORT) */\n\tcredentials: Record<string, string>;\n\t/** Resolved port (from --port, workspace config, or default 3000) */\n\tresolvedPort: number;\n\t/** Path where credentials JSON was written */\n\tsecretsJsonPath: string;\n\t/** Resolved app name (if in workspace) */\n\tappName: string | undefined;\n\t/** Secrets root directory */\n\tsecretsRoot: string;\n}\n\n/**\n * Prepare credentials for entry dev mode.\n * Loads workspace config, secrets, and injects PORT.\n * @internal Exported for testing\n */\nexport async function prepareEntryCredentials(options: {\n\texplicitPort?: number;\n\tcwd?: string;\n}): Promise<EntryCredentialsResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\n\t// Try to get workspace app config for port and secrets\n\tlet workspaceAppPort: number | undefined;\n\tlet secretsRoot: string = cwd;\n\tlet appName: string | undefined;\n\n\ttry {\n\t\tconst appConfig = await loadAppConfig(cwd);\n\t\tworkspaceAppPort = appConfig.app.port;\n\t\tsecretsRoot = appConfig.workspaceRoot;\n\t\tappName = appConfig.appName;\n\t} catch (error) {\n\t\t// Not in a workspace - use defaults\n\t\tlogger.log(\n\t\t\t`⚠️ Could not load workspace config: ${(error as Error).message}`,\n\t\t);\n\t\tsecretsRoot = findSecretsRoot(cwd);\n\t\tappName = getAppNameFromCwd(cwd) ?? undefined;\n\t}\n\n\t// Determine port: explicit --port > workspace config > default 3000\n\tconst resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3000;\n\n\t// Load secrets and inject PORT\n\tconst credentials = await loadSecretsForApp(secretsRoot, appName);\n\n\t// Always inject PORT into credentials so apps can read it\n\tcredentials.PORT = String(resolvedPort);\n\n\t// Write secrets to temp JSON file (always write since we have PORT)\n\t// Use app-specific filename to avoid race conditions when running multiple apps via turbo\n\tconst secretsDir = join(secretsRoot, '.gkm');\n\tawait mkdir(secretsDir, { recursive: true });\n\tconst secretsFileName = appName\n\t\t? `dev-secrets-${appName}.json`\n\t\t: 'dev-secrets.json';\n\tconst secretsJsonPath = join(secretsDir, secretsFileName);\n\tawait writeFile(secretsJsonPath, JSON.stringify(credentials, null, 2));\n\n\treturn {\n\t\tcredentials,\n\t\tresolvedPort,\n\t\tsecretsJsonPath,\n\t\tappName,\n\t\tsecretsRoot,\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🎉 Running at http://localhost:${this.port}`);\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\nclass DevServer {\n\tprivate serverProcess: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate actualPort: number;\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\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 on port ${this.actualPort}...`);\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\tlogger.log(`\\n🎉 Server running at http://localhost:${this.actualPort}`);\n\t\t\tif (this.enableOpenApi) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`📚 API Docs available at http://localhost:${this.actualPort}/__docs`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (this.telescope) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`🔭 Telescope available at http://localhost:${this.actualPort}${this.telescope.path}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (this.studio) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`🗄️ Studio available at http://localhost:${this.actualPort}${this.studio.path}`,\n\t\t\t\t);\n\t\t\t}\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\t\tconst { relative, dirname } = await import('node:path');\n\n\t\tconst serverPath = join(this.appRoot, '.gkm', this.provider, 'server.ts');\n\n\t\tconst relativeAppPath = relative(\n\t\t\tdirname(serverPath),\n\t\t\tjoin(dirname(serverPath), 'app.js'),\n\t\t);\n\n\t\t// Generate credentials injection code if secrets are available\n\t\tconst credentialsInjection = this.secretsJsonPath\n\t\t\t? `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets into Credentials (must happen before app import)\nconst secretsPath = '${this.secretsJsonPath}';\nif (existsSync(secretsPath)) {\n Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));\n}\n\n`\n\t\t\t: '';\n\n\t\tconst serveCode =\n\t\t\tthis.runtime === 'bun'\n\t\t\t\t? `Bun.serve({\n port,\n fetch: app.fetch,\n });`\n\t\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\t\tconst content = `#!/usr/bin/env node\n/**\n * Development server entry point\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}import { createApp } from './${relativeAppPath.startsWith('.') ? relativeAppPath : `./${relativeAppPath}`}';\n\nconst port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// createApp is async to support optional WebSocket setup\nconst { app, start } = await createApp(undefined, ${this.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\t\tawait fsWriteFile(serverPath, content);\n\t}\n}\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 workspace config and secrets)\n\t// Don't inject PORT for exec since we're not running a server\n\tconst { credentials, secretsJsonPath, appName } =\n\t\tawait prepareEntryCredentials({ cwd });\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// Create in cwd so package resolution works (finds node_modules in app directory)\n\tconst preloadDir = join(cwd, '.gkm');\n\tawait mkdir(preloadDir, { recursive: true });\n\tconst preloadPath = join(preloadDir, 'credentials-preload.ts');\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: ${commandArgs.join(' ')}`);\n\n\t// Merge NODE_OPTIONS with existing value (if any)\n\t// Add tsx loader first so our .ts preload can be loaded\n\tconst existingNodeOptions = process.env.NODE_OPTIONS ?? '';\n\tconst tsxImport = '--import=tsx';\n\tconst preloadImport = `--import=${preloadPath}`;\n\n\t// Build NODE_OPTIONS: existing + tsx loader + our preload\n\tconst nodeOptions = [existingNodeOptions, tsxImport, 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 { mkdir, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type {\n\tCronInfo,\n\tFunctionInfo,\n\tRouteInfo,\n\tSubscriberInfo,\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\nexport async function generateAwsManifest(\n\toutputDir: string,\n\troutes: RouteInfo[],\n\tfunctions: FunctionInfo[],\n\tcrons: CronInfo[],\n\tsubscribers: SubscriberInfo[],\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 = routes.filter((r) => r.method !== 'ALL');\n\n\tconst content = `export const manifest = {\n routes: ${JSON.stringify(awsRoutes, null, 2)},\n functions: ${JSON.stringify(functions, null, 2)},\n crons: ${JSON.stringify(crons, null, 2)},\n subscribers: ${JSON.stringify(subscribers, null, 2)},\n} as const;\n\n// Derived types\nexport type Route = (typeof manifest.routes)[number];\nexport type Function = (typeof manifest.functions)[number];\nexport type Cron = (typeof manifest.crons)[number];\nexport type Subscriber = (typeof manifest.subscribers)[number];\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 ${awsRoutes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\n}\n\nexport async function generateServerManifest(\n\toutputDir: string,\n\tappInfo: ServerAppInfo,\n\troutes: RouteInfo[],\n\tsubscribers: SubscriberInfo[],\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 = routes\n\t\t.filter((r) => r.method !== 'ALL')\n\t\t.map((r) => ({\n\t\t\tpath: r.path,\n\t\t\tmethod: r.method,\n\t\t\tauthorizer: r.authorizer,\n\t\t}));\n\n\t// Server subscribers only need name and events\n\tconst serverSubscribers = subscribers.map((s) => ({\n\t\tname: s.name,\n\t\tsubscribedEvents: s.subscribedEvents,\n\t}));\n\n\tconst content = `export const manifest = {\n app: ${JSON.stringify(appInfo, null, 2)},\n routes: ${JSON.stringify(serverRoutes, null, 2)},\n subscribers: ${JSON.stringify(serverSubscribers, null, 2)},\n} as const;\n\n// Derived types\nexport type Route = (typeof manifest.routes)[number];\nexport type Subscriber = (typeof manifest.subscribers)[number];\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 ${serverRoutes.length} routes, ${serverSubscribers.length} subscribers`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\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 { Subscriber } from '@geekmidas/constructs/subscribers';\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\tSubscriberGenerator,\n} from '../generators';\nimport type {\n\tBuildOptions,\n\tBuildResult,\n\tLegacyProvider,\n\tRouteInfo,\n} from '../types';\nimport {\n\tgetAppBuildOrder,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport {\n\tgenerateAwsManifest,\n\tgenerateServerManifest,\n\ttype ServerAppInfo,\n} from './manifests';\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: ${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 (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};\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\n\t// Load all constructs in parallel\n\tconst [allEndpoints, allFunctions, allCrons, allSubscribers] =\n\t\tawait Promise.all([\n\t\t\tendpointGenerator.load(config.routes),\n\t\t\tconfig.functions ? functionGenerator.load(config.functions) : [],\n\t\t\tconfig.crons ? cronGenerator.load(config.crons) : [],\n\t\t\tconfig.subscribers ? subscriberGenerator.load(config.subscribers) : [],\n\t\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\n\tif (\n\t\tallEndpoints.length === 0 &&\n\t\tallFunctions.length === 0 &&\n\t\tallCrons.length === 0 &&\n\t\tallSubscribers.length === 0\n\t) {\n\t\tlogger.log(\n\t\t\t'No endpoints, functions, crons, or subscribers 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\tallEndpoints,\n\t\t\tallFunctions,\n\t\t\tallCrons,\n\t\t\tallSubscribers,\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\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\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\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\tconst [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(\n\t\t[\n\t\t\tendpointGenerator.build(context, endpoints, outputDir, {\n\t\t\t\tprovider,\n\t\t\t\tenableOpenApi,\n\t\t\t}),\n\t\t\tfunctionGenerator.build(context, functions, outputDir, { provider }),\n\t\t\tcronGenerator.build(context, crons, outputDir, { provider }),\n\t\t\tsubscriberGenerator.build(context, subscribers, outputDir, { provider }),\n\t\t],\n\t);\n\n\tlogger.log(\n\t\t`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,\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 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\trouteMetadata,\n\t\t\tsubscriberInfos,\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];\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\troutes,\n\t\t\tfunctionInfos,\n\t\t\tcronInfos,\n\t\t\tsubscriberInfos,\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' | 'frontend';\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 === 'frontend');\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// Summary\n\t\tlogger.log(`\\n📋 Build Summary:`);\n\t\tfor (const result of results) {\n\t\t\tconst icon = result.type === 'backend' ? '⚙️' : '🌐';\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 === 'frontend') {\n\t\t// Next.js standalone output\n\t\treturn join(appPath, '.next');\n\t} else {\n\t\t// Backend .gkm output\n\t\treturn join(appPath, '.gkm');\n\t}\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 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};\n\n/** Default Docker image versions for services */\nexport const DEFAULT_SERVICE_VERSIONS: Record<ComposeServiceName, string> = {\n\tpostgres: '16-alpine',\n\tredis: '7-alpine',\n\trabbitmq: '3-management-alpine',\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 = `version: '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:postgres@postgres:5432/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\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 - postgres_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\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\t// Add volumes\n\tyaml += `\nvolumes:\n`;\n\n\tif (serviceMap.has('postgres')) {\n\t\tyaml += ` postgres_data:\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\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 `version: '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\n\t// Get image versions from config\n\tconst postgresImage = getInfraServiceImage('postgres', services.db);\n\tconst redisImage = getInfraServiceImage('redis', services.cache);\n\n\tlet yaml = `# Docker Compose for ${workspace.name} workspace\n# Generated by gkm - do not edit manually\n\nservices:\n`;\n\n\t// Generate service for each app\n\tfor (const [appName, app] of apps) {\n\t\tyaml += generateAppService(appName, app, apps, {\n\t\t\tregistry,\n\t\t\thasPostgres,\n\t\t\thasRedis,\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 - postgres_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\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 ports:\n - \"8025:8025\" # Web UI\n - \"1025:1025\" # SMTP\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 += ` postgres_data:\n`;\n\t}\n\n\tif (hasRedis) {\n\t\tyaml += ` redis_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',\n\tconfig: boolean | { version?: string; image?: string } | undefined,\n): string {\n\tconst defaults: Record<'postgres' | 'redis', string> = {\n\t\tpostgres: 'postgres:16-alpine',\n\t\tredis: 'redis:7-alpine',\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 baseImage = serviceName === 'postgres' ? 'postgres' : 'redis';\n\t\t\treturn `${baseImage}:${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\thasPostgres: boolean;\n\t\thasRedis: boolean;\n\t},\n): string {\n\tconst { registry, hasPostgres, hasRedis } = options;\n\tconst imageRef = registry ? `\\${REGISTRY:-${registry}}/` : '';\n\n\t// Health check path - frontends use /, backends use /health\n\tconst healthCheckPath = app.type === 'frontend' ? '/' : '/health';\n\tconst healthCheckCmd =\n\t\tapp.type === 'frontend'\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:postgres@postgres:5432/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}\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}\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","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 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\tgenerateSlimDockerfile,\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' | 'frontend';\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\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 === 'frontend') {\n\t\t\t// Generate Next.js Dockerfile\n\t\t\tdockerfile = generateNextjsDockerfile({\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});\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 = result.type === 'backend' ? '⚙️' : '🌐';\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","import 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 !== 'frontend') {\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 === 'frontend') {\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 frontend app based on its dependencies.\n *\n * @param app - The frontend 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 buildArgs: string[] = [];\n\n\tfor (const dep of app.dependencies) {\n\t\tconst publicUrl = deployedUrls[dep];\n\t\tif (publicUrl) {\n\t\t\t// Convert app name to UPPER_SNAKE_CASE for env var\n\t\t\tconst envVarName = `NEXT_PUBLIC_${dep.toUpperCase()}_URL`;\n\t\t\tbuildArgs.push(`${envVarName}=${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 frontend app configuration\n * @returns Array of arg names like 'NEXT_PUBLIC_API_URL'\n */\nexport function getPublicUrlArgNames(app: NormalizedAppConfig): string[] {\n\treturn app.dependencies.map((dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`);\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 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 NEXT_PUBLIC_ prefix for frontend apps (NEXT_PUBLIC_AUTH_URL -> dependencyUrls.auth)\n\tif (context.dependencyUrls && varName.endsWith('_URL')) {\n\t\tlet depName: string;\n\n\t\tif (varName.startsWith('NEXT_PUBLIC_')) {\n\t\t\t// NEXT_PUBLIC_AUTH_URL -> auth\n\t\t\tdepName = varName.slice(12, -4).toLowerCase();\n\t\t} else {\n\t\t\t// AUTH_URL -> auth\n\t\t\tdepName = varName.slice(0, -4).toLowerCase();\n\t\t}\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 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\trequiredEnvVars: 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}\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 } = options;\n\n\t// 1. Frontend apps - handle dependencies and config sniffing\n\tif (app.type === 'frontend') {\n\t\t// Auto-generate NEXT_PUBLIC_{DEP}_URL from dependencies\n\t\tconst depVars = (app.dependencies ?? []).map(\n\t\t\t(dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`,\n\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\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}\n\n\t\t\t// Combine: dependency vars + sniffed vars (deduplicated)\n\t\t\tconst allVars = [...new Set([...depVars, ...sniffedVars])];\n\t\t\treturn { appName, requiredEnvVars: allVars };\n\t\t}\n\n\t\treturn { appName, requiredEnvVars: depVars };\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 { appName, requiredEnvVars: result.envVars };\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(app.routes, app.path, workspacePath);\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 { appName, requiredEnvVars: result.envVars };\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 { appName, requiredEnvVars: result.envVars };\n\t}\n\n\t// 5. No env detection method available\n\treturn { appName, requiredEnvVars: [] };\n}\n\n/**\n * Result from sniffing an entry file.\n */\ninterface EntrySniffResult {\n\tenvVars: 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\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\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\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 { envVars: [], error: new Error('No route patterns provided') };\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\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\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\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: [], 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: [], 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\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\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 === 'frontend',\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 (NEXT_PUBLIC_* must be present at build time)\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: all NEXT_PUBLIC_* vars must be present at Next.js build time\n\t\t\t\tconst buildArgs: string[] = [];\n\t\t\t\tconst publicUrlArgNames: string[] = [];\n\n\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\tif (key.startsWith('NEXT_PUBLIC_')) {\n\t\t\t\t\t\tbuildArgs.push(`${key}=${value}`);\n\t\t\t\t\t\tpublicUrlArgNames.push(key);\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 NEXT_PUBLIC_* 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 { randomBytes } from 'node:crypto';\nimport type { ComposeServiceName } from '../types';\nimport type { ServiceCredentials, StageSecrets } from './types';\n\n/**\n * Generate a secure random password using URL-safe base64 characters.\n * @param length Password length (default: 32)\n */\nexport function generateSecurePassword(length = 32): string {\n\treturn randomBytes(Math.ceil((length * 3) / 4))\n\t\t.toString('base64url')\n\t\t.slice(0, length);\n}\n\n/** Default service configurations */\nconst SERVICE_DEFAULTS: Record<\n\tComposeServiceName,\n\tOmit<ServiceCredentials, 'password'>\n> = {\n\tpostgres: {\n\t\thost: 'postgres',\n\t\tport: 5432,\n\t\tusername: 'app',\n\t\tdatabase: 'app',\n\t},\n\tredis: {\n\t\thost: 'redis',\n\t\tport: 6379,\n\t\tusername: 'default',\n\t},\n\trabbitmq: {\n\t\thost: 'rabbitmq',\n\t\tport: 5672,\n\t\tusername: 'app',\n\t\tvhost: '/',\n\t},\n};\n\n/**\n * Generate credentials for a specific service.\n */\nexport function generateServiceCredentials(\n\tservice: ComposeServiceName,\n): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS[service];\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t};\n}\n\n/**\n * Generate credentials for multiple services.\n */\nexport function generateServicesCredentials(\n\tservices: ComposeServiceName[],\n): StageSecrets['services'] {\n\tconst result: StageSecrets['services'] = {};\n\n\tfor (const service of services) {\n\t\tresult[service] = generateServiceCredentials(service);\n\t}\n\n\treturn result;\n}\n\n/**\n * Generate connection URL for PostgreSQL.\n */\nexport function generatePostgresUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, database } = creds;\n\treturn `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;\n}\n\n/**\n * Generate connection URL for Redis.\n */\nexport function generateRedisUrl(creds: ServiceCredentials): string {\n\tconst { password, host, port } = creds;\n\treturn `redis://:${encodeURIComponent(password)}@${host}:${port}`;\n}\n\n/**\n * Generate connection URL for RabbitMQ.\n */\nexport function generateRabbitmqUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, vhost } = creds;\n\tconst encodedVhost = encodeURIComponent(vhost ?? '/');\n\treturn `amqp://${username}:${encodeURIComponent(password)}@${host}:${port}/${encodedVhost}`;\n}\n\n/**\n * Generate connection URLs from service credentials.\n */\nexport function generateConnectionUrls(\n\tservices: StageSecrets['services'],\n): StageSecrets['urls'] {\n\tconst urls: StageSecrets['urls'] = {};\n\n\tif (services.postgres) {\n\t\turls.DATABASE_URL = generatePostgresUrl(services.postgres);\n\t}\n\n\tif (services.redis) {\n\t\turls.REDIS_URL = generateRedisUrl(services.redis);\n\t}\n\n\tif (services.rabbitmq) {\n\t\turls.RABBITMQ_URL = generateRabbitmqUrl(services.rabbitmq);\n\t}\n\n\treturn urls;\n}\n\n/**\n * Create a new StageSecrets object with generated credentials.\n */\nexport function createStageSecrets(\n\tstage: string,\n\tservices: ComposeServiceName[],\n): StageSecrets {\n\tconst now = new Date().toISOString();\n\tconst serviceCredentials = generateServicesCredentials(services);\n\tconst urls = generateConnectionUrls(serviceCredentials);\n\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: serviceCredentials,\n\t\turls,\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Rotate password for a specific service.\n */\nexport function rotateServicePassword(\n\tsecrets: StageSecrets,\n\tservice: ComposeServiceName,\n): StageSecrets {\n\tconst currentCreds = secrets.services[service];\n\tif (!currentCreds) {\n\t\tthrow new Error(`Service \"${service}\" not configured in secrets`);\n\t}\n\n\tconst newCreds: ServiceCredentials = {\n\t\t...currentCreds,\n\t\tpassword: generateSecurePassword(),\n\t};\n\n\tconst newServices = {\n\t\t...secrets.services,\n\t\t[service]: newCreds,\n\t};\n\n\treturn {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tservices: newServices,\n\t\turls: generateConnectionUrls(newServices),\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': '~1.0.0',\n\t'@geekmidas/auth': '~1.0.0',\n\t'@geekmidas/cache': '~1.0.0',\n\t'@geekmidas/client': '~1.0.0',\n\t'@geekmidas/cloud': '~1.0.0',\n\t'@geekmidas/constructs': '~1.0.4',\n\t'@geekmidas/db': '~1.0.0',\n\t'@geekmidas/emailkit': '~1.0.0',\n\t'@geekmidas/envkit': '~1.0.1',\n\t'@geekmidas/errors': '~1.0.0',\n\t'@geekmidas/events': '~1.0.0',\n\t'@geekmidas/logger': '~1.0.0',\n\t'@geekmidas/rate-limit': '~1.0.0',\n\t'@geekmidas/schema': '~1.0.0',\n\t'@geekmidas/services': '~1.0.0',\n\t'@geekmidas/storage': '~1.0.0',\n\t'@geekmidas/studio': '~1.0.0',\n\t'@geekmidas/telescope': '~1.0.0',\n\t'@geekmidas/testkit': '~1.0.1',\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\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.js';\nimport { logger } from './config/logger.js';\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.js';\nimport { envParser } from './config/env.js';\nimport { logger } from './config/logger.js';\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 * 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\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\tdeclaration: true,\n\t\t\t\t\tdeclarationMap: true,\n\t\t\t\t\toutDir: './dist',\n\t\t\t\t\trootDir: './src',\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\treturn [\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\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\treturn [\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\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\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\treturn [\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","import 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:16-alpine\n container_name: ${options.name}-postgres\n restart: unless-stopped${envFile}\n environment:\n POSTGRES_USER: postgres\n POSTGRES_PASSWORD: postgres\n POSTGRES_DB: ${options.name.replace(/-/g, '_')}_dev\n ports:\n - '5432:5432'\n volumes:\n - postgres_data:/var/lib/postgresql/data${initVolume}\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U postgres']\n interval: 5s\n timeout: 5s\n retries: 5`);\n\t\tvolumes.push(' postgres_data:');\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),\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),\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 - '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 - '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 - '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 - '5672:5672'\n - '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 - '1025:1025'\n - '8025:8025'\n environment:\n MP_SMTP_AUTH_ACCEPT_ANY: 1\n MP_SMTP_AUTH_ALLOW_INSECURE: 1`);\n\t}\n\n\t// Build docker-compose.yml\n\tlet dockerCompose = `services:\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(apps: DatabaseAppConfig[]): 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\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 environment variables for passwords (more secure than hardcoded values)\n * - api user: uses public schema\n * - auth user: uses auth schema with search_path=auth\n */\nfunction generatePostgresInitScript(apps: DatabaseAppConfig[]): 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\t// API user uses public schema\n\t\t\treturn `\n# Create ${app.name} user (uses public schema)\necho \"Creating user ${userName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n CREATE USER ${userName} WITH PASSWORD '$${envVar}';\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\t// Other users get their own schema with search_path\n\t\treturn `\n# Create ${app.name} user with dedicated schema\necho \"Creating user ${userName} with schema ${schemaName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n CREATE USER ${userName} WITH PASSWORD '$${envVar}';\n CREATE SCHEMA ${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\treturn `#!/bin/bash\nset -e\n\n# Auto-generated PostgreSQL init script\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${userCreations.join('\\n')}\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';\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\tdeclaration: true,\n\t\t\tdeclarationMap: true,\n\t\t\toutDir: './dist',\n\t\t\trootDir: './src',\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.js';\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 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 envParser: './src/config/env#envParser',\n logger: './src/config/logger#logger',\n },\n web: {\n type: 'frontend',\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 client: {\n output: './src/api',\n },\n },\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 (services.db || services.cache || services.mail) {\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\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\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';\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.js';\nimport { logger } from './config/logger.js';\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';\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.js';\nimport { envParser } from './env.js';\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.js';\nimport { envParser } from './env.js';\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.js';\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.js';\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 * 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}\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}\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 * 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];\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\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}\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': {\n\t\t\t\ttypes: OPENAPI_OUTPUT_PATH,\n\t\t\t\timport: OPENAPI_OUTPUT_PATH,\n\t\t\t},\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 { 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\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';\nexport { Input } from './input';\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardDescription,\n CardContent,\n} from './card';\nexport { Label } from './label';\nexport { Badge, type BadgeProps, badgeVariants } from './badge';\nexport { Separator } from './separator';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';\nexport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n TooltipProvider,\n} from './tooltip';\nexport {\n Dialog,\n DialogPortal,\n DialogOverlay,\n DialogTrigger,\n DialogClose,\n DialogContent,\n DialogHeader,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n} from './dialog';\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';\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';\n\n// Utilities\nexport { cn } from './lib/utils';\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 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[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: ['${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\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[`${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: '../../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';\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';\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 - uses createApi with shared QueryClient\n\tconst apiIndexTs = `import { createApi } from './openapi';\nimport { getQueryClient } from '~/lib/query-client';\nimport { clientConfig } from '~/config/client';\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';\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';\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 { existsSync } from 'node:fs';\nimport { join } from 'node:path';\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","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 type { ComposeServiceName } 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 { generateModelsPackage } from './generators/models.js';\nimport { generateMonorepoFiles } from './generators/monorepo.js';\nimport { generatePackageJson } from './generators/package.js';\nimport { generateSourceFiles } from './generators/source.js';\nimport { generateUiPackageFiles } from './generators/ui.js';\nimport { generateWebAppFiles } from './generators/web.js';\nimport {\n\ttype DeployTarget,\n\tdeployTargetChoices,\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 * Generate a secure random password for database users\n */\nfunction generateDbPassword(): string {\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Generate database URL for an app\n * All apps connect to the same database, but use different users/schemas\n */\nfunction generateDbUrl(\n\tappName: string,\n\tpassword: string,\n\tprojectName: string,\n\thost = 'localhost',\n\tport = 5432,\n): string {\n\tconst userName = appName.replace(/-/g, '_');\n\tconst dbName = `${projectName.replace(/-/g, '_')}_dev`;\n\treturn `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;\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: '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],\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']\n\t\t: answers.services || [];\n\tconst services: ServicesSelection = {\n\t\tdb: servicesArray.includes('db'),\n\t\tcache: servicesArray.includes('cache'),\n\t\tmail: servicesArray.includes('mail'),\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 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};\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...(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 web app files for fullstack template\n\tconst webAppFiles = isFullstack ? generateWebAppFiles(templateOptions) : [];\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\n\tconst devSecrets = createStageSecrets('development', secretServices);\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\tconsole.log(` │ └── web/ # Next.js frontend`);\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 } from '../config';\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// Generate secrets\n\tconst secrets = createStageSecrets(stage, services);\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\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}\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\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 { readStageSecrets, toEmbeddableSecrets } from '../secrets/storage';\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}\n\n/**\n * Run tests with secrets loaded from the specified stage.\n * Secrets are decrypted and injected into the environment.\n */\nexport async function testCommand(options: TestOptions = {}): Promise<void> {\n\tconst stage = options.stage ?? 'development';\n\n\tconsole.log(`\\n🧪 Running tests with ${stage} secrets...\\n`);\n\n\t// Load and decrypt secrets\n\tlet envVars: Record<string, string> = {};\n\ttry {\n\t\tconst secrets = await readStageSecrets(stage);\n\t\tif (secrets) {\n\t\t\tenvVars = toEmbeddableSecrets(secrets);\n\t\t\tconsole.log(\n\t\t\t\t` Loaded ${Object.keys(envVars).length} secrets from ${stage}\\n`,\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.log(` No secrets found for ${stage}, running without secrets\\n`);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('key not found')) {\n\t\t\tconsole.log(\n\t\t\t\t` Decryption key not found for ${stage}, running without secrets\\n`,\n\t\t\t);\n\t\t} else {\n\t\t\tthrow error;\n\t\t}\n\t}\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 secrets in environment\n\tconst vitestProcess = spawn('npx', ['vitest', ...args], {\n\t\tcwd: process.cwd(),\n\t\tstdio: 'inherit',\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...envVars,\n\t\t\t// Ensure NODE_ENV is set to test\n\t\t\tNODE_ENV: 'test',\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","#!/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 { 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 TestOptions, testCommand } from './test/index';\nimport type { ComposeServiceName, LegacyProvider, MainProvider } from './types';\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\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(error instanceof Error ? error.message : 'Command failed');\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.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}) => {\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});\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});\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});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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.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(error instanceof Error ? error.message : 'Command failed');\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.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\t\t\tawait openapiCommand({});\n\t\t} catch (error) {\n\t\t\tconsole.error(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Deploy failed');\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(\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: 'Failed to initialize deployment',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Failed to list resources',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Failed to login',\n\t\t\t\t);\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(\n\t\t\t\terror instanceof Error ? error.message : 'Failed to logout',\n\t\t\t);\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(\n\t\t\t\terror instanceof Error ? error.message : 'Failed to get status',\n\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram.parse();\n"],"mappings":"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"}
1
+ {"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<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","logger","workspace: NormalizedWorkspace","backendAppName: string","dependentApps: string[]","content: string","options: { silent?: boolean }","results: ClientCopyResult[]","result: ClientCopyResult","allResults: ClientCopyResult[]","logger","envConfig: string | string[] | undefined","cwd: string","loaded: string[]","missing: string[]","port: number","resolve","err: NodeJS.ErrnoException","preferredPort: number","composePath: string","results: ComposePortMapping[]","workspaceRoot: string","ports: PortState","service: string","containerPort: number","dockerEnv: Record<string, string>","url: string","oldPort: number","newPort: number","secrets: Record<string, string>","resolvedPorts: ResolvedServicePorts","portReplacements: { defaultPort: number; resolvedPort: number }[]","config: GkmConfig['telescope']","isEnabled","telescopeConfig: TelescopeConfig","config: GkmConfig['studio']","studioConfig: StudioConfig","config: GkmConfig['hooks']","cliProduction: boolean","configProduction?: ProductionConfig","config: GkmConfig","options: DevOptions","appRoot: string","secretsRoot: string","workspaceAppName: string | undefined","workspaceAppPort: number | 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 }[]","appName: string","appPath: string","errors: string[]","warnings: string[]","pkg","results: FrontendValidationResult[]","appName?: string","portEnv?: Record<string, string>","servicesToStart: string[]","turboFilter: string[]","turboEnv: Record<string, string>","openApiWatcher: ReturnType<typeof chokidar.watch> | null","openApiPaths: { path: string; appName: string }[]","copyTimeout: NodeJS.Timeout | null","changedPath: string","config: any","context: BuildContext","provider: LegacyProvider","enableOpenApi: boolean","EndpointGenerator","startDir: string","secretsJsonPath: string","preloadPath: string","wrapperPath: string","entryPath: string","secretsJsonPath?: string","options: {\n\texplicitPort?: number;\n\tcwd?: string;\n}","appName: string | undefined","watch: boolean","restartTimeout: NodeJS.Timeout | null","requestedPort: number","portExplicit: boolean","telescope: NormalizedTelescopeConfig | undefined","studio: NormalizedStudioConfig | undefined","commandArgs: string[]","options: ExecOptions","code: number | null","error: Error","logger","outputDir: string","routes: RouteInfo[]","functions: FunctionInfo[]","crons: CronInfo[]","subscribers: SubscriberInfo[]","appInfo: ServerAppInfo","logger","options: BuildOptions","buildContext: BuildContext","EndpointGenerator","result: BuildResult","provider: LegacyProvider","context: BuildContext","rootOutputDir: string","endpointGenerator: EndpointGenerator","functionGenerator: FunctionGenerator","cronGenerator: CronGenerator","subscriberGenerator: SubscriberGenerator","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>>[]","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","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[]","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'","config: boolean | { version?: string; image?: string } | undefined","defaults: Record<'postgres' | 'redis', string>","appName: string","app: NormalizedAppConfig","allApps: [string, NormalizedAppConfig][]","options: {\n\t\tregistry?: string;\n\t\thasPostgres: boolean;\n\t\thasRedis: boolean;\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>","appName: string","app: NormalizedAppConfig","stage: string","dokployConfig: DokployWorkspaceConfig | undefined","isMainFrontend: boolean","allApps: Record<string, NormalizedAppConfig>","name","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","depName: string","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[]","configPaths: string[]","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","SERVICE_DEFAULTS: Record<\n\tComposeServiceName,\n\tOmit<ServiceCredentials, 'password'>\n>","service: ComposeServiceName","services: ComposeServiceName[]","result: StageSecrets['services']","creds: ServiceCredentials","services: StageSecrets['services']","urls: StageSecrets['urls']","stage: string","secrets: StageSecrets","newCreds: ServiceCredentials","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[]","options: TemplateOptions","_template: TemplateConfig","files: GeneratedFile[]","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","cwd: string","name: string","name","pkgManager: PackageManager","script: string","appName: string","password: string","projectName: string","projectName?: string","options: InitOptions","value: string","name","template: TemplateName","servicesArray: string[]","services: ServicesSelection","pkgManager: PackageManager","deployTarget: DeployTarget","templateOptions: TemplateOptions","isMonorepo","dbApps: DatabaseAppConfig[]","secretServices: ComposeServiceName[]","customSecrets: Record<string, string>","options: TemplateOptions","devCommand","services: ComposeServicesConfig | ComposeServiceName[] | undefined","name","options: SecretsInitOptions","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","secretsEnv: Record<string, string>","dependencyEnv: Record<string, string>","filteredEnv: Record<string, string>","args: string[]","resolve","env: Record<string, string>","pg","err: unknown","Command","pkg","name: string | undefined","options: InitOptions","name","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}","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: { 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 }"],"sources":["../package.json","../src/auth/index.ts","../src/build/providerResolver.ts","../src/generators/CronGenerator.ts","../src/generators/FunctionGenerator.ts","../src/generators/SubscriberGenerator.ts","../src/workspace/client-generator.ts","../src/dev/index.ts","../src/build/manifests.ts","../src/build/index.ts","../src/deploy/state.ts","../src/deploy/dns/DnsProvider.ts","../src/deploy/dns/index.ts","../src/docker/compose.ts","../src/docker/templates.ts","../src/docker/index.ts","../src/deploy/docker.ts","../src/deploy/dokploy.ts","../src/deploy/domain.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/secrets/generator.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/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/utils.ts","../src/init/index.ts","../src/secrets/index.ts","../src/test/index.ts","../src/index.ts"],"sourcesContent":["{\n\t\"name\": \"@geekmidas/cli\",\n\t\"version\": \"1.5.1\",\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\"types\": \"./dist/index.d.ts\",\n\t\t\t\"import\": \"./dist/index.mjs\",\n\t\t\t\"require\": \"./dist/index.cjs\"\n\t\t},\n\t\t\"./config\": {\n\t\t\t\"types\": \"./dist/config.d.ts\",\n\t\t\t\"import\": \"./dist/config.mjs\",\n\t\t\t\"require\": \"./dist/config.cjs\"\n\t\t},\n\t\t\"./workspace\": {\n\t\t\t\"types\": \"./dist/workspace/index.d.ts\",\n\t\t\t\"import\": \"./dist/workspace/index.mjs\",\n\t\t\t\"require\": \"./dist/workspace/index.cjs\"\n\t\t},\n\t\t\"./openapi\": {\n\t\t\t\"types\": \"./dist/openapi.d.ts\",\n\t\t\t\"import\": \"./dist/openapi.mjs\",\n\t\t\t\"require\": \"./dist/openapi.cjs\"\n\t\t},\n\t\t\"./openapi-react-query\": {\n\t\t\t\"types\": \"./dist/openapi-react-query.d.ts\",\n\t\t\t\"import\": \"./dist/openapi-react-query.mjs\",\n\t\t\t\"require\": \"./dist/openapi-react-query.cjs\"\n\t\t}\n\t},\n\t\"bin\": {\n\t\t\"gkm\": \"./dist/index.cjs\"\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.971.0\",\n\t\t\"@aws-sdk/client-route-53\": \"~3.971.0\",\n\t\t\"@aws-sdk/client-s3\": \"~3.971.0\",\n\t\t\"@aws-sdk/client-ssm\": \"~3.971.0\",\n\t\t\"@aws-sdk/credential-providers\": \"~3.971.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/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});\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});\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 { 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\ttimeout: construct.timeout,\n\t\t\t\tmemorySize: construct.memorySize,\n\t\t\t\tenvironment: await construct.getEnvironment(),\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 * - 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 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().optional(),\n })).parse();\n\n if (!config.connectionString) {\n logger.warn('EVENT_SUBSCRIBER_CONNECTION_STRING not configured, skipping subscriber setup');\n return;\n }\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 { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative } from 'node:path';\nimport type { NormalizedWorkspace } from './types.js';\n\nconst logger = console;\n\n/**\n * Result of copying a client to a frontend app.\n */\nexport interface ClientCopyResult {\n\tfrontendApp: string;\n\tbackendApp: string;\n\toutputPath: string;\n\tendpointCount: number;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Normalize routes to an array of patterns.\n * @internal Exported for use in dev command\n */\nexport function normalizeRoutes(\n\troutes: string | string[] | undefined,\n): string[] {\n\tif (!routes) return [];\n\treturn Array.isArray(routes) ? routes : [routes];\n}\n\n/**\n * Get the first routes pattern as a string (for simple cases).\n * @internal Exported for use in dev command\n */\nexport function getFirstRoute(\n\troutes: string | string[] | undefined,\n): string | null {\n\tconst normalized = normalizeRoutes(routes);\n\treturn normalized[0] || null;\n}\n\n/**\n * Check if a file path matches endpoint patterns that could affect OpenAPI schema.\n * Returns true for changes that should trigger client regeneration.\n */\nexport function shouldRegenerateClient(\n\tfilePath: string,\n\troutesPattern: string,\n): boolean {\n\t// Normalize path separators\n\tconst normalizedPath = filePath.replace(/\\\\/g, '/');\n\tconst normalizedPattern = routesPattern.replace(/\\\\/g, '/');\n\n\t// Check if the file matches the routes pattern\n\t// This is a simple check - the file should be within the routes directory\n\tconst patternDir = normalizedPattern.split('*')[0] || '';\n\n\tif (!normalizedPath.includes(patternDir.replace('./', ''))) {\n\t\treturn false;\n\t}\n\n\t// Check file extension - only TypeScript endpoint files\n\tif (!normalizedPath.endsWith('.ts') && !normalizedPath.endsWith('.tsx')) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Get backend apps that a frontend depends on.\n */\nexport function getBackendDependencies(\n\tworkspace: NormalizedWorkspace,\n\tfrontendAppName: string,\n): string[] {\n\tconst frontendApp = workspace.apps[frontendAppName];\n\tif (!frontendApp || frontendApp.type !== 'frontend') {\n\t\treturn [];\n\t}\n\n\treturn frontendApp.dependencies.filter((dep) => {\n\t\tconst depApp = workspace.apps[dep];\n\t\treturn depApp?.type === 'backend' && depApp.routes;\n\t});\n}\n\n/**\n * Get frontend apps that depend on a backend app.\n */\nexport function getDependentFrontends(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n): string[] {\n\tconst dependentApps: string[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'frontend' && app.dependencies.includes(backendAppName)) {\n\t\t\tdependentApps.push(appName);\n\t\t}\n\t}\n\n\treturn dependentApps;\n}\n\n/**\n * Get the path to a backend's OpenAPI spec file.\n */\nexport function getBackendOpenApiPath(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n): string | null {\n\tconst app = workspace.apps[backendAppName];\n\tif (!app || app.type !== 'backend') {\n\t\treturn null;\n\t}\n\n\treturn join(workspace.root, app.path, '.gkm', 'openapi.ts');\n}\n\n/**\n * Count endpoints in an OpenAPI spec content.\n */\nfunction countEndpoints(content: string): number {\n\tconst endpointMatches = content.match(\n\t\t/'(GET|POST|PUT|PATCH|DELETE)\\s+\\/[^']+'/g,\n\t);\n\treturn endpointMatches?.length ?? 0;\n}\n\n/**\n * Copy the OpenAPI client from a backend to all dependent frontend apps.\n * Called when the backend's .gkm/openapi.ts file changes.\n */\nexport async function copyClientToFrontends(\n\tworkspace: NormalizedWorkspace,\n\tbackendAppName: string,\n\toptions: { silent?: boolean } = {},\n): Promise<ClientCopyResult[]> {\n\tconst log = options.silent ? () => {} : logger.log.bind(logger);\n\tconst results: ClientCopyResult[] = [];\n\n\tconst backendApp = workspace.apps[backendAppName];\n\tif (!backendApp || backendApp.type !== 'backend') {\n\t\treturn results;\n\t}\n\n\t// Get the backend's OpenAPI spec\n\tconst openApiPath = join(\n\t\tworkspace.root,\n\t\tbackendApp.path,\n\t\t'.gkm',\n\t\t'openapi.ts',\n\t);\n\n\tif (!existsSync(openApiPath)) {\n\t\treturn results;\n\t}\n\n\tconst content = await readFile(openApiPath, 'utf-8');\n\tconst endpointCount = countEndpoints(content);\n\n\t// Get all frontends that depend on this backend\n\tconst dependentFrontends = getDependentFrontends(workspace, backendAppName);\n\n\tfor (const frontendAppName of dependentFrontends) {\n\t\tconst frontendApp = workspace.apps[frontendAppName];\n\t\tif (!frontendApp || frontendApp.type !== 'frontend') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if frontend has client output configured\n\t\tconst clientOutput = frontendApp.client?.output;\n\t\tif (!clientOutput) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst result: ClientCopyResult = {\n\t\t\tfrontendApp: frontendAppName,\n\t\t\tbackendApp: backendAppName,\n\t\t\toutputPath: '',\n\t\t\tendpointCount,\n\t\t\tsuccess: false,\n\t\t};\n\n\t\ttry {\n\t\t\tconst frontendPath = join(workspace.root, frontendApp.path);\n\t\t\tconst outputDir = join(frontendPath, clientOutput);\n\t\t\tawait mkdir(outputDir, { recursive: true });\n\n\t\t\t// Use backend app name as filename\n\t\t\tconst fileName = `${backendAppName}.ts`;\n\t\t\tconst outputPath = join(outputDir, fileName);\n\n\t\t\t// Add header comment with backend reference\n\t\t\tconst backendRelPath = relative(\n\t\t\t\tdirname(outputPath),\n\t\t\t\tjoin(workspace.root, backendApp.path),\n\t\t\t);\n\n\t\t\tconst clientContent = `/**\n * Auto-generated API client for ${backendAppName}\n * Generated from: ${backendRelPath}\n *\n * DO NOT EDIT - This file is automatically regenerated when backend schemas change.\n */\n\n${content}\n`;\n\n\t\t\tawait writeFile(outputPath, clientContent);\n\n\t\t\tresult.outputPath = outputPath;\n\t\t\tresult.success = true;\n\n\t\t\tlog(\n\t\t\t\t`📦 Copied client to ${frontendAppName} from ${backendAppName} (${endpointCount} endpoints)`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tresult.error = (error as Error).message;\n\t\t}\n\n\t\tresults.push(result);\n\t}\n\n\treturn results;\n}\n\n/**\n * Copy clients from all backends to their dependent frontends.\n * Useful for initial setup or force refresh.\n */\nexport async function copyAllClients(\n\tworkspace: NormalizedWorkspace,\n\toptions: { silent?: boolean } = {},\n): Promise<ClientCopyResult[]> {\n\tconst allResults: ClientCopyResult[] = [];\n\n\tfor (const [appName, app] of Object.entries(workspace.apps)) {\n\t\tif (app.type === 'backend' && app.routes) {\n\t\t\tconst results = await copyClientToFrontends(workspace, appName, options);\n\t\t\tallResults.push(...results);\n\t\t}\n\t}\n\n\treturn allResults;\n}\n","import { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { dirname, join, resolve } from 'node:path';\nimport chokidar from 'chokidar';\nimport { config as dotenvConfig } from 'dotenv';\nimport fg from 'fast-glob';\nimport { parse as parseYaml } from 'yaml';\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\tloadWorkspaceAppInfo,\n\tloadWorkspaceConfig,\n\tparseModuleConfig,\n} from '../config';\nimport {\n\tCronGenerator,\n\tEndpointGenerator,\n\tFunctionGenerator,\n\tSubscriberGenerator,\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\tcopyAllClients,\n\tcopyClientToFrontends,\n\tgetBackendOpenApiPath,\n} from '../workspace/client-generator.js';\nimport {\n\tgetAppBuildOrder,\n\tgetDependencyEnvVars,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\n\nconst logger = console;\n\n/**\n * Load environment files\n * @internal Exported for testing\n */\nexport function loadEnvFiles(\n\tenvConfig: string | string[] | undefined,\n\tcwd: string = process.cwd(),\n): { loaded: string[]; missing: string[] } {\n\tconst loaded: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Normalize to array\n\tconst envFiles = envConfig\n\t\t? Array.isArray(envConfig)\n\t\t\t? envConfig\n\t\t\t: [envConfig]\n\t\t: ['.env'];\n\n\t// Load each env file in order (later files override earlier)\n\tfor (const envFile of envFiles) {\n\t\tconst envPath = resolve(cwd, envFile);\n\t\tif (existsSync(envPath)) {\n\t\t\tdotenvConfig({ path: envPath, override: true, quiet: true });\n\t\t\tloaded.push(envFile);\n\t\t} else if (envConfig) {\n\t\t\t// Only report as missing if explicitly configured\n\t\t\tmissing.push(envFile);\n\t\t}\n\t}\n\n\treturn { loaded, missing };\n}\n\n/**\n * Check if a port is available\n * @internal Exported for testing\n */\nexport async function isPortAvailable(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst server = createServer();\n\n\t\tserver.once('error', (err: NodeJS.ErrnoException) => {\n\t\t\tif (err.code === 'EADDRINUSE') {\n\t\t\t\tresolve(false);\n\t\t\t} else {\n\t\t\t\tresolve(false);\n\t\t\t}\n\t\t});\n\n\t\tserver.once('listening', () => {\n\t\t\tserver.close();\n\t\t\tresolve(true);\n\t\t});\n\n\t\tserver.listen(port);\n\t});\n}\n\n/**\n * Find an available port starting from the preferred port\n * @internal Exported for testing\n */\nexport async function findAvailablePort(\n\tpreferredPort: number,\n\tmaxAttempts = 10,\n): Promise<number> {\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tconst port = preferredPort + i;\n\t\tif (await isPortAvailable(port)) {\n\t\t\treturn port;\n\t\t}\n\t\tlogger.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);\n\t}\n\n\tthrow new Error(\n\t\t`Could not find an available port after trying ${maxAttempts} ports starting from ${preferredPort}`,\n\t);\n}\n\n/**\n * A port mapping extracted from docker-compose.yml.\n * Only entries using env var interpolation (e.g., `${VAR:-default}:container`) are captured.\n */\nexport interface ComposePortMapping {\n\tservice: string;\n\tenvVar: string;\n\tdefaultPort: number;\n\tcontainerPort: number;\n}\n\n/** Port state persisted to .gkm/ports.json, keyed by env var name. */\nexport type PortState = Record<string, number>;\n\nexport interface ResolvedServicePorts {\n\tdockerEnv: Record<string, string>;\n\tports: PortState;\n\tmappings: ComposePortMapping[];\n}\n\nconst PORT_STATE_PATH = '.gkm/ports.json';\n\n/**\n * Parse docker-compose.yml and extract all port mappings that use env var interpolation.\n * Entries like `'${POSTGRES_HOST_PORT:-5432}:5432'` are captured.\n * Fixed port mappings like `'5050:80'` are skipped.\n * @internal Exported for testing\n */\nexport function parseComposePortMappings(\n\tcomposePath: string,\n): ComposePortMapping[] {\n\tif (!existsSync(composePath)) {\n\t\treturn [];\n\t}\n\n\tconst content = readFileSync(composePath, 'utf-8');\n\tconst compose = parseYaml(content) as {\n\t\tservices?: Record<string, { ports?: string[] }>;\n\t};\n\n\tif (!compose?.services) {\n\t\treturn [];\n\t}\n\n\tconst results: ComposePortMapping[] = [];\n\n\tfor (const [serviceName, serviceConfig] of Object.entries(compose.services)) {\n\t\tfor (const portMapping of serviceConfig?.ports ?? []) {\n\t\t\tconst match = String(portMapping).match(/\\$\\{(\\w+):-(\\d+)\\}:(\\d+)/);\n\t\t\tif (match?.[1] && match[2] && match[3]) {\n\t\t\t\tresults.push({\n\t\t\t\t\tservice: serviceName,\n\t\t\t\t\tenvVar: match[1],\n\t\t\t\t\tdefaultPort: Number(match[2]),\n\t\t\t\t\tcontainerPort: Number(match[3]),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Load saved port state from .gkm/ports.json.\n * @internal Exported for testing\n */\nexport async function loadPortState(workspaceRoot: string): Promise<PortState> {\n\ttry {\n\t\tconst raw = await readFile(join(workspaceRoot, PORT_STATE_PATH), 'utf-8');\n\t\treturn JSON.parse(raw) as PortState;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n/**\n * Save port state to .gkm/ports.json.\n * @internal Exported for testing\n */\nexport async function savePortState(\n\tworkspaceRoot: string,\n\tports: PortState,\n): Promise<void> {\n\tconst dir = join(workspaceRoot, '.gkm');\n\tawait mkdir(dir, { recursive: true });\n\tawait writeFile(\n\t\tjoin(workspaceRoot, PORT_STATE_PATH),\n\t\t`${JSON.stringify(ports, null, 2)}\\n`,\n\t);\n}\n\n/**\n * Check if a project's own Docker container is running and return its host port.\n * Uses `docker compose port` scoped to the project's compose file.\n * @internal Exported for testing\n */\nexport function getContainerHostPort(\n\tworkspaceRoot: string,\n\tservice: string,\n\tcontainerPort: number,\n): number | null {\n\ttry {\n\t\tconst result = execSync(`docker compose port ${service} ${containerPort}`, {\n\t\t\tcwd: workspaceRoot,\n\t\t\tstdio: 'pipe',\n\t\t})\n\t\t\t.toString()\n\t\t\t.trim();\n\t\tconst match = result.match(/:(\\d+)$/);\n\t\treturn match ? Number(match[1]) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Resolve host ports for Docker services by parsing docker-compose.yml.\n * Priority: running container → saved state → find available port.\n * Persists resolved ports to .gkm/ports.json.\n * @internal Exported for testing\n */\nexport async function resolveServicePorts(\n\tworkspaceRoot: string,\n): Promise<ResolvedServicePorts> {\n\tconst composePath = join(workspaceRoot, 'docker-compose.yml');\n\tconst mappings = parseComposePortMappings(composePath);\n\n\tif (mappings.length === 0) {\n\t\treturn { dockerEnv: {}, ports: {}, mappings: [] };\n\t}\n\n\tconst savedState = await loadPortState(workspaceRoot);\n\tconst dockerEnv: Record<string, string> = {};\n\tconst ports: PortState = {};\n\n\tlogger.log('\\n🔌 Resolving service ports...');\n\n\tfor (const mapping of mappings) {\n\t\t// 1. Check if own container is already running\n\t\tconst containerPort = getContainerHostPort(\n\t\t\tworkspaceRoot,\n\t\t\tmapping.service,\n\t\t\tmapping.containerPort,\n\t\t);\n\t\tif (containerPort !== null) {\n\t\t\tports[mapping.envVar] = containerPort;\n\t\t\tdockerEnv[mapping.envVar] = String(containerPort);\n\t\t\tlogger.log(\n\t\t\t\t` 🔄 ${mapping.service}:${mapping.containerPort}: reusing existing container on port ${containerPort}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// 2. Check saved port state\n\t\tconst savedPort = savedState[mapping.envVar];\n\t\tif (savedPort && (await isPortAvailable(savedPort))) {\n\t\t\tports[mapping.envVar] = savedPort;\n\t\t\tdockerEnv[mapping.envVar] = String(savedPort);\n\t\t\tlogger.log(\n\t\t\t\t` 💾 ${mapping.service}:${mapping.containerPort}: using saved port ${savedPort}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// 3. Find available port\n\t\tconst resolvedPort = await findAvailablePort(mapping.defaultPort);\n\t\tports[mapping.envVar] = resolvedPort;\n\t\tdockerEnv[mapping.envVar] = String(resolvedPort);\n\n\t\tif (resolvedPort !== mapping.defaultPort) {\n\t\t\tlogger.log(\n\t\t\t\t` ⚡ ${mapping.service}:${mapping.containerPort}: port ${mapping.defaultPort} occupied, using port ${resolvedPort}`,\n\t\t\t);\n\t\t} else {\n\t\t\tlogger.log(\n\t\t\t\t` ✅ ${mapping.service}:${mapping.containerPort}: using default port ${resolvedPort}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tawait savePortState(workspaceRoot, ports);\n\n\treturn { dockerEnv, ports, mappings };\n}\n\n/**\n * Replace a port in a URL string.\n * Handles both `hostname:port` and `localhost:port` patterns.\n * @internal Exported for testing\n */\nexport function replacePortInUrl(\n\turl: string,\n\toldPort: number,\n\tnewPort: number,\n): string {\n\tif (oldPort === newPort) return url;\n\treturn url.replace(new RegExp(`:${oldPort}(?=/|$)`, 'g'), `:${newPort}`);\n}\n\n/**\n * Rewrite connection URLs and port vars in secrets with resolved ports.\n * Uses the parsed compose mappings to determine which default ports to replace.\n * Pure transform — does not modify secrets on disk.\n * @internal Exported for testing\n */\nexport function rewriteUrlsWithPorts(\n\tsecrets: Record<string, string>,\n\tresolvedPorts: ResolvedServicePorts,\n): Record<string, string> {\n\tconst { ports, mappings } = resolvedPorts;\n\tconst result = { ...secrets };\n\n\t// Build a map of defaultPort → resolvedPort for all changed ports\n\tconst portReplacements: { defaultPort: number; resolvedPort: number }[] = [];\n\tfor (const mapping of mappings) {\n\t\tconst resolved = ports[mapping.envVar];\n\t\tif (resolved !== undefined) {\n\t\t\tportReplacements.push({\n\t\t\t\tdefaultPort: mapping.defaultPort,\n\t\t\t\tresolvedPort: resolved,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Rewrite _PORT env vars whose values match a default port\n\tfor (const [key, value] of Object.entries(result)) {\n\t\tif (!key.endsWith('_PORT')) continue;\n\t\tfor (const { defaultPort, resolvedPort } of portReplacements) {\n\t\t\tif (value === String(defaultPort)) {\n\t\t\t\tresult[key] = String(resolvedPort);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Rewrite URLs containing default ports\n\tfor (const [key, value] of Object.entries(result)) {\n\t\tif (!key.endsWith('_URL') && key !== 'DATABASE_URL') continue;\n\n\t\tlet rewritten = value;\n\t\tfor (const { defaultPort, resolvedPort } of portReplacements) {\n\t\t\trewritten = replacePortInUrl(rewritten, defaultPort, resolvedPort);\n\t\t}\n\t\tresult[key] = rewritten;\n\t}\n\n\treturn result;\n}\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\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\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 and write to JSON file\n\tlet secretsJsonPath: string | undefined;\n\tconst appSecrets = await loadSecretsForApp(secretsRoot, workspaceAppName);\n\tif (Object.keys(appSecrets).length > 0) {\n\t\tconst secretsDir = join(secretsRoot, '.gkm');\n\t\tawait mkdir(secretsDir, { recursive: true });\n\t\tsecretsJsonPath = join(secretsDir, 'dev-secrets.json');\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\tlogger.error('❌ Rebuild failed:', (error as Error).message);\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 * Next.js config file patterns to check.\n */\nconst NEXTJS_CONFIG_FILES = [\n\t'next.config.js',\n\t'next.config.ts',\n\t'next.config.mjs',\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 (Next.js) app configuration.\n * Checks for Next.js config file and dependency.\n * @internal Exported for testing\n */\nexport async function validateFrontendApp(\n\tappName: string,\n\tappPath: string,\n\tworkspaceRoot: string,\n): Promise<FrontendValidationResult> {\n\tconst errors: string[] = [];\n\tconst warnings: string[] = [];\n\tconst fullPath = join(workspaceRoot, appPath);\n\n\t// Check for Next.js config file\n\tconst hasConfigFile = NEXTJS_CONFIG_FILES.some((file) =>\n\t\texistsSync(join(fullPath, file)),\n\t);\n\n\tif (!hasConfigFile) {\n\t\terrors.push(\n\t\t\t`Next.js config file not found. Expected one of: ${NEXTJS_CONFIG_FILES.join(', ')}`,\n\t\t);\n\t}\n\n\t// Check for package.json\n\tconst packageJsonPath = join(fullPath, 'package.json');\n\tif (existsSync(packageJsonPath)) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\t\tconst pkg = require(packageJsonPath);\n\t\t\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n\t\t\tif (!deps.next) {\n\t\t\t\terrors.push(\n\t\t\t\t\t'Next.js not found in dependencies. Run: pnpm add next react react-dom',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Check for dev script\n\t\t\tif (!pkg.scripts?.dev) {\n\t\t\t\twarnings.push(\n\t\t\t\t\t'No \"dev\" script found in package.json. Turbo expects a \"dev\" script to run.',\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {\n\t\t\terrors.push(`Failed to read package.json at ${packageJsonPath}`);\n\t\t}\n\t} else {\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}\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 === 'frontend') {\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);\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 secrets:init --stage dev\"',\n\t);\n\treturn {};\n}\n\n/**\n * Load secrets from a path for dev mode.\n * For single app: returns secrets as-is.\n * For workspace app: maps {APP}_DATABASE_URL → DATABASE_URL.\n * @internal Exported for testing\n */\nexport async function loadSecretsForApp(\n\tsecretsRoot: string,\n\tappName?: string,\n): Promise<Record<string, string>> {\n\t// Try 'dev' stage first, then 'development'\n\tconst stages = ['dev', 'development'];\n\n\tlet secrets: Record<string, string> = {};\n\n\tfor (const stage of stages) {\n\t\tif (secretsExist(stage, secretsRoot)) {\n\t\t\tconst stageSecrets = await readStageSecrets(stage, secretsRoot);\n\t\t\tif (stageSecrets) {\n\t\t\t\tlogger.log(`🔐 Loading secrets from stage: ${stage}`);\n\t\t\t\tsecrets = toEmbeddableSecrets(stageSecrets);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (Object.keys(secrets).length === 0) {\n\t\treturn {};\n\t}\n\n\t// Single app mode - no mapping needed\n\tif (!appName) {\n\t\treturn secrets;\n\t}\n\n\t// Workspace app mode - map {APP}_* to generic names\n\tconst prefix = appName.toUpperCase();\n\tconst mapped = { ...secrets };\n\n\t// Map {APP}_DATABASE_URL → DATABASE_URL\n\tconst appDbUrl = secrets[`${prefix}_DATABASE_URL`];\n\tif (appDbUrl) {\n\t\tmapped.DATABASE_URL = appDbUrl;\n\t}\n\n\treturn mapped;\n}\n\n/**\n * Start docker-compose services for the workspace.\n * @internal Exported for testing\n */\nexport async function startWorkspaceServices(\n\tworkspace: NormalizedWorkspace,\n\tportEnv?: Record<string, string>,\n): Promise<void> {\n\tconst services = workspace.services;\n\tif (!services.db && !services.cache && !services.mail) {\n\t\treturn;\n\t}\n\n\tconst servicesToStart: string[] = [];\n\n\tif (services.db) {\n\t\tservicesToStart.push('postgres');\n\t}\n\tif (services.cache) {\n\t\tservicesToStart.push('redis');\n\t}\n\tif (services.mail) {\n\t\tservicesToStart.push('mailpit');\n\t}\n\n\tif (servicesToStart.length === 0) {\n\t\treturn;\n\t}\n\n\tlogger.log(`🐳 Starting services: ${servicesToStart.join(', ')}`);\n\n\ttry {\n\t\t// Check if docker-compose.yml exists\n\t\tconst composeFile = join(workspace.root, 'docker-compose.yml');\n\t\tif (!existsSync(composeFile)) {\n\t\t\tlogger.warn(\n\t\t\t\t'⚠️ No docker-compose.yml found. Services will not be started.',\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Start services with docker-compose\n\t\texecSync(`docker compose up -d ${servicesToStart.join(' ')}`, {\n\t\t\tcwd: workspace.root,\n\t\t\tstdio: 'inherit',\n\t\t\tenv: { ...process.env, ...portEnv },\n\t\t});\n\n\t\tlogger.log('✅ Services started');\n\t} catch (error) {\n\t\tlogger.error('❌ Failed to start services:', (error as Error).message);\n\t\tthrow error;\n\t}\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 === 'frontend',\n\t);\n\n\tlogger.log(`\\n🚀 Starting workspace: ${workspace.name}`);\n\tlogger.log(\n\t\t` ${backendApps.length} backend app(s), ${frontendApps.length} frontend app(s)`,\n\t);\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// Copy initial clients from backends to frontends\n\tif (frontendApps.length > 0 && backendApps.length > 0) {\n\t\tconst clientResults = await copyAllClients(workspace);\n\t\tconst copiedCount = clientResults.filter((r) => r.success).length;\n\t\tif (copiedCount > 0) {\n\t\t\tlogger.log(`\\n📦 Copied ${copiedCount} API client(s)`);\n\t\t}\n\t}\n\n\t// Resolve dynamic service ports from docker-compose.yml\n\tconst resolvedPorts = await resolveServicePorts(workspace.root);\n\n\t// Start docker-compose services with resolved ports\n\tawait startWorkspaceServices(workspace, resolvedPorts.dockerEnv);\n\n\t// Load secrets if enabled, then rewrite URLs with resolved ports\n\tconst secretsEnv = rewriteUrlsWithPorts(\n\t\tawait loadDevSecrets(workspace),\n\t\tresolvedPorts,\n\t);\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\tlogger.log(\n\t\t\t` ${app.type === 'backend' ? '🔧' : '🌐'} ${appName} → http://localhost:${app.port}${deps}`,\n\t\t);\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});\n\n\t// Set up file watcher for backend .gkm/openapi.ts changes (auto-copy to frontends)\n\tlet openApiWatcher: ReturnType<typeof chokidar.watch> | null = null;\n\n\tif (frontendApps.length > 0 && backendApps.length > 0) {\n\t\t// Collect all backend openapi.ts file paths to watch\n\t\tconst openApiPaths: { path: string; appName: string }[] = [];\n\n\t\tfor (const [appName] of backendApps) {\n\t\t\tconst openApiPath = getBackendOpenApiPath(workspace, appName);\n\t\t\tif (openApiPath) {\n\t\t\t\topenApiPaths.push({ path: openApiPath, appName });\n\t\t\t}\n\t\t}\n\n\t\tif (openApiPaths.length > 0) {\n\t\t\tlogger.log(\n\t\t\t\t`\\n👀 Watching ${openApiPaths.length} backend OpenAPI spec(s) for changes`,\n\t\t\t);\n\n\t\t\t// Create a map for quick lookup of app name from path\n\t\t\tconst pathToApp = new Map(openApiPaths.map((p) => [p.path, p.appName]));\n\n\t\t\topenApiWatcher = chokidar.watch(\n\t\t\t\topenApiPaths.map((p) => p.path),\n\t\t\t\t{\n\t\t\t\t\tpersistent: true,\n\t\t\t\t\tignoreInitial: true,\n\t\t\t\t\t// Watch parent directory too since file may not exist yet\n\t\t\t\t\tdepth: 0,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tlet copyTimeout: NodeJS.Timeout | null = null;\n\n\t\t\tconst handleChange = async (changedPath: string) => {\n\t\t\t\t// Debounce to handle rapid changes\n\t\t\t\tif (copyTimeout) {\n\t\t\t\t\tclearTimeout(copyTimeout);\n\t\t\t\t}\n\n\t\t\t\tcopyTimeout = setTimeout(async () => {\n\t\t\t\t\tconst backendAppName = pathToApp.get(changedPath);\n\t\t\t\t\tif (!backendAppName) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlogger.log(`\\n🔄 OpenAPI spec changed for ${backendAppName}`);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst results = await copyClientToFrontends(\n\t\t\t\t\t\t\tworkspace,\n\t\t\t\t\t\t\tbackendAppName,\n\t\t\t\t\t\t\t{ silent: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\t\tif (result.success) {\n\t\t\t\t\t\t\t\tlogger.log(\n\t\t\t\t\t\t\t\t\t` 📦 Copied client to ${result.frontendApp} (${result.endpointCount} endpoints)`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (result.error) {\n\t\t\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t\t\t` ❌ Failed to copy client to ${result.frontendApp}: ${result.error}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t` ❌ Failed to copy clients: ${(error as Error).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}, 200); // 200ms debounce\n\t\t\t};\n\n\t\t\topenApiWatcher.on('change', handleChange);\n\t\t\topenApiWatcher.on('add', handleChange);\n\t\t}\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 workspace...');\n\n\t\t// Close OpenAPI watcher\n\t\tif (openApiWatcher) {\n\t\t\topenApiWatcher.close().catch(() => {});\n\t\t}\n\n\t\t// Kill turbo process\n\t\tif (turboProcess.pid) {\n\t\t\ttry {\n\t\t\t\t// Try to kill the process group\n\t\t\t\tprocess.kill(-turboProcess.pid, 'SIGTERM');\n\t\t\t} catch {\n\t\t\t\t// Fall back to killing just the process\n\t\t\t\tturboProcess.kill('SIGTERM');\n\t\t\t}\n\t\t}\n\n\t\t// Give processes time to clean up\n\t\tsetTimeout(() => {\n\t\t\tprocess.exit(0);\n\t\t}, 2000);\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\t// Close watcher on exit\n\t\t\tif (openApiWatcher) {\n\t\t\t\topenApiWatcher.close().catch(() => {});\n\t\t\t}\n\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\n\t// Load all constructs (resolve paths relative to appRoot)\n\tconst [allEndpoints, allFunctions, allCrons, allSubscribers] =\n\t\tawait Promise.all([\n\t\t\tendpointGenerator.load(config.routes, appRoot, bustCache),\n\t\t\tconfig.functions\n\t\t\t\t? functionGenerator.load(config.functions, appRoot, bustCache)\n\t\t\t\t: [],\n\t\t\tconfig.crons ? cronGenerator.load(config.crons, appRoot, bustCache) : [],\n\t\t\tconfig.subscribers\n\t\t\t\t? subscriberGenerator.load(config.subscribers, appRoot, bustCache)\n\t\t\t\t: [],\n\t\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]);\n}\n\n/**\n * Find the directory containing .gkm/secrets/.\n * Walks up from cwd until it finds one, or returns cwd.\n * @internal Exported for testing\n */\nexport function findSecretsRoot(startDir: string): string {\n\tlet dir = startDir;\n\twhile (dir !== '/') {\n\t\tif (existsSync(join(dir, '.gkm', 'secrets'))) {\n\t\t\treturn dir;\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn startDir;\n}\n\n/**\n * Generate the credentials injection code snippet.\n * This is the common logic used by both entry wrapper and exec preload.\n * @internal\n */\nfunction generateCredentialsInjection(secretsJsonPath: string): string {\n\treturn `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets into Credentials and process.env\nconst secretsPath = '${secretsJsonPath}';\nif (existsSync(secretsPath)) {\n const secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));\n Object.assign(Credentials, secrets);\n Object.assign(process.env, secrets);\n // Debug: uncomment to verify preload is running\n // console.log('[gkm preload] Injected', Object.keys(secrets).length, 'credentials');\n}\n`;\n}\n\n/**\n * Create a preload script that injects secrets into Credentials.\n * Used by `gkm exec` to inject secrets before running any command.\n * @internal Exported for testing\n */\nexport async function createCredentialsPreload(\n\tpreloadPath: string,\n\tsecretsJsonPath: string,\n): Promise<void> {\n\tconst content = `/**\n * Credentials preload generated by 'gkm exec'\n * This file is loaded via NODE_OPTIONS=\"--import <path>\"\n */\n${generateCredentialsInjection(secretsJsonPath)}`;\n\n\tawait writeFile(preloadPath, content);\n}\n\n/**\n * Create a wrapper script that injects secrets before importing the entry file.\n * @internal Exported for testing\n */\nexport async function createEntryWrapper(\n\twrapperPath: string,\n\tentryPath: string,\n\tsecretsJsonPath?: string,\n): Promise<void> {\n\tconst credentialsInjection = secretsJsonPath\n\t\t? `${generateCredentialsInjection(secretsJsonPath)}\n`\n\t\t: '';\n\n\t// Use dynamic import() to ensure secrets are assigned before the entry file loads\n\t// Static imports are hoisted, so Object.assign would run after the entry file is loaded\n\tconst content = `#!/usr/bin/env node\n/**\n * Entry wrapper generated by 'gkm dev --entry'\n */\n${credentialsInjection}// Import and run the user's entry file (dynamic import ensures secrets load first)\nawait import('${entryPath}');\n`;\n\n\tawait writeFile(wrapperPath, content);\n}\n\n/**\n * Result of preparing entry credentials for dev mode.\n */\nexport interface EntryCredentialsResult {\n\t/** Credentials to inject (secrets + PORT) */\n\tcredentials: Record<string, string>;\n\t/** Resolved port (from --port, workspace config, or default 3000) */\n\tresolvedPort: number;\n\t/** Path where credentials JSON was written */\n\tsecretsJsonPath: string;\n\t/** Resolved app name (if in workspace) */\n\tappName: string | undefined;\n\t/** Secrets root directory */\n\tsecretsRoot: string;\n}\n\n/**\n * Prepare credentials for entry dev mode.\n * Loads workspace config, secrets, and injects PORT.\n * @internal Exported for testing\n */\nexport async function prepareEntryCredentials(options: {\n\texplicitPort?: number;\n\tcwd?: string;\n}): Promise<EntryCredentialsResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\n\t// Try to get workspace app config for port and secrets\n\tlet workspaceAppPort: number | undefined;\n\tlet secretsRoot: string = cwd;\n\tlet appName: string | undefined;\n\n\ttry {\n\t\tconst appInfo = await loadWorkspaceAppInfo(cwd);\n\t\tworkspaceAppPort = appInfo.app.port;\n\t\tsecretsRoot = appInfo.workspaceRoot;\n\t\tappName = appInfo.appName;\n\t} catch (error) {\n\t\t// Not in a workspace - use defaults\n\t\tlogger.log(\n\t\t\t`⚠️ Could not load workspace config: ${(error as Error).message}`,\n\t\t);\n\t\tsecretsRoot = findSecretsRoot(cwd);\n\t\tappName = getAppNameFromCwd(cwd) ?? undefined;\n\t}\n\n\t// Determine port: explicit --port > workspace config > default 3000\n\tconst resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3000;\n\n\t// Load secrets and inject PORT\n\tconst credentials = await loadSecretsForApp(secretsRoot, appName);\n\n\t// Always inject PORT into credentials so apps can read it\n\tcredentials.PORT = String(resolvedPort);\n\n\t// Write secrets to temp JSON file (always write since we have PORT)\n\t// Use app-specific filename to avoid race conditions when running multiple apps via turbo\n\tconst secretsDir = join(secretsRoot, '.gkm');\n\tawait mkdir(secretsDir, { recursive: true });\n\tconst secretsFileName = appName\n\t\t? `dev-secrets-${appName}.json`\n\t\t: 'dev-secrets.json';\n\tconst secretsJsonPath = join(secretsDir, secretsFileName);\n\tawait writeFile(secretsJsonPath, JSON.stringify(credentials, null, 2));\n\n\treturn {\n\t\tcredentials,\n\t\tresolvedPort,\n\t\tsecretsJsonPath,\n\t\tappName,\n\t\tsecretsRoot,\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🎉 Running at http://localhost:${this.port}`);\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\nclass DevServer {\n\tprivate serverProcess: ChildProcess | null = null;\n\tprivate isRunning = false;\n\tprivate actualPort: number;\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\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 on port ${this.actualPort}...`);\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\tlogger.log(`\\n🎉 Server running at http://localhost:${this.actualPort}`);\n\t\t\tif (this.enableOpenApi) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`📚 API Docs available at http://localhost:${this.actualPort}/__docs`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (this.telescope) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`🔭 Telescope available at http://localhost:${this.actualPort}${this.telescope.path}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (this.studio) {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`🗄️ Studio available at http://localhost:${this.actualPort}${this.studio.path}`,\n\t\t\t\t);\n\t\t\t}\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\t\tconst { relative, dirname } = await import('node:path');\n\n\t\tconst serverPath = join(this.appRoot, '.gkm', this.provider, 'server.ts');\n\n\t\tconst relativeAppPath = relative(\n\t\t\tdirname(serverPath),\n\t\t\tjoin(dirname(serverPath), 'app.js'),\n\t\t);\n\n\t\t// Generate credentials injection code if secrets are available\n\t\tconst credentialsInjection = this.secretsJsonPath\n\t\t\t? `import { Credentials } from '@geekmidas/envkit/credentials';\nimport { existsSync, readFileSync } from 'node:fs';\n\n// Inject dev secrets into Credentials (must happen before app import)\nconst secretsPath = '${this.secretsJsonPath}';\nif (existsSync(secretsPath)) {\n Object.assign(Credentials, JSON.parse(readFileSync(secretsPath, 'utf-8')));\n}\n\n`\n\t\t\t: '';\n\n\t\tconst serveCode =\n\t\t\tthis.runtime === 'bun'\n\t\t\t\t? `Bun.serve({\n port,\n fetch: app.fetch,\n });`\n\t\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\t\tconst content = `#!/usr/bin/env node\n/**\n * Development server entry point\n * This file is auto-generated by 'gkm dev'\n */\n${credentialsInjection}import { createApp } from './${relativeAppPath.startsWith('.') ? relativeAppPath : `./${relativeAppPath}`}';\n\nconst port = process.argv.includes('--port')\n ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])\n : 3000;\n\n// createApp is async to support optional WebSocket setup\nconst { app, start } = await createApp(undefined, ${this.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\t\tawait fsWriteFile(serverPath, content);\n\t}\n}\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 workspace config and secrets)\n\t// Don't inject PORT for exec since we're not running a server\n\tconst { credentials, secretsJsonPath, appName, secretsRoot } =\n\t\tawait prepareEntryCredentials({ cwd });\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// Rewrite URLs with resolved Docker ports (from gkm dev)\n\tconst composePath = join(secretsRoot, 'docker-compose.yml');\n\tconst mappings = parseComposePortMappings(composePath);\n\tif (mappings.length > 0) {\n\t\tconst ports = await loadPortState(secretsRoot);\n\t\tif (Object.keys(ports).length > 0) {\n\t\t\tconst rewritten = rewriteUrlsWithPorts(credentials, {\n\t\t\t\tdockerEnv: {},\n\t\t\t\tports,\n\t\t\t\tmappings,\n\t\t\t});\n\t\t\tObject.assign(credentials, rewritten);\n\t\t\tlogger.log(`🔌 Applied ${Object.keys(ports).length} port mapping(s)`);\n\t\t}\n\t}\n\n\t// Inject dependency URLs (works for both frontend and backend apps)\n\ttry {\n\t\tconst appInfo = await loadWorkspaceAppInfo(cwd);\n\t\tif (appInfo.appName) {\n\t\t\tconst depEnv = getDependencyEnvVars(appInfo.workspace, appInfo.appName);\n\t\t\tObject.assign(credentials, depEnv);\n\t\t}\n\t} catch {\n\t\t// Not in a workspace — skip dependency URL injection\n\t}\n\n\t// Create preload script that injects Credentials\n\t// Create in cwd so package resolution works (finds node_modules in app directory)\n\tconst preloadDir = join(cwd, '.gkm');\n\tawait mkdir(preloadDir, { recursive: true });\n\tconst preloadPath = join(preloadDir, 'credentials-preload.ts');\n\tawait createCredentialsPreload(preloadPath, secretsJsonPath);\n\n\t// Build command\n\tconst [cmd, ...rawArgs] = commandArgs;\n\n\tif (!cmd) {\n\t\tthrow new Error('No command specified');\n\t}\n\n\t// Replace template variables in command args (e.g. $PORT -> resolved port)\n\tconst args = rawArgs.map((arg) =>\n\t\targ.replace(/\\$PORT\\b/g, credentials.PORT ?? '3000'),\n\t);\n\n\tlogger.log(`🚀 Running: ${[cmd, ...args].join(' ')}`);\n\n\t// Merge NODE_OPTIONS with existing value (if any)\n\t// Add tsx loader first so our .ts preload can be loaded\n\tconst existingNodeOptions = process.env.NODE_OPTIONS ?? '';\n\tconst tsxImport = '--import=tsx';\n\tconst preloadImport = `--import=${preloadPath}`;\n\n\t// Build NODE_OPTIONS: existing + tsx loader + our preload\n\tconst nodeOptions = [existingNodeOptions, tsxImport, 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 { mkdir, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type {\n\tCronInfo,\n\tFunctionInfo,\n\tRouteInfo,\n\tSubscriberInfo,\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\nexport async function generateAwsManifest(\n\toutputDir: string,\n\troutes: RouteInfo[],\n\tfunctions: FunctionInfo[],\n\tcrons: CronInfo[],\n\tsubscribers: SubscriberInfo[],\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 = routes.filter((r) => r.method !== 'ALL');\n\n\tconst content = `export const manifest = {\n routes: ${JSON.stringify(awsRoutes, null, 2)},\n functions: ${JSON.stringify(functions, null, 2)},\n crons: ${JSON.stringify(crons, null, 2)},\n subscribers: ${JSON.stringify(subscribers, null, 2)},\n} as const;\n\n// Derived types\nexport type Route = (typeof manifest.routes)[number];\nexport type Function = (typeof manifest.functions)[number];\nexport type Cron = (typeof manifest.crons)[number];\nexport type Subscriber = (typeof manifest.subscribers)[number];\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 ${awsRoutes.length} routes, ${functions.length} functions, ${crons.length} crons, ${subscribers.length} subscribers`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\n}\n\nexport async function generateServerManifest(\n\toutputDir: string,\n\tappInfo: ServerAppInfo,\n\troutes: RouteInfo[],\n\tsubscribers: SubscriberInfo[],\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 = routes\n\t\t.filter((r) => r.method !== 'ALL')\n\t\t.map((r) => ({\n\t\t\tpath: r.path,\n\t\t\tmethod: r.method,\n\t\t\tauthorizer: r.authorizer,\n\t\t}));\n\n\t// Server subscribers only need name and events\n\tconst serverSubscribers = subscribers.map((s) => ({\n\t\tname: s.name,\n\t\tsubscribedEvents: s.subscribedEvents,\n\t}));\n\n\tconst content = `export const manifest = {\n app: ${JSON.stringify(appInfo, null, 2)},\n routes: ${JSON.stringify(serverRoutes, null, 2)},\n subscribers: ${JSON.stringify(serverSubscribers, null, 2)},\n} as const;\n\n// Derived types\nexport type Route = (typeof manifest.routes)[number];\nexport type Subscriber = (typeof manifest.subscribers)[number];\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 ${serverRoutes.length} routes, ${serverSubscribers.length} subscribers`,\n\t);\n\tlogger.log(`Manifest: ${relative(process.cwd(), manifestPath)}`);\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 { Subscriber } from '@geekmidas/constructs/subscribers';\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\tSubscriberGenerator,\n} from '../generators';\nimport type {\n\tBuildOptions,\n\tBuildResult,\n\tLegacyProvider,\n\tRouteInfo,\n} from '../types';\nimport {\n\tgetAppBuildOrder,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n} from '../workspace/index.js';\nimport {\n\tgenerateAwsManifest,\n\tgenerateServerManifest,\n\ttype ServerAppInfo,\n} from './manifests';\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: ${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 (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};\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\n\t// Load all constructs in parallel\n\tconst [allEndpoints, allFunctions, allCrons, allSubscribers] =\n\t\tawait Promise.all([\n\t\t\tendpointGenerator.load(config.routes),\n\t\t\tconfig.functions ? functionGenerator.load(config.functions) : [],\n\t\t\tconfig.crons ? cronGenerator.load(config.crons) : [],\n\t\t\tconfig.subscribers ? subscriberGenerator.load(config.subscribers) : [],\n\t\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\n\tif (\n\t\tallEndpoints.length === 0 &&\n\t\tallFunctions.length === 0 &&\n\t\tallCrons.length === 0 &&\n\t\tallSubscribers.length === 0\n\t) {\n\t\tlogger.log(\n\t\t\t'No endpoints, functions, crons, or subscribers 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\tallEndpoints,\n\t\t\tallFunctions,\n\t\t\tallCrons,\n\t\t\tallSubscribers,\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\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\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\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\tconst [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all(\n\t\t[\n\t\t\tendpointGenerator.build(context, endpoints, outputDir, {\n\t\t\t\tprovider,\n\t\t\t\tenableOpenApi,\n\t\t\t}),\n\t\t\tfunctionGenerator.build(context, functions, outputDir, { provider }),\n\t\t\tcronGenerator.build(context, crons, outputDir, { provider }),\n\t\t\tsubscriberGenerator.build(context, subscribers, outputDir, { provider }),\n\t\t],\n\t);\n\n\tlogger.log(\n\t\t`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`,\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 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\trouteMetadata,\n\t\t\tsubscriberInfos,\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];\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\troutes,\n\t\t\tfunctionInfos,\n\t\t\tcronInfos,\n\t\t\tsubscriberInfos,\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' | 'frontend';\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 === 'frontend');\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// Summary\n\t\tlogger.log(`\\n📋 Build Summary:`);\n\t\tfor (const result of results) {\n\t\t\tconst icon = result.type === 'backend' ? '⚙️' : '🌐';\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 === 'frontend') {\n\t\t// Next.js standalone output\n\t\treturn join(appPath, '.next');\n\t} else {\n\t\t// Backend .gkm output\n\t\treturn join(appPath, '.gkm');\n\t}\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 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};\n\n/** Default Docker image versions for services */\nexport const DEFAULT_SERVICE_VERSIONS: Record<ComposeServiceName, string> = {\n\tpostgres: '16-alpine',\n\tredis: '7-alpine',\n\trabbitmq: '3-management-alpine',\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 = `version: '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:postgres@postgres:5432/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\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 - postgres_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\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\t// Add volumes\n\tyaml += `\nvolumes:\n`;\n\n\tif (serviceMap.has('postgres')) {\n\t\tyaml += ` postgres_data:\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\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 `version: '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\n\t// Get image versions from config\n\tconst postgresImage = getInfraServiceImage('postgres', services.db);\n\tconst redisImage = getInfraServiceImage('redis', services.cache);\n\n\tlet yaml = `# Docker Compose for ${workspace.name} workspace\n# Generated by gkm - do not edit manually\n\nservices:\n`;\n\n\t// Generate service for each app\n\tfor (const [appName, app] of apps) {\n\t\tyaml += generateAppService(appName, app, apps, {\n\t\t\tregistry,\n\t\t\thasPostgres,\n\t\t\thasRedis,\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 - postgres_data:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\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 ports:\n - \"8025:8025\" # Web UI\n - \"1025:1025\" # SMTP\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 += ` postgres_data:\n`;\n\t}\n\n\tif (hasRedis) {\n\t\tyaml += ` redis_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',\n\tconfig: boolean | { version?: string; image?: string } | undefined,\n): string {\n\tconst defaults: Record<'postgres' | 'redis', string> = {\n\t\tpostgres: 'postgres:16-alpine',\n\t\tredis: 'redis:7-alpine',\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 baseImage = serviceName === 'postgres' ? 'postgres' : 'redis';\n\t\t\treturn `${baseImage}:${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\thasPostgres: boolean;\n\t\thasRedis: boolean;\n\t},\n): string {\n\tconst { registry, hasPostgres, hasRedis } = options;\n\tconst imageRef = registry ? `\\${REGISTRY:-${registry}}/` : '';\n\n\t// Health check path - frontends use /, backends use /health\n\tconst healthCheckPath = app.type === 'frontend' ? '/' : '/health';\n\tconst healthCheckCmd =\n\t\tapp.type === 'frontend'\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:postgres@postgres:5432/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}\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}\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","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 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\tgenerateSlimDockerfile,\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' | 'frontend';\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\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 === 'frontend') {\n\t\t\t// Generate Next.js Dockerfile\n\t\t\tdockerfile = generateNextjsDockerfile({\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});\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 = result.type === 'backend' ? '⚙️' : '🌐';\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","import 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 !== 'frontend') {\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 === 'frontend') {\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 frontend app based on its dependencies.\n *\n * @param app - The frontend 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 buildArgs: string[] = [];\n\n\tfor (const dep of app.dependencies) {\n\t\tconst publicUrl = deployedUrls[dep];\n\t\tif (publicUrl) {\n\t\t\t// Convert app name to UPPER_SNAKE_CASE for env var\n\t\t\tconst envVarName = `NEXT_PUBLIC_${dep.toUpperCase()}_URL`;\n\t\t\tbuildArgs.push(`${envVarName}=${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 frontend app configuration\n * @returns Array of arg names like 'NEXT_PUBLIC_API_URL'\n */\nexport function getPublicUrlArgNames(app: NormalizedAppConfig): string[] {\n\treturn app.dependencies.map((dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`);\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 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 NEXT_PUBLIC_ prefix for frontend apps (NEXT_PUBLIC_AUTH_URL -> dependencyUrls.auth)\n\tif (context.dependencyUrls && varName.endsWith('_URL')) {\n\t\tlet depName: string;\n\n\t\tif (varName.startsWith('NEXT_PUBLIC_')) {\n\t\t\t// NEXT_PUBLIC_AUTH_URL -> auth\n\t\t\tdepName = varName.slice(12, -4).toLowerCase();\n\t\t} else {\n\t\t\t// AUTH_URL -> auth\n\t\t\tdepName = varName.slice(0, -4).toLowerCase();\n\t\t}\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 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\trequiredEnvVars: 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}\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 } = options;\n\n\t// 1. Frontend apps - handle dependencies and config sniffing\n\tif (app.type === 'frontend') {\n\t\t// Auto-generate NEXT_PUBLIC_{DEP}_URL from dependencies\n\t\tconst depVars = (app.dependencies ?? []).map(\n\t\t\t(dep) => `NEXT_PUBLIC_${dep.toUpperCase()}_URL`,\n\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\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}\n\n\t\t\t// Combine: dependency vars + sniffed vars (deduplicated)\n\t\t\tconst allVars = [...new Set([...depVars, ...sniffedVars])];\n\t\t\treturn { appName, requiredEnvVars: allVars };\n\t\t}\n\n\t\treturn { appName, requiredEnvVars: depVars };\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 { appName, requiredEnvVars: result.envVars };\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(app.routes, app.path, workspacePath);\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 { appName, requiredEnvVars: result.envVars };\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 { appName, requiredEnvVars: result.envVars };\n\t}\n\n\t// 5. No env detection method available\n\treturn { appName, requiredEnvVars: [] };\n}\n\n/**\n * Result from sniffing an entry file.\n */\ninterface EntrySniffResult {\n\tenvVars: 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\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\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\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 { envVars: [], error: new Error('No route patterns provided') };\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\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\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\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: [], 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: [], 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\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\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 === 'frontend',\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 (NEXT_PUBLIC_* must be present at build time)\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: all NEXT_PUBLIC_* vars must be present at Next.js build time\n\t\t\t\tconst buildArgs: string[] = [];\n\t\t\t\tconst publicUrlArgNames: string[] = [];\n\n\t\t\t\tfor (const [key, value] of Object.entries(resolved)) {\n\t\t\t\t\tif (key.startsWith('NEXT_PUBLIC_')) {\n\t\t\t\t\t\tbuildArgs.push(`${key}=${value}`);\n\t\t\t\t\t\tpublicUrlArgNames.push(key);\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 NEXT_PUBLIC_* 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 { randomBytes } from 'node:crypto';\nimport type { ComposeServiceName } from '../types';\nimport type { ServiceCredentials, StageSecrets } from './types';\n\n/**\n * Generate a secure random password using URL-safe base64 characters.\n * @param length Password length (default: 32)\n */\nexport function generateSecurePassword(length = 32): string {\n\treturn randomBytes(Math.ceil((length * 3) / 4))\n\t\t.toString('base64url')\n\t\t.slice(0, length);\n}\n\n/** Default service configurations */\nconst SERVICE_DEFAULTS: Record<\n\tComposeServiceName,\n\tOmit<ServiceCredentials, 'password'>\n> = {\n\tpostgres: {\n\t\thost: 'postgres',\n\t\tport: 5432,\n\t\tusername: 'app',\n\t\tdatabase: 'app',\n\t},\n\tredis: {\n\t\thost: 'redis',\n\t\tport: 6379,\n\t\tusername: 'default',\n\t},\n\trabbitmq: {\n\t\thost: 'rabbitmq',\n\t\tport: 5672,\n\t\tusername: 'app',\n\t\tvhost: '/',\n\t},\n};\n\n/**\n * Generate credentials for a specific service.\n */\nexport function generateServiceCredentials(\n\tservice: ComposeServiceName,\n): ServiceCredentials {\n\tconst defaults = SERVICE_DEFAULTS[service];\n\treturn {\n\t\t...defaults,\n\t\tpassword: generateSecurePassword(),\n\t};\n}\n\n/**\n * Generate credentials for multiple services.\n */\nexport function generateServicesCredentials(\n\tservices: ComposeServiceName[],\n): StageSecrets['services'] {\n\tconst result: StageSecrets['services'] = {};\n\n\tfor (const service of services) {\n\t\tresult[service] = generateServiceCredentials(service);\n\t}\n\n\treturn result;\n}\n\n/**\n * Generate connection URL for PostgreSQL.\n */\nexport function generatePostgresUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, database } = creds;\n\treturn `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;\n}\n\n/**\n * Generate connection URL for Redis.\n */\nexport function generateRedisUrl(creds: ServiceCredentials): string {\n\tconst { password, host, port } = creds;\n\treturn `redis://:${encodeURIComponent(password)}@${host}:${port}`;\n}\n\n/**\n * Generate connection URL for RabbitMQ.\n */\nexport function generateRabbitmqUrl(creds: ServiceCredentials): string {\n\tconst { username, password, host, port, vhost } = creds;\n\tconst encodedVhost = encodeURIComponent(vhost ?? '/');\n\treturn `amqp://${username}:${encodeURIComponent(password)}@${host}:${port}/${encodedVhost}`;\n}\n\n/**\n * Generate connection URLs from service credentials.\n */\nexport function generateConnectionUrls(\n\tservices: StageSecrets['services'],\n): StageSecrets['urls'] {\n\tconst urls: StageSecrets['urls'] = {};\n\n\tif (services.postgres) {\n\t\turls.DATABASE_URL = generatePostgresUrl(services.postgres);\n\t}\n\n\tif (services.redis) {\n\t\turls.REDIS_URL = generateRedisUrl(services.redis);\n\t}\n\n\tif (services.rabbitmq) {\n\t\turls.RABBITMQ_URL = generateRabbitmqUrl(services.rabbitmq);\n\t}\n\n\treturn urls;\n}\n\n/**\n * Create a new StageSecrets object with generated credentials.\n */\nexport function createStageSecrets(\n\tstage: string,\n\tservices: ComposeServiceName[],\n): StageSecrets {\n\tconst now = new Date().toISOString();\n\tconst serviceCredentials = generateServicesCredentials(services);\n\tconst urls = generateConnectionUrls(serviceCredentials);\n\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: serviceCredentials,\n\t\turls,\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Rotate password for a specific service.\n */\nexport function rotateServicePassword(\n\tsecrets: StageSecrets,\n\tservice: ComposeServiceName,\n): StageSecrets {\n\tconst currentCreds = secrets.services[service];\n\tif (!currentCreds) {\n\t\tthrow new Error(`Service \"${service}\" not configured in secrets`);\n\t}\n\n\tconst newCreds: ServiceCredentials = {\n\t\t...currentCreds,\n\t\tpassword: generateSecurePassword(),\n\t};\n\n\tconst newServices = {\n\t\t...secrets.services,\n\t\t[service]: newCreds,\n\t};\n\n\treturn {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tservices: newServices,\n\t\turls: generateConnectionUrls(newServices),\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': '~1.0.0',\n\t'@geekmidas/auth': '~1.0.0',\n\t'@geekmidas/cache': '~1.0.0',\n\t'@geekmidas/client': '~1.0.0',\n\t'@geekmidas/cloud': '~1.0.0',\n\t'@geekmidas/constructs': '~1.0.5',\n\t'@geekmidas/db': '~1.0.0',\n\t'@geekmidas/emailkit': '~1.0.0',\n\t'@geekmidas/envkit': '~1.0.2',\n\t'@geekmidas/errors': '~1.0.0',\n\t'@geekmidas/events': '~1.0.0',\n\t'@geekmidas/logger': '~1.0.0',\n\t'@geekmidas/rate-limit': '~1.0.0',\n\t'@geekmidas/schema': '~1.0.0',\n\t'@geekmidas/services': '~1.0.1',\n\t'@geekmidas/storage': '~1.0.0',\n\t'@geekmidas/studio': '~1.0.0',\n\t'@geekmidas/telescope': '~1.0.0',\n\t'@geekmidas/testkit': '~1.0.1',\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 {\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:16-alpine\n container_name: ${options.name}-postgres\n restart: unless-stopped${envFile}\n environment:\n POSTGRES_USER: postgres\n POSTGRES_PASSWORD: postgres\n POSTGRES_DB: ${options.name.replace(/-/g, '_')}_dev\n ports:\n - '\\${POSTGRES_HOST_PORT:-5432}:5432'\n volumes:\n - postgres_data:/var/lib/postgresql/data${initVolume}\n healthcheck:\n test: ['CMD-SHELL', 'pg_isready -U postgres']\n interval: 5s\n timeout: 5s\n retries: 5`);\n\t\tvolumes.push(' postgres_data:');\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),\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),\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 - '\\${MAILPIT_SMTP_HOST_PORT:-1025}:1025'\n - '\\${MAILPIT_UI_HOST_PORT:-8025}:8025'\n environment:\n MP_SMTP_AUTH_ACCEPT_ANY: 1\n MP_SMTP_AUTH_ALLOW_INSECURE: 1`);\n\t}\n\n\t// Build docker-compose.yml\n\tlet dockerCompose = `services:\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(apps: DatabaseAppConfig[]): 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\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 environment variables for passwords (more secure than hardcoded values)\n * - api user: uses public schema\n * - auth user: uses auth schema with search_path=auth\n */\nfunction generatePostgresInitScript(apps: DatabaseAppConfig[]): 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\t// API user uses public schema\n\t\t\treturn `\n# Create ${app.name} user (uses public schema)\necho \"Creating user ${userName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n CREATE USER ${userName} WITH PASSWORD '$${envVar}';\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\t// Other users get their own schema with search_path\n\t\treturn `\n# Create ${app.name} user with dedicated schema\necho \"Creating user ${userName} with schema ${schemaName}...\"\npsql -v ON_ERROR_STOP=1 --username \"$POSTGRES_USER\" --dbname \"$POSTGRES_DB\" <<-EOSQL\n CREATE USER ${userName} WITH PASSWORD '$${envVar}';\n CREATE SCHEMA ${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\treturn `#!/bin/bash\nset -e\n\n# Auto-generated PostgreSQL init script\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${userCreations.join('\\n')}\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';\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 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 envParser: './src/config/env#envParser',\n logger: './src/config/logger#logger',\n },\n web: {\n type: 'frontend',\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 client: {\n output: './src/api',\n },\n },\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 (services.db || services.cache || services.mail) {\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\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\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 * 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}\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}\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 * 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];\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\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['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': {\n\t\t\t\ttypes: OPENAPI_OUTPUT_PATH,\n\t\t\t\timport: OPENAPI_OUTPUT_PATH,\n\t\t\t},\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// 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 - Runs migrations on the test database\n\t\t// Note: gkm test automatically rewrites DATABASE_URL to use a _test\n\t\t// suffixed database and creates it if needed. This setup only runs\n\t\t// migrations.\n\t\t{\n\t\t\tpath: 'test/globalSetup.ts',\n\t\t\tcontent: `import { Kysely, PostgresDialect } from 'kysely';\nimport pg from 'pg';\nimport { PostgresKyselyMigrator } from '@geekmidas/testkit/kysely';\nimport type { Database } from '~/services/database.ts';\n\nexport async function setup() {\n const testUrl = process.env.DATABASE_URL;\n if (!testUrl) throw new Error('DATABASE_URL is required for tests');\n\n // Run migrations on the test database\n // (gkm test already rewrites DATABASE_URL to point to the _test database)\n const db = new Kysely<Database>({\n dialect: new PostgresDialect({\n pool: new pg.Pool({ connectionString: testUrl }),\n }),\n });\n\n const migrator = new PostgresKyselyMigrator({\n db,\n migrationsPath: './src/migrations',\n });\n\n await migrator.migrateToLatest();\n await db.destroy();\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 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 -p $PORT',\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[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: ['${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[`${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: '../../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 - uses createApi with shared QueryClient\n\tconst apiIndexTs = `import { createApi } from './api.ts';\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 { existsSync } from 'node:fs';\nimport { join } from 'node:path';\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","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 type { ComposeServiceName } 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 { 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 {\n\ttype DeployTarget,\n\tdeployTargetChoices,\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 * Generate a secure random password for database users\n */\nfunction generateDbPassword(): string {\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Generate database URL for an app\n * All apps connect to the same database, but use different users/schemas\n */\nfunction generateDbUrl(\n\tappName: string,\n\tpassword: string,\n\tprojectName: string,\n\thost = 'localhost',\n\tport = 5432,\n): string {\n\tconst userName = appName.replace(/-/g, '_');\n\tconst dbName = `${projectName.replace(/-/g, '_')}_dev`;\n\treturn `postgresql://${userName}:${password}@${host}:${port}/${dbName}`;\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: '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],\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']\n\t\t: answers.services || [];\n\tconst services: ServicesSelection = {\n\t\tdb: servicesArray.includes('db'),\n\t\tcache: servicesArray.includes('cache'),\n\t\tmail: servicesArray.includes('mail'),\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 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};\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 web app files for fullstack template\n\tconst webAppFiles = isFullstack ? generateWebAppFiles(templateOptions) : [];\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\n\tconst devSecrets = createStageSecrets('development', secretServices);\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\tconsole.log(` │ └── web/ # Next.js frontend`);\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 } from '../config';\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// Generate secrets\n\tconst secrets = createStageSecrets(stage, services);\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\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}\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\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 { join } from 'node:path';\nimport { loadWorkspaceAppInfo } from '../config';\nimport { sniffAppEnvironment } from '../deploy/sniffer';\nimport {\n\tloadEnvFiles,\n\tloadPortState,\n\tparseComposePortMappings,\n\trewriteUrlsWithPorts,\n} from '../dev/index';\nimport { readStageSecrets, toEmbeddableSecrets } from '../secrets/storage';\nimport { getDependencyEnvVars } from '../workspace/index';\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}\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// 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. Load and decrypt secrets\n\tlet secretsEnv: Record<string, string> = {};\n\ttry {\n\t\tconst secrets = await readStageSecrets(stage);\n\t\tif (secrets) {\n\t\t\tsecretsEnv = toEmbeddableSecrets(secrets);\n\t\t\tconsole.log(\n\t\t\t\t` 🔐 Loaded ${Object.keys(secretsEnv).length} secrets from ${stage}`,\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.log(` No secrets found for ${stage}`);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('key not found')) {\n\t\t\tconsole.log(` Decryption key not found for ${stage}`);\n\t\t} else {\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// 3. Rewrite URLs with resolved Docker ports (from gkm dev)\n\tconst composePath = join(cwd, 'docker-compose.yml');\n\tconst mappings = parseComposePortMappings(composePath);\n\tif (mappings.length > 0) {\n\t\tconst ports = await loadPortState(cwd);\n\t\tif (Object.keys(ports).length > 0) {\n\t\t\tsecretsEnv = rewriteUrlsWithPorts(secretsEnv, {\n\t\t\t\tdockerEnv: {},\n\t\t\t\tports,\n\t\t\t\tmappings,\n\t\t\t});\n\t\t\tconsole.log(` 🔌 Applied ${Object.keys(ports).length} port mapping(s)`);\n\t\t}\n\t}\n\n\t// 4. Use a separate test database (append _test suffix)\n\tsecretsEnv = rewriteDatabaseUrlForTests(secretsEnv);\n\tawait ensureTestDatabase(secretsEnv);\n\n\t// 5. Load workspace config + dependency URLs + sniff env vars\n\tlet dependencyEnv: Record<string, string> = {};\n\ttry {\n\t\tconst appInfo = await loadWorkspaceAppInfo(cwd);\n\t\tdependencyEnv = getDependencyEnvVars(appInfo.workspace, appInfo.appName);\n\n\t\tif (Object.keys(dependencyEnv).length > 0) {\n\t\t\tconsole.log(\n\t\t\t\t` 🔗 Loaded ${Object.keys(dependencyEnv).length} dependency URL(s)`,\n\t\t\t);\n\t\t}\n\n\t\t// 6. Sniff to detect which env vars the app needs\n\t\tconst sniffed = await sniffAppEnvironment(\n\t\t\tappInfo.app,\n\t\t\tappInfo.appName,\n\t\t\tappInfo.workspaceRoot,\n\t\t\t{ logWarnings: false },\n\t\t);\n\n\t\t// Filter to only include what the app needs\n\t\tif (sniffed.requiredEnvVars.length > 0) {\n\t\t\tconst needed = new Set(sniffed.requiredEnvVars);\n\t\t\tconst allEnv = { ...secretsEnv, ...dependencyEnv };\n\t\t\tconst filteredEnv: Record<string, string> = {};\n\t\t\tfor (const [key, value] of Object.entries(allEnv)) {\n\t\t\t\tif (needed.has(key)) {\n\t\t\t\t\tfilteredEnv[key] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsecretsEnv = {};\n\t\t\tdependencyEnv = filteredEnv;\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} catch {\n\t\t// Not in a workspace — continue with just secrets\n\t}\n\n\tconsole.log('');\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\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...secretsEnv,\n\t\t\t...dependencyEnv,\n\t\t\t// Ensure NODE_ENV is set to test\n\t\t\tNODE_ENV: 'test',\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\n/**\n * Ensure the test database exists by connecting to the default database\n * and running CREATE DATABASE IF NOT EXISTS.\n * @internal Exported for testing\n */\nexport async function ensureTestDatabase(\n\tenv: Record<string, string>,\n): Promise<void> {\n\tconst databaseUrl = env.DATABASE_URL;\n\tif (!databaseUrl) return;\n\n\ttry {\n\t\tconst url = new URL(databaseUrl);\n\t\tconst testDbName = url.pathname.slice(1);\n\t\tif (!testDbName) return;\n\n\t\t// Connect to the default 'postgres' database to create the test database\n\t\turl.pathname = '/postgres';\n\t\tconst { default: pg } = await import('pg');\n\t\tconst client = new pg.Client({ connectionString: url.toString() });\n\t\tawait client.connect();\n\n\t\ttry {\n\t\t\tawait client.query(`CREATE DATABASE \"${testDbName}\"`);\n\t\t\tconsole.log(` 📦 Created test database \"${testDbName}\"`);\n\t\t} catch (err: unknown) {\n\t\t\t// 42P04 = database already exists — that's fine\n\t\t\tif ((err as { code?: string }).code !== '42P04') throw err;\n\t\t} finally {\n\t\t\tawait client.end();\n\t\t}\n\t} catch (err) {\n\t\t// Don't fail test startup if we can't create the database\n\t\t// (e.g., postgres not running yet, will fail later with a clear error)\n\t\tconsole.log(\n\t\t\t` ⚠️ Could not ensure test database: ${(err as Error).message}`,\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 { 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 TestOptions, testCommand } from './test/index';\nimport type { ComposeServiceName, LegacyProvider, MainProvider } from './types';\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\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(error instanceof Error ? error.message : 'Command failed');\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.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}) => {\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});\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});\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});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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.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(error instanceof Error ? error.message : 'Command failed');\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.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\t\t\tawait openapiCommand({});\n\t\t} catch (error) {\n\t\t\tconsole.error(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Command failed',\n\t\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Deploy failed');\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(\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: 'Failed to initialize deployment',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Failed to list resources',\n\t\t\t\t);\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(\n\t\t\t\t\terror instanceof Error ? error.message : 'Failed to login',\n\t\t\t\t);\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(\n\t\t\t\terror instanceof Error ? error.message : 'Failed to logout',\n\t\t\t);\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(\n\t\t\t\terror instanceof Error ? error.message : 'Failed to get status',\n\t\t\t);\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\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(error instanceof Error ? error.message : 'Command failed');\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nprogram.parse();\n"],"mappings":"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EAAE,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC;EACjD;EACD;GACC,MAAM;GACN,UAAU,EAAE,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;EAC9C;EACD;GACC,MAAM;GACN,UAAU,EAAE,KAAK,UAAU,gBAAgB,MAAM,EAAE,CAAC;EACpD;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;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,iBAAiB,GAAG,QAAQ,KAAK;CACvC,MAAM,aAAa,GAAG,QAAQ,KAAK;CAGnC,MAAM,cAAc;EACnB,MAAM;EACN,SAAS;EACT,SAAS;EACT,MAAM;EACN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"}