@percepta/create 3.6.1 → 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +37 -6
  2. package/dist/{git-ops-C2CIjuce.js → git-ops-BD7JNnal.js} +1 -1
  3. package/dist/{git-ops-C2CIjuce.js.map → git-ops-BD7JNnal.js.map} +1 -1
  4. package/dist/github-RCIMUq70.js +131 -0
  5. package/dist/github-RCIMUq70.js.map +1 -0
  6. package/dist/index.js +63 -122
  7. package/dist/index.js.map +1 -1
  8. package/dist/{init-sI9aIrkU.js → init-COp0nGdk.js} +4 -2
  9. package/dist/{init-sI9aIrkU.js.map → init-COp0nGdk.js.map} +1 -1
  10. package/dist/manifest-CqIDnbgs.js +58 -0
  11. package/dist/manifest-CqIDnbgs.js.map +1 -0
  12. package/dist/register-app-C7ZBpAaZ.js +103 -0
  13. package/dist/register-app-C7ZBpAaZ.js.map +1 -0
  14. package/dist/register-os-blueprint-DGjBUZYa.js +90 -0
  15. package/dist/register-os-blueprint-DGjBUZYa.js.map +1 -0
  16. package/dist/{status-CKe4aKso.js → status-BXYaQ4a2.js} +3 -3
  17. package/dist/{status-CKe4aKso.js.map → status-BXYaQ4a2.js.map} +1 -1
  18. package/dist/{sync-D1vkoofl.js → sync-BayU4w1j.js} +3 -3
  19. package/dist/{sync-D1vkoofl.js.map → sync-BayU4w1j.js.map} +1 -1
  20. package/dist/template-versions-CEIP9vhl.js +35 -0
  21. package/dist/template-versions-CEIP9vhl.js.map +1 -0
  22. package/dist/{upstream-gUHLWSR1.js → upstream-CZEzLrS4.js} +3 -3
  23. package/dist/{upstream-gUHLWSR1.js.map → upstream-CZEzLrS4.js.map} +1 -1
  24. package/dist/validate-dssldJAj.js +14 -0
  25. package/dist/validate-dssldJAj.js.map +1 -0
  26. package/package.json +1 -1
  27. package/template-versions.json +2 -2
  28. package/templates/infra/os.blueprint.yaml.template +138 -0
  29. package/templates/monorepo/README.md +41 -3
  30. package/templates/monorepo/auth/README.md +6 -3
  31. package/templates/monorepo/auth/package.json +2 -4
  32. package/templates/monorepo/auth/src/config/database.ts +1 -1
  33. package/templates/{webapp → monorepo}/docker-compose.yml +2 -2
  34. package/templates/monorepo/package.json.template +5 -2
  35. package/templates/monorepo/pnpm-workspace.yaml +4 -0
  36. package/templates/monorepo/scripts/setup-local-databases.mjs +183 -0
  37. package/templates/webapp/AGENTS.md +13 -20
  38. package/templates/webapp/README.md +32 -36
  39. package/templates/webapp/agent-skills/database.md +21 -21
  40. package/templates/webapp/agent-skills/langfuse.md +7 -7
  41. package/templates/webapp/agent-skills/llm.md +4 -2
  42. package/templates/webapp/agent-skills/oneshot.md +7 -6
  43. package/templates/webapp/agent-skills/ryvn.md +12 -16
  44. package/templates/webapp/deploy/README.md +10 -51
  45. package/templates/webapp/drizzle.config.ts +2 -23
  46. package/templates/webapp/env.example.template +8 -14
  47. package/templates/webapp/package.json.template +8 -15
  48. package/templates/webapp/scripts/start.sh +12 -16
  49. package/templates/webapp/src/config/getEnvConfig.ts +4 -10
  50. package/templates/webapp/src/drizzle/db.ts +6 -21
  51. package/templates/webapp/src/startup-checks.ts +28 -7
  52. package/templates/monorepo/auth/scripts/setup-database.ts +0 -11
  53. package/templates/webapp/.github/workflows/__APP_NAME__-terraform-ryvn-release.yaml +0 -92
  54. package/templates/webapp/agent-skills/deploy.md +0 -92
  55. package/templates/webapp/deploy/ryvn/__APP_NAME__-terraform.service.yaml +0 -10
  56. package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml +0 -11
  57. package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +0 -154
  58. package/templates/webapp/terraform/README.md +0 -147
  59. package/templates/webapp/terraform/deploy.sh +0 -97
  60. package/templates/webapp/terraform/main.tf +0 -101
  61. package/templates/webapp/terraform/modules/cloudtrail/main.tf +0 -27
  62. package/templates/webapp/terraform/modules/cloudtrail/outputs.tf +0 -10
  63. package/templates/webapp/terraform/modules/cloudtrail/variables.tf +0 -15
  64. package/templates/webapp/terraform/modules/networking/main.tf +0 -118
  65. package/templates/webapp/terraform/modules/networking/outputs.tf +0 -38
  66. package/templates/webapp/terraform/modules/networking/variables.tf +0 -24
  67. package/templates/webapp/terraform/modules/rds/main.tf +0 -227
  68. package/templates/webapp/terraform/modules/rds/outputs.tf +0 -73
  69. package/templates/webapp/terraform/modules/rds/variables.tf +0 -61
  70. package/templates/webapp/terraform/modules/s3-logging/main.tf +0 -148
  71. package/templates/webapp/terraform/modules/s3-logging/outputs.tf +0 -10
  72. package/templates/webapp/terraform/modules/s3-logging/variables.tf +0 -16
  73. package/templates/webapp/terraform/modules/secrets/main.tf +0 -39
  74. package/templates/webapp/terraform/modules/secrets/outputs.tf +0 -9
  75. package/templates/webapp/terraform/modules/secrets/variables.tf +0 -51
  76. package/templates/webapp/terraform/outputs.tf +0 -102
  77. package/templates/webapp/terraform/providers.tf +0 -32
  78. package/templates/webapp/terraform/schema/main.tf +0 -4
  79. package/templates/webapp/terraform/schema/outputs.tf +0 -9
  80. package/templates/webapp/terraform/schema/variables.tf +0 -19
  81. package/templates/webapp/terraform/schema/versions.tf +0 -38
  82. package/templates/webapp/terraform/terraform.tfvars.example +0 -65
  83. package/templates/webapp/terraform/variables.tf +0 -129
