@kuckit/cli 2.0.4 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as isLegacyConfig, c as loadTryLoadKuckitConfig, i as isGcpConfig, l as addModule, o as migrateLegacyConfig, s as discoverModules, u as generateModule } from "./provider-
|
|
2
|
+
import { a as isLegacyConfig, c as loadTryLoadKuckitConfig, i as isGcpConfig, l as addModule, o as migrateLegacyConfig, s as discoverModules, u as generateModule } from "./provider-DFTQgffJ.js";
|
|
3
3
|
import { program } from "commander";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/commands/generate-module.ts","../src/commands/add-module.ts","../src/commands/discover-module.ts","../src/commands/infra/provider.ts","../src/commands/infra/types.ts"],"sourcesContent":[],"mappings":";UAGU,qBAAA;EAAA,GAAA,EAAA,MAAA;EAwBY,GAAA,EAAA,MAAA;;iBAAA,cAAA,wBAAsC,wBAAwB;;;UCtB1E,gBAAA;EDFA,WAAA,EAAA,OAAA;AAwBV;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/commands/generate-module.ts","../src/commands/add-module.ts","../src/commands/discover-module.ts","../src/commands/infra/provider.ts","../src/commands/infra/types.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as isLegacyConfig, i as isGcpConfig, l as addModule, n as isAwsConfig, o as migrateLegacyConfig, r as isAzureConfig, s as discoverModules, t as defineInfraProvider, u as generateModule } from "./provider-
|
|
1
|
+
import { a as isLegacyConfig, i as isGcpConfig, l as addModule, n as isAwsConfig, o as migrateLegacyConfig, r as isAzureConfig, s as discoverModules, t as defineInfraProvider, u as generateModule } from "./provider-DFTQgffJ.js";
|
|
2
2
|
|
|
3
3
|
export { addModule, defineInfraProvider, discoverModules, generateModule, isAwsConfig, isAzureConfig, isGcpConfig, isLegacyConfig, migrateLegacyConfig };
|
|
@@ -678,6 +678,10 @@ const MODULES_MARKER_START = "// KUCKIT_MODULES_START";
|
|
|
678
678
|
const MODULES_MARKER_END = "// KUCKIT_MODULES_END";
|
|
679
679
|
const CLIENT_MODULES_MARKER_START = "// KUCKIT_CLIENT_MODULES_START";
|
|
680
680
|
const CLIENT_MODULES_MARKER_END = "// KUCKIT_CLIENT_MODULES_END";
|
|
681
|
+
const KNOWN_MODULES_MARKER_START = "// KUCKIT_KNOWN_MODULES_START";
|
|
682
|
+
const KNOWN_MODULES_MARKER_END = "// KUCKIT_KNOWN_MODULES_END";
|
|
683
|
+
const KNOWN_CLIENT_MODULES_MARKER_START = "// KUCKIT_KNOWN_CLIENT_MODULES_START";
|
|
684
|
+
const KNOWN_CLIENT_MODULES_MARKER_END = "// KUCKIT_KNOWN_CLIENT_MODULES_END";
|
|
681
685
|
/**
|
|
682
686
|
* Execute module setup scaffolds (create directories, copy templates)
|
|
683
687
|
*/
|
|
@@ -744,6 +748,13 @@ async function addToUnifiedConfig(packageName, configPath, moduleConfig) {
|
|
|
744
748
|
console.log(` Added to unified config: ${configPath}`);
|
|
745
749
|
return true;
|
|
746
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Generate a valid JS variable name from package name
|
|
753
|
+
* e.g., "@acme/billing-module" -> "billingModule"
|
|
754
|
+
*/
|
|
755
|
+
function packageToVarName(packageName) {
|
|
756
|
+
return packageName.replace(/^@[^/]+\//, "").replace(/-module$/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase()) + "Module";
|
|
757
|
+
}
|
|
747
758
|
async function addToServerModules(packageName, cwd) {
|
|
748
759
|
const modulesPath = join(cwd, "apps", "server", "src", "modules.ts");
|
|
749
760
|
if (!await fileExists(modulesPath)) {
|
|
@@ -751,10 +762,29 @@ async function addToServerModules(packageName, cwd) {
|
|
|
751
762
|
return false;
|
|
752
763
|
}
|
|
753
764
|
let content = await readFile(modulesPath, "utf-8");
|
|
754
|
-
if (content.includes(`
|
|
765
|
+
if (content.includes(`'${packageName}'`)) {
|
|
755
766
|
console.log(` Module ${packageName} is already in server modules`);
|
|
756
767
|
return true;
|
|
757
768
|
}
|
|
769
|
+
const varName = packageToVarName(packageName);
|
|
770
|
+
if (content.includes(KNOWN_MODULES_MARKER_START)) {
|
|
771
|
+
const importStatement = `import { kuckitModule as ${varName} } from '${packageName}'`;
|
|
772
|
+
const lastImportMatch = content.match(/^import .+ from ['"][^'"]+['"].*$/gm);
|
|
773
|
+
if (lastImportMatch) {
|
|
774
|
+
const lastImport = lastImportMatch[lastImportMatch.length - 1];
|
|
775
|
+
content = content.replace(lastImport, `${lastImport}\n${importStatement}`);
|
|
776
|
+
}
|
|
777
|
+
const knownModulesEntry = `\t'${packageName}': {\n\t\tmodule: ${varName},\n\t},`;
|
|
778
|
+
const markerEndPos$1 = content.indexOf(KNOWN_MODULES_MARKER_END);
|
|
779
|
+
if (markerEndPos$1 !== -1) {
|
|
780
|
+
const before$1 = content.slice(0, markerEndPos$1);
|
|
781
|
+
const after$1 = content.slice(markerEndPos$1);
|
|
782
|
+
content = before$1 + `${knownModulesEntry}\n\t` + after$1;
|
|
783
|
+
}
|
|
784
|
+
await writeFile(modulesPath, content);
|
|
785
|
+
console.log(` Added to server KNOWN_MODULES: ${modulesPath}`);
|
|
786
|
+
return true;
|
|
787
|
+
}
|
|
758
788
|
if (!content.includes(MODULES_MARKER_START)) {
|
|
759
789
|
if (content.match(/return modules\s*$/)) {
|
|
760
790
|
const insertPos = content.lastIndexOf("return modules");
|
|
@@ -799,11 +829,30 @@ export const getClientModuleSpecs = (): ClientModuleSpec[] => [
|
|
|
799
829
|
console.log(` Created client modules file: ${clientModulesPath}`);
|
|
800
830
|
}
|
|
801
831
|
let content = await readFile(clientModulesPath, "utf-8");
|
|
802
|
-
|
|
803
|
-
if (content.includes(`package: '${clientPackagePath}'`)) {
|
|
832
|
+
if (content.includes(`'${packageName}'`) || content.includes(`'${packageName}/`)) {
|
|
804
833
|
console.log(` Client module is already registered`);
|
|
805
834
|
return true;
|
|
806
835
|
}
|
|
836
|
+
const varName = packageToVarName(packageName) + "Client";
|
|
837
|
+
const clientPackagePath = `${packageName}/${clientPath.replace("./", "")}`;
|
|
838
|
+
if (content.includes(KNOWN_CLIENT_MODULES_MARKER_START)) {
|
|
839
|
+
const importStatement = `import { kuckitClientModule as ${varName} } from '${clientPackagePath}'`;
|
|
840
|
+
const lastImportMatch = content.match(/^import .+ from ['"][^'"]+['"].*$/gm);
|
|
841
|
+
if (lastImportMatch) {
|
|
842
|
+
const lastImport = lastImportMatch[lastImportMatch.length - 1];
|
|
843
|
+
content = content.replace(lastImport, `${lastImport}\n${importStatement}`);
|
|
844
|
+
}
|
|
845
|
+
const knownModulesEntry = `\t'${packageName}': {\n\t\tmodule: ${varName},\n\t},`;
|
|
846
|
+
const markerEndPos$1 = content.indexOf(KNOWN_CLIENT_MODULES_MARKER_END);
|
|
847
|
+
if (markerEndPos$1 !== -1) {
|
|
848
|
+
const before$1 = content.slice(0, markerEndPos$1);
|
|
849
|
+
const after$1 = content.slice(markerEndPos$1);
|
|
850
|
+
content = before$1 + `${knownModulesEntry}\n\t` + after$1;
|
|
851
|
+
}
|
|
852
|
+
await writeFile(clientModulesPath, content);
|
|
853
|
+
console.log(` Added to client KNOWN_CLIENT_MODULES: ${clientModulesPath}`);
|
|
854
|
+
return true;
|
|
855
|
+
}
|
|
807
856
|
const newEntry = `{ package: '${clientPackagePath}' },`;
|
|
808
857
|
const markerEndPos = content.indexOf(CLIENT_MODULES_MARKER_END);
|
|
809
858
|
if (markerEndPos === -1) {
|
|
@@ -1133,4 +1182,4 @@ function defineInfraProvider(provider) {
|
|
|
1133
1182
|
|
|
1134
1183
|
//#endregion
|
|
1135
1184
|
export { isLegacyConfig as a, loadTryLoadKuckitConfig as c, isGcpConfig as i, addModule as l, isAwsConfig as n, migrateLegacyConfig as o, isAzureConfig as r, discoverModules as s, defineInfraProvider as t, generateModule as u };
|
|
1136
|
-
//# sourceMappingURL=provider-
|
|
1185
|
+
//# sourceMappingURL=provider-DFTQgffJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-DFTQgffJ.js","names":["newEntry: string","markerEndPos","before","after","pm","discovered: DiscoveredModule[]","writeFile","result: DiscoverResult"],"sources":["../src/commands/generate-module.ts","../src/commands/add-module.ts","../src/lib/sdk-loader.ts","../src/commands/discover-module.ts","../src/commands/infra/types.ts","../src/commands/infra/provider.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\ninterface GenerateModuleOptions {\n\torg: string\n\tdir: string\n}\n\nfunction toKebabCase(str: string): string {\n\treturn str\n\t\t.replace(/([a-z])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase()\n}\n\nfunction toPascalCase(str: string): string {\n\treturn str\n\t\t.split(/[-_\\s]+/)\n\t\t.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join('')\n}\n\nfunction toCamelCase(str: string): string {\n\tconst pascal = toPascalCase(str)\n\treturn pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\nexport async function generateModule(name: string, options: GenerateModuleOptions): Promise<void> {\n\tconst kebabName = toKebabCase(name)\n\tconst pascalName = toPascalCase(name)\n\tconst camelName = toCamelCase(name)\n\tconst moduleDirName = `${kebabName}-module`\n\n\tconst packageName = options.org ? `@${options.org}/${moduleDirName}` : `@kuckit/${moduleDirName}`\n\tconst moduleId = options.org ? `${options.org}.${kebabName}` : `kuckit.${kebabName}`\n\n\tconst targetDir = join(process.cwd(), options.dir, moduleDirName)\n\n\tconsole.log(`Creating module: ${packageName}`)\n\tconsole.log(` Directory: ${targetDir}`)\n\n\t// Create directory structure (Clean Architecture)\n\tawait mkdir(join(targetDir, 'src', 'domain'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'ports'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'adapters'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'usecases'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'api'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'ui'), { recursive: true })\n\n\t// Generate package.json\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.1.0',\n\t\tprivate: true,\n\t\tdescription: `${pascalName} module for Kuckit`,\n\t\ttype: 'module',\n\t\tmain: 'src/index.ts',\n\t\ttypes: 'src/index.ts',\n\t\texports: {\n\t\t\t'.': {\n\t\t\t\ttypes: './src/index.ts',\n\t\t\t\tdefault: './src/index.ts',\n\t\t\t},\n\t\t\t'./client': {\n\t\t\t\ttypes: './src/client-module.ts',\n\t\t\t\tdefault: './src/client-module.ts',\n\t\t\t},\n\t\t\t'./ui': {\n\t\t\t\ttypes: './src/ui/index.ts',\n\t\t\t\tdefault: './src/ui/index.ts',\n\t\t\t},\n\t\t},\n\t\tpeerDependencies: {\n\t\t\ttypescript: '^5',\n\t\t},\n\t\tdependencies: {\n\t\t\t'@kuckit/sdk': '^1.0.0',\n\t\t\t'@kuckit/sdk-react': '^1.0.0',\n\t\t\t'@kuckit/api': '^1.0.0',\n\t\t\t'@orpc/server': '^1.10.0',\n\t\t\t'@orpc/zod': '^1.10.0',\n\t\t\t'drizzle-orm': '^0.44.0',\n\t\t\tzod: '^3.23.0',\n\t\t\treact: '^19.0.0',\n\t\t\t'@tanstack/react-query': '^5.0.0',\n\t\t},\n\t}\n\n\tawait writeFile(join(targetDir, 'package.json'), JSON.stringify(packageJson, null, '\\t') + '\\n')\n\n\t// Generate tsconfig.json\n\tconst tsconfig = {\n\t\textends: '../../tsconfig.base.json',\n\t\tcompilerOptions: {\n\t\t\toutDir: 'dist',\n\t\t\trootDir: 'src',\n\t\t},\n\t\tinclude: ['src'],\n\t}\n\n\tawait writeFile(join(targetDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, '\\t') + '\\n')\n\n\t// =====================\n\t// DOMAIN LAYER\n\t// =====================\n\n\tconst entityFile = `import { z } from 'zod'\n\n/**\n * ${pascalName} entity schema\n */\nexport const ${pascalName}Schema = z.object({\n\tid: z.string(),\n\tname: z.string().min(1, 'Name is required'),\n\tdescription: z.string().optional(),\n\tcreatedAt: z.date(),\n\tupdatedAt: z.date(),\n\tuserId: z.string(),\n})\n\nexport type ${pascalName} = z.infer<typeof ${pascalName}Schema>\n\n/**\n * Create ${camelName} input schema\n */\nexport const Create${pascalName}InputSchema = z.object({\n\tname: z.string().min(1, 'Name is required'),\n\tdescription: z.string().optional(),\n})\n\nexport type Create${pascalName}Input = z.infer<typeof Create${pascalName}InputSchema>\n\n/**\n * Update ${camelName} input schema\n */\nexport const Update${pascalName}InputSchema = z.object({\n\tid: z.string(),\n\tname: z.string().min(1, 'Name is required').optional(),\n\tdescription: z.string().optional(),\n})\n\nexport type Update${pascalName}Input = z.infer<typeof Update${pascalName}InputSchema>\n`\n\n\tawait writeFile(join(targetDir, 'src', 'domain', `${kebabName}.entity.ts`), entityFile)\n\n\t// =====================\n\t// PORTS LAYER\n\t// =====================\n\n\tconst repositoryPort = `import type { ${pascalName}, Create${pascalName}Input, Update${pascalName}Input } from '../domain/${kebabName}.entity'\n\n/**\n * ${pascalName} repository port interface\n * Defines the contract for ${camelName} persistence operations\n */\nexport interface ${pascalName}Repository {\n\tfindById(id: string): Promise<${pascalName} | null>\n\tfindByUserId(userId: string): Promise<${pascalName}[]>\n\tcreate(input: Create${pascalName}Input & { id: string; userId: string }): Promise<${pascalName}>\n\tupdate(input: Update${pascalName}Input): Promise<${pascalName} | null>\n\tdelete(id: string): Promise<boolean>\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ports', `${kebabName}.repository.ts`), repositoryPort)\n\n\t// =====================\n\t// ADAPTERS LAYER\n\t// =====================\n\n\tconst drizzleAdapter = `import { pgTable, text, timestamp } from 'drizzle-orm/pg-core'\nimport { eq } from 'drizzle-orm'\nimport type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName}, Create${pascalName}Input, Update${pascalName}Input } from '../domain/${kebabName}.entity'\n\n/**\n * ${pascalName}s table schema for Drizzle ORM\n */\nexport const ${camelName}sTable = pgTable('${kebabName}s', {\n\tid: text('id').primaryKey(),\n\tname: text('name').notNull(),\n\tdescription: text('description'),\n\tcreatedAt: timestamp('created_at').notNull().defaultNow(),\n\tupdatedAt: timestamp('updated_at').notNull().defaultNow(),\n\tuserId: text('user_id').notNull(),\n})\n\n/**\n * Create a Drizzle-based ${camelName} repository\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function make${pascalName}Repository(db: any): ${pascalName}Repository {\n\treturn {\n\t\tasync findById(id: string): Promise<${pascalName} | null> {\n\t\t\tconst results = await db.select().from(${camelName}sTable).where(eq(${camelName}sTable.id, id))\n\t\t\treturn results[0] ?? null\n\t\t},\n\n\t\tasync findByUserId(userId: string): Promise<${pascalName}[]> {\n\t\t\treturn db.select().from(${camelName}sTable).where(eq(${camelName}sTable.userId, userId))\n\t\t},\n\n\t\tasync create(input: Create${pascalName}Input & { id: string; userId: string }): Promise<${pascalName}> {\n\t\t\tconst now = new Date()\n\t\t\tconst ${camelName} = {\n\t\t\t\tid: input.id,\n\t\t\t\tname: input.name,\n\t\t\t\tdescription: input.description ?? null,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tuserId: input.userId,\n\t\t\t}\n\t\t\tawait db.insert(${camelName}sTable).values(${camelName})\n\t\t\treturn ${camelName} as ${pascalName}\n\t\t},\n\n\t\tasync update(input: Update${pascalName}Input): Promise<${pascalName} | null> {\n\t\t\tconst existing = await this.findById(input.id)\n\t\t\tif (!existing) return null\n\n\t\t\tconst updated = {\n\t\t\t\t...existing,\n\t\t\t\t...(input.name !== undefined && { name: input.name }),\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t}\n\t\t\tawait db.update(${camelName}sTable).set(updated).where(eq(${camelName}sTable.id, input.id))\n\t\t\treturn updated\n\t\t},\n\n\t\tasync delete(id: string): Promise<boolean> {\n\t\t\tconst result = await db.delete(${camelName}sTable).where(eq(${camelName}sTable.id, id))\n\t\t\treturn result.rowCount > 0\n\t\t},\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'adapters', `${kebabName}.drizzle.ts`), drizzleAdapter)\n\n\t// =====================\n\t// USE CASES LAYER\n\t// =====================\n\n\tconst listUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName} } from '../domain/${kebabName}.entity'\n\ninterface List${pascalName}sDeps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * List ${camelName}s use case\n */\nexport function makeList${pascalName}s(deps: List${pascalName}sDeps) {\n\treturn async (userId: string): Promise<${pascalName}[]> => {\n\t\treturn deps.${camelName}Repository.findByUserId(userId)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `list-${kebabName}s.ts`), listUseCase)\n\n\tconst getUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName} } from '../domain/${kebabName}.entity'\n\ninterface Get${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Get ${camelName} use case\n */\nexport function makeGet${pascalName}(deps: Get${pascalName}Deps) {\n\treturn async (id: string): Promise<${pascalName} | null> => {\n\t\treturn deps.${camelName}Repository.findById(id)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `get-${kebabName}.ts`), getUseCase)\n\n\tconst createUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName}, Create${pascalName}Input } from '../domain/${kebabName}.entity'\n\nexport interface Create${pascalName}UseCaseInput extends Create${pascalName}Input {\n\tuserId: string\n}\n\ninterface Create${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Create ${camelName} use case\n */\nexport function makeCreate${pascalName}(deps: Create${pascalName}Deps) {\n\treturn async (input: Create${pascalName}UseCaseInput): Promise<${pascalName}> => {\n\t\tconst id = crypto.randomUUID()\n\t\treturn deps.${camelName}Repository.create({\n\t\t\tid,\n\t\t\tname: input.name,\n\t\t\tdescription: input.description,\n\t\t\tuserId: input.userId,\n\t\t})\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `create-${kebabName}.ts`), createUseCase)\n\n\tconst deleteUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\n\ninterface Delete${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Delete ${camelName} use case\n */\nexport function makeDelete${pascalName}(deps: Delete${pascalName}Deps) {\n\treturn async (id: string): Promise<boolean> => {\n\t\treturn deps.${camelName}Repository.delete(id)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `delete-${kebabName}.ts`), deleteUseCase)\n\n\t// =====================\n\t// API LAYER\n\t// =====================\n\n\tconst routerFile = `import { z } from 'zod'\nimport { protectedProcedure } from '@kuckit/api'\nimport { Create${pascalName}InputSchema } from '../domain/${kebabName}.entity'\nimport type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\n\n/**\n * ${pascalName}s oRPC router\n * Provides CRUD operations for ${camelName}s\n */\nexport const ${camelName}sRouter = {\n\tlist: protectedProcedure.input(z.object({})).handler(async ({ context }) => {\n\t\tconst userId = context.session?.user?.id\n\t\tif (!userId) throw new Error('User not authenticated')\n\n\t\tconst ${camelName}s = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').findByUserId(userId)\n\t\treturn ${camelName}s\n\t}),\n\n\tget: protectedProcedure\n\t\t.input(z.object({ id: z.string() }))\n\t\t.handler(async ({ input, context }) => {\n\t\t\tconst ${camelName} = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').findById(input.id)\n\t\t\treturn ${camelName}\n\t\t}),\n\n\tcreate: protectedProcedure.input(Create${pascalName}InputSchema).handler(async ({ input, context }) => {\n\t\tconst userId = context.session?.user?.id\n\t\tif (!userId) throw new Error('User not authenticated')\n\n\t\tconst id = crypto.randomUUID()\n\t\tconst ${camelName} = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').create({\n\t\t\tid,\n\t\t\tname: input.name,\n\t\t\tdescription: input.description,\n\t\t\tuserId,\n\t\t})\n\t\treturn ${camelName}\n\t}),\n\n\tdelete: protectedProcedure\n\t\t.input(z.object({ id: z.string() }))\n\t\t.handler(async ({ input, context }) => {\n\t\t\tconst success = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').delete(input.id)\n\t\t\treturn { success }\n\t\t}),\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'api', `${kebabName}s.router.ts`), routerFile)\n\n\t// =====================\n\t// UI LAYER\n\t// =====================\n\n\tconst pageComponent = `import { useState } from 'react'\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useRpc } from '@kuckit/sdk-react'\n\ninterface ${pascalName} {\n\tid: string\n\tname: string\n\tdescription?: string\n\tcreatedAt: Date\n\tupdatedAt: Date\n}\n\ninterface ${pascalName}sRpc {\n\t${camelName}s: {\n\t\tlist: (input: Record<string, never>) => Promise<${pascalName}[]>\n\t\tcreate: (input: { name: string; description?: string }) => Promise<${pascalName}>\n\t\tdelete: (input: { id: string }) => Promise<void>\n\t}\n}\n\n/**\n * ${pascalName}s page component\n * Demonstrates CRUD operations using the ${camelName}s module with useRpc and TanStack Query\n */\nexport function ${pascalName}sPage() {\n\tconst rpc = useRpc<${pascalName}sRpc>()\n\tconst queryClient = useQueryClient()\n\tconst [newName, setNewName] = useState('')\n\tconst [newDescription, setNewDescription] = useState('')\n\n\tconst {\n\t\tdata: ${camelName}s = [],\n\t\tisLoading,\n\t\terror,\n\t} = useQuery({\n\t\tqueryKey: ['${camelName}s'],\n\t\tqueryFn: () => rpc.${camelName}s.list({}),\n\t})\n\n\tconst createMutation = useMutation({\n\t\tmutationFn: (data: { name: string; description?: string }) => rpc.${camelName}s.create(data),\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: ['${camelName}s'] }),\n\t})\n\n\tconst deleteMutation = useMutation({\n\t\tmutationFn: (id: string) => rpc.${camelName}s.delete({ id }),\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: ['${camelName}s'] }),\n\t})\n\n\tconst create${pascalName} = async (e: React.FormEvent) => {\n\t\te.preventDefault()\n\t\tif (!newName.trim()) return\n\n\t\tcreateMutation.mutate(\n\t\t\t{ name: newName, description: newDescription || undefined },\n\t\t\t{\n\t\t\t\tonSuccess: () => {\n\t\t\t\t\tsetNewName('')\n\t\t\t\t\tsetNewDescription('')\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t}\n\n\tconst delete${pascalName} = (id: string) => {\n\t\tdeleteMutation.mutate(id)\n\t}\n\n\tif (isLoading) {\n\t\treturn <div style={{ padding: '2rem' }}>Loading ${camelName}s...</div>\n\t}\n\n\treturn (\n\t\t<div style={{ padding: '2rem', fontFamily: 'system-ui', maxWidth: '600px', margin: '0 auto' }}>\n\t\t\t<h1>${pascalName}s</h1>\n\n\t\t\t{(error || createMutation.error || deleteMutation.error) && (\n\t\t\t\t<div style={{ color: 'red', marginBottom: '1rem' }}>\n\t\t\t\t\t{error?.message || createMutation.error?.message || deleteMutation.error?.message}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<form onSubmit={create${pascalName}} style={{ marginBottom: '2rem' }}>\n\t\t\t\t<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Name\"\n\t\t\t\t\t\tvalue={newName}\n\t\t\t\t\t\tonChange={(e) => setNewName(e.target.value)}\n\t\t\t\t\t\trequired\n\t\t\t\t\t\tstyle={{ padding: '0.5rem', fontSize: '1rem' }}\n\t\t\t\t\t/>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Description (optional)\"\n\t\t\t\t\t\tvalue={newDescription}\n\t\t\t\t\t\tonChange={(e) => setNewDescription(e.target.value)}\n\t\t\t\t\t\tstyle={{ padding: '0.5rem', fontSize: '1rem' }}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={createMutation.isPending}\n\t\t\t\t\t\tstyle={{ padding: '0.5rem 1rem', cursor: 'pointer' }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{createMutation.isPending ? 'Adding...' : 'Add ${pascalName}'}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</form>\n\n\t\t\t<ul style={{ listStyle: 'none', padding: 0 }}>\n\t\t\t\t{${camelName}s.map((${camelName}) => (\n\t\t\t\t\t<li\n\t\t\t\t\t\tkey={${camelName}.id}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tpadding: '1rem',\n\t\t\t\t\t\t\tborder: '1px solid #ccc',\n\t\t\t\t\t\t\tmarginBottom: '0.5rem',\n\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<strong>{${camelName}.name}</strong>\n\t\t\t\t\t\t\t{${camelName}.description && (\n\t\t\t\t\t\t\t\t<p style={{ margin: '0.5rem 0 0 0', color: '#666' }}>{${camelName}.description}</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tonClick={() => delete${pascalName}(${camelName}.id)}\n\t\t\t\t\t\t\tdisabled={deleteMutation.isPending}\n\t\t\t\t\t\t\tstyle={{ cursor: 'pointer', color: 'red', background: 'none', border: 'none' }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tDelete\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</li>\n\t\t\t\t))}\n\t\t\t</ul>\n\n\t\t\t{${camelName}s.length === 0 && <p>No ${camelName}s yet. Create one above!</p>}\n\t\t</div>\n\t)\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ui', `${pascalName}sPage.tsx`), pageComponent)\n\n\tconst uiIndex = `export { ${pascalName}sPage } from './${pascalName}sPage'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ui', 'index.ts'), uiIndex)\n\n\t// =====================\n\t// SERVER MODULE\n\t// =====================\n\n\tconst serverModule = `import { defineKuckitModule, asFunction, type KuckitModuleContext } from '@kuckit/sdk'\nimport { ${camelName}sTable, make${pascalName}Repository } from './adapters/${kebabName}.drizzle'\nimport { ${camelName}sRouter } from './api/${kebabName}s.router'\n\nexport type ${pascalName}ModuleConfig = Record<string, never>\n\n/**\n * ${pascalName} module - Kuckit module demonstrating Clean Architecture pattern\n *\n * This module shows:\n * - Domain entity with Zod validation\n * - Repository port/adapter pattern\n * - Use cases for business logic\n * - oRPC router for API endpoints\n */\nexport const kuckitModule = defineKuckitModule<${pascalName}ModuleConfig>({\n\tid: '${moduleId}',\n\tdisplayName: '${pascalName}',\n\tdescription: '${pascalName} module for CRUD operations',\n\tversion: '0.1.0',\n\n\tasync register(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\n\t\t// Register schema for migrations\n\t\tctx.registerSchema('${camelName}s', ${camelName}sTable)\n\n\t\t// Register repository\n\t\tcontainer.register({\n\t\t\t${camelName}Repository: asFunction(({ db }) => make${pascalName}Repository(db)).scoped(),\n\t\t})\n\t},\n\n\tregisterApi(ctx) {\n\t\tctx.addApiRegistration({\n\t\t\ttype: 'rpc-router',\n\t\t\tname: '${camelName}s',\n\t\t\trouter: ${camelName}sRouter,\n\t\t})\n\t},\n\n\tasync onBootstrap(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\t\tconst logger = container.resolve('logger')\n\t\tlogger.info('${pascalName} module initialized')\n\t},\n\n\tasync onShutdown(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\t\tconst logger = container.resolve('logger')\n\t\tlogger.info('${pascalName} module shutting down')\n\t},\n})\n`\n\n\tawait writeFile(join(targetDir, 'src', 'module.ts'), serverModule)\n\n\t// =====================\n\t// CLIENT MODULE\n\t// =====================\n\n\tconst clientModule = `import { defineKuckitClientModule, type KuckitClientModuleContext } from '@kuckit/sdk-react'\nimport { ${pascalName}sPage } from './ui/${pascalName}sPage'\n\n/**\n * ${pascalName} client module\n * Registers routes and components for the web app\n */\nexport const kuckitClientModule = defineKuckitClientModule({\n\tid: '${moduleId}',\n\tdisplayName: '${pascalName}',\n\tversion: '0.1.0',\n\n\tregister(ctx: KuckitClientModuleContext) {\n\t\t// Register the ${camelName}s page component\n\t\tctx.registerComponent('${pascalName}sPage', ${pascalName}sPage)\n\n\t\t// Add route for ${camelName}s page\n\t\tctx.addRoute({\n\t\t\tid: '${kebabName}s',\n\t\t\tpath: '/${kebabName}s',\n\t\t\tcomponent: ${pascalName}sPage,\n\t\t\tmeta: {\n\t\t\t\ttitle: '${pascalName}s',\n\t\t\t\trequiresAuth: true,\n\t\t\t},\n\t\t})\n\n\t\t// Add navigation item\n\t\tctx.addNavItem({\n\t\t\tid: '${kebabName}s-nav',\n\t\t\tlabel: '${pascalName}s',\n\t\t\tpath: '/${kebabName}s',\n\t\t\ticon: 'list',\n\t\t\torder: 100,\n\t\t})\n\t},\n})\n\nexport { ${pascalName}sPage } from './ui/${pascalName}sPage'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'client-module.ts'), clientModule)\n\n\t// =====================\n\t// INDEX FILE\n\t// =====================\n\n\tconst indexFile = `// Server module\nexport { kuckitModule } from './module'\n\n// Domain\nexport * from './domain/${kebabName}.entity'\n\n// Ports\nexport type { ${pascalName}Repository } from './ports/${kebabName}.repository'\n\n// Adapters\nexport { ${camelName}sTable, make${pascalName}Repository } from './adapters/${kebabName}.drizzle'\n\n// Use cases\nexport { makeList${pascalName}s } from './usecases/list-${kebabName}s'\nexport { makeGet${pascalName} } from './usecases/get-${kebabName}'\nexport { makeCreate${pascalName} } from './usecases/create-${kebabName}'\nexport { makeDelete${pascalName} } from './usecases/delete-${kebabName}'\n\n// API\nexport { ${camelName}sRouter } from './api/${kebabName}s.router'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'index.ts'), indexFile)\n\n\tconsole.log(`\n✅ Module created successfully!\n\n📁 Structure:\n ${options.dir}/${moduleDirName}/\n ├── src/\n │ ├── domain/\n │ │ └── ${kebabName}.entity.ts # Zod schema for entity\n │ ├── ports/\n │ │ └── ${kebabName}.repository.ts # Repository interface\n │ ├── adapters/\n │ │ └── ${kebabName}.drizzle.ts # Drizzle implementation\n │ ├── usecases/\n │ │ ├── list-${kebabName}s.ts\n │ │ ├── get-${kebabName}.ts\n │ │ ├── create-${kebabName}.ts\n │ │ └── delete-${kebabName}.ts\n │ ├── api/\n │ │ └── ${kebabName}s.router.ts # oRPC router\n │ ├── ui/\n │ │ └── ${pascalName}sPage.tsx # React component\n │ ├── module.ts # Server module\n │ ├── client-module.ts # Client module\n │ └── index.ts\n ├── package.json\n └── tsconfig.json\n\n📝 Next steps:\n 1. Run 'bun install' from the root to link the new package\n 2. Add server module to apps/server/src/config/modules.ts:\n import { kuckitModule as ${camelName}Module } from '${packageName}'\n // Then inside getModuleSpecs(), between the KUCKIT_SERVER_MODULES markers:\n { module: ${camelName}Module },\n 3. Add client module to apps/web/src/modules.client.ts:\n import { kuckitClientModule as ${camelName}Client } from '${packageName}/client'\n // Then inside getClientModuleSpecs(), between the KUCKIT_CLIENT_MODULES markers:\n { module: ${camelName}Client },\n 4. Add schema path to drizzle.config.ts:\n resolve(currentDirPath, './packages/${moduleDirName}/src/adapters'),\n 5. Run 'bun run db:push' to create the table\n`)\n}\n","import { execSync } from 'node:child_process'\nimport { readFile, writeFile, access, mkdir, copyFile } from 'node:fs/promises'\nimport { accessSync, constants, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\n\ninterface AddModuleOptions {\n\tskipInstall: boolean\n}\n\ninterface ScaffoldEntry {\n\ttype: 'directory' | 'template'\n\tpath: string\n\tsrc?: string // For templates, relative to module package\n\tdest?: string // For templates, destination in project\n}\n\ninterface KuckitSetup {\n\tscaffolds?: ScaffoldEntry[]\n\tconfigDefaults?: Record<string, unknown>\n\tdevDependencies?: Record<string, string>\n\tpostInstallMessage?: string\n}\n\ninterface KuckitMetadata {\n\tid: string\n\tserver?: string\n\tclient?: string\n\tsetup?: KuckitSetup\n}\n\ninterface PackageJson {\n\tname: string\n\tkuckit?: KuckitMetadata\n}\n\nconst CONFIG_FILES = ['kuckit.config.ts', 'kuckit.config.js', 'kuckit.config.mjs']\n\nasync function fileExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path, constants.F_OK)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction findConfigFile(cwd: string): string | null {\n\tfor (const file of CONFIG_FILES) {\n\t\tconst configPath = join(cwd, file)\n\t\tif (existsSync(configPath)) {\n\t\t\treturn configPath\n\t\t}\n\t}\n\treturn null\n}\n\nfunction detectPackageManager(cwd: string): 'bun' | 'npm' | 'yarn' | 'pnpm' {\n\tconst lockFiles: Record<string, 'bun' | 'npm' | 'yarn' | 'pnpm'> = {\n\t\t'bun.lock': 'bun',\n\t\t'bun.lockb': 'bun',\n\t\t'package-lock.json': 'npm',\n\t\t'yarn.lock': 'yarn',\n\t\t'pnpm-lock.yaml': 'pnpm',\n\t}\n\n\tfor (const [file, pm] of Object.entries(lockFiles)) {\n\t\ttry {\n\t\t\taccessSync(join(cwd, file), constants.F_OK)\n\t\t\treturn pm\n\t\t} catch {\n\t\t\t// continue\n\t\t}\n\t}\n\n\treturn 'npm'\n}\n\nasync function readPackageKuckitMetadata(\n\tpackageName: string,\n\tcwd: string\n): Promise<KuckitMetadata | null> {\n\t// After install, read from node_modules\n\tconst packageJsonPath = join(cwd, 'node_modules', packageName, 'package.json')\n\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg: PackageJson = JSON.parse(content)\n\t\treturn pkg.kuckit ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nconst MODULES_MARKER_START = '// KUCKIT_MODULES_START'\nconst MODULES_MARKER_END = '// KUCKIT_MODULES_END'\nconst CLIENT_MODULES_MARKER_START = '// KUCKIT_CLIENT_MODULES_START'\nconst CLIENT_MODULES_MARKER_END = '// KUCKIT_CLIENT_MODULES_END'\n// New markers for config-driven approach\nconst KNOWN_MODULES_MARKER_START = '// KUCKIT_KNOWN_MODULES_START'\nconst KNOWN_MODULES_MARKER_END = '// KUCKIT_KNOWN_MODULES_END'\nconst KNOWN_CLIENT_MODULES_MARKER_START = '// KUCKIT_KNOWN_CLIENT_MODULES_START'\nconst KNOWN_CLIENT_MODULES_MARKER_END = '// KUCKIT_KNOWN_CLIENT_MODULES_END'\n\n/**\n * Execute module setup scaffolds (create directories, copy templates)\n */\nasync function executeSetupScaffolds(\n\tpackageName: string,\n\tsetup: KuckitSetup,\n\tcwd: string\n): Promise<void> {\n\tif (!setup.scaffolds || setup.scaffolds.length === 0) return\n\n\tconsole.log(` Running module setup...`)\n\tconst moduleDir = join(cwd, 'node_modules', packageName)\n\n\tfor (const scaffold of setup.scaffolds) {\n\t\tif (scaffold.type === 'directory') {\n\t\t\tconst dirPath = join(cwd, scaffold.path)\n\t\t\tif (!existsSync(dirPath)) {\n\t\t\t\tawait mkdir(dirPath, { recursive: true })\n\t\t\t\tconsole.log(` Created directory: ${scaffold.path}`)\n\t\t\t}\n\t\t} else if (scaffold.type === 'template' && scaffold.src && scaffold.dest) {\n\t\t\tconst srcPath = join(moduleDir, scaffold.src)\n\t\t\tconst destPath = join(cwd, scaffold.dest)\n\n\t\t\t// Don't overwrite existing files\n\t\t\tif (existsSync(destPath)) {\n\t\t\t\tconsole.log(` Skipped (exists): ${scaffold.dest}`)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Ensure destination directory exists\n\t\t\tawait mkdir(dirname(destPath), { recursive: true })\n\t\t\tawait copyFile(srcPath, destPath)\n\t\t\tconsole.log(` Created file: ${scaffold.dest}`)\n\t\t}\n\t}\n}\n\n/**\n * Install additional dev dependencies specified by module setup\n */\nasync function installSetupDependencies(\n\tsetup: KuckitSetup,\n\tcwd: string,\n\tpm: 'bun' | 'npm' | 'yarn' | 'pnpm'\n): Promise<void> {\n\tif (!setup.devDependencies || Object.keys(setup.devDependencies).length === 0) return\n\n\tconst deps = Object.entries(setup.devDependencies)\n\t\t.map(([name, version]) => `${name}@${version}`)\n\t\t.join(' ')\n\n\tconsole.log(` Installing additional dependencies...`)\n\tconst installCmd =\n\t\tpm === 'npm'\n\t\t\t? `npm install -D ${deps}`\n\t\t\t: pm === 'yarn'\n\t\t\t\t? `yarn add -D ${deps}`\n\t\t\t\t: `${pm} add -D ${deps}`\n\n\ttry {\n\t\texecSync(installCmd, { cwd: join(cwd, 'apps', 'web'), stdio: 'inherit' })\n\t} catch {\n\t\tconsole.warn(` Warning: Could not install ${deps} in apps/web`)\n\t}\n}\n\n/**\n * Add module to unified kuckit.config.ts with optional config\n */\nasync function addToUnifiedConfig(\n\tpackageName: string,\n\tconfigPath: string,\n\tmoduleConfig?: Record<string, unknown>\n): Promise<boolean> {\n\tlet content = await readFile(configPath, 'utf-8')\n\n\t// Check if package is already in config\n\tif (content.includes(`'${packageName}'`) || content.includes(`\"${packageName}\"`)) {\n\t\tconsole.log(` Module ${packageName} is already in ${configPath}`)\n\t\treturn true\n\t}\n\n\t// Find the modules array and add the new entry\n\t// Pattern: modules: [ ... ]\n\tconst modulesArrayMatch = content.match(/modules:\\s*\\[/)\n\tif (!modulesArrayMatch) {\n\t\tconsole.warn(`Warning: Could not find 'modules' array in ${configPath}`)\n\t\tconsole.log(` Please manually add: { package: '${packageName}' }`)\n\t\treturn false\n\t}\n\n\t// Find the position right after 'modules: ['\n\tconst insertPos = modulesArrayMatch.index! + modulesArrayMatch[0].length\n\n\t// Build the new entry with optional config\n\tlet newEntry: string\n\tif (moduleConfig && Object.keys(moduleConfig).length > 0) {\n\t\tconst configStr = JSON.stringify(moduleConfig, null, 2)\n\t\t\t.replace(/^/gm, '\\t\\t\\t') // Indent\n\t\t\t.replace(/^\\t\\t\\t{/, '{') // Fix opening brace\n\t\t\t.trim()\n\t\tnewEntry = `\\n\\t\\t{ package: '${packageName}', config: ${configStr} },`\n\t} else {\n\t\tnewEntry = `\\n\\t\\t{ package: '${packageName}' },`\n\t}\n\n\tcontent = content.slice(0, insertPos) + newEntry + content.slice(insertPos)\n\n\tawait writeFile(configPath, content)\n\tconsole.log(` Added to unified config: ${configPath}`)\n\treturn true\n}\n\n/**\n * Generate a valid JS variable name from package name\n * e.g., \"@acme/billing-module\" -> \"billingModule\"\n */\nfunction packageToVarName(packageName: string): string {\n\t// Remove org prefix and -module suffix, convert to camelCase\n\tconst name = packageName\n\t\t.replace(/^@[^/]+\\//, '') // Remove @org/\n\t\t.replace(/-module$/, '') // Remove -module suffix\n\t\t.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) // kebab to camel\n\treturn name + 'Module'\n}\n\nasync function addToServerModules(packageName: string, cwd: string): Promise<boolean> {\n\tconst modulesPath = join(cwd, 'apps', 'server', 'src', 'modules.ts')\n\n\tif (!(await fileExists(modulesPath))) {\n\t\tconsole.warn(`Warning: Server modules file not found at ${modulesPath}`)\n\t\treturn false\n\t}\n\n\tlet content = await readFile(modulesPath, 'utf-8')\n\n\t// Check if package is already added (check both old and new patterns)\n\tif (content.includes(`'${packageName}'`)) {\n\t\tconsole.log(` Module ${packageName} is already in server modules`)\n\t\treturn true\n\t}\n\n\tconst varName = packageToVarName(packageName)\n\n\t// Check for new config-driven pattern (KNOWN_MODULES)\n\tif (content.includes(KNOWN_MODULES_MARKER_START)) {\n\t\t// Add import at the top (after existing imports)\n\t\tconst importStatement = `import { kuckitModule as ${varName} } from '${packageName}'`\n\t\tconst lastImportMatch = content.match(/^import .+ from ['\"][^'\"]+['\"].*$/gm)\n\t\tif (lastImportMatch) {\n\t\t\tconst lastImport = lastImportMatch[lastImportMatch.length - 1]\n\t\t\tcontent = content.replace(lastImport, `${lastImport}\\n${importStatement}`)\n\t\t}\n\n\t\t// Add to KNOWN_MODULES mapping\n\t\tconst knownModulesEntry = `\\t'${packageName}': {\\n\\t\\tmodule: ${varName},\\n\\t},`\n\t\tconst markerEndPos = content.indexOf(KNOWN_MODULES_MARKER_END)\n\n\t\tif (markerEndPos !== -1) {\n\t\t\tconst before = content.slice(0, markerEndPos)\n\t\t\tconst after = content.slice(markerEndPos)\n\t\t\tcontent = before + `${knownModulesEntry}\\n\\t` + after\n\t\t}\n\n\t\tawait writeFile(modulesPath, content)\n\t\tconsole.log(` Added to server KNOWN_MODULES: ${modulesPath}`)\n\t\treturn true\n\t}\n\n\t// Fall back to old pattern (KUCKIT_MODULES_START/END)\n\tif (!content.includes(MODULES_MARKER_START)) {\n\t\tconst returnMatch = content.match(/return modules\\s*$/)\n\t\tif (returnMatch) {\n\t\t\tconst insertPos = content.lastIndexOf('return modules')\n\t\t\tconst before = content.slice(0, insertPos)\n\t\t\tconst after = content.slice(insertPos)\n\n\t\t\tcontent =\n\t\t\t\tbefore +\n\t\t\t\t`\\n\\t\\t${MODULES_MARKER_START}\\n\\t\\t// Modules installed via 'kuckit add' will be added here\\n\\t\\t${MODULES_MARKER_END}\\n\\n\\t\\t` +\n\t\t\t\tafter\n\t\t}\n\t}\n\n\tconst newEntry = `{ package: '${packageName}' },`\n\tconst markerEndPos = content.indexOf(MODULES_MARKER_END)\n\n\tif (markerEndPos === -1) {\n\t\tconsole.warn(`Warning: Could not find marker in ${modulesPath}`)\n\t\tconsole.log(` Please manually add: ${newEntry}`)\n\t\treturn false\n\t}\n\n\tconst before = content.slice(0, markerEndPos)\n\tconst after = content.slice(markerEndPos)\n\n\tcontent = before + `${newEntry}\\n\\t\\t` + after\n\n\tawait writeFile(modulesPath, content)\n\tconsole.log(` Added to server modules: ${modulesPath}`)\n\treturn true\n}\n\nasync function addToClientModules(\n\tpackageName: string,\n\tclientPath: string,\n\tcwd: string\n): Promise<boolean> {\n\tconst clientModulesPath = join(cwd, 'apps', 'web', 'src', 'modules.client.ts')\n\n\tif (!(await fileExists(clientModulesPath))) {\n\t\t// Create the file if it doesn't exist (legacy template)\n\t\tconst template = `import type { ClientModuleSpec } from '@kuckit/sdk-react'\n\n/**\n * Client module specifications\n *\n * Add your Kuckit client modules here. Modules can be:\n * - Direct references: { module: myModule }\n * - Package imports: { package: '@acme/billing-module/client' }\n *\n * The CLI command \\`kuckit add <package>\\` will automatically update this file.\n */\nexport const getClientModuleSpecs = (): ClientModuleSpec[] => [\n\t${CLIENT_MODULES_MARKER_START}\n\t${CLIENT_MODULES_MARKER_END}\n]\n`\n\t\tawait writeFile(clientModulesPath, template)\n\t\tconsole.log(` Created client modules file: ${clientModulesPath}`)\n\t}\n\n\tlet content = await readFile(clientModulesPath, 'utf-8')\n\n\t// Check if package is already added (check both old and new patterns)\n\tif (content.includes(`'${packageName}'`) || content.includes(`'${packageName}/`)) {\n\t\tconsole.log(` Client module is already registered`)\n\t\treturn true\n\t}\n\n\tconst varName = packageToVarName(packageName) + 'Client'\n\tconst clientPackagePath = `${packageName}/${clientPath.replace('./', '')}`\n\n\t// Check for new config-driven pattern (KNOWN_CLIENT_MODULES)\n\tif (content.includes(KNOWN_CLIENT_MODULES_MARKER_START)) {\n\t\t// Add import at the top (after existing imports)\n\t\tconst importStatement = `import { kuckitClientModule as ${varName} } from '${clientPackagePath}'`\n\t\tconst lastImportMatch = content.match(/^import .+ from ['\"][^'\"]+['\"].*$/gm)\n\t\tif (lastImportMatch) {\n\t\t\tconst lastImport = lastImportMatch[lastImportMatch.length - 1]\n\t\t\tcontent = content.replace(lastImport, `${lastImport}\\n${importStatement}`)\n\t\t}\n\n\t\t// Add to KNOWN_CLIENT_MODULES mapping\n\t\tconst knownModulesEntry = `\\t'${packageName}': {\\n\\t\\tmodule: ${varName},\\n\\t},`\n\t\tconst markerEndPos = content.indexOf(KNOWN_CLIENT_MODULES_MARKER_END)\n\n\t\tif (markerEndPos !== -1) {\n\t\t\tconst before = content.slice(0, markerEndPos)\n\t\t\tconst after = content.slice(markerEndPos)\n\t\t\tcontent = before + `${knownModulesEntry}\\n\\t` + after\n\t\t}\n\n\t\tawait writeFile(clientModulesPath, content)\n\t\tconsole.log(` Added to client KNOWN_CLIENT_MODULES: ${clientModulesPath}`)\n\t\treturn true\n\t}\n\n\t// Fall back to old pattern (KUCKIT_CLIENT_MODULES_START/END)\n\tconst newEntry = `{ package: '${clientPackagePath}' },`\n\tconst markerEndPos = content.indexOf(CLIENT_MODULES_MARKER_END)\n\n\tif (markerEndPos === -1) {\n\t\tconsole.warn(`Warning: Could not find marker in ${clientModulesPath}`)\n\t\tconsole.log(` Please manually add: ${newEntry}`)\n\t\treturn false\n\t}\n\n\tconst before = content.slice(0, markerEndPos)\n\tconst after = content.slice(markerEndPos)\n\n\tcontent = before + `${newEntry}\\n\\t` + after\n\n\tawait writeFile(clientModulesPath, content)\n\tconsole.log(` Added to client modules: ${clientModulesPath}`)\n\treturn true\n}\n\nexport async function addModule(packageName: string, options: AddModuleOptions): Promise<void> {\n\tconst cwd = process.cwd()\n\n\tconsole.log(`Adding module: ${packageName}`)\n\n\t// Step 1: Install the package\n\tif (!options.skipInstall) {\n\t\tconst pm = detectPackageManager(cwd)\n\t\tconst installCmd = pm === 'npm' ? `${pm} install ${packageName}` : `${pm} add ${packageName}`\n\n\t\tconsole.log(` Installing with ${pm}...`)\n\t\ttry {\n\t\t\texecSync(installCmd, { cwd, stdio: 'inherit' })\n\t\t} catch {\n\t\t\tconsole.error(`Failed to install ${packageName}`)\n\t\t\tprocess.exit(1)\n\t\t}\n\t}\n\n\t// Step 2: Validate kuckit metadata\n\tconst metadata = await readPackageKuckitMetadata(packageName, cwd)\n\n\tif (!metadata) {\n\t\tconsole.error(`\\nError: ${packageName} is not a valid Kuckit module.`)\n\t\tconsole.error(`The package.json must contain a \"kuckit\" field with module metadata.`)\n\t\tconsole.error(`\\nExpected structure:`)\n\t\tconsole.error(`{\n \"kuckit\": {\n \"id\": \"acme.billing\",\n \"server\": \".\",\n \"client\": \"./client\"\n }\n}`)\n\t\tprocess.exit(1)\n\t}\n\n\tconsole.log(` Found Kuckit module: ${metadata.id}`)\n\n\t// Step 3: Detect package manager for potential setup dependencies\n\tconst pm = detectPackageManager(cwd)\n\n\t// Step 4: Execute module setup (scaffolds, dev dependencies)\n\tif (metadata.setup) {\n\t\tawait executeSetupScaffolds(packageName, metadata.setup, cwd)\n\t\tawait installSetupDependencies(metadata.setup, cwd, pm)\n\t}\n\n\t// Step 5: Check for unified config\n\tconst configPath = findConfigFile(cwd)\n\n\tif (configPath) {\n\t\t// Use unified config with optional module config defaults\n\t\tawait addToUnifiedConfig(packageName, configPath, metadata.setup?.configDefaults)\n\t} else {\n\t\t// Fall back to separate config files\n\t\tif (metadata.server) {\n\t\t\tawait addToServerModules(packageName, cwd)\n\t\t}\n\t\tif (metadata.client) {\n\t\t\tawait addToClientModules(packageName, metadata.client, cwd)\n\t\t}\n\t}\n\n\t// Step 6: Print post-install message if provided\n\tif (metadata.setup?.postInstallMessage) {\n\t\tconsole.log(`\\n${metadata.setup.postInstallMessage}`)\n\t}\n\n\tconsole.log(`\nModule ${packageName} added successfully!\n\nRun 'bun run dev' to start the server with the new module.\n`)\n}\n","interface KuckitConfig {\n\tmodules: Array<{ package?: string; disabled?: boolean }>\n\t_configPath?: string\n}\n\ntype TryLoadKuckitConfig = (cwd: string) => Promise<KuckitConfig | null>\n\nexport async function loadTryLoadKuckitConfig(): Promise<TryLoadKuckitConfig> {\n\ttry {\n\t\tconst sdk = (await import('@kuckit/sdk')) as { tryLoadKuckitConfig?: TryLoadKuckitConfig }\n\t\tif (!sdk.tryLoadKuckitConfig) {\n\t\t\tthrow new Error('Invalid @kuckit/sdk version: tryLoadKuckitConfig not found.')\n\t\t}\n\t\treturn sdk.tryLoadKuckitConfig\n\t} catch {\n\t\tconsole.error('Error: This command requires @kuckit/sdk to be installed in your project.')\n\t\tconsole.error('Install it with one of:')\n\t\tconsole.error(' npm install -D @kuckit/sdk')\n\t\tconsole.error(' pnpm add -D @kuckit/sdk')\n\t\tconsole.error(' bun add -d @kuckit/sdk')\n\t\tprocess.exit(1)\n\t}\n}\n","import { readdir, readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { loadTryLoadKuckitConfig } from '../lib/sdk-loader.js'\n\nexport interface DiscoverOptions {\n\tjson: boolean\n\tinteractive: boolean\n}\n\ninterface KuckitMetadata {\n\tid: string\n\tserver?: string\n\tclient?: string\n}\n\ninterface DiscoveredModule {\n\tpackage: string\n\tid: string\n\tserver?: string\n\tclient?: string\n\tenabled: boolean\n\tlocal?: boolean\n}\n\ninterface DiscoverResult {\n\tdiscovered: DiscoveredModule[]\n\tenabled: number\n\tunconfigured: number\n}\n\nasync function readKuckitMetadataFromPath(packageJsonPath: string): Promise<KuckitMetadata | null> {\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg = JSON.parse(content) as { kuckit?: KuckitMetadata }\n\t\treturn pkg.kuckit ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function readPackageName(packageJsonPath: string): Promise<string | null> {\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg = JSON.parse(content) as { name?: string }\n\t\treturn pkg.name ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function scanWorkspacePackages(cwd: string): Promise<DiscoveredModule[]> {\n\tconst discovered: DiscoveredModule[] = []\n\tconst packagesDir = join(cwd, 'packages')\n\n\tif (!existsSync(packagesDir)) return discovered\n\n\ttry {\n\t\tconst entries = await readdir(packagesDir, { withFileTypes: true })\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory()) continue\n\n\t\t\tconst packageJsonPath = join(packagesDir, entry.name, 'package.json')\n\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\n\t\t\tif (metadata) {\n\t\t\t\tconst packageName = await readPackageName(packageJsonPath)\n\t\t\t\tif (packageName) {\n\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tlocal: true,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// packages directory not accessible\n\t}\n\n\treturn discovered\n}\n\nasync function scanNodeModules(cwd: string): Promise<DiscoveredModule[]> {\n\tconst nodeModulesPath = join(cwd, 'node_modules')\n\tconst discovered: DiscoveredModule[] = []\n\n\ttry {\n\t\tconst entries = await readdir(nodeModulesPath, { withFileTypes: true })\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue\n\t\t\tif (entry.name.startsWith('.')) continue\n\n\t\t\tif (entry.name.startsWith('@')) {\n\t\t\t\tconst scopePath = join(nodeModulesPath, entry.name)\n\t\t\t\ttry {\n\t\t\t\t\tconst scopedEntries = await readdir(scopePath, { withFileTypes: true })\n\t\t\t\t\tfor (const scopedEntry of scopedEntries) {\n\t\t\t\t\t\tif (!scopedEntry.isDirectory() && !scopedEntry.isSymbolicLink()) continue\n\t\t\t\t\t\tconst packageName = `${entry.name}/${scopedEntry.name}`\n\t\t\t\t\t\tconst packageJsonPath = join(nodeModulesPath, packageName, 'package.json')\n\t\t\t\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\t\t\t\t\t\tif (metadata) {\n\t\t\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Skip inaccessible scoped directories\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst packageJsonPath = join(nodeModulesPath, entry.name, 'package.json')\n\t\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\t\t\t\tif (metadata) {\n\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\tpackage: entry.name,\n\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// node_modules doesn't exist\n\t}\n\n\treturn discovered\n}\n\nasync function addModulesToConfig(packages: string[], configPath: string): Promise<void> {\n\tconst content = await readFile(configPath, 'utf-8')\n\tlet updated = content\n\n\tfor (const pkg of packages) {\n\t\tif (updated.includes(`'${pkg}'`) || updated.includes(`\"${pkg}\"`)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst modulesArrayMatch = updated.match(/modules:\\s*\\[/)\n\t\tif (!modulesArrayMatch) continue\n\n\t\tconst insertPos = modulesArrayMatch.index! + modulesArrayMatch[0].length\n\t\tconst newEntry = `\\n\\t\\t{ package: '${pkg}' },`\n\t\tupdated = updated.slice(0, insertPos) + newEntry + updated.slice(insertPos)\n\t}\n\n\tif (updated !== content) {\n\t\tconst { writeFile } = await import('node:fs/promises')\n\t\tawait writeFile(configPath, updated)\n\t}\n}\n\nexport async function discoverModules(options: DiscoverOptions): Promise<void> {\n\tconst cwd = process.cwd()\n\n\tif (!options.json) {\n\t\tconsole.log('Scanning for Kuckit modules...\\n')\n\t}\n\n\t// Load current config\n\tconst tryLoadKuckitConfig = await loadTryLoadKuckitConfig()\n\tconst config = await tryLoadKuckitConfig(cwd)\n\tconst configuredPackages = new Set(config?.modules.map((m) => m.package) ?? [])\n\n\t// Scan both workspace packages and node_modules\n\tconst workspaceModules = await scanWorkspacePackages(cwd)\n\tconst nodeModules = await scanNodeModules(cwd)\n\n\t// Combine and dedupe (workspace takes precedence)\n\tconst seen = new Set<string>()\n\tconst discovered: DiscoveredModule[] = []\n\n\tfor (const mod of workspaceModules) {\n\t\tseen.add(mod.package)\n\t\tmod.enabled = configuredPackages.has(mod.package)\n\t\tdiscovered.push(mod)\n\t}\n\n\tfor (const mod of nodeModules) {\n\t\tif (!seen.has(mod.package)) {\n\t\t\tmod.enabled = configuredPackages.has(mod.package)\n\t\t\tdiscovered.push(mod)\n\t\t}\n\t}\n\n\t// Sort: enabled first, then alphabetically\n\tdiscovered.sort((a, b) => {\n\t\tif (a.enabled !== b.enabled) return a.enabled ? -1 : 1\n\t\treturn a.package.localeCompare(b.package)\n\t})\n\n\tconst result: DiscoverResult = {\n\t\tdiscovered,\n\t\tenabled: discovered.filter((m) => m.enabled).length,\n\t\tunconfigured: discovered.filter((m) => !m.enabled).length,\n\t}\n\n\tif (options.json) {\n\t\tconsole.log(JSON.stringify(result, null, 2))\n\t\treturn\n\t}\n\n\tif (discovered.length === 0) {\n\t\tconsole.log('No Kuckit modules found.')\n\t\tconsole.log('\\nInstall modules with: kuckit add <package>')\n\t\treturn\n\t}\n\n\tconsole.log(`Found ${discovered.length} Kuckit module${discovered.length === 1 ? '' : 's'}:`)\n\tfor (const mod of discovered) {\n\t\tconst status = mod.enabled ? '✓' : '○'\n\t\tconst label = mod.enabled ? '(enabled)' : '(not configured)'\n\t\tconst localLabel = mod.local ? ' [local]' : ''\n\t\tconsole.log(` ${status} ${mod.package}${localLabel} ${label}`)\n\t}\n\n\tconst unconfigured = discovered.filter((m) => !m.enabled)\n\tif (unconfigured.length === 0) {\n\t\tconsole.log('\\nAll discovered modules are already configured.')\n\t\treturn\n\t}\n\n\tif (!options.interactive) {\n\t\tconsole.log(\n\t\t\t`\\n${unconfigured.length} module${unconfigured.length === 1 ? '' : 's'} not configured.`\n\t\t)\n\t\tconsole.log('Run without --no-interactive to enable them.')\n\t\treturn\n\t}\n\n\tif (!config?._configPath) {\n\t\tconsole.log('\\nNo kuckit.config.ts found. Create one first with:')\n\t\tconsole.log(' npx create-kuckit-app --init')\n\t\treturn\n\t}\n\n\t// Interactive mode: prompt for module selection\n\ttry {\n\t\tconst { checkbox } = await import('@inquirer/prompts')\n\n\t\tconst selected = await checkbox({\n\t\t\tmessage: 'Enable modules:',\n\t\t\tchoices: unconfigured.map((m) => ({\n\t\t\t\tname: m.package,\n\t\t\t\tvalue: m.package,\n\t\t\t\tchecked: true,\n\t\t\t})),\n\t\t})\n\n\t\tif (selected.length === 0) {\n\t\t\tconsole.log('\\nNo modules selected.')\n\t\t\treturn\n\t\t}\n\n\t\tawait addModulesToConfig(selected, config._configPath)\n\t\tconsole.log(\n\t\t\t`\\nUpdated kuckit.config.ts with ${selected.length} new module${selected.length === 1 ? '' : 's'}.`\n\t\t)\n\t} catch (error) {\n\t\tif ((error as Error).name === 'ExitPromptError') {\n\t\t\tconsole.log('\\nCancelled.')\n\t\t\treturn\n\t\t}\n\t\tthrow error\n\t}\n}\n","/**\n * Infrastructure types for CLI\n *\n * These types define the config schema stored in .kuckit/infra.json.\n * They are designed to support multiple cloud providers while maintaining\n * backward compatibility with existing GCP-only configurations.\n */\n\nimport type { BaseInfraConfig } from './provider.js'\n\n// ============================================================================\n// Provider-Specific Configuration Types\n// ============================================================================\n\n/**\n * GCP-specific configuration fields\n */\nexport interface GcpProviderConfig {\n\t/** GCP Project ID */\n\tgcpProject: string\n}\n\n/**\n * AWS-specific configuration fields (future)\n */\nexport interface AwsProviderConfig {\n\t/** AWS Account ID */\n\tawsAccountId: string\n\t/** AWS Profile name */\n\tawsProfile?: string\n}\n\n/**\n * Azure-specific configuration fields (future)\n */\nexport interface AzureProviderConfig {\n\t/** Azure Subscription ID */\n\tsubscriptionId: string\n\t/** Azure Resource Group */\n\tresourceGroup: string\n}\n\n/**\n * Union of all provider configs\n */\nexport type ProviderConfig = GcpProviderConfig | AwsProviderConfig | AzureProviderConfig\n\n// ============================================================================\n// Deployment Outputs (Provider-Specific)\n// ============================================================================\n\n/**\n * Base deployment outputs common to all providers\n */\nexport interface BaseDeploymentOutputs {\n\t/** Container registry URL */\n\tregistryUrl: string\n\t/** Service URL after deployment */\n\tserviceUrl?: string\n}\n\n/**\n * GCP-specific deployment outputs\n */\nexport interface GcpDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** Cloud SQL connection name for Cloud SQL Auth Proxy */\n\tdatabaseConnectionName: string\n\t/** Database name inside Cloud SQL instance */\n\tdatabaseName?: string\n\t/** Database user for Cloud SQL */\n\tdatabaseUser?: string\n\t/** Memorystore Redis private IP address */\n\tredisHost: string\n\t/** Secret Manager secret IDs */\n\tsecretIds: {\n\t\t/** Database password secret ID */\n\t\tdbPassword: string\n\t\t/** Redis AUTH string secret ID */\n\t\tredisAuth: string\n\t}\n\t/** Cloud Run Job name for database migrations */\n\tmigrationJobName?: string\n}\n\n/**\n * AWS-specific deployment outputs (future)\n */\nexport interface AwsDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** RDS instance endpoint */\n\tdatabaseEndpoint?: string\n\t/** ElastiCache endpoint */\n\tredisEndpoint?: string\n\t/** ECS service ARN */\n\tecsServiceArn?: string\n}\n\n/**\n * Azure-specific deployment outputs (future)\n */\nexport interface AzureDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** Azure SQL server name */\n\tsqlServerName?: string\n\t/** Azure Cache for Redis hostname */\n\tredisHostname?: string\n\t/** Container Apps URL */\n\tcontainerAppUrl?: string\n}\n\n/**\n * Union of all deployment output types\n */\nexport type DeploymentOutputs = GcpDeploymentOutputs | AwsDeploymentOutputs | AzureDeploymentOutputs\n\n// ============================================================================\n// Stored Infrastructure Configuration\n// ============================================================================\n\n/**\n * Supported cloud provider IDs\n */\nexport type SupportedProvider = 'gcp' | 'aws' | 'azure'\n\n/**\n * CLI config stored in .kuckit/infra.json\n *\n * This is an extended version of BaseInfraConfig with additional fields\n * specific to CLI storage and provider management.\n */\nexport interface StoredInfraConfig extends BaseInfraConfig {\n\t/**\n\t * Provider ID (e.g., 'gcp', 'aws', 'azure')\n\t * @override Narrows the base string type to supported providers\n\t */\n\tprovider: SupportedProvider\n\n\t/**\n\t * npm package name of the provider (e.g., '@kuckit/infra-gcp')\n\t * Used to load the provider dynamically at runtime.\n\t */\n\tproviderPackage: string\n\n\t/**\n\t * Environment (dev/staging/prod)\n\t * @override Narrows to common environments\n\t */\n\tenv: 'dev' | 'staging' | 'prod'\n\n\t/**\n\t * Provider-specific configuration.\n\t * Contains fields that vary by cloud provider.\n\t */\n\tproviderConfig: ProviderConfig\n\n\t/**\n\t * Optional local infrastructure directory.\n\t * Set when provider has been ejected for customization.\n\t * If not set, uses provider's bundled infra.\n\t */\n\tlocalInfraDir?: string\n\n\t/**\n\t * Deployment outputs from the last successful deployment.\n\t * Structure varies by provider.\n\t */\n\toutputs?: DeploymentOutputs\n}\n\n// ============================================================================\n// Legacy Type Support (Backward Compatibility)\n// ============================================================================\n\n/**\n * Legacy config format (pre-provider-module)\n * Used for migration and backward compatibility\n *\n * @deprecated Use StoredInfraConfig instead\n */\nexport interface LegacyInfraConfig {\n\tprovider: 'gcp'\n\tgcpProject: string\n\tregion: string\n\tprojectName: string\n\tstackName: string\n\tenv: 'dev' | 'prod'\n\toutputs?: GcpDeploymentOutputs\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\n/**\n * Check if config is legacy format\n */\nexport function isLegacyConfig(\n\tconfig: StoredInfraConfig | LegacyInfraConfig\n): config is LegacyInfraConfig {\n\treturn 'gcpProject' in config && !('providerPackage' in config)\n}\n\n/**\n * Migrate legacy config to new format\n */\nexport function migrateLegacyConfig(legacy: LegacyInfraConfig): StoredInfraConfig {\n\treturn {\n\t\tprovider: 'gcp',\n\t\tproviderPackage: '@kuckit/infra-gcp',\n\t\tregion: legacy.region,\n\t\tprojectName: legacy.projectName,\n\t\tstackName: legacy.stackName,\n\t\tenv: legacy.env,\n\t\tproviderConfig: {\n\t\t\tgcpProject: legacy.gcpProject,\n\t\t},\n\t\toutputs: legacy.outputs,\n\t\tcreatedAt: legacy.createdAt,\n\t\tupdatedAt: legacy.updatedAt,\n\t}\n}\n\n// ============================================================================\n// Type Guards for Provider-Specific Configs\n// ============================================================================\n\n/**\n * Check if config is for GCP\n */\nexport function isGcpConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'gcp'\n\tproviderConfig: GcpProviderConfig\n\toutputs?: GcpDeploymentOutputs\n} {\n\treturn config.provider === 'gcp'\n}\n\n/**\n * Check if config is for AWS\n */\nexport function isAwsConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'aws'\n\tproviderConfig: AwsProviderConfig\n\toutputs?: AwsDeploymentOutputs\n} {\n\treturn config.provider === 'aws'\n}\n\n/**\n * Check if config is for Azure\n */\nexport function isAzureConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'azure'\n\tproviderConfig: AzureProviderConfig\n\toutputs?: AzureDeploymentOutputs\n} {\n\treturn config.provider === 'azure'\n}\n","/**\n * KuckitInfraProvider Interface\n *\n * This interface defines the contract that all cloud infrastructure providers must implement.\n * It enables multi-cloud support by abstracting provider-specific logic behind a common interface.\n *\n * Provider packages (e.g., @kuckit/infra-gcp, @kuckit/infra-aws) implement this interface\n * and are discovered/loaded by the CLI at runtime.\n *\n * @example\n * ```typescript\n * // In @kuckit/infra-gcp/src/provider.ts\n * import { defineInfraProvider } from '@kuckit/cli'\n *\n * export const provider = defineInfraProvider({\n * id: 'gcp',\n * label: 'Google Cloud Platform',\n * // ... implementation\n * })\n * ```\n */\n\n/**\n * Base configuration stored by CLI (provider-agnostic fields)\n */\nexport interface BaseInfraConfig {\n\t/** Provider ID (e.g., 'gcp', 'aws', 'azure') */\n\tprovider: string\n\t/** Environment (dev/staging/prod) */\n\tenv: string\n\t/** Deployment region */\n\tregion: string\n\t/** Project/app name for resource naming */\n\tprojectName: string\n\t/** Pulumi stack name */\n\tstackName: string\n\t/** ISO timestamp of config creation */\n\tcreatedAt: string\n\t/** ISO timestamp of last update */\n\tupdatedAt: string\n}\n\n/**\n * Result from an infrastructure operation (init/deploy/destroy)\n */\nexport interface InfraOperationResult<TOutputs = Record<string, unknown>> {\n\t/** Whether the operation succeeded */\n\tsuccess: boolean\n\t/** Human-readable message */\n\tmessage: string\n\t/** Deployment outputs (only on success) */\n\toutputs?: TOutputs\n\t/** Error details (only on failure) */\n\terror?: {\n\t\tcode: string\n\t\tmessage: string\n\t\tdetails?: string\n\t}\n}\n\n/**\n * Options passed to provider init\n */\nexport interface ProviderInitOptions {\n\t/** Environment to initialize */\n\tenv: string\n\t/** Target region */\n\tregion: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Skip confirmation prompts */\n\tyes?: boolean\n\t/** Provider-specific options */\n\tproviderOptions?: Record<string, unknown>\n}\n\n/**\n * Options passed to provider deploy\n */\nexport interface ProviderDeployOptions {\n\t/** Environment to deploy */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Preview changes without applying */\n\tpreview?: boolean\n\t/** Skip Docker build (use existing image) */\n\tskipBuild?: boolean\n\t/** Use specific image URL */\n\timage?: string\n\t/** Skip confirmation prompts */\n\tyes?: boolean\n}\n\n/**\n * Options passed to provider destroy\n */\nexport interface ProviderDestroyOptions {\n\t/** Environment to destroy */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Only destroy application layer, keep persistent resources */\n\tappOnly?: boolean\n\t/** Skip confirmation prompts */\n\tforce?: boolean\n}\n\n/**\n * Options passed to provider status check\n */\nexport interface ProviderStatusOptions {\n\t/** Environment to check */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n}\n\n/**\n * Status information returned by provider\n */\nexport interface ProviderStatus {\n\t/** Whether infrastructure is deployed */\n\tdeployed: boolean\n\t/** Current state (initializing/ready/deploying/error) */\n\tstate: 'initializing' | 'ready' | 'deploying' | 'error' | 'not_initialized'\n\t/** Service URL if deployed */\n\tserviceUrl?: string\n\t/** Last deployment timestamp */\n\tlastDeployment?: string\n\t/** Provider-specific status details */\n\tdetails?: Record<string, unknown>\n}\n\n/**\n * Options for ejecting provider to local packages\n */\nexport interface ProviderEjectOptions {\n\t/** Target directory for ejected code */\n\ttargetDir: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Skip confirmation prompts */\n\tforce?: boolean\n}\n\n/**\n * The main infrastructure provider interface.\n *\n * All provider packages must export a `provider` object implementing this interface.\n * The CLI discovers and loads providers dynamically based on installed packages.\n *\n * @typeParam TConfig - Provider-specific configuration extending BaseInfraConfig\n * @typeParam TOutputs - Provider-specific deployment outputs\n */\nexport interface KuckitInfraProvider<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n> {\n\t/**\n\t * Unique provider identifier (e.g., 'gcp', 'aws', 'azure')\n\t * Used for config storage and provider resolution\n\t */\n\treadonly id: string\n\n\t/**\n\t * Human-readable provider name for display\n\t * (e.g., 'Google Cloud Platform', 'Amazon Web Services')\n\t */\n\treadonly label: string\n\n\t/**\n\t * Provider version (semver)\n\t */\n\treadonly version: string\n\n\t/**\n\t * Get the infrastructure directory path for this provider.\n\t * This is where Pulumi/Terraform/CDK code lives.\n\t *\n\t * @param projectRoot - The project root directory\n\t * @returns Absolute path to infrastructure directory\n\t */\n\tgetInfraDir(projectRoot: string): string\n\n\t/**\n\t * Check if provider prerequisites are met (CLI tools, auth, etc.)\n\t *\n\t * @returns Object with status and any missing prerequisites\n\t */\n\tcheckPrerequisites(): Promise<{\n\t\tok: boolean\n\t\tmissing: Array<{ name: string; installUrl: string }>\n\t}>\n\n\t/**\n\t * Initialize base infrastructure for the project.\n\t * Creates foundational resources (VPC, registry, database) without deploying the app.\n\t *\n\t * @param options - Initialization options\n\t * @returns Operation result with deployment outputs\n\t */\n\tinit(options: ProviderInitOptions): Promise<InfraOperationResult<TOutputs>>\n\n\t/**\n\t * Deploy the application to the infrastructure.\n\t * Builds container image (if needed) and deploys to compute platform.\n\t *\n\t * @param options - Deployment options\n\t * @param config - Current stored configuration\n\t * @returns Operation result with deployment outputs\n\t */\n\tdeploy(options: ProviderDeployOptions, config: TConfig): Promise<InfraOperationResult<TOutputs>>\n\n\t/**\n\t * Destroy infrastructure resources.\n\t *\n\t * @param options - Destroy options\n\t * @param config - Current stored configuration\n\t * @returns Operation result\n\t */\n\tdestroy(options: ProviderDestroyOptions, config: TConfig): Promise<InfraOperationResult>\n\n\t/**\n\t * Get current infrastructure status.\n\t *\n\t * @param options - Status options\n\t * @param config - Current stored configuration\n\t * @returns Current provider status\n\t */\n\tstatus(options: ProviderStatusOptions, config: TConfig): Promise<ProviderStatus>\n\n\t/**\n\t * Get provider-specific configuration prompts for init.\n\t * Returns questions to ask user during interactive init.\n\t *\n\t * @param defaults - Any existing config values to use as defaults\n\t * @returns Array of prompts for inquirer\n\t */\n\tgetInitPrompts(defaults?: Partial<TConfig>): Promise<\n\t\tArray<{\n\t\t\tname: string\n\t\t\tmessage: string\n\t\t\ttype: 'input' | 'select' | 'confirm'\n\t\t\tdefault?: string | boolean\n\t\t\tchoices?: Array<{ value: string; label: string }>\n\t\t\tvalidate?: (value: string) => boolean | string\n\t\t}>\n\t>\n\n\t/**\n\t * Build provider-specific config from user responses.\n\t *\n\t * @param responses - User responses from init prompts\n\t * @param baseConfig - Base config fields\n\t * @returns Complete provider config\n\t */\n\tbuildConfig(\n\t\tresponses: Record<string, unknown>,\n\t\tbaseConfig: Pick<BaseInfraConfig, 'env' | 'region' | 'projectName' | 'stackName'>\n\t): TConfig\n\n\t/**\n\t * Optional: Eject provider infrastructure code to local project.\n\t * Allows customization of infrastructure beyond provider defaults.\n\t *\n\t * @param options - Eject options\n\t * @returns Operation result\n\t */\n\teject?(options: ProviderEjectOptions): Promise<InfraOperationResult>\n\n\t/**\n\t * Optional: Generate Dockerfile for the project.\n\t * Providers can include optimized Dockerfile templates.\n\t *\n\t * @param projectRoot - Project root directory\n\t * @returns Dockerfile content or null if using existing\n\t */\n\tgenerateDockerfile?(projectRoot: string): Promise<string | null>\n\n\t/**\n\t * Optional: Validate that project structure is compatible with provider.\n\t *\n\t * @param projectRoot - Project root directory\n\t * @returns Validation result with any issues\n\t */\n\tvalidateProject?(projectRoot: string): Promise<{\n\t\tvalid: boolean\n\t\tissues: Array<{ severity: 'error' | 'warning'; message: string }>\n\t}>\n}\n\n/**\n * Helper to define a provider with type inference.\n *\n * @example\n * ```typescript\n * export const provider = defineInfraProvider({\n * id: 'gcp',\n * label: 'Google Cloud Platform',\n * version: '1.0.0',\n * getInfraDir: (root) => join(root, 'node_modules/@kuckit/infra-gcp/infra'),\n * // ... rest of implementation\n * })\n * ```\n */\nexport function defineInfraProvider<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n>(provider: KuckitInfraProvider<TConfig, TOutputs>): KuckitInfraProvider<TConfig, TOutputs> {\n\treturn provider\n}\n\n/**\n * Type for the provider module export.\n * Provider packages should default export this shape.\n */\nexport interface KuckitInfraProviderModule<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n> {\n\tprovider: KuckitInfraProvider<TConfig, TOutputs>\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"provider-CzYx3ADU.js","names":["newEntry: string","before","after","pm","discovered: DiscoveredModule[]","writeFile","result: DiscoverResult"],"sources":["../src/commands/generate-module.ts","../src/commands/add-module.ts","../src/lib/sdk-loader.ts","../src/commands/discover-module.ts","../src/commands/infra/types.ts","../src/commands/infra/provider.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\ninterface GenerateModuleOptions {\n\torg: string\n\tdir: string\n}\n\nfunction toKebabCase(str: string): string {\n\treturn str\n\t\t.replace(/([a-z])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase()\n}\n\nfunction toPascalCase(str: string): string {\n\treturn str\n\t\t.split(/[-_\\s]+/)\n\t\t.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join('')\n}\n\nfunction toCamelCase(str: string): string {\n\tconst pascal = toPascalCase(str)\n\treturn pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\nexport async function generateModule(name: string, options: GenerateModuleOptions): Promise<void> {\n\tconst kebabName = toKebabCase(name)\n\tconst pascalName = toPascalCase(name)\n\tconst camelName = toCamelCase(name)\n\tconst moduleDirName = `${kebabName}-module`\n\n\tconst packageName = options.org ? `@${options.org}/${moduleDirName}` : `@kuckit/${moduleDirName}`\n\tconst moduleId = options.org ? `${options.org}.${kebabName}` : `kuckit.${kebabName}`\n\n\tconst targetDir = join(process.cwd(), options.dir, moduleDirName)\n\n\tconsole.log(`Creating module: ${packageName}`)\n\tconsole.log(` Directory: ${targetDir}`)\n\n\t// Create directory structure (Clean Architecture)\n\tawait mkdir(join(targetDir, 'src', 'domain'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'ports'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'adapters'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'usecases'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'api'), { recursive: true })\n\tawait mkdir(join(targetDir, 'src', 'ui'), { recursive: true })\n\n\t// Generate package.json\n\tconst packageJson = {\n\t\tname: packageName,\n\t\tversion: '0.1.0',\n\t\tprivate: true,\n\t\tdescription: `${pascalName} module for Kuckit`,\n\t\ttype: 'module',\n\t\tmain: 'src/index.ts',\n\t\ttypes: 'src/index.ts',\n\t\texports: {\n\t\t\t'.': {\n\t\t\t\ttypes: './src/index.ts',\n\t\t\t\tdefault: './src/index.ts',\n\t\t\t},\n\t\t\t'./client': {\n\t\t\t\ttypes: './src/client-module.ts',\n\t\t\t\tdefault: './src/client-module.ts',\n\t\t\t},\n\t\t\t'./ui': {\n\t\t\t\ttypes: './src/ui/index.ts',\n\t\t\t\tdefault: './src/ui/index.ts',\n\t\t\t},\n\t\t},\n\t\tpeerDependencies: {\n\t\t\ttypescript: '^5',\n\t\t},\n\t\tdependencies: {\n\t\t\t'@kuckit/sdk': '^1.0.0',\n\t\t\t'@kuckit/sdk-react': '^1.0.0',\n\t\t\t'@kuckit/api': '^1.0.0',\n\t\t\t'@orpc/server': '^1.10.0',\n\t\t\t'@orpc/zod': '^1.10.0',\n\t\t\t'drizzle-orm': '^0.44.0',\n\t\t\tzod: '^3.23.0',\n\t\t\treact: '^19.0.0',\n\t\t\t'@tanstack/react-query': '^5.0.0',\n\t\t},\n\t}\n\n\tawait writeFile(join(targetDir, 'package.json'), JSON.stringify(packageJson, null, '\\t') + '\\n')\n\n\t// Generate tsconfig.json\n\tconst tsconfig = {\n\t\textends: '../../tsconfig.base.json',\n\t\tcompilerOptions: {\n\t\t\toutDir: 'dist',\n\t\t\trootDir: 'src',\n\t\t},\n\t\tinclude: ['src'],\n\t}\n\n\tawait writeFile(join(targetDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, '\\t') + '\\n')\n\n\t// =====================\n\t// DOMAIN LAYER\n\t// =====================\n\n\tconst entityFile = `import { z } from 'zod'\n\n/**\n * ${pascalName} entity schema\n */\nexport const ${pascalName}Schema = z.object({\n\tid: z.string(),\n\tname: z.string().min(1, 'Name is required'),\n\tdescription: z.string().optional(),\n\tcreatedAt: z.date(),\n\tupdatedAt: z.date(),\n\tuserId: z.string(),\n})\n\nexport type ${pascalName} = z.infer<typeof ${pascalName}Schema>\n\n/**\n * Create ${camelName} input schema\n */\nexport const Create${pascalName}InputSchema = z.object({\n\tname: z.string().min(1, 'Name is required'),\n\tdescription: z.string().optional(),\n})\n\nexport type Create${pascalName}Input = z.infer<typeof Create${pascalName}InputSchema>\n\n/**\n * Update ${camelName} input schema\n */\nexport const Update${pascalName}InputSchema = z.object({\n\tid: z.string(),\n\tname: z.string().min(1, 'Name is required').optional(),\n\tdescription: z.string().optional(),\n})\n\nexport type Update${pascalName}Input = z.infer<typeof Update${pascalName}InputSchema>\n`\n\n\tawait writeFile(join(targetDir, 'src', 'domain', `${kebabName}.entity.ts`), entityFile)\n\n\t// =====================\n\t// PORTS LAYER\n\t// =====================\n\n\tconst repositoryPort = `import type { ${pascalName}, Create${pascalName}Input, Update${pascalName}Input } from '../domain/${kebabName}.entity'\n\n/**\n * ${pascalName} repository port interface\n * Defines the contract for ${camelName} persistence operations\n */\nexport interface ${pascalName}Repository {\n\tfindById(id: string): Promise<${pascalName} | null>\n\tfindByUserId(userId: string): Promise<${pascalName}[]>\n\tcreate(input: Create${pascalName}Input & { id: string; userId: string }): Promise<${pascalName}>\n\tupdate(input: Update${pascalName}Input): Promise<${pascalName} | null>\n\tdelete(id: string): Promise<boolean>\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ports', `${kebabName}.repository.ts`), repositoryPort)\n\n\t// =====================\n\t// ADAPTERS LAYER\n\t// =====================\n\n\tconst drizzleAdapter = `import { pgTable, text, timestamp } from 'drizzle-orm/pg-core'\nimport { eq } from 'drizzle-orm'\nimport type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName}, Create${pascalName}Input, Update${pascalName}Input } from '../domain/${kebabName}.entity'\n\n/**\n * ${pascalName}s table schema for Drizzle ORM\n */\nexport const ${camelName}sTable = pgTable('${kebabName}s', {\n\tid: text('id').primaryKey(),\n\tname: text('name').notNull(),\n\tdescription: text('description'),\n\tcreatedAt: timestamp('created_at').notNull().defaultNow(),\n\tupdatedAt: timestamp('updated_at').notNull().defaultNow(),\n\tuserId: text('user_id').notNull(),\n})\n\n/**\n * Create a Drizzle-based ${camelName} repository\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function make${pascalName}Repository(db: any): ${pascalName}Repository {\n\treturn {\n\t\tasync findById(id: string): Promise<${pascalName} | null> {\n\t\t\tconst results = await db.select().from(${camelName}sTable).where(eq(${camelName}sTable.id, id))\n\t\t\treturn results[0] ?? null\n\t\t},\n\n\t\tasync findByUserId(userId: string): Promise<${pascalName}[]> {\n\t\t\treturn db.select().from(${camelName}sTable).where(eq(${camelName}sTable.userId, userId))\n\t\t},\n\n\t\tasync create(input: Create${pascalName}Input & { id: string; userId: string }): Promise<${pascalName}> {\n\t\t\tconst now = new Date()\n\t\t\tconst ${camelName} = {\n\t\t\t\tid: input.id,\n\t\t\t\tname: input.name,\n\t\t\t\tdescription: input.description ?? null,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\tuserId: input.userId,\n\t\t\t}\n\t\t\tawait db.insert(${camelName}sTable).values(${camelName})\n\t\t\treturn ${camelName} as ${pascalName}\n\t\t},\n\n\t\tasync update(input: Update${pascalName}Input): Promise<${pascalName} | null> {\n\t\t\tconst existing = await this.findById(input.id)\n\t\t\tif (!existing) return null\n\n\t\t\tconst updated = {\n\t\t\t\t...existing,\n\t\t\t\t...(input.name !== undefined && { name: input.name }),\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t}\n\t\t\tawait db.update(${camelName}sTable).set(updated).where(eq(${camelName}sTable.id, input.id))\n\t\t\treturn updated\n\t\t},\n\n\t\tasync delete(id: string): Promise<boolean> {\n\t\t\tconst result = await db.delete(${camelName}sTable).where(eq(${camelName}sTable.id, id))\n\t\t\treturn result.rowCount > 0\n\t\t},\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'adapters', `${kebabName}.drizzle.ts`), drizzleAdapter)\n\n\t// =====================\n\t// USE CASES LAYER\n\t// =====================\n\n\tconst listUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName} } from '../domain/${kebabName}.entity'\n\ninterface List${pascalName}sDeps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * List ${camelName}s use case\n */\nexport function makeList${pascalName}s(deps: List${pascalName}sDeps) {\n\treturn async (userId: string): Promise<${pascalName}[]> => {\n\t\treturn deps.${camelName}Repository.findByUserId(userId)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `list-${kebabName}s.ts`), listUseCase)\n\n\tconst getUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName} } from '../domain/${kebabName}.entity'\n\ninterface Get${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Get ${camelName} use case\n */\nexport function makeGet${pascalName}(deps: Get${pascalName}Deps) {\n\treturn async (id: string): Promise<${pascalName} | null> => {\n\t\treturn deps.${camelName}Repository.findById(id)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `get-${kebabName}.ts`), getUseCase)\n\n\tconst createUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\nimport type { ${pascalName}, Create${pascalName}Input } from '../domain/${kebabName}.entity'\n\nexport interface Create${pascalName}UseCaseInput extends Create${pascalName}Input {\n\tuserId: string\n}\n\ninterface Create${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Create ${camelName} use case\n */\nexport function makeCreate${pascalName}(deps: Create${pascalName}Deps) {\n\treturn async (input: Create${pascalName}UseCaseInput): Promise<${pascalName}> => {\n\t\tconst id = crypto.randomUUID()\n\t\treturn deps.${camelName}Repository.create({\n\t\t\tid,\n\t\t\tname: input.name,\n\t\t\tdescription: input.description,\n\t\t\tuserId: input.userId,\n\t\t})\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `create-${kebabName}.ts`), createUseCase)\n\n\tconst deleteUseCase = `import type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\n\ninterface Delete${pascalName}Deps {\n\t${camelName}Repository: ${pascalName}Repository\n}\n\n/**\n * Delete ${camelName} use case\n */\nexport function makeDelete${pascalName}(deps: Delete${pascalName}Deps) {\n\treturn async (id: string): Promise<boolean> => {\n\t\treturn deps.${camelName}Repository.delete(id)\n\t}\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'usecases', `delete-${kebabName}.ts`), deleteUseCase)\n\n\t// =====================\n\t// API LAYER\n\t// =====================\n\n\tconst routerFile = `import { z } from 'zod'\nimport { protectedProcedure } from '@kuckit/api'\nimport { Create${pascalName}InputSchema } from '../domain/${kebabName}.entity'\nimport type { ${pascalName}Repository } from '../ports/${kebabName}.repository'\n\n/**\n * ${pascalName}s oRPC router\n * Provides CRUD operations for ${camelName}s\n */\nexport const ${camelName}sRouter = {\n\tlist: protectedProcedure.input(z.object({})).handler(async ({ context }) => {\n\t\tconst userId = context.session?.user?.id\n\t\tif (!userId) throw new Error('User not authenticated')\n\n\t\tconst ${camelName}s = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').findByUserId(userId)\n\t\treturn ${camelName}s\n\t}),\n\n\tget: protectedProcedure\n\t\t.input(z.object({ id: z.string() }))\n\t\t.handler(async ({ input, context }) => {\n\t\t\tconst ${camelName} = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').findById(input.id)\n\t\t\treturn ${camelName}\n\t\t}),\n\n\tcreate: protectedProcedure.input(Create${pascalName}InputSchema).handler(async ({ input, context }) => {\n\t\tconst userId = context.session?.user?.id\n\t\tif (!userId) throw new Error('User not authenticated')\n\n\t\tconst id = crypto.randomUUID()\n\t\tconst ${camelName} = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').create({\n\t\t\tid,\n\t\t\tname: input.name,\n\t\t\tdescription: input.description,\n\t\t\tuserId,\n\t\t})\n\t\treturn ${camelName}\n\t}),\n\n\tdelete: protectedProcedure\n\t\t.input(z.object({ id: z.string() }))\n\t\t.handler(async ({ input, context }) => {\n\t\t\tconst success = await context.di.resolve<${pascalName}Repository>('${camelName}Repository').delete(input.id)\n\t\t\treturn { success }\n\t\t}),\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'api', `${kebabName}s.router.ts`), routerFile)\n\n\t// =====================\n\t// UI LAYER\n\t// =====================\n\n\tconst pageComponent = `import { useState } from 'react'\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useRpc } from '@kuckit/sdk-react'\n\ninterface ${pascalName} {\n\tid: string\n\tname: string\n\tdescription?: string\n\tcreatedAt: Date\n\tupdatedAt: Date\n}\n\ninterface ${pascalName}sRpc {\n\t${camelName}s: {\n\t\tlist: (input: Record<string, never>) => Promise<${pascalName}[]>\n\t\tcreate: (input: { name: string; description?: string }) => Promise<${pascalName}>\n\t\tdelete: (input: { id: string }) => Promise<void>\n\t}\n}\n\n/**\n * ${pascalName}s page component\n * Demonstrates CRUD operations using the ${camelName}s module with useRpc and TanStack Query\n */\nexport function ${pascalName}sPage() {\n\tconst rpc = useRpc<${pascalName}sRpc>()\n\tconst queryClient = useQueryClient()\n\tconst [newName, setNewName] = useState('')\n\tconst [newDescription, setNewDescription] = useState('')\n\n\tconst {\n\t\tdata: ${camelName}s = [],\n\t\tisLoading,\n\t\terror,\n\t} = useQuery({\n\t\tqueryKey: ['${camelName}s'],\n\t\tqueryFn: () => rpc.${camelName}s.list({}),\n\t})\n\n\tconst createMutation = useMutation({\n\t\tmutationFn: (data: { name: string; description?: string }) => rpc.${camelName}s.create(data),\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: ['${camelName}s'] }),\n\t})\n\n\tconst deleteMutation = useMutation({\n\t\tmutationFn: (id: string) => rpc.${camelName}s.delete({ id }),\n\t\tonSuccess: () => queryClient.invalidateQueries({ queryKey: ['${camelName}s'] }),\n\t})\n\n\tconst create${pascalName} = async (e: React.FormEvent) => {\n\t\te.preventDefault()\n\t\tif (!newName.trim()) return\n\n\t\tcreateMutation.mutate(\n\t\t\t{ name: newName, description: newDescription || undefined },\n\t\t\t{\n\t\t\t\tonSuccess: () => {\n\t\t\t\t\tsetNewName('')\n\t\t\t\t\tsetNewDescription('')\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t}\n\n\tconst delete${pascalName} = (id: string) => {\n\t\tdeleteMutation.mutate(id)\n\t}\n\n\tif (isLoading) {\n\t\treturn <div style={{ padding: '2rem' }}>Loading ${camelName}s...</div>\n\t}\n\n\treturn (\n\t\t<div style={{ padding: '2rem', fontFamily: 'system-ui', maxWidth: '600px', margin: '0 auto' }}>\n\t\t\t<h1>${pascalName}s</h1>\n\n\t\t\t{(error || createMutation.error || deleteMutation.error) && (\n\t\t\t\t<div style={{ color: 'red', marginBottom: '1rem' }}>\n\t\t\t\t\t{error?.message || createMutation.error?.message || deleteMutation.error?.message}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<form onSubmit={create${pascalName}} style={{ marginBottom: '2rem' }}>\n\t\t\t\t<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Name\"\n\t\t\t\t\t\tvalue={newName}\n\t\t\t\t\t\tonChange={(e) => setNewName(e.target.value)}\n\t\t\t\t\t\trequired\n\t\t\t\t\t\tstyle={{ padding: '0.5rem', fontSize: '1rem' }}\n\t\t\t\t\t/>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Description (optional)\"\n\t\t\t\t\t\tvalue={newDescription}\n\t\t\t\t\t\tonChange={(e) => setNewDescription(e.target.value)}\n\t\t\t\t\t\tstyle={{ padding: '0.5rem', fontSize: '1rem' }}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\tdisabled={createMutation.isPending}\n\t\t\t\t\t\tstyle={{ padding: '0.5rem 1rem', cursor: 'pointer' }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{createMutation.isPending ? 'Adding...' : 'Add ${pascalName}'}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</form>\n\n\t\t\t<ul style={{ listStyle: 'none', padding: 0 }}>\n\t\t\t\t{${camelName}s.map((${camelName}) => (\n\t\t\t\t\t<li\n\t\t\t\t\t\tkey={${camelName}.id}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tpadding: '1rem',\n\t\t\t\t\t\t\tborder: '1px solid #ccc',\n\t\t\t\t\t\t\tmarginBottom: '0.5rem',\n\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\tjustifyContent: 'space-between',\n\t\t\t\t\t\t\talignItems: 'center',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<strong>{${camelName}.name}</strong>\n\t\t\t\t\t\t\t{${camelName}.description && (\n\t\t\t\t\t\t\t\t<p style={{ margin: '0.5rem 0 0 0', color: '#666' }}>{${camelName}.description}</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tonClick={() => delete${pascalName}(${camelName}.id)}\n\t\t\t\t\t\t\tdisabled={deleteMutation.isPending}\n\t\t\t\t\t\t\tstyle={{ cursor: 'pointer', color: 'red', background: 'none', border: 'none' }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tDelete\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</li>\n\t\t\t\t))}\n\t\t\t</ul>\n\n\t\t\t{${camelName}s.length === 0 && <p>No ${camelName}s yet. Create one above!</p>}\n\t\t</div>\n\t)\n}\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ui', `${pascalName}sPage.tsx`), pageComponent)\n\n\tconst uiIndex = `export { ${pascalName}sPage } from './${pascalName}sPage'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'ui', 'index.ts'), uiIndex)\n\n\t// =====================\n\t// SERVER MODULE\n\t// =====================\n\n\tconst serverModule = `import { defineKuckitModule, asFunction, type KuckitModuleContext } from '@kuckit/sdk'\nimport { ${camelName}sTable, make${pascalName}Repository } from './adapters/${kebabName}.drizzle'\nimport { ${camelName}sRouter } from './api/${kebabName}s.router'\n\nexport type ${pascalName}ModuleConfig = Record<string, never>\n\n/**\n * ${pascalName} module - Kuckit module demonstrating Clean Architecture pattern\n *\n * This module shows:\n * - Domain entity with Zod validation\n * - Repository port/adapter pattern\n * - Use cases for business logic\n * - oRPC router for API endpoints\n */\nexport const kuckitModule = defineKuckitModule<${pascalName}ModuleConfig>({\n\tid: '${moduleId}',\n\tdisplayName: '${pascalName}',\n\tdescription: '${pascalName} module for CRUD operations',\n\tversion: '0.1.0',\n\n\tasync register(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\n\t\t// Register schema for migrations\n\t\tctx.registerSchema('${camelName}s', ${camelName}sTable)\n\n\t\t// Register repository\n\t\tcontainer.register({\n\t\t\t${camelName}Repository: asFunction(({ db }) => make${pascalName}Repository(db)).scoped(),\n\t\t})\n\t},\n\n\tregisterApi(ctx) {\n\t\tctx.addApiRegistration({\n\t\t\ttype: 'rpc-router',\n\t\t\tname: '${camelName}s',\n\t\t\trouter: ${camelName}sRouter,\n\t\t})\n\t},\n\n\tasync onBootstrap(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\t\tconst logger = container.resolve('logger')\n\t\tlogger.info('${pascalName} module initialized')\n\t},\n\n\tasync onShutdown(ctx: KuckitModuleContext<${pascalName}ModuleConfig>) {\n\t\tconst { container } = ctx\n\t\tconst logger = container.resolve('logger')\n\t\tlogger.info('${pascalName} module shutting down')\n\t},\n})\n`\n\n\tawait writeFile(join(targetDir, 'src', 'module.ts'), serverModule)\n\n\t// =====================\n\t// CLIENT MODULE\n\t// =====================\n\n\tconst clientModule = `import { defineKuckitClientModule, type KuckitClientModuleContext } from '@kuckit/sdk-react'\nimport { ${pascalName}sPage } from './ui/${pascalName}sPage'\n\n/**\n * ${pascalName} client module\n * Registers routes and components for the web app\n */\nexport const kuckitClientModule = defineKuckitClientModule({\n\tid: '${moduleId}',\n\tdisplayName: '${pascalName}',\n\tversion: '0.1.0',\n\n\tregister(ctx: KuckitClientModuleContext) {\n\t\t// Register the ${camelName}s page component\n\t\tctx.registerComponent('${pascalName}sPage', ${pascalName}sPage)\n\n\t\t// Add route for ${camelName}s page\n\t\tctx.addRoute({\n\t\t\tid: '${kebabName}s',\n\t\t\tpath: '/${kebabName}s',\n\t\t\tcomponent: ${pascalName}sPage,\n\t\t\tmeta: {\n\t\t\t\ttitle: '${pascalName}s',\n\t\t\t\trequiresAuth: true,\n\t\t\t},\n\t\t})\n\n\t\t// Add navigation item\n\t\tctx.addNavItem({\n\t\t\tid: '${kebabName}s-nav',\n\t\t\tlabel: '${pascalName}s',\n\t\t\tpath: '/${kebabName}s',\n\t\t\ticon: 'list',\n\t\t\torder: 100,\n\t\t})\n\t},\n})\n\nexport { ${pascalName}sPage } from './ui/${pascalName}sPage'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'client-module.ts'), clientModule)\n\n\t// =====================\n\t// INDEX FILE\n\t// =====================\n\n\tconst indexFile = `// Server module\nexport { kuckitModule } from './module'\n\n// Domain\nexport * from './domain/${kebabName}.entity'\n\n// Ports\nexport type { ${pascalName}Repository } from './ports/${kebabName}.repository'\n\n// Adapters\nexport { ${camelName}sTable, make${pascalName}Repository } from './adapters/${kebabName}.drizzle'\n\n// Use cases\nexport { makeList${pascalName}s } from './usecases/list-${kebabName}s'\nexport { makeGet${pascalName} } from './usecases/get-${kebabName}'\nexport { makeCreate${pascalName} } from './usecases/create-${kebabName}'\nexport { makeDelete${pascalName} } from './usecases/delete-${kebabName}'\n\n// API\nexport { ${camelName}sRouter } from './api/${kebabName}s.router'\n`\n\n\tawait writeFile(join(targetDir, 'src', 'index.ts'), indexFile)\n\n\tconsole.log(`\n✅ Module created successfully!\n\n📁 Structure:\n ${options.dir}/${moduleDirName}/\n ├── src/\n │ ├── domain/\n │ │ └── ${kebabName}.entity.ts # Zod schema for entity\n │ ├── ports/\n │ │ └── ${kebabName}.repository.ts # Repository interface\n │ ├── adapters/\n │ │ └── ${kebabName}.drizzle.ts # Drizzle implementation\n │ ├── usecases/\n │ │ ├── list-${kebabName}s.ts\n │ │ ├── get-${kebabName}.ts\n │ │ ├── create-${kebabName}.ts\n │ │ └── delete-${kebabName}.ts\n │ ├── api/\n │ │ └── ${kebabName}s.router.ts # oRPC router\n │ ├── ui/\n │ │ └── ${pascalName}sPage.tsx # React component\n │ ├── module.ts # Server module\n │ ├── client-module.ts # Client module\n │ └── index.ts\n ├── package.json\n └── tsconfig.json\n\n📝 Next steps:\n 1. Run 'bun install' from the root to link the new package\n 2. Add server module to apps/server/src/config/modules.ts:\n import { kuckitModule as ${camelName}Module } from '${packageName}'\n // Then inside getModuleSpecs(), between the KUCKIT_SERVER_MODULES markers:\n { module: ${camelName}Module },\n 3. Add client module to apps/web/src/modules.client.ts:\n import { kuckitClientModule as ${camelName}Client } from '${packageName}/client'\n // Then inside getClientModuleSpecs(), between the KUCKIT_CLIENT_MODULES markers:\n { module: ${camelName}Client },\n 4. Add schema path to drizzle.config.ts:\n resolve(currentDirPath, './packages/${moduleDirName}/src/adapters'),\n 5. Run 'bun run db:push' to create the table\n`)\n}\n","import { execSync } from 'node:child_process'\nimport { readFile, writeFile, access, mkdir, copyFile } from 'node:fs/promises'\nimport { accessSync, constants, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\n\ninterface AddModuleOptions {\n\tskipInstall: boolean\n}\n\ninterface ScaffoldEntry {\n\ttype: 'directory' | 'template'\n\tpath: string\n\tsrc?: string // For templates, relative to module package\n\tdest?: string // For templates, destination in project\n}\n\ninterface KuckitSetup {\n\tscaffolds?: ScaffoldEntry[]\n\tconfigDefaults?: Record<string, unknown>\n\tdevDependencies?: Record<string, string>\n\tpostInstallMessage?: string\n}\n\ninterface KuckitMetadata {\n\tid: string\n\tserver?: string\n\tclient?: string\n\tsetup?: KuckitSetup\n}\n\ninterface PackageJson {\n\tname: string\n\tkuckit?: KuckitMetadata\n}\n\nconst CONFIG_FILES = ['kuckit.config.ts', 'kuckit.config.js', 'kuckit.config.mjs']\n\nasync function fileExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path, constants.F_OK)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction findConfigFile(cwd: string): string | null {\n\tfor (const file of CONFIG_FILES) {\n\t\tconst configPath = join(cwd, file)\n\t\tif (existsSync(configPath)) {\n\t\t\treturn configPath\n\t\t}\n\t}\n\treturn null\n}\n\nfunction detectPackageManager(cwd: string): 'bun' | 'npm' | 'yarn' | 'pnpm' {\n\tconst lockFiles: Record<string, 'bun' | 'npm' | 'yarn' | 'pnpm'> = {\n\t\t'bun.lock': 'bun',\n\t\t'bun.lockb': 'bun',\n\t\t'package-lock.json': 'npm',\n\t\t'yarn.lock': 'yarn',\n\t\t'pnpm-lock.yaml': 'pnpm',\n\t}\n\n\tfor (const [file, pm] of Object.entries(lockFiles)) {\n\t\ttry {\n\t\t\taccessSync(join(cwd, file), constants.F_OK)\n\t\t\treturn pm\n\t\t} catch {\n\t\t\t// continue\n\t\t}\n\t}\n\n\treturn 'npm'\n}\n\nasync function readPackageKuckitMetadata(\n\tpackageName: string,\n\tcwd: string\n): Promise<KuckitMetadata | null> {\n\t// After install, read from node_modules\n\tconst packageJsonPath = join(cwd, 'node_modules', packageName, 'package.json')\n\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg: PackageJson = JSON.parse(content)\n\t\treturn pkg.kuckit ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nconst MODULES_MARKER_START = '// KUCKIT_MODULES_START'\nconst MODULES_MARKER_END = '// KUCKIT_MODULES_END'\nconst CLIENT_MODULES_MARKER_START = '// KUCKIT_CLIENT_MODULES_START'\nconst CLIENT_MODULES_MARKER_END = '// KUCKIT_CLIENT_MODULES_END'\n\n/**\n * Execute module setup scaffolds (create directories, copy templates)\n */\nasync function executeSetupScaffolds(\n\tpackageName: string,\n\tsetup: KuckitSetup,\n\tcwd: string\n): Promise<void> {\n\tif (!setup.scaffolds || setup.scaffolds.length === 0) return\n\n\tconsole.log(` Running module setup...`)\n\tconst moduleDir = join(cwd, 'node_modules', packageName)\n\n\tfor (const scaffold of setup.scaffolds) {\n\t\tif (scaffold.type === 'directory') {\n\t\t\tconst dirPath = join(cwd, scaffold.path)\n\t\t\tif (!existsSync(dirPath)) {\n\t\t\t\tawait mkdir(dirPath, { recursive: true })\n\t\t\t\tconsole.log(` Created directory: ${scaffold.path}`)\n\t\t\t}\n\t\t} else if (scaffold.type === 'template' && scaffold.src && scaffold.dest) {\n\t\t\tconst srcPath = join(moduleDir, scaffold.src)\n\t\t\tconst destPath = join(cwd, scaffold.dest)\n\n\t\t\t// Don't overwrite existing files\n\t\t\tif (existsSync(destPath)) {\n\t\t\t\tconsole.log(` Skipped (exists): ${scaffold.dest}`)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Ensure destination directory exists\n\t\t\tawait mkdir(dirname(destPath), { recursive: true })\n\t\t\tawait copyFile(srcPath, destPath)\n\t\t\tconsole.log(` Created file: ${scaffold.dest}`)\n\t\t}\n\t}\n}\n\n/**\n * Install additional dev dependencies specified by module setup\n */\nasync function installSetupDependencies(\n\tsetup: KuckitSetup,\n\tcwd: string,\n\tpm: 'bun' | 'npm' | 'yarn' | 'pnpm'\n): Promise<void> {\n\tif (!setup.devDependencies || Object.keys(setup.devDependencies).length === 0) return\n\n\tconst deps = Object.entries(setup.devDependencies)\n\t\t.map(([name, version]) => `${name}@${version}`)\n\t\t.join(' ')\n\n\tconsole.log(` Installing additional dependencies...`)\n\tconst installCmd =\n\t\tpm === 'npm'\n\t\t\t? `npm install -D ${deps}`\n\t\t\t: pm === 'yarn'\n\t\t\t\t? `yarn add -D ${deps}`\n\t\t\t\t: `${pm} add -D ${deps}`\n\n\ttry {\n\t\texecSync(installCmd, { cwd: join(cwd, 'apps', 'web'), stdio: 'inherit' })\n\t} catch {\n\t\tconsole.warn(` Warning: Could not install ${deps} in apps/web`)\n\t}\n}\n\n/**\n * Add module to unified kuckit.config.ts with optional config\n */\nasync function addToUnifiedConfig(\n\tpackageName: string,\n\tconfigPath: string,\n\tmoduleConfig?: Record<string, unknown>\n): Promise<boolean> {\n\tlet content = await readFile(configPath, 'utf-8')\n\n\t// Check if package is already in config\n\tif (content.includes(`'${packageName}'`) || content.includes(`\"${packageName}\"`)) {\n\t\tconsole.log(` Module ${packageName} is already in ${configPath}`)\n\t\treturn true\n\t}\n\n\t// Find the modules array and add the new entry\n\t// Pattern: modules: [ ... ]\n\tconst modulesArrayMatch = content.match(/modules:\\s*\\[/)\n\tif (!modulesArrayMatch) {\n\t\tconsole.warn(`Warning: Could not find 'modules' array in ${configPath}`)\n\t\tconsole.log(` Please manually add: { package: '${packageName}' }`)\n\t\treturn false\n\t}\n\n\t// Find the position right after 'modules: ['\n\tconst insertPos = modulesArrayMatch.index! + modulesArrayMatch[0].length\n\n\t// Build the new entry with optional config\n\tlet newEntry: string\n\tif (moduleConfig && Object.keys(moduleConfig).length > 0) {\n\t\tconst configStr = JSON.stringify(moduleConfig, null, 2)\n\t\t\t.replace(/^/gm, '\\t\\t\\t') // Indent\n\t\t\t.replace(/^\\t\\t\\t{/, '{') // Fix opening brace\n\t\t\t.trim()\n\t\tnewEntry = `\\n\\t\\t{ package: '${packageName}', config: ${configStr} },`\n\t} else {\n\t\tnewEntry = `\\n\\t\\t{ package: '${packageName}' },`\n\t}\n\n\tcontent = content.slice(0, insertPos) + newEntry + content.slice(insertPos)\n\n\tawait writeFile(configPath, content)\n\tconsole.log(` Added to unified config: ${configPath}`)\n\treturn true\n}\n\nasync function addToServerModules(packageName: string, cwd: string): Promise<boolean> {\n\tconst modulesPath = join(cwd, 'apps', 'server', 'src', 'modules.ts')\n\n\tif (!(await fileExists(modulesPath))) {\n\t\tconsole.warn(`Warning: Server modules file not found at ${modulesPath}`)\n\t\treturn false\n\t}\n\n\tlet content = await readFile(modulesPath, 'utf-8')\n\n\t// Check if package is already added\n\tif (content.includes(`package: '${packageName}'`)) {\n\t\tconsole.log(` Module ${packageName} is already in server modules`)\n\t\treturn true\n\t}\n\n\t// If markers don't exist, add them\n\tif (!content.includes(MODULES_MARKER_START)) {\n\t\t// Find the return statement and insert before it\n\t\tconst returnMatch = content.match(/return modules\\s*$/)\n\t\tif (returnMatch) {\n\t\t\tconst insertPos = content.lastIndexOf('return modules')\n\t\t\tconst before = content.slice(0, insertPos)\n\t\t\tconst after = content.slice(insertPos)\n\n\t\t\tcontent =\n\t\t\t\tbefore +\n\t\t\t\t`\\n\\t\\t${MODULES_MARKER_START}\\n\\t\\t// Modules installed via 'kuckit add' will be added here\\n\\t\\t${MODULES_MARKER_END}\\n\\n\\t\\t` +\n\t\t\t\tafter\n\t\t}\n\t}\n\n\t// Insert the module before the end marker\n\tconst newEntry = `{ package: '${packageName}' },`\n\tconst markerEndPos = content.indexOf(MODULES_MARKER_END)\n\n\tif (markerEndPos === -1) {\n\t\tconsole.warn(`Warning: Could not find marker in ${modulesPath}`)\n\t\tconsole.log(` Please manually add: ${newEntry}`)\n\t\treturn false\n\t}\n\n\tconst before = content.slice(0, markerEndPos)\n\tconst after = content.slice(markerEndPos)\n\n\tcontent = before + `${newEntry}\\n\\t\\t` + after\n\n\tawait writeFile(modulesPath, content)\n\tconsole.log(` Added to server modules: ${modulesPath}`)\n\treturn true\n}\n\nasync function addToClientModules(\n\tpackageName: string,\n\tclientPath: string,\n\tcwd: string\n): Promise<boolean> {\n\t// Check if there's a client modules file in apps/web\n\tconst clientModulesPath = join(cwd, 'apps', 'web', 'src', 'modules.client.ts')\n\n\tif (!(await fileExists(clientModulesPath))) {\n\t\t// Create the file if it doesn't exist\n\t\tconst template = `import type { ClientModuleSpec } from '@kuckit/sdk-react'\n\n/**\n * Client module specifications\n *\n * Add your Kuckit client modules here. Modules can be:\n * - Direct references: { module: myModule }\n * - Package imports: { package: '@acme/billing-module/client' }\n *\n * The CLI command \\`kuckit add <package>\\` will automatically update this file.\n */\nexport const getClientModuleSpecs = (): ClientModuleSpec[] => [\n\t${CLIENT_MODULES_MARKER_START}\n\t${CLIENT_MODULES_MARKER_END}\n]\n`\n\t\tawait writeFile(clientModulesPath, template)\n\t\tconsole.log(` Created client modules file: ${clientModulesPath}`)\n\t}\n\n\tlet content = await readFile(clientModulesPath, 'utf-8')\n\n\t// Check if package is already added\n\tconst clientPackagePath = `${packageName}/${clientPath.replace('./', '')}`\n\tif (content.includes(`package: '${clientPackagePath}'`)) {\n\t\tconsole.log(` Client module is already registered`)\n\t\treturn true\n\t}\n\n\t// Insert the module before the end marker\n\tconst newEntry = `{ package: '${clientPackagePath}' },`\n\tconst markerEndPos = content.indexOf(CLIENT_MODULES_MARKER_END)\n\n\tif (markerEndPos === -1) {\n\t\tconsole.warn(`Warning: Could not find marker in ${clientModulesPath}`)\n\t\tconsole.log(` Please manually add: ${newEntry}`)\n\t\treturn false\n\t}\n\n\tconst before = content.slice(0, markerEndPos)\n\tconst after = content.slice(markerEndPos)\n\n\tcontent = before + `${newEntry}\\n\\t` + after\n\n\tawait writeFile(clientModulesPath, content)\n\tconsole.log(` Added to client modules: ${clientModulesPath}`)\n\treturn true\n}\n\nexport async function addModule(packageName: string, options: AddModuleOptions): Promise<void> {\n\tconst cwd = process.cwd()\n\n\tconsole.log(`Adding module: ${packageName}`)\n\n\t// Step 1: Install the package\n\tif (!options.skipInstall) {\n\t\tconst pm = detectPackageManager(cwd)\n\t\tconst installCmd = pm === 'npm' ? `${pm} install ${packageName}` : `${pm} add ${packageName}`\n\n\t\tconsole.log(` Installing with ${pm}...`)\n\t\ttry {\n\t\t\texecSync(installCmd, { cwd, stdio: 'inherit' })\n\t\t} catch {\n\t\t\tconsole.error(`Failed to install ${packageName}`)\n\t\t\tprocess.exit(1)\n\t\t}\n\t}\n\n\t// Step 2: Validate kuckit metadata\n\tconst metadata = await readPackageKuckitMetadata(packageName, cwd)\n\n\tif (!metadata) {\n\t\tconsole.error(`\\nError: ${packageName} is not a valid Kuckit module.`)\n\t\tconsole.error(`The package.json must contain a \"kuckit\" field with module metadata.`)\n\t\tconsole.error(`\\nExpected structure:`)\n\t\tconsole.error(`{\n \"kuckit\": {\n \"id\": \"acme.billing\",\n \"server\": \".\",\n \"client\": \"./client\"\n }\n}`)\n\t\tprocess.exit(1)\n\t}\n\n\tconsole.log(` Found Kuckit module: ${metadata.id}`)\n\n\t// Step 3: Detect package manager for potential setup dependencies\n\tconst pm = detectPackageManager(cwd)\n\n\t// Step 4: Execute module setup (scaffolds, dev dependencies)\n\tif (metadata.setup) {\n\t\tawait executeSetupScaffolds(packageName, metadata.setup, cwd)\n\t\tawait installSetupDependencies(metadata.setup, cwd, pm)\n\t}\n\n\t// Step 5: Check for unified config\n\tconst configPath = findConfigFile(cwd)\n\n\tif (configPath) {\n\t\t// Use unified config with optional module config defaults\n\t\tawait addToUnifiedConfig(packageName, configPath, metadata.setup?.configDefaults)\n\t} else {\n\t\t// Fall back to separate config files\n\t\tif (metadata.server) {\n\t\t\tawait addToServerModules(packageName, cwd)\n\t\t}\n\t\tif (metadata.client) {\n\t\t\tawait addToClientModules(packageName, metadata.client, cwd)\n\t\t}\n\t}\n\n\t// Step 6: Print post-install message if provided\n\tif (metadata.setup?.postInstallMessage) {\n\t\tconsole.log(`\\n${metadata.setup.postInstallMessage}`)\n\t}\n\n\tconsole.log(`\nModule ${packageName} added successfully!\n\nRun 'bun run dev' to start the server with the new module.\n`)\n}\n","interface KuckitConfig {\n\tmodules: Array<{ package?: string; disabled?: boolean }>\n\t_configPath?: string\n}\n\ntype TryLoadKuckitConfig = (cwd: string) => Promise<KuckitConfig | null>\n\nexport async function loadTryLoadKuckitConfig(): Promise<TryLoadKuckitConfig> {\n\ttry {\n\t\tconst sdk = (await import('@kuckit/sdk')) as { tryLoadKuckitConfig?: TryLoadKuckitConfig }\n\t\tif (!sdk.tryLoadKuckitConfig) {\n\t\t\tthrow new Error('Invalid @kuckit/sdk version: tryLoadKuckitConfig not found.')\n\t\t}\n\t\treturn sdk.tryLoadKuckitConfig\n\t} catch {\n\t\tconsole.error('Error: This command requires @kuckit/sdk to be installed in your project.')\n\t\tconsole.error('Install it with one of:')\n\t\tconsole.error(' npm install -D @kuckit/sdk')\n\t\tconsole.error(' pnpm add -D @kuckit/sdk')\n\t\tconsole.error(' bun add -d @kuckit/sdk')\n\t\tprocess.exit(1)\n\t}\n}\n","import { readdir, readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { loadTryLoadKuckitConfig } from '../lib/sdk-loader.js'\n\nexport interface DiscoverOptions {\n\tjson: boolean\n\tinteractive: boolean\n}\n\ninterface KuckitMetadata {\n\tid: string\n\tserver?: string\n\tclient?: string\n}\n\ninterface DiscoveredModule {\n\tpackage: string\n\tid: string\n\tserver?: string\n\tclient?: string\n\tenabled: boolean\n\tlocal?: boolean\n}\n\ninterface DiscoverResult {\n\tdiscovered: DiscoveredModule[]\n\tenabled: number\n\tunconfigured: number\n}\n\nasync function readKuckitMetadataFromPath(packageJsonPath: string): Promise<KuckitMetadata | null> {\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg = JSON.parse(content) as { kuckit?: KuckitMetadata }\n\t\treturn pkg.kuckit ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function readPackageName(packageJsonPath: string): Promise<string | null> {\n\ttry {\n\t\tconst content = await readFile(packageJsonPath, 'utf-8')\n\t\tconst pkg = JSON.parse(content) as { name?: string }\n\t\treturn pkg.name ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function scanWorkspacePackages(cwd: string): Promise<DiscoveredModule[]> {\n\tconst discovered: DiscoveredModule[] = []\n\tconst packagesDir = join(cwd, 'packages')\n\n\tif (!existsSync(packagesDir)) return discovered\n\n\ttry {\n\t\tconst entries = await readdir(packagesDir, { withFileTypes: true })\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory()) continue\n\n\t\t\tconst packageJsonPath = join(packagesDir, entry.name, 'package.json')\n\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\n\t\t\tif (metadata) {\n\t\t\t\tconst packageName = await readPackageName(packageJsonPath)\n\t\t\t\tif (packageName) {\n\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tlocal: true,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// packages directory not accessible\n\t}\n\n\treturn discovered\n}\n\nasync function scanNodeModules(cwd: string): Promise<DiscoveredModule[]> {\n\tconst nodeModulesPath = join(cwd, 'node_modules')\n\tconst discovered: DiscoveredModule[] = []\n\n\ttry {\n\t\tconst entries = await readdir(nodeModulesPath, { withFileTypes: true })\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue\n\t\t\tif (entry.name.startsWith('.')) continue\n\n\t\t\tif (entry.name.startsWith('@')) {\n\t\t\t\tconst scopePath = join(nodeModulesPath, entry.name)\n\t\t\t\ttry {\n\t\t\t\t\tconst scopedEntries = await readdir(scopePath, { withFileTypes: true })\n\t\t\t\t\tfor (const scopedEntry of scopedEntries) {\n\t\t\t\t\t\tif (!scopedEntry.isDirectory() && !scopedEntry.isSymbolicLink()) continue\n\t\t\t\t\t\tconst packageName = `${entry.name}/${scopedEntry.name}`\n\t\t\t\t\t\tconst packageJsonPath = join(nodeModulesPath, packageName, 'package.json')\n\t\t\t\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\t\t\t\t\t\tif (metadata) {\n\t\t\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\t\t\tpackage: packageName,\n\t\t\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Skip inaccessible scoped directories\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst packageJsonPath = join(nodeModulesPath, entry.name, 'package.json')\n\t\t\t\tconst metadata = await readKuckitMetadataFromPath(packageJsonPath)\n\t\t\t\tif (metadata) {\n\t\t\t\t\tdiscovered.push({\n\t\t\t\t\t\tpackage: entry.name,\n\t\t\t\t\t\tid: metadata.id,\n\t\t\t\t\t\tserver: metadata.server,\n\t\t\t\t\t\tclient: metadata.client,\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// node_modules doesn't exist\n\t}\n\n\treturn discovered\n}\n\nasync function addModulesToConfig(packages: string[], configPath: string): Promise<void> {\n\tconst content = await readFile(configPath, 'utf-8')\n\tlet updated = content\n\n\tfor (const pkg of packages) {\n\t\tif (updated.includes(`'${pkg}'`) || updated.includes(`\"${pkg}\"`)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst modulesArrayMatch = updated.match(/modules:\\s*\\[/)\n\t\tif (!modulesArrayMatch) continue\n\n\t\tconst insertPos = modulesArrayMatch.index! + modulesArrayMatch[0].length\n\t\tconst newEntry = `\\n\\t\\t{ package: '${pkg}' },`\n\t\tupdated = updated.slice(0, insertPos) + newEntry + updated.slice(insertPos)\n\t}\n\n\tif (updated !== content) {\n\t\tconst { writeFile } = await import('node:fs/promises')\n\t\tawait writeFile(configPath, updated)\n\t}\n}\n\nexport async function discoverModules(options: DiscoverOptions): Promise<void> {\n\tconst cwd = process.cwd()\n\n\tif (!options.json) {\n\t\tconsole.log('Scanning for Kuckit modules...\\n')\n\t}\n\n\t// Load current config\n\tconst tryLoadKuckitConfig = await loadTryLoadKuckitConfig()\n\tconst config = await tryLoadKuckitConfig(cwd)\n\tconst configuredPackages = new Set(config?.modules.map((m) => m.package) ?? [])\n\n\t// Scan both workspace packages and node_modules\n\tconst workspaceModules = await scanWorkspacePackages(cwd)\n\tconst nodeModules = await scanNodeModules(cwd)\n\n\t// Combine and dedupe (workspace takes precedence)\n\tconst seen = new Set<string>()\n\tconst discovered: DiscoveredModule[] = []\n\n\tfor (const mod of workspaceModules) {\n\t\tseen.add(mod.package)\n\t\tmod.enabled = configuredPackages.has(mod.package)\n\t\tdiscovered.push(mod)\n\t}\n\n\tfor (const mod of nodeModules) {\n\t\tif (!seen.has(mod.package)) {\n\t\t\tmod.enabled = configuredPackages.has(mod.package)\n\t\t\tdiscovered.push(mod)\n\t\t}\n\t}\n\n\t// Sort: enabled first, then alphabetically\n\tdiscovered.sort((a, b) => {\n\t\tif (a.enabled !== b.enabled) return a.enabled ? -1 : 1\n\t\treturn a.package.localeCompare(b.package)\n\t})\n\n\tconst result: DiscoverResult = {\n\t\tdiscovered,\n\t\tenabled: discovered.filter((m) => m.enabled).length,\n\t\tunconfigured: discovered.filter((m) => !m.enabled).length,\n\t}\n\n\tif (options.json) {\n\t\tconsole.log(JSON.stringify(result, null, 2))\n\t\treturn\n\t}\n\n\tif (discovered.length === 0) {\n\t\tconsole.log('No Kuckit modules found.')\n\t\tconsole.log('\\nInstall modules with: kuckit add <package>')\n\t\treturn\n\t}\n\n\tconsole.log(`Found ${discovered.length} Kuckit module${discovered.length === 1 ? '' : 's'}:`)\n\tfor (const mod of discovered) {\n\t\tconst status = mod.enabled ? '✓' : '○'\n\t\tconst label = mod.enabled ? '(enabled)' : '(not configured)'\n\t\tconst localLabel = mod.local ? ' [local]' : ''\n\t\tconsole.log(` ${status} ${mod.package}${localLabel} ${label}`)\n\t}\n\n\tconst unconfigured = discovered.filter((m) => !m.enabled)\n\tif (unconfigured.length === 0) {\n\t\tconsole.log('\\nAll discovered modules are already configured.')\n\t\treturn\n\t}\n\n\tif (!options.interactive) {\n\t\tconsole.log(\n\t\t\t`\\n${unconfigured.length} module${unconfigured.length === 1 ? '' : 's'} not configured.`\n\t\t)\n\t\tconsole.log('Run without --no-interactive to enable them.')\n\t\treturn\n\t}\n\n\tif (!config?._configPath) {\n\t\tconsole.log('\\nNo kuckit.config.ts found. Create one first with:')\n\t\tconsole.log(' npx create-kuckit-app --init')\n\t\treturn\n\t}\n\n\t// Interactive mode: prompt for module selection\n\ttry {\n\t\tconst { checkbox } = await import('@inquirer/prompts')\n\n\t\tconst selected = await checkbox({\n\t\t\tmessage: 'Enable modules:',\n\t\t\tchoices: unconfigured.map((m) => ({\n\t\t\t\tname: m.package,\n\t\t\t\tvalue: m.package,\n\t\t\t\tchecked: true,\n\t\t\t})),\n\t\t})\n\n\t\tif (selected.length === 0) {\n\t\t\tconsole.log('\\nNo modules selected.')\n\t\t\treturn\n\t\t}\n\n\t\tawait addModulesToConfig(selected, config._configPath)\n\t\tconsole.log(\n\t\t\t`\\nUpdated kuckit.config.ts with ${selected.length} new module${selected.length === 1 ? '' : 's'}.`\n\t\t)\n\t} catch (error) {\n\t\tif ((error as Error).name === 'ExitPromptError') {\n\t\t\tconsole.log('\\nCancelled.')\n\t\t\treturn\n\t\t}\n\t\tthrow error\n\t}\n}\n","/**\n * Infrastructure types for CLI\n *\n * These types define the config schema stored in .kuckit/infra.json.\n * They are designed to support multiple cloud providers while maintaining\n * backward compatibility with existing GCP-only configurations.\n */\n\nimport type { BaseInfraConfig } from './provider.js'\n\n// ============================================================================\n// Provider-Specific Configuration Types\n// ============================================================================\n\n/**\n * GCP-specific configuration fields\n */\nexport interface GcpProviderConfig {\n\t/** GCP Project ID */\n\tgcpProject: string\n}\n\n/**\n * AWS-specific configuration fields (future)\n */\nexport interface AwsProviderConfig {\n\t/** AWS Account ID */\n\tawsAccountId: string\n\t/** AWS Profile name */\n\tawsProfile?: string\n}\n\n/**\n * Azure-specific configuration fields (future)\n */\nexport interface AzureProviderConfig {\n\t/** Azure Subscription ID */\n\tsubscriptionId: string\n\t/** Azure Resource Group */\n\tresourceGroup: string\n}\n\n/**\n * Union of all provider configs\n */\nexport type ProviderConfig = GcpProviderConfig | AwsProviderConfig | AzureProviderConfig\n\n// ============================================================================\n// Deployment Outputs (Provider-Specific)\n// ============================================================================\n\n/**\n * Base deployment outputs common to all providers\n */\nexport interface BaseDeploymentOutputs {\n\t/** Container registry URL */\n\tregistryUrl: string\n\t/** Service URL after deployment */\n\tserviceUrl?: string\n}\n\n/**\n * GCP-specific deployment outputs\n */\nexport interface GcpDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** Cloud SQL connection name for Cloud SQL Auth Proxy */\n\tdatabaseConnectionName: string\n\t/** Database name inside Cloud SQL instance */\n\tdatabaseName?: string\n\t/** Database user for Cloud SQL */\n\tdatabaseUser?: string\n\t/** Memorystore Redis private IP address */\n\tredisHost: string\n\t/** Secret Manager secret IDs */\n\tsecretIds: {\n\t\t/** Database password secret ID */\n\t\tdbPassword: string\n\t\t/** Redis AUTH string secret ID */\n\t\tredisAuth: string\n\t}\n\t/** Cloud Run Job name for database migrations */\n\tmigrationJobName?: string\n}\n\n/**\n * AWS-specific deployment outputs (future)\n */\nexport interface AwsDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** RDS instance endpoint */\n\tdatabaseEndpoint?: string\n\t/** ElastiCache endpoint */\n\tredisEndpoint?: string\n\t/** ECS service ARN */\n\tecsServiceArn?: string\n}\n\n/**\n * Azure-specific deployment outputs (future)\n */\nexport interface AzureDeploymentOutputs extends BaseDeploymentOutputs {\n\t/** Azure SQL server name */\n\tsqlServerName?: string\n\t/** Azure Cache for Redis hostname */\n\tredisHostname?: string\n\t/** Container Apps URL */\n\tcontainerAppUrl?: string\n}\n\n/**\n * Union of all deployment output types\n */\nexport type DeploymentOutputs = GcpDeploymentOutputs | AwsDeploymentOutputs | AzureDeploymentOutputs\n\n// ============================================================================\n// Stored Infrastructure Configuration\n// ============================================================================\n\n/**\n * Supported cloud provider IDs\n */\nexport type SupportedProvider = 'gcp' | 'aws' | 'azure'\n\n/**\n * CLI config stored in .kuckit/infra.json\n *\n * This is an extended version of BaseInfraConfig with additional fields\n * specific to CLI storage and provider management.\n */\nexport interface StoredInfraConfig extends BaseInfraConfig {\n\t/**\n\t * Provider ID (e.g., 'gcp', 'aws', 'azure')\n\t * @override Narrows the base string type to supported providers\n\t */\n\tprovider: SupportedProvider\n\n\t/**\n\t * npm package name of the provider (e.g., '@kuckit/infra-gcp')\n\t * Used to load the provider dynamically at runtime.\n\t */\n\tproviderPackage: string\n\n\t/**\n\t * Environment (dev/staging/prod)\n\t * @override Narrows to common environments\n\t */\n\tenv: 'dev' | 'staging' | 'prod'\n\n\t/**\n\t * Provider-specific configuration.\n\t * Contains fields that vary by cloud provider.\n\t */\n\tproviderConfig: ProviderConfig\n\n\t/**\n\t * Optional local infrastructure directory.\n\t * Set when provider has been ejected for customization.\n\t * If not set, uses provider's bundled infra.\n\t */\n\tlocalInfraDir?: string\n\n\t/**\n\t * Deployment outputs from the last successful deployment.\n\t * Structure varies by provider.\n\t */\n\toutputs?: DeploymentOutputs\n}\n\n// ============================================================================\n// Legacy Type Support (Backward Compatibility)\n// ============================================================================\n\n/**\n * Legacy config format (pre-provider-module)\n * Used for migration and backward compatibility\n *\n * @deprecated Use StoredInfraConfig instead\n */\nexport interface LegacyInfraConfig {\n\tprovider: 'gcp'\n\tgcpProject: string\n\tregion: string\n\tprojectName: string\n\tstackName: string\n\tenv: 'dev' | 'prod'\n\toutputs?: GcpDeploymentOutputs\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\n/**\n * Check if config is legacy format\n */\nexport function isLegacyConfig(\n\tconfig: StoredInfraConfig | LegacyInfraConfig\n): config is LegacyInfraConfig {\n\treturn 'gcpProject' in config && !('providerPackage' in config)\n}\n\n/**\n * Migrate legacy config to new format\n */\nexport function migrateLegacyConfig(legacy: LegacyInfraConfig): StoredInfraConfig {\n\treturn {\n\t\tprovider: 'gcp',\n\t\tproviderPackage: '@kuckit/infra-gcp',\n\t\tregion: legacy.region,\n\t\tprojectName: legacy.projectName,\n\t\tstackName: legacy.stackName,\n\t\tenv: legacy.env,\n\t\tproviderConfig: {\n\t\t\tgcpProject: legacy.gcpProject,\n\t\t},\n\t\toutputs: legacy.outputs,\n\t\tcreatedAt: legacy.createdAt,\n\t\tupdatedAt: legacy.updatedAt,\n\t}\n}\n\n// ============================================================================\n// Type Guards for Provider-Specific Configs\n// ============================================================================\n\n/**\n * Check if config is for GCP\n */\nexport function isGcpConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'gcp'\n\tproviderConfig: GcpProviderConfig\n\toutputs?: GcpDeploymentOutputs\n} {\n\treturn config.provider === 'gcp'\n}\n\n/**\n * Check if config is for AWS\n */\nexport function isAwsConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'aws'\n\tproviderConfig: AwsProviderConfig\n\toutputs?: AwsDeploymentOutputs\n} {\n\treturn config.provider === 'aws'\n}\n\n/**\n * Check if config is for Azure\n */\nexport function isAzureConfig(config: StoredInfraConfig): config is StoredInfraConfig & {\n\tprovider: 'azure'\n\tproviderConfig: AzureProviderConfig\n\toutputs?: AzureDeploymentOutputs\n} {\n\treturn config.provider === 'azure'\n}\n","/**\n * KuckitInfraProvider Interface\n *\n * This interface defines the contract that all cloud infrastructure providers must implement.\n * It enables multi-cloud support by abstracting provider-specific logic behind a common interface.\n *\n * Provider packages (e.g., @kuckit/infra-gcp, @kuckit/infra-aws) implement this interface\n * and are discovered/loaded by the CLI at runtime.\n *\n * @example\n * ```typescript\n * // In @kuckit/infra-gcp/src/provider.ts\n * import { defineInfraProvider } from '@kuckit/cli'\n *\n * export const provider = defineInfraProvider({\n * id: 'gcp',\n * label: 'Google Cloud Platform',\n * // ... implementation\n * })\n * ```\n */\n\n/**\n * Base configuration stored by CLI (provider-agnostic fields)\n */\nexport interface BaseInfraConfig {\n\t/** Provider ID (e.g., 'gcp', 'aws', 'azure') */\n\tprovider: string\n\t/** Environment (dev/staging/prod) */\n\tenv: string\n\t/** Deployment region */\n\tregion: string\n\t/** Project/app name for resource naming */\n\tprojectName: string\n\t/** Pulumi stack name */\n\tstackName: string\n\t/** ISO timestamp of config creation */\n\tcreatedAt: string\n\t/** ISO timestamp of last update */\n\tupdatedAt: string\n}\n\n/**\n * Result from an infrastructure operation (init/deploy/destroy)\n */\nexport interface InfraOperationResult<TOutputs = Record<string, unknown>> {\n\t/** Whether the operation succeeded */\n\tsuccess: boolean\n\t/** Human-readable message */\n\tmessage: string\n\t/** Deployment outputs (only on success) */\n\toutputs?: TOutputs\n\t/** Error details (only on failure) */\n\terror?: {\n\t\tcode: string\n\t\tmessage: string\n\t\tdetails?: string\n\t}\n}\n\n/**\n * Options passed to provider init\n */\nexport interface ProviderInitOptions {\n\t/** Environment to initialize */\n\tenv: string\n\t/** Target region */\n\tregion: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Skip confirmation prompts */\n\tyes?: boolean\n\t/** Provider-specific options */\n\tproviderOptions?: Record<string, unknown>\n}\n\n/**\n * Options passed to provider deploy\n */\nexport interface ProviderDeployOptions {\n\t/** Environment to deploy */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Preview changes without applying */\n\tpreview?: boolean\n\t/** Skip Docker build (use existing image) */\n\tskipBuild?: boolean\n\t/** Use specific image URL */\n\timage?: string\n\t/** Skip confirmation prompts */\n\tyes?: boolean\n}\n\n/**\n * Options passed to provider destroy\n */\nexport interface ProviderDestroyOptions {\n\t/** Environment to destroy */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Only destroy application layer, keep persistent resources */\n\tappOnly?: boolean\n\t/** Skip confirmation prompts */\n\tforce?: boolean\n}\n\n/**\n * Options passed to provider status check\n */\nexport interface ProviderStatusOptions {\n\t/** Environment to check */\n\tenv: string\n\t/** Project root directory */\n\tprojectRoot: string\n}\n\n/**\n * Status information returned by provider\n */\nexport interface ProviderStatus {\n\t/** Whether infrastructure is deployed */\n\tdeployed: boolean\n\t/** Current state (initializing/ready/deploying/error) */\n\tstate: 'initializing' | 'ready' | 'deploying' | 'error' | 'not_initialized'\n\t/** Service URL if deployed */\n\tserviceUrl?: string\n\t/** Last deployment timestamp */\n\tlastDeployment?: string\n\t/** Provider-specific status details */\n\tdetails?: Record<string, unknown>\n}\n\n/**\n * Options for ejecting provider to local packages\n */\nexport interface ProviderEjectOptions {\n\t/** Target directory for ejected code */\n\ttargetDir: string\n\t/** Project root directory */\n\tprojectRoot: string\n\t/** Skip confirmation prompts */\n\tforce?: boolean\n}\n\n/**\n * The main infrastructure provider interface.\n *\n * All provider packages must export a `provider` object implementing this interface.\n * The CLI discovers and loads providers dynamically based on installed packages.\n *\n * @typeParam TConfig - Provider-specific configuration extending BaseInfraConfig\n * @typeParam TOutputs - Provider-specific deployment outputs\n */\nexport interface KuckitInfraProvider<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n> {\n\t/**\n\t * Unique provider identifier (e.g., 'gcp', 'aws', 'azure')\n\t * Used for config storage and provider resolution\n\t */\n\treadonly id: string\n\n\t/**\n\t * Human-readable provider name for display\n\t * (e.g., 'Google Cloud Platform', 'Amazon Web Services')\n\t */\n\treadonly label: string\n\n\t/**\n\t * Provider version (semver)\n\t */\n\treadonly version: string\n\n\t/**\n\t * Get the infrastructure directory path for this provider.\n\t * This is where Pulumi/Terraform/CDK code lives.\n\t *\n\t * @param projectRoot - The project root directory\n\t * @returns Absolute path to infrastructure directory\n\t */\n\tgetInfraDir(projectRoot: string): string\n\n\t/**\n\t * Check if provider prerequisites are met (CLI tools, auth, etc.)\n\t *\n\t * @returns Object with status and any missing prerequisites\n\t */\n\tcheckPrerequisites(): Promise<{\n\t\tok: boolean\n\t\tmissing: Array<{ name: string; installUrl: string }>\n\t}>\n\n\t/**\n\t * Initialize base infrastructure for the project.\n\t * Creates foundational resources (VPC, registry, database) without deploying the app.\n\t *\n\t * @param options - Initialization options\n\t * @returns Operation result with deployment outputs\n\t */\n\tinit(options: ProviderInitOptions): Promise<InfraOperationResult<TOutputs>>\n\n\t/**\n\t * Deploy the application to the infrastructure.\n\t * Builds container image (if needed) and deploys to compute platform.\n\t *\n\t * @param options - Deployment options\n\t * @param config - Current stored configuration\n\t * @returns Operation result with deployment outputs\n\t */\n\tdeploy(options: ProviderDeployOptions, config: TConfig): Promise<InfraOperationResult<TOutputs>>\n\n\t/**\n\t * Destroy infrastructure resources.\n\t *\n\t * @param options - Destroy options\n\t * @param config - Current stored configuration\n\t * @returns Operation result\n\t */\n\tdestroy(options: ProviderDestroyOptions, config: TConfig): Promise<InfraOperationResult>\n\n\t/**\n\t * Get current infrastructure status.\n\t *\n\t * @param options - Status options\n\t * @param config - Current stored configuration\n\t * @returns Current provider status\n\t */\n\tstatus(options: ProviderStatusOptions, config: TConfig): Promise<ProviderStatus>\n\n\t/**\n\t * Get provider-specific configuration prompts for init.\n\t * Returns questions to ask user during interactive init.\n\t *\n\t * @param defaults - Any existing config values to use as defaults\n\t * @returns Array of prompts for inquirer\n\t */\n\tgetInitPrompts(defaults?: Partial<TConfig>): Promise<\n\t\tArray<{\n\t\t\tname: string\n\t\t\tmessage: string\n\t\t\ttype: 'input' | 'select' | 'confirm'\n\t\t\tdefault?: string | boolean\n\t\t\tchoices?: Array<{ value: string; label: string }>\n\t\t\tvalidate?: (value: string) => boolean | string\n\t\t}>\n\t>\n\n\t/**\n\t * Build provider-specific config from user responses.\n\t *\n\t * @param responses - User responses from init prompts\n\t * @param baseConfig - Base config fields\n\t * @returns Complete provider config\n\t */\n\tbuildConfig(\n\t\tresponses: Record<string, unknown>,\n\t\tbaseConfig: Pick<BaseInfraConfig, 'env' | 'region' | 'projectName' | 'stackName'>\n\t): TConfig\n\n\t/**\n\t * Optional: Eject provider infrastructure code to local project.\n\t * Allows customization of infrastructure beyond provider defaults.\n\t *\n\t * @param options - Eject options\n\t * @returns Operation result\n\t */\n\teject?(options: ProviderEjectOptions): Promise<InfraOperationResult>\n\n\t/**\n\t * Optional: Generate Dockerfile for the project.\n\t * Providers can include optimized Dockerfile templates.\n\t *\n\t * @param projectRoot - Project root directory\n\t * @returns Dockerfile content or null if using existing\n\t */\n\tgenerateDockerfile?(projectRoot: string): Promise<string | null>\n\n\t/**\n\t * Optional: Validate that project structure is compatible with provider.\n\t *\n\t * @param projectRoot - Project root directory\n\t * @returns Validation result with any issues\n\t */\n\tvalidateProject?(projectRoot: string): Promise<{\n\t\tvalid: boolean\n\t\tissues: Array<{ severity: 'error' | 'warning'; message: string }>\n\t}>\n}\n\n/**\n * Helper to define a provider with type inference.\n *\n * @example\n * ```typescript\n * export const provider = defineInfraProvider({\n * id: 'gcp',\n * label: 'Google Cloud Platform',\n * version: '1.0.0',\n * getInfraDir: (root) => join(root, 'node_modules/@kuckit/infra-gcp/infra'),\n * // ... rest of implementation\n * })\n * ```\n */\nexport function defineInfraProvider<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n>(provider: KuckitInfraProvider<TConfig, TOutputs>): KuckitInfraProvider<TConfig, TOutputs> {\n\treturn provider\n}\n\n/**\n * Type for the provider module export.\n * Provider packages should default export this shape.\n */\nexport interface KuckitInfraProviderModule<\n\tTConfig extends BaseInfraConfig = BaseInfraConfig,\n\tTOutputs extends Record<string, unknown> = Record<string, unknown>,\n> {\n\tprovider: KuckitInfraProvider<TConfig, TOutputs>\n}\n"],"mappings":"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"}
|