@@ -0,0 +1,103 @@
1
+ import { n as toKebabCase } from "./template-versions-CEIP9vhl.js";
2
+ import { t as validateProjectName } from "./validate-dssldJAj.js";
3
+ import { i as detectMonorepo, t as readWorkspaceManifest } from "./index.js";
4
+ import { a as resolveGitHubToken, i as createOrUpdateInfraPullRequest, n as INFRA_REPOSITORY, r as createInfraGitHubApi, t as INFRA_BASE_BRANCH } from "./github-RCIMUq70.js";
5
+ import chalk from "chalk";
6
+ import { isMap, isSeq, parseDocument } from "yaml";
7
+ //#region src/commands/infra/register-app.ts
8
+ async function registerApp(appNameInput, args = {}) {
9
+ const appName = normalizeAppName(appNameInput);
10
+ const monorepoContext = await detectMonorepo(args.cwd ?? process.cwd());
11
+ if (!monorepoContext.found || !monorepoContext.rootDir) throw new Error("Run this command from a Mosaic customer monorepo with a .mosaic-workspace.json file.");
12
+ const customerSlug = (await readWorkspaceManifest(monorepoContext.rootDir))?.customerSlug;
13
+ if (!customerSlug) throw new Error(".mosaic-workspace.json is missing customerSlug. Recreate the monorepo with a current @percepta/create.");
14
+ const github = args.github ?? createInfraGitHubApi(resolveGitHubToken());
15
+ const blueprintName = `${customerSlug}-os`;
16
+ const branchName = `blueberry/register-${customerSlug}-${appName}-database`;
17
+ const targetPath = [
18
+ "ryvn",
19
+ "definitions",
20
+ customerSlug,
21
+ "blueprints",
22
+ `${blueprintName}.blueprint.yaml`
23
+ ].join("/");
24
+ const mainFile = await github.getFile(targetPath, INFRA_BASE_BRANCH);
25
+ if (!mainFile) throw new Error(`${targetPath} does not exist in ${INFRA_REPOSITORY}. Run \`pnpm mosaic infra register-os-blueprint\` and merge that infra PR first.`);
26
+ const content = addAppDatabaseToBlueprint(mainFile.content, appName);
27
+ if (content === mainFile.content) return {
28
+ appName,
29
+ blueprintName,
30
+ branchName,
31
+ customerSlug,
32
+ pullRequestUrl: null,
33
+ repository: INFRA_REPOSITORY,
34
+ status: "already_registered",
35
+ targetPath
36
+ };
37
+ const pullRequest = await createOrUpdateInfraPullRequest({
38
+ baseFileSha: mainFile.sha,
39
+ branchName,
40
+ content,
41
+ github,
42
+ message: `Register ${appName} app database`,
43
+ targetPath,
44
+ title: `Register ${appName} app database`,
45
+ body: [
46
+ `Registers the ${appName} app database in ${blueprintName}.`,
47
+ "",
48
+ "Generated by `mosaic infra register-app`."
49
+ ].join("\n")
50
+ });
51
+ return {
52
+ appName,
53
+ blueprintName,
54
+ branchName,
55
+ customerSlug,
56
+ pullRequestUrl: pullRequest.pullRequestUrl,
57
+ repository: INFRA_REPOSITORY,
58
+ status: pullRequest.status,
59
+ targetPath
60
+ };
61
+ }
62
+ async function registerAppCommand(appName) {
63
+ try {
64
+ const result = await registerApp(appName);
65
+ if (result.status === "already_registered") {
66
+ console.log(chalk.green("✔"), `${result.appName} is already registered in ${result.repository} at`, chalk.cyan(result.targetPath));
67
+ return;
68
+ }
69
+ const verb = result.status === "created_pr" ? "Created" : "Updated existing";
70
+ console.log(chalk.green("✔"), `${verb} infra PR for ${result.appName}:`, chalk.cyan(result.pullRequestUrl));
71
+ } catch (error) {
72
+ console.error(chalk.red("Error:"), error.message);
73
+ process.exit(1);
74
+ }
75
+ }
76
+ function addAppDatabaseToBlueprint(blueprintContent, appName) {
77
+ const document = parseDocument(blueprintContent);
78
+ if (document.errors.length > 0) throw new Error(`Invalid OS blueprint YAML: ${document.errors.map((error) => error.message).join("; ")}`);
79
+ const spec = document.get("spec", true);
80
+ if (!isMap(spec)) throw new Error("OS blueprint must include a spec map.");
81
+ const inputs = spec.get("inputs", true);
82
+ if (!isSeq(inputs)) throw new Error("OS blueprint spec.inputs must be a sequence.");
83
+ const appDatabasesInput = inputs.items.find((item) => isMap(item) && item.get("name") === "app_databases");
84
+ if (!isMap(appDatabasesInput)) throw new Error("OS blueprint must include an app_databases input.");
85
+ const defaultValue = appDatabasesInput.get("default", true);
86
+ if (!isMap(defaultValue)) throw new Error("OS blueprint app_databases default must be a map.");
87
+ if (defaultValue.has(appName)) return blueprintContent;
88
+ defaultValue.flow = false;
89
+ const appDatabaseValue = document.createNode({});
90
+ if (isMap(appDatabaseValue)) appDatabaseValue.flow = true;
91
+ defaultValue.set(appName, appDatabaseValue);
92
+ return document.toString();
93
+ }
94
+ function normalizeAppName(appNameInput) {
95
+ const appName = toKebabCase(appNameInput);
96
+ const validation = validateProjectName(appName);
97
+ if (!validation.valid) throw new Error(`Invalid app name: ${validation.error}`);
98
+ return appName;
99
+ }
100
+ //#endregion
101
+ export { registerAppCommand };
102
+
103
+ //# sourceMappingURL=register-app-C7ZBpAaZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-app-C7ZBpAaZ.js","names":[],"sources":["../src/commands/infra/register-app.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { isMap, isSeq, parseDocument } from \"yaml\";\nimport { toKebabCase } from \"../../utils/case-converters.js\";\nimport { detectMonorepo } from \"../../utils/detect-monorepo.js\";\nimport { validateProjectName } from \"../../utils/validate.js\";\nimport { readWorkspaceManifest } from \"../../utils/workspace-manifest.js\";\nimport {\n createInfraGitHubApi,\n createOrUpdateInfraPullRequest,\n INFRA_BASE_BRANCH,\n INFRA_REPOSITORY,\n type InfraGitHubApi,\n resolveGitHubToken,\n} from \"./github.js\";\n\nexport interface RegisterAppResult {\n appName: string;\n blueprintName: string;\n branchName: string;\n customerSlug: string;\n pullRequestUrl: string | null;\n repository: typeof INFRA_REPOSITORY;\n status: \"already_registered\" | \"created_pr\" | \"updated_pr\";\n targetPath: string;\n}\n\nexport async function registerApp(\n appNameInput: string,\n args: {\n cwd?: string;\n github?: InfraGitHubApi;\n } = {},\n): Promise<RegisterAppResult> {\n const appName = normalizeAppName(appNameInput);\n const cwd = args.cwd ?? process.cwd();\n const monorepoContext = await detectMonorepo(cwd);\n if (!monorepoContext.found || !monorepoContext.rootDir) {\n throw new Error(\n \"Run this command from a Mosaic customer monorepo with a .mosaic-workspace.json file.\",\n );\n }\n\n const workspaceManifest = await readWorkspaceManifest(\n monorepoContext.rootDir,\n );\n const customerSlug = workspaceManifest?.customerSlug;\n if (!customerSlug) {\n throw new Error(\n \".mosaic-workspace.json is missing customerSlug. Recreate the monorepo with a current @percepta/create.\",\n );\n }\n\n const github = args.github ?? createInfraGitHubApi(resolveGitHubToken());\n const blueprintName = `${customerSlug}-os`;\n const branchName = `blueberry/register-${customerSlug}-${appName}-database`;\n const targetPath = [\n \"ryvn\",\n \"definitions\",\n customerSlug,\n \"blueprints\",\n `${blueprintName}.blueprint.yaml`,\n ].join(\"/\");\n\n const mainFile = await github.getFile(targetPath, INFRA_BASE_BRANCH);\n if (!mainFile) {\n throw new Error(\n `${targetPath} does not exist in ${INFRA_REPOSITORY}. Run \\`pnpm mosaic infra register-os-blueprint\\` and merge that infra PR first.`,\n );\n }\n\n const content = addAppDatabaseToBlueprint(mainFile.content, appName);\n if (content === mainFile.content) {\n return {\n appName,\n blueprintName,\n branchName,\n customerSlug,\n pullRequestUrl: null,\n repository: INFRA_REPOSITORY,\n status: \"already_registered\",\n targetPath,\n };\n }\n\n const pullRequest = await createOrUpdateInfraPullRequest({\n baseFileSha: mainFile.sha,\n branchName,\n content,\n github,\n message: `Register ${appName} app database`,\n targetPath,\n title: `Register ${appName} app database`,\n body: [\n `Registers the ${appName} app database in ${blueprintName}.`,\n \"\",\n \"Generated by `mosaic infra register-app`.\",\n ].join(\"\\n\"),\n });\n\n return {\n appName,\n blueprintName,\n branchName,\n customerSlug,\n pullRequestUrl: pullRequest.pullRequestUrl,\n repository: INFRA_REPOSITORY,\n status: pullRequest.status,\n targetPath,\n };\n}\n\nexport async function registerAppCommand(appName: string): Promise<void> {\n try {\n const result = await registerApp(appName);\n\n if (result.status === \"already_registered\") {\n console.log(\n chalk.green(\"✔\"),\n `${result.appName} is already registered in ${result.repository} at`,\n chalk.cyan(result.targetPath),\n );\n return;\n }\n\n const verb =\n result.status === \"created_pr\" ? \"Created\" : \"Updated existing\";\n console.log(\n chalk.green(\"✔\"),\n `${verb} infra PR for ${result.appName}:`,\n chalk.cyan(result.pullRequestUrl),\n );\n } catch (error) {\n console.error(chalk.red(\"Error:\"), (error as Error).message);\n process.exit(1);\n }\n}\n\nexport function addAppDatabaseToBlueprint(\n blueprintContent: string,\n appName: string,\n): string {\n const document = parseDocument(blueprintContent);\n if (document.errors.length > 0) {\n throw new Error(\n `Invalid OS blueprint YAML: ${document.errors.map((error) => error.message).join(\"; \")}`,\n );\n }\n\n const spec = document.get(\"spec\", true);\n if (!isMap(spec)) {\n throw new Error(\"OS blueprint must include a spec map.\");\n }\n\n const inputs = spec.get(\"inputs\", true);\n if (!isSeq(inputs)) {\n throw new Error(\"OS blueprint spec.inputs must be a sequence.\");\n }\n\n const appDatabasesInput = inputs.items.find(\n (item) => isMap(item) && item.get(\"name\") === \"app_databases\",\n );\n if (!isMap(appDatabasesInput)) {\n throw new Error(\"OS blueprint must include an app_databases input.\");\n }\n\n const defaultValue = appDatabasesInput.get(\"default\", true);\n if (!isMap(defaultValue)) {\n throw new Error(\"OS blueprint app_databases default must be a map.\");\n }\n\n if (defaultValue.has(appName)) return blueprintContent;\n\n defaultValue.flow = false;\n const appDatabaseValue = document.createNode({});\n if (isMap(appDatabaseValue)) appDatabaseValue.flow = true;\n defaultValue.set(appName, appDatabaseValue);\n\n return document.toString();\n}\n\nfunction normalizeAppName(appNameInput: string): string {\n const appName = toKebabCase(appNameInput);\n const validation = validateProjectName(appName);\n if (!validation.valid) {\n throw new Error(`Invalid app name: ${validation.error}`);\n }\n return appName;\n}\n"],"mappings":";;;;;;;AA0BA,eAAsB,YACpB,cACA,OAGI,EAAE,EACsB;CAC5B,MAAM,UAAU,iBAAiB,aAAa;CAE9C,MAAM,kBAAkB,MAAM,eADlB,KAAK,OAAO,QAAQ,KAAK,CACY;AACjD,KAAI,CAAC,gBAAgB,SAAS,CAAC,gBAAgB,QAC7C,OAAM,IAAI,MACR,uFACD;CAMH,MAAM,gBAAe,MAHW,sBAC9B,gBAAgB,QACjB,GACuC;AACxC,KAAI,CAAC,aACH,OAAM,IAAI,MACR,yGACD;CAGH,MAAM,SAAS,KAAK,UAAU,qBAAqB,oBAAoB,CAAC;CACxE,MAAM,gBAAgB,GAAG,aAAa;CACtC,MAAM,aAAa,sBAAsB,aAAa,GAAG,QAAQ;CACjE,MAAM,aAAa;EACjB;EACA;EACA;EACA;EACA,GAAG,cAAc;EAClB,CAAC,KAAK,IAAI;CAEX,MAAM,WAAW,MAAM,OAAO,QAAQ,YAAY,kBAAkB;AACpE,KAAI,CAAC,SACH,OAAM,IAAI,MACR,GAAG,WAAW,qBAAqB,iBAAiB,kFACrD;CAGH,MAAM,UAAU,0BAA0B,SAAS,SAAS,QAAQ;AACpE,KAAI,YAAY,SAAS,QACvB,QAAO;EACL;EACA;EACA;EACA;EACA,gBAAgB;EAChB,YAAY;EACZ,QAAQ;EACR;EACD;CAGH,MAAM,cAAc,MAAM,+BAA+B;EACvD,aAAa,SAAS;EACtB;EACA;EACA;EACA,SAAS,YAAY,QAAQ;EAC7B;EACA,OAAO,YAAY,QAAQ;EAC3B,MAAM;GACJ,iBAAiB,QAAQ,mBAAmB,cAAc;GAC1D;GACA;GACD,CAAC,KAAK,KAAK;EACb,CAAC;AAEF,QAAO;EACL;EACA;EACA;EACA;EACA,gBAAgB,YAAY;EAC5B,YAAY;EACZ,QAAQ,YAAY;EACpB;EACD;;AAGH,eAAsB,mBAAmB,SAAgC;AACvE,KAAI;EACF,MAAM,SAAS,MAAM,YAAY,QAAQ;AAEzC,MAAI,OAAO,WAAW,sBAAsB;AAC1C,WAAQ,IACN,MAAM,MAAM,IAAI,EAChB,GAAG,OAAO,QAAQ,4BAA4B,OAAO,WAAW,MAChE,MAAM,KAAK,OAAO,WAAW,CAC9B;AACD;;EAGF,MAAM,OACJ,OAAO,WAAW,eAAe,YAAY;AAC/C,UAAQ,IACN,MAAM,MAAM,IAAI,EAChB,GAAG,KAAK,gBAAgB,OAAO,QAAQ,IACvC,MAAM,KAAK,OAAO,eAAe,CAClC;UACM,OAAO;AACd,UAAQ,MAAM,MAAM,IAAI,SAAS,EAAG,MAAgB,QAAQ;AAC5D,UAAQ,KAAK,EAAE;;;AAInB,SAAgB,0BACd,kBACA,SACQ;CACR,MAAM,WAAW,cAAc,iBAAiB;AAChD,KAAI,SAAS,OAAO,SAAS,EAC3B,OAAM,IAAI,MACR,8BAA8B,SAAS,OAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,KAAK,KAAK,GACvF;CAGH,MAAM,OAAO,SAAS,IAAI,QAAQ,KAAK;AACvC,KAAI,CAAC,MAAM,KAAK,CACd,OAAM,IAAI,MAAM,wCAAwC;CAG1D,MAAM,SAAS,KAAK,IAAI,UAAU,KAAK;AACvC,KAAI,CAAC,MAAM,OAAO,CAChB,OAAM,IAAI,MAAM,+CAA+C;CAGjE,MAAM,oBAAoB,OAAO,MAAM,MACpC,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,gBAC/C;AACD,KAAI,CAAC,MAAM,kBAAkB,CAC3B,OAAM,IAAI,MAAM,oDAAoD;CAGtE,MAAM,eAAe,kBAAkB,IAAI,WAAW,KAAK;AAC3D,KAAI,CAAC,MAAM,aAAa,CACtB,OAAM,IAAI,MAAM,oDAAoD;AAGtE,KAAI,aAAa,IAAI,QAAQ,CAAE,QAAO;AAEtC,cAAa,OAAO;CACpB,MAAM,mBAAmB,SAAS,WAAW,EAAE,CAAC;AAChD,KAAI,MAAM,iBAAiB,CAAE,kBAAiB,OAAO;AACrD,cAAa,IAAI,SAAS,iBAAiB;AAE3C,QAAO,SAAS,UAAU;;AAG5B,SAAS,iBAAiB,cAA8B;CACtD,MAAM,UAAU,YAAY,aAAa;CACzC,MAAM,aAAa,oBAAoB,QAAQ;AAC/C,KAAI,CAAC,WAAW,MACd,OAAM,IAAI,MAAM,qBAAqB,WAAW,QAAQ;AAE1D,QAAO"}
@@ -0,0 +1,90 @@
1
+ import { i as toTitleCase } from "./template-versions-CEIP9vhl.js";
2
+ import { i as detectMonorepo, t as readWorkspaceManifest } from "./index.js";
3
+ import { a as resolveGitHubToken, i as createOrUpdateInfraPullRequest, n as INFRA_REPOSITORY, r as createInfraGitHubApi, t as INFRA_BASE_BRANCH } from "./github-RCIMUq70.js";
4
+ import path from "node:path";
5
+ import chalk from "chalk";
6
+ import fs from "fs-extra";
7
+ import { fileURLToPath } from "node:url";
8
+ //#region src/commands/infra/register-os-blueprint.ts
9
+ const OS_BLUEPRINT_TEMPLATE = "os.blueprint.yaml.template";
10
+ async function registerOsBlueprint(args = {}) {
11
+ const monorepoContext = await detectMonorepo(args.cwd ?? process.cwd());
12
+ if (!monorepoContext.found || !monorepoContext.rootDir) throw new Error("Run this command from a Mosaic customer monorepo with a .mosaic-workspace.json file.");
13
+ const customerSlug = (await readWorkspaceManifest(monorepoContext.rootDir))?.customerSlug;
14
+ if (!customerSlug) throw new Error(".mosaic-workspace.json is missing customerSlug. Recreate the monorepo with a current @percepta/create.");
15
+ const github = args.github ?? createInfraGitHubApi(resolveGitHubToken());
16
+ const blueprintName = `${customerSlug}-os`;
17
+ const branchName = `blueberry/register-${blueprintName}-blueprint`;
18
+ const targetPath = [
19
+ "ryvn",
20
+ "definitions",
21
+ customerSlug,
22
+ "blueprints",
23
+ `${blueprintName}.blueprint.yaml`
24
+ ].join("/");
25
+ const content = await renderOsBlueprint(customerSlug);
26
+ const mainFile = await github.getFile(targetPath, INFRA_BASE_BRANCH);
27
+ if (mainFile) {
28
+ if (mainFile.content === content) return {
29
+ blueprintName,
30
+ branchName,
31
+ customerSlug,
32
+ pullRequestUrl: null,
33
+ repository: INFRA_REPOSITORY,
34
+ status: "already_registered",
35
+ targetPath
36
+ };
37
+ throw new Error(`${targetPath} already exists in ${INFRA_REPOSITORY}. Not overwriting an existing customer OS blueprint.`);
38
+ }
39
+ const pullRequest = await createOrUpdateInfraPullRequest({
40
+ branchName,
41
+ content,
42
+ github,
43
+ message: `Register ${blueprintName} blueprint`,
44
+ targetPath,
45
+ title: `Register ${blueprintName} blueprint`,
46
+ body: [
47
+ `Registers the ${blueprintName} OS blueprint for ${customerSlug}.`,
48
+ "",
49
+ "Generated by `mosaic infra register-os-blueprint`."
50
+ ].join("\n")
51
+ });
52
+ return {
53
+ blueprintName,
54
+ branchName,
55
+ customerSlug,
56
+ pullRequestUrl: pullRequest.pullRequestUrl,
57
+ repository: INFRA_REPOSITORY,
58
+ status: pullRequest.status,
59
+ targetPath
60
+ };
61
+ }
62
+ async function registerOsBlueprintCommand() {
63
+ try {
64
+ const result = await registerOsBlueprint();
65
+ if (result.status === "already_registered") {
66
+ console.log(chalk.green("✔"), `${result.blueprintName} is already registered in ${result.repository} at`, chalk.cyan(result.targetPath));
67
+ return;
68
+ }
69
+ const verb = result.status === "created_pr" ? "Created" : "Updated existing";
70
+ console.log(chalk.green("✔"), `${verb} infra PR for ${result.blueprintName}:`, chalk.cyan(result.pullRequestUrl));
71
+ } catch (error) {
72
+ console.error(chalk.red("Error:"), error.message);
73
+ process.exit(1);
74
+ }
75
+ }
76
+ async function renderOsBlueprint(customerSlug) {
77
+ const template = await fs.readFile(getOsBlueprintTemplatePath(), "utf-8");
78
+ const customerTitle = toTitleCase(customerSlug);
79
+ return template.replaceAll("__CUSTOMER_SLUG__", customerSlug).replaceAll("__CUSTOMER_TITLE__", customerTitle);
80
+ }
81
+ function getOsBlueprintTemplatePath() {
82
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
83
+ const candidates = [path.resolve(currentDir, "../templates/infra", OS_BLUEPRINT_TEMPLATE), path.resolve(currentDir, "../../../templates/infra", OS_BLUEPRINT_TEMPLATE)];
84
+ for (const candidate of candidates) if (fs.existsSync(candidate)) return candidate;
85
+ throw new Error(`OS blueprint template not found. Checked: ${candidates.join(", ")}`);
86
+ }
87
+ //#endregion
88
+ export { registerOsBlueprintCommand };
89
+
90
+ //# sourceMappingURL=register-os-blueprint-DGjBUZYa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-os-blueprint-DGjBUZYa.js","names":[],"sources":["../src/commands/infra/register-os-blueprint.ts"],"sourcesContent":["import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { toTitleCase } from \"../../utils/case-converters.js\";\nimport { detectMonorepo } from \"../../utils/detect-monorepo.js\";\nimport { readWorkspaceManifest } from \"../../utils/workspace-manifest.js\";\nimport {\n createOrUpdateInfraPullRequest,\n createInfraGitHubApi,\n INFRA_BASE_BRANCH,\n INFRA_REPOSITORY,\n type InfraGitHubApi,\n resolveGitHubToken,\n} from \"./github.js\";\n\nconst OS_BLUEPRINT_TEMPLATE = \"os.blueprint.yaml.template\";\n\nexport interface RegisterOsBlueprintResult {\n blueprintName: string;\n branchName: string;\n customerSlug: string;\n pullRequestUrl: string | null;\n repository: typeof INFRA_REPOSITORY;\n status: \"already_registered\" | \"created_pr\" | \"updated_pr\";\n targetPath: string;\n}\n\nexport async function registerOsBlueprint(\n args: {\n cwd?: string;\n github?: InfraGitHubApi;\n } = {},\n): Promise<RegisterOsBlueprintResult> {\n const cwd = args.cwd ?? process.cwd();\n const monorepoContext = await detectMonorepo(cwd);\n if (!monorepoContext.found || !monorepoContext.rootDir) {\n throw new Error(\n \"Run this command from a Mosaic customer monorepo with a .mosaic-workspace.json file.\",\n );\n }\n\n const workspaceManifest = await readWorkspaceManifest(\n monorepoContext.rootDir,\n );\n const customerSlug = workspaceManifest?.customerSlug;\n if (!customerSlug) {\n throw new Error(\n \".mosaic-workspace.json is missing customerSlug. Recreate the monorepo with a current @percepta/create.\",\n );\n }\n\n const github = args.github ?? createInfraGitHubApi(resolveGitHubToken());\n const blueprintName = `${customerSlug}-os`;\n const branchName = `blueberry/register-${blueprintName}-blueprint`;\n const targetPath = [\n \"ryvn\",\n \"definitions\",\n customerSlug,\n \"blueprints\",\n `${blueprintName}.blueprint.yaml`,\n ].join(\"/\");\n const content = await renderOsBlueprint(customerSlug);\n\n const mainFile = await github.getFile(targetPath, INFRA_BASE_BRANCH);\n if (mainFile) {\n if (mainFile.content === content) {\n return {\n blueprintName,\n branchName,\n customerSlug,\n pullRequestUrl: null,\n repository: INFRA_REPOSITORY,\n status: \"already_registered\",\n targetPath,\n };\n }\n\n throw new Error(\n `${targetPath} already exists in ${INFRA_REPOSITORY}. Not overwriting an existing customer OS blueprint.`,\n );\n }\n\n const pullRequest = await createOrUpdateInfraPullRequest({\n branchName,\n content,\n github,\n message: `Register ${blueprintName} blueprint`,\n targetPath,\n title: `Register ${blueprintName} blueprint`,\n body: [\n `Registers the ${blueprintName} OS blueprint for ${customerSlug}.`,\n \"\",\n \"Generated by `mosaic infra register-os-blueprint`.\",\n ].join(\"\\n\"),\n });\n\n return {\n blueprintName,\n branchName,\n customerSlug,\n pullRequestUrl: pullRequest.pullRequestUrl,\n repository: INFRA_REPOSITORY,\n status: pullRequest.status,\n targetPath,\n };\n}\n\nexport async function registerOsBlueprintCommand(): Promise<void> {\n try {\n const result = await registerOsBlueprint();\n\n if (result.status === \"already_registered\") {\n console.log(\n chalk.green(\"✔\"),\n `${result.blueprintName} is already registered in ${result.repository} at`,\n chalk.cyan(result.targetPath),\n );\n return;\n }\n\n const verb =\n result.status === \"created_pr\" ? \"Created\" : \"Updated existing\";\n console.log(\n chalk.green(\"✔\"),\n `${verb} infra PR for ${result.blueprintName}:`,\n chalk.cyan(result.pullRequestUrl),\n );\n } catch (error) {\n console.error(chalk.red(\"Error:\"), (error as Error).message);\n process.exit(1);\n }\n}\n\nasync function renderOsBlueprint(customerSlug: string): Promise<string> {\n const template = await fs.readFile(getOsBlueprintTemplatePath(), \"utf-8\");\n const customerTitle = toTitleCase(customerSlug);\n\n return template\n .replaceAll(\"__CUSTOMER_SLUG__\", customerSlug)\n .replaceAll(\"__CUSTOMER_TITLE__\", customerTitle);\n}\n\nfunction getOsBlueprintTemplatePath(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(currentDir, \"../templates/infra\", OS_BLUEPRINT_TEMPLATE),\n path.resolve(currentDir, \"../../../templates/infra\", OS_BLUEPRINT_TEMPLATE),\n ];\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n throw new Error(\n `OS blueprint template not found. Checked: ${candidates.join(\", \")}`,\n );\n}\n"],"mappings":";;;;;;;;AAgBA,MAAM,wBAAwB;AAY9B,eAAsB,oBACpB,OAGI,EAAE,EAC8B;CAEpC,MAAM,kBAAkB,MAAM,eADlB,KAAK,OAAO,QAAQ,KAAK,CACY;AACjD,KAAI,CAAC,gBAAgB,SAAS,CAAC,gBAAgB,QAC7C,OAAM,IAAI,MACR,uFACD;CAMH,MAAM,gBAAe,MAHW,sBAC9B,gBAAgB,QACjB,GACuC;AACxC,KAAI,CAAC,aACH,OAAM,IAAI,MACR,yGACD;CAGH,MAAM,SAAS,KAAK,UAAU,qBAAqB,oBAAoB,CAAC;CACxE,MAAM,gBAAgB,GAAG,aAAa;CACtC,MAAM,aAAa,sBAAsB,cAAc;CACvD,MAAM,aAAa;EACjB;EACA;EACA;EACA;EACA,GAAG,cAAc;EAClB,CAAC,KAAK,IAAI;CACX,MAAM,UAAU,MAAM,kBAAkB,aAAa;CAErD,MAAM,WAAW,MAAM,OAAO,QAAQ,YAAY,kBAAkB;AACpE,KAAI,UAAU;AACZ,MAAI,SAAS,YAAY,QACvB,QAAO;GACL;GACA;GACA;GACA,gBAAgB;GAChB,YAAY;GACZ,QAAQ;GACR;GACD;AAGH,QAAM,IAAI,MACR,GAAG,WAAW,qBAAqB,iBAAiB,sDACrD;;CAGH,MAAM,cAAc,MAAM,+BAA+B;EACvD;EACA;EACA;EACA,SAAS,YAAY,cAAc;EACnC;EACA,OAAO,YAAY,cAAc;EACjC,MAAM;GACJ,iBAAiB,cAAc,oBAAoB,aAAa;GAChE;GACA;GACD,CAAC,KAAK,KAAK;EACb,CAAC;AAEF,QAAO;EACL;EACA;EACA;EACA,gBAAgB,YAAY;EAC5B,YAAY;EACZ,QAAQ,YAAY;EACpB;EACD;;AAGH,eAAsB,6BAA4C;AAChE,KAAI;EACF,MAAM,SAAS,MAAM,qBAAqB;AAE1C,MAAI,OAAO,WAAW,sBAAsB;AAC1C,WAAQ,IACN,MAAM,MAAM,IAAI,EAChB,GAAG,OAAO,cAAc,4BAA4B,OAAO,WAAW,MACtE,MAAM,KAAK,OAAO,WAAW,CAC9B;AACD;;EAGF,MAAM,OACJ,OAAO,WAAW,eAAe,YAAY;AAC/C,UAAQ,IACN,MAAM,MAAM,IAAI,EAChB,GAAG,KAAK,gBAAgB,OAAO,cAAc,IAC7C,MAAM,KAAK,OAAO,eAAe,CAClC;UACM,OAAO;AACd,UAAQ,MAAM,MAAM,IAAI,SAAS,EAAG,MAAgB,QAAQ;AAC5D,UAAQ,KAAK,EAAE;;;AAInB,eAAe,kBAAkB,cAAuC;CACtE,MAAM,WAAW,MAAM,GAAG,SAAS,4BAA4B,EAAE,QAAQ;CACzE,MAAM,gBAAgB,YAAY,aAAa;AAE/C,QAAO,SACJ,WAAW,qBAAqB,aAAa,CAC7C,WAAW,sBAAsB,cAAc;;AAGpD,SAAS,6BAAqC;CAC5C,MAAM,aAAa,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;CAC/D,MAAM,aAAa,CACjB,KAAK,QAAQ,YAAY,sBAAsB,sBAAsB,EACrE,KAAK,QAAQ,YAAY,4BAA4B,sBAAsB,CAC5E;AAED,MAAK,MAAM,aAAa,WACtB,KAAI,GAAG,WAAW,UAAU,CAAE,QAAO;AAGvC,OAAM,IAAI,MACR,6CAA6C,WAAW,KAAK,KAAK,GACnE"}
@@ -1,5 +1,5 @@
1
- import { o as readManifest } from "./index.js";
2
- import { i as getTemplateVersionFromTag, n as getLatestTemplateTag } from "./git-ops-C2CIjuce.js";
1
+ import { r as readManifest } from "./manifest-CqIDnbgs.js";
2
+ import { i as getTemplateVersionFromTag, n as getLatestTemplateTag } from "./git-ops-BD7JNnal.js";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
5
  //#region src/commands/status.ts
@@ -45,4 +45,4 @@ async function statusCommand(options) {
45
45
  //#endregion
46
46
  export { statusCommand };
47
47
 
48
- //# sourceMappingURL=status-CKe4aKso.js.map
48
+ //# sourceMappingURL=status-BXYaQ4a2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-CKe4aKso.js","names":[],"sources":["../src/commands/status.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n getLatestTemplateTag,\n getTemplateVersionFromTag,\n} from \"../utils/git-ops.js\";\nimport { readManifest } from \"../utils/manifest.js\";\n\nexport interface StatusOptions {\n mosaicTemplatePath?: string;\n}\n\nexport async function statusCommand(options: StatusOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n\n console.log();\n console.log(chalk.bold(\"Mosaic Template Status\"));\n console.log();\n console.log(chalk.dim(\" Template type:\"), manifest.templateType);\n console.log(chalk.dim(\" Current version:\"), manifest.templateVersion);\n console.log(chalk.dim(\" Template commit:\"), manifest.templateCommit);\n console.log(chalk.dim(\" Created:\"), manifest.createdAt);\n if (manifest.lastSyncedAt) {\n console.log(chalk.dim(\" Last synced:\"), manifest.lastSyncedAt);\n }\n\n const rawPath =\n options.mosaicTemplatePath || process.env.MOSAIC_TEMPLATE_PATH;\n const mosaicTemplatePath = rawPath ? path.resolve(rawPath) : undefined;\n\n if (mosaicTemplatePath) {\n const latestTag = getLatestTemplateTag(\n manifest.templateType,\n mosaicTemplatePath,\n );\n if (latestTag) {\n const latestVersion = getTemplateVersionFromTag(latestTag);\n console.log(chalk.dim(\" Latest version:\"), latestVersion);\n console.log();\n\n if (latestVersion !== manifest.templateVersion) {\n console.log(\n chalk.yellow(\n ` Update available: ${manifest.templateVersion} → ${latestVersion}`,\n ),\n );\n console.log(\n chalk.dim(\" Run:\"),\n `create sync --mosaic-template-path ${mosaicTemplatePath}`,\n );\n } else {\n console.log(chalk.green(\" Up to date\"));\n }\n } else {\n console.log();\n console.log(chalk.yellow(\" No template tags found in mosaic repo.\"));\n console.log(\n chalk.dim(\" Run:\"),\n `cd ${mosaicTemplatePath} && pnpm template:tag`,\n );\n }\n } else {\n console.log();\n console.log(\n chalk.dim(\n \" Use --mosaic-template-path or set MOSAIC_TEMPLATE_PATH to check for updates\",\n ),\n );\n }\n\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;AAYA,eAAsB,cAAc,SAAuC;CACzE,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,yBAAyB,CAAC;AACjD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,mBAAmB,EAAE,SAAS,aAAa;AACjE,UAAQ,IAAI,MAAM,IAAI,qBAAqB,EAAE,SAAS,gBAAgB;AACtE,UAAQ,IAAI,MAAM,IAAI,qBAAqB,EAAE,SAAS,eAAe;AACrE,UAAQ,IAAI,MAAM,IAAI,aAAa,EAAE,SAAS,UAAU;AACxD,MAAI,SAAS,aACX,SAAQ,IAAI,MAAM,IAAI,iBAAiB,EAAE,SAAS,aAAa;EAGjE,MAAM,UACJ,QAAQ,sBAAsB,QAAQ,IAAI;EAC5C,MAAM,qBAAqB,UAAU,KAAK,QAAQ,QAAQ,GAAG,KAAA;AAE7D,MAAI,oBAAoB;GACtB,MAAM,YAAY,qBAChB,SAAS,cACT,mBACD;AACD,OAAI,WAAW;IACb,MAAM,gBAAgB,0BAA0B,UAAU;AAC1D,YAAQ,IAAI,MAAM,IAAI,oBAAoB,EAAE,cAAc;AAC1D,YAAQ,KAAK;AAEb,QAAI,kBAAkB,SAAS,iBAAiB;AAC9C,aAAQ,IACN,MAAM,OACJ,uBAAuB,SAAS,gBAAgB,KAAK,gBACtD,CACF;AACD,aAAQ,IACN,MAAM,IAAI,SAAS,EACnB,sCAAsC,qBACvC;UAED,SAAQ,IAAI,MAAM,MAAM,eAAe,CAAC;UAErC;AACL,YAAQ,KAAK;AACb,YAAQ,IAAI,MAAM,OAAO,2CAA2C,CAAC;AACrE,YAAQ,IACN,MAAM,IAAI,SAAS,EACnB,MAAM,mBAAmB,uBAC1B;;SAEE;AACL,WAAQ,KAAK;AACb,WAAQ,IACN,MAAM,IACJ,gFACD,CACF;;AAGH,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
1
+ {"version":3,"file":"status-BXYaQ4a2.js","names":[],"sources":["../src/commands/status.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n getLatestTemplateTag,\n getTemplateVersionFromTag,\n} from \"../utils/git-ops.js\";\nimport { readManifest } from \"../utils/manifest.js\";\n\nexport interface StatusOptions {\n mosaicTemplatePath?: string;\n}\n\nexport async function statusCommand(options: StatusOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n\n console.log();\n console.log(chalk.bold(\"Mosaic Template Status\"));\n console.log();\n console.log(chalk.dim(\" Template type:\"), manifest.templateType);\n console.log(chalk.dim(\" Current version:\"), manifest.templateVersion);\n console.log(chalk.dim(\" Template commit:\"), manifest.templateCommit);\n console.log(chalk.dim(\" Created:\"), manifest.createdAt);\n if (manifest.lastSyncedAt) {\n console.log(chalk.dim(\" Last synced:\"), manifest.lastSyncedAt);\n }\n\n const rawPath =\n options.mosaicTemplatePath || process.env.MOSAIC_TEMPLATE_PATH;\n const mosaicTemplatePath = rawPath ? path.resolve(rawPath) : undefined;\n\n if (mosaicTemplatePath) {\n const latestTag = getLatestTemplateTag(\n manifest.templateType,\n mosaicTemplatePath,\n );\n if (latestTag) {\n const latestVersion = getTemplateVersionFromTag(latestTag);\n console.log(chalk.dim(\" Latest version:\"), latestVersion);\n console.log();\n\n if (latestVersion !== manifest.templateVersion) {\n console.log(\n chalk.yellow(\n ` Update available: ${manifest.templateVersion} → ${latestVersion}`,\n ),\n );\n console.log(\n chalk.dim(\" Run:\"),\n `create sync --mosaic-template-path ${mosaicTemplatePath}`,\n );\n } else {\n console.log(chalk.green(\" Up to date\"));\n }\n } else {\n console.log();\n console.log(chalk.yellow(\" No template tags found in mosaic repo.\"));\n console.log(\n chalk.dim(\" Run:\"),\n `cd ${mosaicTemplatePath} && pnpm template:tag`,\n );\n }\n } else {\n console.log();\n console.log(\n chalk.dim(\n \" Use --mosaic-template-path or set MOSAIC_TEMPLATE_PATH to check for updates\",\n ),\n );\n }\n\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;AAYA,eAAsB,cAAc,SAAuC;CACzE,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,yBAAyB,CAAC;AACjD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,mBAAmB,EAAE,SAAS,aAAa;AACjE,UAAQ,IAAI,MAAM,IAAI,qBAAqB,EAAE,SAAS,gBAAgB;AACtE,UAAQ,IAAI,MAAM,IAAI,qBAAqB,EAAE,SAAS,eAAe;AACrE,UAAQ,IAAI,MAAM,IAAI,aAAa,EAAE,SAAS,UAAU;AACxD,MAAI,SAAS,aACX,SAAQ,IAAI,MAAM,IAAI,iBAAiB,EAAE,SAAS,aAAa;EAGjE,MAAM,UACJ,QAAQ,sBAAsB,QAAQ,IAAI;EAC5C,MAAM,qBAAqB,UAAU,KAAK,QAAQ,QAAQ,GAAG,KAAA;AAE7D,MAAI,oBAAoB;GACtB,MAAM,YAAY,qBAChB,SAAS,cACT,mBACD;AACD,OAAI,WAAW;IACb,MAAM,gBAAgB,0BAA0B,UAAU;AAC1D,YAAQ,IAAI,MAAM,IAAI,oBAAoB,EAAE,cAAc;AAC1D,YAAQ,KAAK;AAEb,QAAI,kBAAkB,SAAS,iBAAiB;AAC9C,aAAQ,IACN,MAAM,OACJ,uBAAuB,SAAS,gBAAgB,KAAK,gBACtD,CACF;AACD,aAAQ,IACN,MAAM,IAAI,SAAS,EACnB,sCAAsC,qBACvC;UAED,SAAQ,IAAI,MAAM,MAAM,eAAe,CAAC;UAErC;AACL,YAAQ,KAAK;AACb,YAAQ,IAAI,MAAM,OAAO,2CAA2C,CAAC;AACrE,YAAQ,IACN,MAAM,IAAI,SAAS,EACnB,MAAM,mBAAmB,uBAC1B;;SAEE;AACL,WAAQ,KAAK;AACb,WAAQ,IACN,MAAM,IACJ,gFACD,CACF;;AAGH,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
@@ -1,5 +1,5 @@
1
- import { o as readManifest, s as resolveMosaicTemplatePath } from "./index.js";
2
- import { i as getTemplateVersionFromTag, n as getLatestTemplateTag, r as getTemplateDiff } from "./git-ops-C2CIjuce.js";
1
+ import { i as resolveMosaicTemplatePath, r as readManifest } from "./manifest-CqIDnbgs.js";
2
+ import { i as getTemplateVersionFromTag, n as getLatestTemplateTag, r as getTemplateDiff } from "./git-ops-BD7JNnal.js";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
5
  import fs from "fs-extra";
@@ -98,4 +98,4 @@ async function syncCommand(options) {
98
98
  //#endregion
99
99
  export { syncCommand };
100
100
 
101
- //# sourceMappingURL=sync-D1vkoofl.js.map
101
+ //# sourceMappingURL=sync-BayU4w1j.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-D1vkoofl.js","names":[],"sources":["../src/commands/sync.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport {\n getLatestTemplateTag,\n getTemplateVersionFromTag,\n getTemplateDiff,\n} from \"../utils/git-ops.js\";\nimport {\n readManifest,\n resolveMosaicTemplatePath,\n type MosaicManifest,\n} from \"../utils/manifest.js\";\n\nexport interface SyncOptions {\n mosaicTemplatePath?: string;\n to?: string;\n}\n\nfunction generateSyncContext(\n manifest: MosaicManifest,\n toVersion: string,\n diff: string,\n notes: string,\n): string {\n let content = `# Mosaic Sync Context\n\n## App Info\n- **Template:** ${manifest.templateType}\n- **Current version:** ${manifest.templateVersion}\n- **Target version:** ${toVersion}\n\n## Placeholder Mappings\n\nWhen applying template changes, replace these placeholder tokens with the actual values:\n\n| Placeholder | Value |\n|------------|-------|\n${Object.entries(manifest.placeholders)\n .map(([k, v]) => `| \\`${k}\\` | \\`${v}\\` |`)\n .join(\"\\n\")}\n\n## Template Changes (${manifest.templateVersion} → ${toVersion})\n\n\\`\\`\\`diff\n${diff}\n\\`\\`\\`\n`;\n\n if (notes.trim()) {\n content += `\n## Divergence Notes (from mosaic-template-notes.md)\n\n${notes}\n`;\n }\n\n content += `\n## Instructions\n\n1. Apply the template changes above to this app\n2. When you see placeholder tokens (e.g. \\`__APP_NAME__\\`), replace them with the actual values from the mapping table\n3. Check the divergence notes — preserve intentional divergences\n4. For files not modified locally: apply changes directly\n5. For files modified locally: merge intelligently, preserving local customizations\n6. After applying all changes, run: \\`pnpm install && pnpm build && pnpm lint\\`\n7. Update \\`.mosaic-template.json\\`: set \\`templateVersion\\` to \\`\"${toVersion}\"\\` and update \\`templateCommit\\`\n8. If you made decisions about merge conflicts, add notes to \\`mosaic-template-notes.md\\`\n9. Delete this file (\\`.mosaic-sync-context.md\\`) when done\n`;\n\n return content;\n}\n\nexport async function syncCommand(options: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n const mosaicTemplatePath = resolveMosaicTemplatePath(options);\n\n const fromTag = `template/${manifest.templateType}/${manifest.templateVersion}`;\n\n let toTag: string;\n if (options.to) {\n toTag = `template/${manifest.templateType}/${options.to}`;\n } else {\n const latest = getLatestTemplateTag(\n manifest.templateType,\n mosaicTemplatePath,\n );\n if (!latest) {\n console.error(\n chalk.red(\n \"No template tags found. Run 'pnpm template:tag' in the mosaic repo first.\",\n ),\n );\n process.exit(1);\n }\n toTag = latest;\n }\n\n const toVersion = getTemplateVersionFromTag(toTag);\n\n if (toVersion === manifest.templateVersion) {\n console.log(chalk.green(\"Already up to date.\"));\n return;\n }\n\n const diff = getTemplateDiff(\n mosaicTemplatePath,\n manifest.source.templatePath,\n fromTag,\n toTag,\n );\n\n if (!diff.trim()) {\n console.log(chalk.green(\"No template file changes between versions.\"));\n return;\n }\n\n // Read mosaic-template-notes.md if it exists\n const notesPath = path.join(cwd, \"mosaic-template-notes.md\");\n let notes = \"\";\n if (await fs.pathExists(notesPath)) {\n notes = await fs.readFile(notesPath, \"utf-8\");\n }\n\n const context = generateSyncContext(manifest, toVersion, diff, notes);\n const contextPath = path.join(cwd, \".mosaic-sync-context.md\");\n await fs.writeFile(contextPath, context);\n\n console.log();\n console.log(chalk.bold(\"Sync Context Generated\"));\n console.log();\n console.log(chalk.dim(\" From:\"), manifest.templateVersion);\n console.log(chalk.dim(\" To:\"), toVersion);\n console.log(chalk.dim(\" Context file:\"), \".mosaic-sync-context.md\");\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1.\"), \"Open Claude Code in this directory\");\n console.log(\n chalk.dim(\" 2.\"),\n 'Tell Claude: \"Read .mosaic-sync-context.md and apply the template changes\"',\n );\n console.log(\n chalk.dim(\" 3.\"),\n \"Review Claude's changes, then delete .mosaic-sync-context.md\",\n );\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;AAmBA,SAAS,oBACP,UACA,WACA,MACA,OACQ;CACR,IAAI,UAAU;;;kBAGE,SAAS,aAAa;yBACf,SAAS,gBAAgB;wBAC1B,UAAU;;;;;;;;EAQhC,OAAO,QAAQ,SAAS,aAAa,CACpC,KAAK,CAAC,GAAG,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAC1C,KAAK,KAAK,CAAC;;uBAES,SAAS,gBAAgB,KAAK,UAAU;;;EAG7D,KAAK;;;AAIL,KAAI,MAAM,MAAM,CACd,YAAW;;;EAGb,MAAM;;AAIN,YAAW;;;;;;;;;qEASwD,UAAU;;;;AAK7E,QAAO;;AAGT,eAAsB,YAAY,SAAqC;CACrE,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;EACxC,MAAM,qBAAqB,0BAA0B,QAAQ;EAE7D,MAAM,UAAU,YAAY,SAAS,aAAa,GAAG,SAAS;EAE9D,IAAI;AACJ,MAAI,QAAQ,GACV,SAAQ,YAAY,SAAS,aAAa,GAAG,QAAQ;OAChD;GACL,MAAM,SAAS,qBACb,SAAS,cACT,mBACD;AACD,OAAI,CAAC,QAAQ;AACX,YAAQ,MACN,MAAM,IACJ,4EACD,CACF;AACD,YAAQ,KAAK,EAAE;;AAEjB,WAAQ;;EAGV,MAAM,YAAY,0BAA0B,MAAM;AAElD,MAAI,cAAc,SAAS,iBAAiB;AAC1C,WAAQ,IAAI,MAAM,MAAM,sBAAsB,CAAC;AAC/C;;EAGF,MAAM,OAAO,gBACX,oBACA,SAAS,OAAO,cAChB,SACA,MACD;AAED,MAAI,CAAC,KAAK,MAAM,EAAE;AAChB,WAAQ,IAAI,MAAM,MAAM,6CAA6C,CAAC;AACtE;;EAIF,MAAM,YAAY,KAAK,KAAK,KAAK,2BAA2B;EAC5D,IAAI,QAAQ;AACZ,MAAI,MAAM,GAAG,WAAW,UAAU,CAChC,SAAQ,MAAM,GAAG,SAAS,WAAW,QAAQ;EAG/C,MAAM,UAAU,oBAAoB,UAAU,WAAW,MAAM,MAAM;EACrE,MAAM,cAAc,KAAK,KAAK,KAAK,0BAA0B;AAC7D,QAAM,GAAG,UAAU,aAAa,QAAQ;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,yBAAyB,CAAC;AACjD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,UAAU,EAAE,SAAS,gBAAgB;AAC3D,UAAQ,IAAI,MAAM,IAAI,QAAQ,EAAE,UAAU;AAC1C,UAAQ,IAAI,MAAM,IAAI,kBAAkB,EAAE,0BAA0B;AACpE,UAAQ,KAAK;AACb,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,qCAAqC;AACpE,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,+EACD;AACD,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,+DACD;AACD,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
1
+ {"version":3,"file":"sync-BayU4w1j.js","names":[],"sources":["../src/commands/sync.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport {\n getLatestTemplateTag,\n getTemplateVersionFromTag,\n getTemplateDiff,\n} from \"../utils/git-ops.js\";\nimport {\n readManifest,\n resolveMosaicTemplatePath,\n type MosaicManifest,\n} from \"../utils/manifest.js\";\n\nexport interface SyncOptions {\n mosaicTemplatePath?: string;\n to?: string;\n}\n\nfunction generateSyncContext(\n manifest: MosaicManifest,\n toVersion: string,\n diff: string,\n notes: string,\n): string {\n let content = `# Mosaic Sync Context\n\n## App Info\n- **Template:** ${manifest.templateType}\n- **Current version:** ${manifest.templateVersion}\n- **Target version:** ${toVersion}\n\n## Placeholder Mappings\n\nWhen applying template changes, replace these placeholder tokens with the actual values:\n\n| Placeholder | Value |\n|------------|-------|\n${Object.entries(manifest.placeholders)\n .map(([k, v]) => `| \\`${k}\\` | \\`${v}\\` |`)\n .join(\"\\n\")}\n\n## Template Changes (${manifest.templateVersion} → ${toVersion})\n\n\\`\\`\\`diff\n${diff}\n\\`\\`\\`\n`;\n\n if (notes.trim()) {\n content += `\n## Divergence Notes (from mosaic-template-notes.md)\n\n${notes}\n`;\n }\n\n content += `\n## Instructions\n\n1. Apply the template changes above to this app\n2. When you see placeholder tokens (e.g. \\`__APP_NAME__\\`), replace them with the actual values from the mapping table\n3. Check the divergence notes — preserve intentional divergences\n4. For files not modified locally: apply changes directly\n5. For files modified locally: merge intelligently, preserving local customizations\n6. After applying all changes, run: \\`pnpm install && pnpm build && pnpm lint\\`\n7. Update \\`.mosaic-template.json\\`: set \\`templateVersion\\` to \\`\"${toVersion}\"\\` and update \\`templateCommit\\`\n8. If you made decisions about merge conflicts, add notes to \\`mosaic-template-notes.md\\`\n9. Delete this file (\\`.mosaic-sync-context.md\\`) when done\n`;\n\n return content;\n}\n\nexport async function syncCommand(options: SyncOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n const mosaicTemplatePath = resolveMosaicTemplatePath(options);\n\n const fromTag = `template/${manifest.templateType}/${manifest.templateVersion}`;\n\n let toTag: string;\n if (options.to) {\n toTag = `template/${manifest.templateType}/${options.to}`;\n } else {\n const latest = getLatestTemplateTag(\n manifest.templateType,\n mosaicTemplatePath,\n );\n if (!latest) {\n console.error(\n chalk.red(\n \"No template tags found. Run 'pnpm template:tag' in the mosaic repo first.\",\n ),\n );\n process.exit(1);\n }\n toTag = latest;\n }\n\n const toVersion = getTemplateVersionFromTag(toTag);\n\n if (toVersion === manifest.templateVersion) {\n console.log(chalk.green(\"Already up to date.\"));\n return;\n }\n\n const diff = getTemplateDiff(\n mosaicTemplatePath,\n manifest.source.templatePath,\n fromTag,\n toTag,\n );\n\n if (!diff.trim()) {\n console.log(chalk.green(\"No template file changes between versions.\"));\n return;\n }\n\n // Read mosaic-template-notes.md if it exists\n const notesPath = path.join(cwd, \"mosaic-template-notes.md\");\n let notes = \"\";\n if (await fs.pathExists(notesPath)) {\n notes = await fs.readFile(notesPath, \"utf-8\");\n }\n\n const context = generateSyncContext(manifest, toVersion, diff, notes);\n const contextPath = path.join(cwd, \".mosaic-sync-context.md\");\n await fs.writeFile(contextPath, context);\n\n console.log();\n console.log(chalk.bold(\"Sync Context Generated\"));\n console.log();\n console.log(chalk.dim(\" From:\"), manifest.templateVersion);\n console.log(chalk.dim(\" To:\"), toVersion);\n console.log(chalk.dim(\" Context file:\"), \".mosaic-sync-context.md\");\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1.\"), \"Open Claude Code in this directory\");\n console.log(\n chalk.dim(\" 2.\"),\n 'Tell Claude: \"Read .mosaic-sync-context.md and apply the template changes\"',\n );\n console.log(\n chalk.dim(\" 3.\"),\n \"Review Claude's changes, then delete .mosaic-sync-context.md\",\n );\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;AAmBA,SAAS,oBACP,UACA,WACA,MACA,OACQ;CACR,IAAI,UAAU;;;kBAGE,SAAS,aAAa;yBACf,SAAS,gBAAgB;wBAC1B,UAAU;;;;;;;;EAQhC,OAAO,QAAQ,SAAS,aAAa,CACpC,KAAK,CAAC,GAAG,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAC1C,KAAK,KAAK,CAAC;;uBAES,SAAS,gBAAgB,KAAK,UAAU;;;EAG7D,KAAK;;;AAIL,KAAI,MAAM,MAAM,CACd,YAAW;;;EAGb,MAAM;;AAIN,YAAW;;;;;;;;;qEASwD,UAAU;;;;AAK7E,QAAO;;AAGT,eAAsB,YAAY,SAAqC;CACrE,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;EACxC,MAAM,qBAAqB,0BAA0B,QAAQ;EAE7D,MAAM,UAAU,YAAY,SAAS,aAAa,GAAG,SAAS;EAE9D,IAAI;AACJ,MAAI,QAAQ,GACV,SAAQ,YAAY,SAAS,aAAa,GAAG,QAAQ;OAChD;GACL,MAAM,SAAS,qBACb,SAAS,cACT,mBACD;AACD,OAAI,CAAC,QAAQ;AACX,YAAQ,MACN,MAAM,IACJ,4EACD,CACF;AACD,YAAQ,KAAK,EAAE;;AAEjB,WAAQ;;EAGV,MAAM,YAAY,0BAA0B,MAAM;AAElD,MAAI,cAAc,SAAS,iBAAiB;AAC1C,WAAQ,IAAI,MAAM,MAAM,sBAAsB,CAAC;AAC/C;;EAGF,MAAM,OAAO,gBACX,oBACA,SAAS,OAAO,cAChB,SACA,MACD;AAED,MAAI,CAAC,KAAK,MAAM,EAAE;AAChB,WAAQ,IAAI,MAAM,MAAM,6CAA6C,CAAC;AACtE;;EAIF,MAAM,YAAY,KAAK,KAAK,KAAK,2BAA2B;EAC5D,IAAI,QAAQ;AACZ,MAAI,MAAM,GAAG,WAAW,UAAU,CAChC,SAAQ,MAAM,GAAG,SAAS,WAAW,QAAQ;EAG/C,MAAM,UAAU,oBAAoB,UAAU,WAAW,MAAM,MAAM;EACrE,MAAM,cAAc,KAAK,KAAK,KAAK,0BAA0B;AAC7D,QAAM,GAAG,UAAU,aAAa,QAAQ;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,yBAAyB,CAAC;AACjD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,UAAU,EAAE,SAAS,gBAAgB;AAC3D,UAAQ,IAAI,MAAM,IAAI,QAAQ,EAAE,UAAU;AAC1C,UAAQ,IAAI,MAAM,IAAI,kBAAkB,EAAE,0BAA0B;AACpE,UAAQ,KAAK;AACb,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,qCAAqC;AACpE,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,+EACD;AACD,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,+DACD;AACD,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
@@ -0,0 +1,35 @@
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ import { fileURLToPath } from "node:url";
4
+ //#region src/utils/case-converters.ts
5
+ /** Lowercase, hyphenated, npm-package-name-safe form: "My Cool App" → "my-cool-app". */
6
+ function toKebabCase(str) {
7
+ return str.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
8
+ }
9
+ /** Display form derived from a kebab-case name: "my-cool-app" → "My Cool App". */
10
+ function toTitleCase(str) {
11
+ return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
12
+ }
13
+ /** Identifier form for env vars and DB names: "my-cool-app" → "my_cool_app". */
14
+ function toSnakeCase(str) {
15
+ return str.replace(/-/g, "_");
16
+ }
17
+ //#endregion
18
+ //#region src/utils/template-versions.ts
19
+ const FALLBACK_TEMPLATE_VERSION = "1.0.0";
20
+ function readTemplateVersions() {
21
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
22
+ const candidates = [path.resolve(currentDir, "../template-versions.json"), path.resolve(currentDir, "../../template-versions.json")];
23
+ for (const versionsPath of candidates) try {
24
+ const content = fs.readFileSync(versionsPath, "utf-8");
25
+ return JSON.parse(content);
26
+ } catch {}
27
+ return {};
28
+ }
29
+ function getTemplateVersion(templateType) {
30
+ return readTemplateVersions()[templateType] ?? FALLBACK_TEMPLATE_VERSION;
31
+ }
32
+ //#endregion
33
+ export { toTitleCase as i, toKebabCase as n, toSnakeCase as r, getTemplateVersion as t };
34
+
35
+ //# sourceMappingURL=template-versions-CEIP9vhl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-versions-CEIP9vhl.js","names":[],"sources":["../src/utils/case-converters.ts","../src/utils/template-versions.ts"],"sourcesContent":["/** Lowercase, hyphenated, npm-package-name-safe form: \"My Cool App\" → \"my-cool-app\". */\nexport function toKebabCase(str: string): string {\n return str\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/** Display form derived from a kebab-case name: \"my-cool-app\" → \"My Cool App\". */\nexport function toTitleCase(str: string): string {\n return str\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\n/** Identifier form for env vars and DB names: \"my-cool-app\" → \"my_cool_app\". */\nexport function toSnakeCase(str: string): string {\n return str.replace(/-/g, \"_\");\n}\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport fs from \"fs-extra\";\n\nconst FALLBACK_TEMPLATE_VERSION = \"1.0.0\";\n\nexport function readTemplateVersions(): Record<string, string> {\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(currentDir, \"../template-versions.json\"),\n path.resolve(currentDir, \"../../template-versions.json\"),\n ];\n\n for (const versionsPath of candidates) {\n try {\n const content = fs.readFileSync(versionsPath, \"utf-8\");\n return JSON.parse(content);\n } catch {\n // Try the next path. Source tests and bundled CLI resolve differently.\n }\n }\n\n return {};\n}\n\nexport function getTemplateVersion(templateType: string): string {\n return readTemplateVersions()[templateType] ?? FALLBACK_TEMPLATE_VERSION;\n}\n"],"mappings":";;;;;AACA,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,aAAa,CACb,QAAQ,eAAe,IAAI,CAC3B,QAAQ,OAAO,IAAI,CACnB,QAAQ,UAAU,GAAG;;;AAI1B,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,IAAI;;;AAId,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IAAI,QAAQ,MAAM,IAAI;;;;ACf/B,MAAM,4BAA4B;AAElC,SAAgB,uBAA+C;CAC7D,MAAM,aAAa,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;CAC/D,MAAM,aAAa,CACjB,KAAK,QAAQ,YAAY,4BAA4B,EACrD,KAAK,QAAQ,YAAY,+BAA+B,CACzD;AAED,MAAK,MAAM,gBAAgB,WACzB,KAAI;EACF,MAAM,UAAU,GAAG,aAAa,cAAc,QAAQ;AACtD,SAAO,KAAK,MAAM,QAAQ;SACpB;AAKV,QAAO,EAAE;;AAGX,SAAgB,mBAAmB,cAA8B;AAC/D,QAAO,sBAAsB,CAAC,iBAAiB"}
@@ -1,5 +1,5 @@
1
- import { o as readManifest, s as resolveMosaicTemplatePath } from "./index.js";
2
- import { t as getFileAtTag } from "./git-ops-C2CIjuce.js";
1
+ import { i as resolveMosaicTemplatePath, r as readManifest } from "./manifest-CqIDnbgs.js";
2
+ import { t as getFileAtTag } from "./git-ops-BD7JNnal.js";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
5
  import fs from "fs-extra";
@@ -82,4 +82,4 @@ async function upstreamCommand(options) {
82
82
  //#endregion
83
83
  export { upstreamCommand };
84
84
 
85
- //# sourceMappingURL=upstream-gUHLWSR1.js.map
85
+ //# sourceMappingURL=upstream-CZEzLrS4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-gUHLWSR1.js","names":[],"sources":["../src/commands/upstream.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { getFileAtTag } from \"../utils/git-ops.js\";\nimport {\n readManifest,\n resolveMosaicTemplatePath,\n type MosaicManifest,\n} from \"../utils/manifest.js\";\n\nexport interface UpstreamOptions {\n mosaicTemplatePath?: string;\n files?: string[];\n}\n\nasync function generateUpstreamContext(\n manifest: MosaicManifest,\n mosaicTemplatePath: string,\n tag: string,\n appDir: string,\n files: string[],\n): Promise<string> {\n let content = `# Mosaic Upstream Context\n\n## App Info\n- **App name:** ${manifest.placeholders.__APP_NAME__ || \"unknown\"}\n- **Template:** ${manifest.templateType}\n- **Template version:** ${manifest.templateVersion}\n\n## Placeholder Mappings\n\nWhen generalizing app code back to template, replace these values with placeholder tokens:\n\n| Value | Placeholder |\n|-------|------------|\n${Object.entries(manifest.placeholders)\n .sort((a, b) => b[1].length - a[1].length) // longest first to avoid partial matches\n .map(([k, v]) => `| \\`${v}\\` | \\`${k}\\` |`)\n .join(\"\\n\")}\n\n## Files to Review\n\n`;\n\n for (const file of files) {\n const appFilePath = path.resolve(appDir, file);\n const templateRelPath = `${manifest.source.templatePath}/${file}`;\n\n const appContent = (await fs.pathExists(appFilePath))\n ? await fs.readFile(appFilePath, \"utf-8\")\n : null;\n const templateContent = getFileAtTag(\n mosaicTemplatePath,\n tag,\n templateRelPath,\n );\n\n content += `### ${file}\\n\\n`;\n\n if (!templateContent && appContent) {\n content += `**New file** (not in template at ${manifest.templateVersion})\\n\\n`;\n content += `\\`\\`\\`\\n${appContent}\\n\\`\\`\\`\\n\\n`;\n } else if (templateContent && !appContent) {\n content += `**Deleted** (exists in template but not in app)\\n\\n`;\n } else if (appContent && templateContent) {\n content += `**App version:**\\n\\`\\`\\`\\n${appContent}\\n\\`\\`\\`\\n\\n`;\n content += `**Template version (at ${manifest.templateVersion}):**\\n\\`\\`\\`\\n${templateContent}\\n\\`\\`\\`\\n\\n`;\n } else {\n content += `**Not found** (file does not exist in app or template)\\n\\n`;\n }\n }\n\n content += `## Instructions\n\n1. Review each file above\n2. Determine which changes are generalizable (useful for all apps) vs app-specific\n3. For generalizable changes: apply them to the template at \\`${manifest.source.templatePath}/\\`\n4. When applying, replace app-specific values with placeholders using the mapping table above (replace longest values first)\n5. After applying, bump the version in \\`packages/blueberry/template-versions.json\\`\n6. Run \\`pnpm template:tag\\` to create the new version tag\n7. Delete this file (\\`.mosaic-upstream-context.md\\`) when done\n`;\n\n return content;\n}\n\nexport async function upstreamCommand(options: UpstreamOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n const mosaicTemplatePath = resolveMosaicTemplatePath(options);\n\n if (!options.files || options.files.length === 0) {\n console.error(\n chalk.red(\"Specify files with --files <file1> <file2> ...\"),\n );\n console.log(\n chalk.dim(\n \" Example: create upstream --files src/config/getEnvConfig.ts\",\n ),\n );\n process.exit(1);\n }\n\n const tag = `template/${manifest.templateType}/${manifest.templateVersion}`;\n\n const context = await generateUpstreamContext(\n manifest,\n mosaicTemplatePath,\n tag,\n cwd,\n options.files,\n );\n const contextPath = path.join(cwd, \".mosaic-upstream-context.md\");\n await fs.writeFile(contextPath, context);\n\n console.log();\n console.log(chalk.bold(\"Upstream Context Generated\"));\n console.log();\n console.log(chalk.dim(\" Files:\"), options.files.join(\", \"));\n console.log(chalk.dim(\" Context file:\"), \".mosaic-upstream-context.md\");\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1.\"), \"Open Claude Code in the mosaic repo\");\n console.log(\n chalk.dim(\" 2.\"),\n `Tell Claude: \"Read ${path.resolve(cwd, \".mosaic-upstream-context.md\")} and apply generalizable changes to the template\"`,\n );\n console.log(chalk.dim(\" 3.\"), \"Review Claude's changes to the template\");\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;AAeA,eAAe,wBACb,UACA,oBACA,KACA,QACA,OACiB;CACjB,IAAI,UAAU;;;kBAGE,SAAS,aAAa,gBAAgB,UAAU;kBAChD,SAAS,aAAa;0BACd,SAAS,gBAAgB;;;;;;;;EAQjD,OAAO,QAAQ,SAAS,aAAa,CACpC,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,OAAO,CACzC,KAAK,CAAC,GAAG,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAC1C,KAAK,KAAK,CAAC;;;;;AAMZ,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAK;EAC9C,MAAM,kBAAkB,GAAG,SAAS,OAAO,aAAa,GAAG;EAE3D,MAAM,aAAc,MAAM,GAAG,WAAW,YAAY,GAChD,MAAM,GAAG,SAAS,aAAa,QAAQ,GACvC;EACJ,MAAM,kBAAkB,aACtB,oBACA,KACA,gBACD;AAED,aAAW,OAAO,KAAK;AAEvB,MAAI,CAAC,mBAAmB,YAAY;AAClC,cAAW,oCAAoC,SAAS,gBAAgB;AACxE,cAAW,WAAW,WAAW;aACxB,mBAAmB,CAAC,WAC7B,YAAW;WACF,cAAc,iBAAiB;AACxC,cAAW,6BAA6B,WAAW;AACnD,cAAW,0BAA0B,SAAS,gBAAgB,gBAAgB,gBAAgB;QAE9F,YAAW;;AAIf,YAAW;;;;gEAImD,SAAS,OAAO,aAAa;;;;;;AAO3F,QAAO;;AAGT,eAAsB,gBAAgB,SAAyC;CAC7E,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;EACxC,MAAM,qBAAqB,0BAA0B,QAAQ;AAE7D,MAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,WAAW,GAAG;AAChD,WAAQ,MACN,MAAM,IAAI,iDAAiD,CAC5D;AACD,WAAQ,IACN,MAAM,IACJ,gEACD,CACF;AACD,WAAQ,KAAK,EAAE;;EAKjB,MAAM,UAAU,MAAM,wBACpB,UACA,oBACA,YALsB,SAAS,aAAa,GAAG,SAAS,mBAMxD,KACA,QAAQ,MACT;EACD,MAAM,cAAc,KAAK,KAAK,KAAK,8BAA8B;AACjE,QAAM,GAAG,UAAU,aAAa,QAAQ;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,6BAA6B,CAAC;AACrD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,WAAW,EAAE,QAAQ,MAAM,KAAK,KAAK,CAAC;AAC5D,UAAQ,IAAI,MAAM,IAAI,kBAAkB,EAAE,8BAA8B;AACxE,UAAQ,KAAK;AACb,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,sCAAsC;AACrE,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,sBAAsB,KAAK,QAAQ,KAAK,8BAA8B,CAAC,mDACxE;AACD,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,0CAA0C;AACzE,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
1
+ {"version":3,"file":"upstream-CZEzLrS4.js","names":[],"sources":["../src/commands/upstream.ts"],"sourcesContent":["import path from \"node:path\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { getFileAtTag } from \"../utils/git-ops.js\";\nimport {\n readManifest,\n resolveMosaicTemplatePath,\n type MosaicManifest,\n} from \"../utils/manifest.js\";\n\nexport interface UpstreamOptions {\n mosaicTemplatePath?: string;\n files?: string[];\n}\n\nasync function generateUpstreamContext(\n manifest: MosaicManifest,\n mosaicTemplatePath: string,\n tag: string,\n appDir: string,\n files: string[],\n): Promise<string> {\n let content = `# Mosaic Upstream Context\n\n## App Info\n- **App name:** ${manifest.placeholders.__APP_NAME__ || \"unknown\"}\n- **Template:** ${manifest.templateType}\n- **Template version:** ${manifest.templateVersion}\n\n## Placeholder Mappings\n\nWhen generalizing app code back to template, replace these values with placeholder tokens:\n\n| Value | Placeholder |\n|-------|------------|\n${Object.entries(manifest.placeholders)\n .sort((a, b) => b[1].length - a[1].length) // longest first to avoid partial matches\n .map(([k, v]) => `| \\`${v}\\` | \\`${k}\\` |`)\n .join(\"\\n\")}\n\n## Files to Review\n\n`;\n\n for (const file of files) {\n const appFilePath = path.resolve(appDir, file);\n const templateRelPath = `${manifest.source.templatePath}/${file}`;\n\n const appContent = (await fs.pathExists(appFilePath))\n ? await fs.readFile(appFilePath, \"utf-8\")\n : null;\n const templateContent = getFileAtTag(\n mosaicTemplatePath,\n tag,\n templateRelPath,\n );\n\n content += `### ${file}\\n\\n`;\n\n if (!templateContent && appContent) {\n content += `**New file** (not in template at ${manifest.templateVersion})\\n\\n`;\n content += `\\`\\`\\`\\n${appContent}\\n\\`\\`\\`\\n\\n`;\n } else if (templateContent && !appContent) {\n content += `**Deleted** (exists in template but not in app)\\n\\n`;\n } else if (appContent && templateContent) {\n content += `**App version:**\\n\\`\\`\\`\\n${appContent}\\n\\`\\`\\`\\n\\n`;\n content += `**Template version (at ${manifest.templateVersion}):**\\n\\`\\`\\`\\n${templateContent}\\n\\`\\`\\`\\n\\n`;\n } else {\n content += `**Not found** (file does not exist in app or template)\\n\\n`;\n }\n }\n\n content += `## Instructions\n\n1. Review each file above\n2. Determine which changes are generalizable (useful for all apps) vs app-specific\n3. For generalizable changes: apply them to the template at \\`${manifest.source.templatePath}/\\`\n4. When applying, replace app-specific values with placeholders using the mapping table above (replace longest values first)\n5. After applying, bump the version in \\`packages/blueberry/template-versions.json\\`\n6. Run \\`pnpm template:tag\\` to create the new version tag\n7. Delete this file (\\`.mosaic-upstream-context.md\\`) when done\n`;\n\n return content;\n}\n\nexport async function upstreamCommand(options: UpstreamOptions): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const manifest = await readManifest(cwd);\n const mosaicTemplatePath = resolveMosaicTemplatePath(options);\n\n if (!options.files || options.files.length === 0) {\n console.error(\n chalk.red(\"Specify files with --files <file1> <file2> ...\"),\n );\n console.log(\n chalk.dim(\n \" Example: create upstream --files src/config/getEnvConfig.ts\",\n ),\n );\n process.exit(1);\n }\n\n const tag = `template/${manifest.templateType}/${manifest.templateVersion}`;\n\n const context = await generateUpstreamContext(\n manifest,\n mosaicTemplatePath,\n tag,\n cwd,\n options.files,\n );\n const contextPath = path.join(cwd, \".mosaic-upstream-context.md\");\n await fs.writeFile(contextPath, context);\n\n console.log();\n console.log(chalk.bold(\"Upstream Context Generated\"));\n console.log();\n console.log(chalk.dim(\" Files:\"), options.files.join(\", \"));\n console.log(chalk.dim(\" Context file:\"), \".mosaic-upstream-context.md\");\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1.\"), \"Open Claude Code in the mosaic repo\");\n console.log(\n chalk.dim(\" 2.\"),\n `Tell Claude: \"Read ${path.resolve(cwd, \".mosaic-upstream-context.md\")} and apply generalizable changes to the template\"`,\n );\n console.log(chalk.dim(\" 3.\"), \"Review Claude's changes to the template\");\n console.log();\n } catch (error) {\n console.error(chalk.red((error as Error).message));\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;AAeA,eAAe,wBACb,UACA,oBACA,KACA,QACA,OACiB;CACjB,IAAI,UAAU;;;kBAGE,SAAS,aAAa,gBAAgB,UAAU;kBAChD,SAAS,aAAa;0BACd,SAAS,gBAAgB;;;;;;;;EAQjD,OAAO,QAAQ,SAAS,aAAa,CACpC,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,OAAO,CACzC,KAAK,CAAC,GAAG,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAC1C,KAAK,KAAK,CAAC;;;;;AAMZ,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAK;EAC9C,MAAM,kBAAkB,GAAG,SAAS,OAAO,aAAa,GAAG;EAE3D,MAAM,aAAc,MAAM,GAAG,WAAW,YAAY,GAChD,MAAM,GAAG,SAAS,aAAa,QAAQ,GACvC;EACJ,MAAM,kBAAkB,aACtB,oBACA,KACA,gBACD;AAED,aAAW,OAAO,KAAK;AAEvB,MAAI,CAAC,mBAAmB,YAAY;AAClC,cAAW,oCAAoC,SAAS,gBAAgB;AACxE,cAAW,WAAW,WAAW;aACxB,mBAAmB,CAAC,WAC7B,YAAW;WACF,cAAc,iBAAiB;AACxC,cAAW,6BAA6B,WAAW;AACnD,cAAW,0BAA0B,SAAS,gBAAgB,gBAAgB,gBAAgB;QAE9F,YAAW;;AAIf,YAAW;;;;gEAImD,SAAS,OAAO,aAAa;;;;;;AAO3F,QAAO;;AAGT,eAAsB,gBAAgB,SAAyC;CAC7E,MAAM,MAAM,QAAQ,KAAK;AAEzB,KAAI;EACF,MAAM,WAAW,MAAM,aAAa,IAAI;EACxC,MAAM,qBAAqB,0BAA0B,QAAQ;AAE7D,MAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,WAAW,GAAG;AAChD,WAAQ,MACN,MAAM,IAAI,iDAAiD,CAC5D;AACD,WAAQ,IACN,MAAM,IACJ,gEACD,CACF;AACD,WAAQ,KAAK,EAAE;;EAKjB,MAAM,UAAU,MAAM,wBACpB,UACA,oBACA,YALsB,SAAS,aAAa,GAAG,SAAS,mBAMxD,KACA,QAAQ,MACT;EACD,MAAM,cAAc,KAAK,KAAK,KAAK,8BAA8B;AACjE,QAAM,GAAG,UAAU,aAAa,QAAQ;AAExC,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,KAAK,6BAA6B,CAAC;AACrD,UAAQ,KAAK;AACb,UAAQ,IAAI,MAAM,IAAI,WAAW,EAAE,QAAQ,MAAM,KAAK,KAAK,CAAC;AAC5D,UAAQ,IAAI,MAAM,IAAI,kBAAkB,EAAE,8BAA8B;AACxE,UAAQ,KAAK;AACb,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,sCAAsC;AACrE,UAAQ,IACN,MAAM,IAAI,OAAO,EACjB,sBAAsB,KAAK,QAAQ,KAAK,8BAA8B,CAAC,mDACxE;AACD,UAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,0CAA0C;AACzE,UAAQ,KAAK;UACN,OAAO;AACd,UAAQ,MAAM,MAAM,IAAK,MAAgB,QAAQ,CAAC;AAClD,UAAQ,KAAK,EAAE"}
@@ -0,0 +1,14 @@
1
+ import validateNpmPackageName from "validate-npm-package-name";
2
+ //#region src/utils/validate.ts
3
+ function validateProjectName(name) {
4
+ const result = validateNpmPackageName(name);
5
+ if (!result.validForNewPackages) return {
6
+ valid: false,
7
+ error: [...result.errors || [], ...result.warnings || []][0] || "Invalid package name"
8
+ };
9
+ return { valid: true };
10
+ }
11
+ //#endregion
12
+ export { validateProjectName as t };
13
+
14
+ //# sourceMappingURL=validate-dssldJAj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-dssldJAj.js","names":[],"sources":["../src/utils/validate.ts"],"sourcesContent":["import validateNpmPackageName from \"validate-npm-package-name\";\n\nexport interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport function validateProjectName(name: string): ValidationResult {\n const result = validateNpmPackageName(name);\n\n if (!result.validForNewPackages) {\n const errors = [...(result.errors || []), ...(result.warnings || [])];\n return {\n valid: false,\n error: errors[0] || \"Invalid package name\",\n };\n }\n\n return { valid: true };\n}\n"],"mappings":";;AAOA,SAAgB,oBAAoB,MAAgC;CAClE,MAAM,SAAS,uBAAuB,KAAK;AAE3C,KAAI,CAAC,OAAO,oBAEV,QAAO;EACL,OAAO;EACP,OAAO,CAHO,GAAI,OAAO,UAAU,EAAE,EAAG,GAAI,OAAO,YAAY,EAAE,CAGpD,CAAC,MAAM;EACrB;AAGH,QAAO,EAAE,OAAO,MAAM"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percepta/create",
3
- "version": "3.6.1",
3
+ "version": "3.6.3",
4
4
  "description": "Scaffold a new Mosaic package",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,5 +1,5 @@
1
1
  {
2
- "monorepo": "1.0.1",
3
- "webapp": "1.2.0",
2
+ "monorepo": "1.0.5",
3
+ "webapp": "1.3.3",
4
4
  "library": "1.0.0"
5
5
  }
@@ -0,0 +1,138 @@
1
+ # yaml-language-server: $schema=https://api.ryvn.app/v1/schemas/resources.json
2
+ kind: Blueprint
3
+ metadata:
4
+ name: __CUSTOMER_SLUG__-os
5
+ spec:
6
+ description: "__CUSTOMER_TITLE__-owned infrastructure for the OS monorepo"
7
+ displayName: "__CUSTOMER_TITLE__ OS"
8
+
9
+ inputs:
10
+ - name: app_databases
11
+ type: map
12
+ group: General
13
+ displayName: "App Databases"
14
+ description: "Application database declarations keyed by app name. This default is the __CUSTOMER_TITLE__ OS app registry; BlueprintInstallation inputs should only override it for environment-specific drift. Each value may set database_name, schema_name, username, and secret_name."
15
+ default: {}
16
+ - name: auth_secret_name
17
+ type: string
18
+ group: General
19
+ displayName: "Auth Secret Name"
20
+ description: "Optional Kubernetes Secret name for shared auth database credentials. Defaults to <environment>-auth-postgresql."
21
+ default: ""
22
+ - name: auth_username
23
+ type: string
24
+ group: General
25
+ displayName: "Auth Username"
26
+ description: "Optional shared auth database username. Defaults to <environment>_auth."
27
+ default: ""
28
+ - name: aws_postgresql_cluster_name
29
+ type: string
30
+ group: "AWS PostgreSQL"
31
+ displayName: "AWS PostgreSQL Cluster Name"
32
+ description: "Optional Aurora PostgreSQL cluster name. Defaults to <environment>-postgresql."
33
+ default: ""
34
+ condition: '{{ eq EnvironmentProviderType "aws" }}'
35
+ - name: azure_postgresql_server_name
36
+ type: string
37
+ group: "Azure PostgreSQL"
38
+ displayName: "Azure PostgreSQL Server Name"
39
+ description: "Optional Azure PostgreSQL flexible server name. Defaults to <environment>-postgresql."
40
+ default: ""
41
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
42
+ - name: azure_postgresql_private_dns_zone_id
43
+ type: string
44
+ group: "Azure PostgreSQL"
45
+ displayName: "Azure PostgreSQL Private DNS Zone ID"
46
+ description: "Existing Azure PostgreSQL private DNS zone ID. Leave empty to create one."
47
+ default: ""
48
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
49
+ - name: azure_postgresql_subnet_id
50
+ type: string
51
+ group: "Azure PostgreSQL"
52
+ displayName: "Azure PostgreSQL Subnet ID"
53
+ description: "Existing delegated PostgreSQL subnet ID. Leave empty to create one."
54
+ default: ""
55
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
56
+ - name: azure_postgresql_subnet_address_prefix
57
+ type: string
58
+ group: "Azure PostgreSQL"
59
+ displayName: "Azure PostgreSQL Subnet Address Prefix"
60
+ description: "Address prefix for the delegated PostgreSQL subnet when creating one."
61
+ default: ""
62
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
63
+ - name: azure_postgresql_key_vault_id
64
+ type: string
65
+ group: "Azure PostgreSQL"
66
+ displayName: "Azure PostgreSQL Key Vault ID"
67
+ description: "Optional Key Vault ID for storing generated PostgreSQL admin credentials."
68
+ default: ""
69
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
70
+ - name: azure_postgresql_sku_name
71
+ type: string
72
+ group: "Azure PostgreSQL"
73
+ displayName: "Azure PostgreSQL SKU Name"
74
+ description: "Azure PostgreSQL flexible server SKU."
75
+ default: "B_Standard_B2s"
76
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
77
+
78
+ installations:
79
+ - service: os-postgresql-terraform-aws
80
+ condition: '{{ eq EnvironmentProviderType "aws" }}'
81
+ config: |
82
+ name: {{ EnvironmentName }}
83
+ namespace: {{ EnvironmentNamespace }}
84
+ {{ if ne (input "auth_secret_name") "" }}
85
+ auth_secret_name: '{{ input "auth_secret_name" }}'
86
+ {{ end }}
87
+ {{ if ne (input "auth_username") "" }}
88
+ auth_username: '{{ input "auth_username" }}'
89
+ {{ end }}
90
+ app_databases:
91
+ {{ input "app_databases" | toYaml | nindent 2 }}
92
+ tags:
93
+ managed-by: mosaic
94
+ ryvn-environment: {{ EnvironmentName }}
95
+
96
+ region: {{ .ryvn.env.state.cluster_region }}
97
+ vpc_id: {{ .ryvn.env.state.vpc.id }}
98
+ subnet_ids:
99
+ {{ .ryvn.env.state.vpc.private_subnet_ids | toYaml | nindent 2 }}
100
+ {{ if ne (input "aws_postgresql_cluster_name") "" }}
101
+ postgresql_cluster_name: '{{ input "aws_postgresql_cluster_name" }}'
102
+ {{ end }}
103
+
104
+ - service: os-postgresql-terraform-azure
105
+ condition: '{{ eq EnvironmentProviderType "azure" }}'
106
+ config: |
107
+ name: {{ EnvironmentName }}
108
+ namespace: {{ EnvironmentNamespace }}
109
+ {{ if ne (input "auth_secret_name") "" }}
110
+ auth_secret_name: '{{ input "auth_secret_name" }}'
111
+ {{ end }}
112
+ {{ if ne (input "auth_username") "" }}
113
+ auth_username: '{{ input "auth_username" }}'
114
+ {{ end }}
115
+ app_databases:
116
+ {{ input "app_databases" | toYaml | nindent 2 }}
117
+ tags:
118
+ managed-by: mosaic
119
+ ryvn-environment: {{ EnvironmentName }}
120
+
121
+ resource_group_name: {{ .ryvn.env.state.resource_group.name }}
122
+ virtual_network_id: {{ .ryvn.env.state.vnet.id }}
123
+ {{ if ne (input "azure_postgresql_server_name") "" }}
124
+ postgresql_server_name: '{{ input "azure_postgresql_server_name" }}'
125
+ {{ end }}
126
+ {{ if ne (input "azure_postgresql_private_dns_zone_id") "" }}
127
+ private_dns_zone_id: '{{ input "azure_postgresql_private_dns_zone_id" }}'
128
+ {{ end }}
129
+ {{ if ne (input "azure_postgresql_subnet_id") "" }}
130
+ subnet_id: '{{ input "azure_postgresql_subnet_id" }}'
131
+ {{ end }}
132
+ {{ if ne (input "azure_postgresql_subnet_address_prefix") "" }}
133
+ subnet_address_prefix: '{{ input "azure_postgresql_subnet_address_prefix" }}'
134
+ {{ end }}
135
+ {{ if ne (input "azure_postgresql_key_vault_id") "" }}
136
+ key_vault_id: '{{ input "azure_postgresql_key_vault_id" }}'
137
+ {{ end }}
138
+ postgresql_sku_name: '{{ input "azure_postgresql_sku_name" }}'