@decohere/scaffold 0.0.1-dev.126 → 0.0.1-dev.18

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 (264) hide show
  1. package/package.json +9 -19
  2. package/src/add-api.action.ts +25 -0
  3. package/src/add-api.command.ts +31 -0
  4. package/src/add.command.ts +20 -0
  5. package/src/add.module.ts +11 -0
  6. package/src/cli.ts +4 -0
  7. package/src/create.command.ts +20 -0
  8. package/src/create.module.ts +11 -0
  9. package/src/domain/prompt.ts +50 -0
  10. package/{types/src/index.d.ts → src/index.ts} +0 -4
  11. package/src/models/compose.model.ts +205 -0
  12. package/src/models/config-yaml.model.ts +83 -0
  13. package/src/models/const.ts +20 -0
  14. package/src/models/dev-container.model.ts +136 -0
  15. package/src/models/docker-image.model.ts +343 -0
  16. package/src/models/env-file.model.ts +45 -0
  17. package/src/models/gitignore.model.ts +35 -0
  18. package/src/models/launch-json.model.ts +60 -0
  19. package/src/models/package-json.model.ts +169 -0
  20. package/src/models/project.model.ts +141 -0
  21. package/{types/src/models/source-file.d.ts → src/models/source-file.ts} +6 -4
  22. package/src/models/tsconfig.model.ts +29 -0
  23. package/src/models/vitest-config.model.ts +26 -0
  24. package/src/models/vscode-settings.model.ts +24 -0
  25. package/src/program.ts +63 -0
  26. package/{types/src/resolve-target-dir.d.ts → src/resolve-target-dir.ts} +4 -1
  27. package/src/services/scaffold.service.ts +89 -0
  28. package/src/version.ts +56 -0
  29. package/src/webapi/api-name.ts +73 -0
  30. package/src/webapi/cli-options.ts +56 -0
  31. package/{types/src/webapi/const.d.ts → src/webapi/const.ts} +21 -9
  32. package/src/webapi/create-api.ts +275 -0
  33. package/src/webapi/devcontainer/host-scripts.ts +35 -0
  34. package/src/webapi/features/auth.feature.ts +454 -0
  35. package/src/webapi/features/auth0-cli.ts +421 -0
  36. package/src/webapi/features/biome-format.ts +34 -0
  37. package/src/webapi/features/database.feature.ts +522 -0
  38. package/src/webapi/features/finalize.feature.ts +112 -0
  39. package/src/webapi/features/postman.feature.ts +287 -0
  40. package/src/webapi/models/api-package-json.model.ts +60 -0
  41. package/src/webapi/models/auth-config.model.ts +36 -0
  42. package/src/webapi/models/controller-source-file.model.ts +232 -0
  43. package/{es6/src/webapi/models/github-ci.model.js → src/webapi/models/github-ci.model.ts} +29 -27
  44. package/src/webapi/models/main-source-file.model.ts +208 -0
  45. package/src/webapi/models/production-dockerfile.model.ts +162 -0
  46. package/src/webapi/models/sample-files.model.ts +45 -0
  47. package/src/webapi/models/webapi-image.model.ts +21 -0
  48. package/src/webapi/postman/hello-openapi.ts +92 -0
  49. package/src/webapi/postman/local-view.ts +195 -0
  50. package/src/webapi/postman/openapi-to-postman.ts +208 -0
  51. package/src/webapi/workspace-readme.ts +192 -0
  52. package/src/webapi.action.ts +22 -0
  53. package/src/webapi.command.ts +41 -0
  54. package/tests/auth-postman.wiring.spec.ts +263 -0
  55. package/tests/auth0-cli.spec.ts +232 -0
  56. package/tests/biome-format.spec.ts +49 -0
  57. package/tests/cli.integration.spec.ts +658 -0
  58. package/tests/compose.model.spec.ts +51 -0
  59. package/tests/container-image.model.spec.ts +162 -0
  60. package/tests/dev-container.model.spec.ts +29 -0
  61. package/tests/devcontainer-base-image.spec.ts +32 -0
  62. package/tests/hello-di-inject.scaffold.spec.ts +18 -0
  63. package/tests/hello-route.contract.spec.ts +94 -0
  64. package/tests/package-json.order.spec.ts +59 -0
  65. package/tests/postman-from-openapi.spec.ts +197 -0
  66. package/tests/seed-devcontainer-templates.ts +40 -0
  67. package/tests/webapi/devcontainer/codebase-rag-mcp.spec.ts +96 -0
  68. package/LICENSE +0 -15
  69. package/commonjs/src/add-api.action.js +0 -37
  70. package/commonjs/src/add-api.command.js +0 -39
  71. package/commonjs/src/add.command.js +0 -22
  72. package/commonjs/src/add.module.js +0 -24
  73. package/commonjs/src/auth0-configure.action.js +0 -28
  74. package/commonjs/src/auth0-configure.command.js +0 -24
  75. package/commonjs/src/auth0-login.action.js +0 -28
  76. package/commonjs/src/auth0-login.command.js +0 -23
  77. package/commonjs/src/auth0.command.js +0 -22
  78. package/commonjs/src/auth0.module.js +0 -28
  79. package/commonjs/src/cli.js +0 -8
  80. package/commonjs/src/create.command.js +0 -22
  81. package/commonjs/src/create.module.js +0 -24
  82. package/commonjs/src/domain/prompt.js +0 -62
  83. package/commonjs/src/index.js +0 -48
  84. package/commonjs/src/models/compose.model.js +0 -258
  85. package/commonjs/src/models/config-yaml.model.js +0 -86
  86. package/commonjs/src/models/const.js +0 -30
  87. package/commonjs/src/models/dev-container.model.js +0 -172
  88. package/commonjs/src/models/docker-image.model.js +0 -277
  89. package/commonjs/src/models/env-file.model.js +0 -48
  90. package/commonjs/src/models/gitignore.model.js +0 -48
  91. package/commonjs/src/models/launch-json.model.js +0 -70
  92. package/commonjs/src/models/package-json.model.js +0 -156
  93. package/commonjs/src/models/project.model.js +0 -132
  94. package/commonjs/src/models/source-file.js +0 -4
  95. package/commonjs/src/models/tsconfig.model.js +0 -32
  96. package/commonjs/src/models/vitest-config.model.js +0 -33
  97. package/commonjs/src/models/vscode-settings.model.js +0 -29
  98. package/commonjs/src/program.js +0 -64
  99. package/commonjs/src/resolve-target-dir.js +0 -17
  100. package/commonjs/src/services/scaffold.service.js +0 -60
  101. package/commonjs/src/version.js +0 -55
  102. package/commonjs/src/webapi/api-name.js +0 -93
  103. package/commonjs/src/webapi/auth0-commands.js +0 -250
  104. package/commonjs/src/webapi/authorize-scopes.js +0 -79
  105. package/commonjs/src/webapi/cli-options.js +0 -99
  106. package/commonjs/src/webapi/const.js +0 -54
  107. package/commonjs/src/webapi/create-api.js +0 -265
  108. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +0 -164
  109. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  110. package/commonjs/src/webapi/devcontainer/host-scripts.js +0 -50
  111. package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  112. package/commonjs/src/webapi/devcontainer/templates/initialize.sh +0 -169
  113. package/commonjs/src/webapi/devcontainer/templates/post-create.sh +0 -35
  114. package/commonjs/src/webapi/devcontainer/templates/post-start.sh +0 -65
  115. package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  116. package/commonjs/src/webapi/features/auth.feature.js +0 -408
  117. package/commonjs/src/webapi/features/auth0-cli.js +0 -472
  118. package/commonjs/src/webapi/features/biome-format.js +0 -47
  119. package/commonjs/src/webapi/features/database.feature.js +0 -433
  120. package/commonjs/src/webapi/features/finalize.feature.js +0 -93
  121. package/commonjs/src/webapi/features/postman.feature.js +0 -322
  122. package/commonjs/src/webapi/models/api-package-json.model.js +0 -58
  123. package/commonjs/src/webapi/models/auth-config.model.js +0 -24
  124. package/commonjs/src/webapi/models/controller-source-file.model.js +0 -190
  125. package/commonjs/src/webapi/models/github-ci.model.js +0 -193
  126. package/commonjs/src/webapi/models/main-source-file.model.js +0 -165
  127. package/commonjs/src/webapi/models/production-dockerfile.model.js +0 -75
  128. package/commonjs/src/webapi/models/sample-files.model.js +0 -58
  129. package/commonjs/src/webapi/models/webapi-image.model.js +0 -25
  130. package/commonjs/src/webapi/postman/hello-openapi.js +0 -173
  131. package/commonjs/src/webapi/postman/local-view.js +0 -182
  132. package/commonjs/src/webapi/postman/openapi-to-postman.js +0 -238
  133. package/commonjs/src/webapi/workspace-readme.js +0 -109
  134. package/commonjs/src/webapi.action.js +0 -28
  135. package/commonjs/src/webapi.command.js +0 -43
  136. package/es6/src/add-api.action.js +0 -27
  137. package/es6/src/add-api.command.js +0 -29
  138. package/es6/src/add.command.js +0 -12
  139. package/es6/src/add.module.js +0 -14
  140. package/es6/src/auth0-configure.action.js +0 -18
  141. package/es6/src/auth0-configure.command.js +0 -14
  142. package/es6/src/auth0-login.action.js +0 -18
  143. package/es6/src/auth0-login.command.js +0 -13
  144. package/es6/src/auth0.command.js +0 -12
  145. package/es6/src/auth0.module.js +0 -18
  146. package/es6/src/cli.js +0 -4
  147. package/es6/src/create.command.js +0 -12
  148. package/es6/src/create.module.js +0 -14
  149. package/es6/src/domain/prompt.js +0 -41
  150. package/es6/src/index.js +0 -9
  151. package/es6/src/models/compose.model.js +0 -254
  152. package/es6/src/models/config-yaml.model.js +0 -74
  153. package/es6/src/models/const.js +0 -20
  154. package/es6/src/models/dev-container.model.js +0 -162
  155. package/es6/src/models/docker-image.model.js +0 -235
  156. package/es6/src/models/env-file.model.js +0 -44
  157. package/es6/src/models/gitignore.model.js +0 -38
  158. package/es6/src/models/launch-json.model.js +0 -60
  159. package/es6/src/models/package-json.model.js +0 -141
  160. package/es6/src/models/project.model.js +0 -117
  161. package/es6/src/models/source-file.js +0 -1
  162. package/es6/src/models/tsconfig.model.js +0 -22
  163. package/es6/src/models/vitest-config.model.js +0 -23
  164. package/es6/src/models/vscode-settings.model.js +0 -19
  165. package/es6/src/program.js +0 -50
  166. package/es6/src/resolve-target-dir.js +0 -7
  167. package/es6/src/services/scaffold.service.js +0 -50
  168. package/es6/src/version.js +0 -34
  169. package/es6/src/webapi/api-name.js +0 -57
  170. package/es6/src/webapi/auth0-commands.js +0 -185
  171. package/es6/src/webapi/authorize-scopes.js +0 -55
  172. package/es6/src/webapi/cli-options.js +0 -34
  173. package/es6/src/webapi/const.js +0 -21
  174. package/es6/src/webapi/create-api.js +0 -245
  175. package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +0 -154
  176. package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  177. package/es6/src/webapi/devcontainer/host-scripts.js +0 -29
  178. package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  179. package/es6/src/webapi/devcontainer/templates/initialize.sh +0 -169
  180. package/es6/src/webapi/devcontainer/templates/post-create.sh +0 -35
  181. package/es6/src/webapi/devcontainer/templates/post-start.sh +0 -65
  182. package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  183. package/es6/src/webapi/features/auth.feature.js +0 -357
  184. package/es6/src/webapi/features/auth0-cli.js +0 -406
  185. package/es6/src/webapi/features/biome-format.js +0 -40
  186. package/es6/src/webapi/features/database.feature.js +0 -423
  187. package/es6/src/webapi/features/finalize.feature.js +0 -83
  188. package/es6/src/webapi/features/postman.feature.js +0 -256
  189. package/es6/src/webapi/models/api-package-json.model.js +0 -53
  190. package/es6/src/webapi/models/auth-config.model.js +0 -20
  191. package/es6/src/webapi/models/controller-source-file.model.js +0 -181
  192. package/es6/src/webapi/models/main-source-file.model.js +0 -161
  193. package/es6/src/webapi/models/production-dockerfile.model.js +0 -66
  194. package/es6/src/webapi/models/sample-files.model.js +0 -40
  195. package/es6/src/webapi/models/webapi-image.model.js +0 -18
  196. package/es6/src/webapi/postman/hello-openapi.js +0 -166
  197. package/es6/src/webapi/postman/local-view.js +0 -167
  198. package/es6/src/webapi/postman/openapi-to-postman.js +0 -179
  199. package/es6/src/webapi/workspace-readme.js +0 -88
  200. package/es6/src/webapi.action.js +0 -18
  201. package/es6/src/webapi.command.js +0 -33
  202. package/types/src/add-api.action.d.ts +0 -13
  203. package/types/src/add-api.command.d.ts +0 -7
  204. package/types/src/add.command.d.ts +0 -6
  205. package/types/src/add.module.d.ts +0 -14
  206. package/types/src/auth0-configure.action.d.ts +0 -7
  207. package/types/src/auth0-configure.command.d.ts +0 -6
  208. package/types/src/auth0-login.action.d.ts +0 -4
  209. package/types/src/auth0-login.command.d.ts +0 -6
  210. package/types/src/auth0.command.d.ts +0 -6
  211. package/types/src/auth0.module.d.ts +0 -18
  212. package/types/src/cli.d.ts +0 -2
  213. package/types/src/create.command.d.ts +0 -6
  214. package/types/src/create.module.d.ts +0 -14
  215. package/types/src/domain/prompt.d.ts +0 -4
  216. package/types/src/models/compose.model.d.ts +0 -73
  217. package/types/src/models/config-yaml.model.d.ts +0 -27
  218. package/types/src/models/const.d.ts +0 -20
  219. package/types/src/models/dev-container.model.d.ts +0 -49
  220. package/types/src/models/docker-image.model.d.ts +0 -90
  221. package/types/src/models/env-file.model.d.ts +0 -16
  222. package/types/src/models/gitignore.model.d.ts +0 -9
  223. package/types/src/models/launch-json.model.d.ts +0 -7
  224. package/types/src/models/package-json.model.d.ts +0 -36
  225. package/types/src/models/project.model.d.ts +0 -60
  226. package/types/src/models/tsconfig.model.d.ts +0 -5
  227. package/types/src/models/vitest-config.model.d.ts +0 -5
  228. package/types/src/models/vscode-settings.model.d.ts +0 -7
  229. package/types/src/program.d.ts +0 -8
  230. package/types/src/services/scaffold.service.d.ts +0 -22
  231. package/types/src/version.d.ts +0 -6
  232. package/types/src/webapi/api-name.d.ts +0 -14
  233. package/types/src/webapi/auth0-commands.d.ts +0 -11
  234. package/types/src/webapi/authorize-scopes.d.ts +0 -7
  235. package/types/src/webapi/cli-options.d.ts +0 -6
  236. package/types/src/webapi/create-api.d.ts +0 -15
  237. package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +0 -32
  238. package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  239. package/types/src/webapi/devcontainer/host-scripts.d.ts +0 -7
  240. package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  241. package/types/src/webapi/devcontainer/templates/initialize.sh +0 -169
  242. package/types/src/webapi/devcontainer/templates/post-create.sh +0 -35
  243. package/types/src/webapi/devcontainer/templates/post-start.sh +0 -65
  244. package/types/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  245. package/types/src/webapi/features/auth.feature.d.ts +0 -10
  246. package/types/src/webapi/features/auth0-cli.d.ts +0 -84
  247. package/types/src/webapi/features/biome-format.d.ts +0 -5
  248. package/types/src/webapi/features/database.feature.d.ts +0 -7
  249. package/types/src/webapi/features/finalize.feature.d.ts +0 -2
  250. package/types/src/webapi/features/postman.feature.d.ts +0 -16
  251. package/types/src/webapi/models/api-package-json.model.d.ts +0 -18
  252. package/types/src/webapi/models/auth-config.model.d.ts +0 -26
  253. package/types/src/webapi/models/controller-source-file.model.d.ts +0 -46
  254. package/types/src/webapi/models/github-ci.model.d.ts +0 -9
  255. package/types/src/webapi/models/main-source-file.model.d.ts +0 -54
  256. package/types/src/webapi/models/production-dockerfile.model.d.ts +0 -18
  257. package/types/src/webapi/models/sample-files.model.d.ts +0 -7
  258. package/types/src/webapi/models/webapi-image.model.d.ts +0 -12
  259. package/types/src/webapi/postman/hello-openapi.d.ts +0 -19
  260. package/types/src/webapi/postman/local-view.d.ts +0 -17
  261. package/types/src/webapi/postman/openapi-to-postman.d.ts +0 -62
  262. package/types/src/webapi/workspace-readme.d.ts +0 -18
  263. package/types/src/webapi.action.d.ts +0 -14
  264. package/types/src/webapi.command.d.ts +0 -11
@@ -0,0 +1,275 @@
1
+ import { existsSync } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
+ import { DockerCompose } from "../models/compose.model.js";
4
+ import { ConfigYaml } from "../models/config-yaml.model.js";
5
+ import { WELL_KNOWN_FILES } from "../models/const.js";
6
+ import { DevContainer } from "../models/dev-container.model.js";
7
+ import { commandHistory } from "../models/docker-image.model.js";
8
+ import { EnvFile } from "../models/env-file.model.js";
9
+ import { Gitignore } from "../models/gitignore.model.js";
10
+ import { LaunchJson } from "../models/launch-json.model.js";
11
+ import { PackageJson } from "../models/package-json.model.js";
12
+ import { MonoRepoScaffold, ProjectScaffold } from "../models/project.model.js";
13
+ import { TsConfig } from "../models/tsconfig.model.js";
14
+ import { VitestConfig } from "../models/vitest-config.model.js";
15
+ import { VSCodeSettings } from "../models/vscode-settings.model.js";
16
+ import { ScaffoldService } from "../services/scaffold.service.js";
17
+ import {
18
+ CreateCliError,
19
+ isDecohereWorkspace,
20
+ listExistingApiNames,
21
+ parseApiNames,
22
+ } from "./api-name.js";
23
+ import {
24
+ DEFAULT_WEBAPI_NAME,
25
+ webapiPackageName,
26
+ webapiPort,
27
+ webapiProjectDir,
28
+ webapiReleaseEntry,
29
+ } from "./const.js";
30
+ import { DevContainerHostScripts } from "./devcontainer/host-scripts.js";
31
+ import { AuthFeature } from "./features/auth.feature.js";
32
+ import { DatabaseFeature } from "./features/database.feature.js";
33
+ import { FinalizeFeature } from "./features/finalize.feature.js";
34
+ import { PostmanFeature } from "./features/postman.feature.js";
35
+ import { ApiPackageJson } from "./models/api-package-json.model.js";
36
+ import { ControllerSourceFile } from "./models/controller-source-file.model.js";
37
+ import { GithubCiWorkflows } from "./models/github-ci.model.js";
38
+ import { MainSourceFile } from "./models/main-source-file.model.js";
39
+ import { WebapiProductionDockerfile } from "./models/production-dockerfile.model.js";
40
+ import { SampleConfigModel, SampleServiceModel } from "./models/sample-files.model.js";
41
+ import { WebapiDevContainer } from "./models/webapi-image.model.js";
42
+
43
+ export { WEBAPI_PROJECT_DIR, WEBAPI_RELEASE_ENTRY } from "./const.js";
44
+
45
+ export type ApiOptions = {
46
+ d?: string;
47
+ /** Host project name (directory basename). Required when scaffolding into `/workspace`. */
48
+ projectName?: string;
49
+ /** API slugs under `projects/`. Default `["api"]`. Repeatable `--name`. */
50
+ names?: string[];
51
+ /** Add APIs to an existing Decohere workspace instead of creating a new one. */
52
+ add?: boolean;
53
+ authProvider?: "auth0" | "none";
54
+ databaseProvider?: "none" | "postgres/typeorm";
55
+ postmanProvider?: "api" | "local" | "none";
56
+ installDependencies?: "yes" | "no";
57
+ };
58
+
59
+ const features = [DatabaseFeature, AuthFeature, PostmanFeature, FinalizeFeature];
60
+
61
+ export async function scaffoldApi(cliOptions: ApiOptions) {
62
+ const targetDir = resolve(cliOptions.d ?? ".");
63
+ const projectName =
64
+ cliOptions.projectName?.trim() ||
65
+ process.env.DECOHERE_PROJECT_NAME?.trim() ||
66
+ basename(targetDir);
67
+ const names = parseApiNames(cliOptions.names);
68
+ const workspace = cliOptions.add
69
+ ? createAddWorkspace(targetDir, projectName, names)
70
+ : createWorkspace(targetDir, projectName, names);
71
+ await ScaffoldService.scaffold(workspace, { ...cliOptions, names }, features);
72
+ }
73
+
74
+ function createWorkspace(
75
+ targetDir: string,
76
+ projectName: string,
77
+ apiNames: readonly string[],
78
+ ): MonoRepoScaffold {
79
+ const monoRepo = new MonoRepoScaffold();
80
+ monoRepo.targetDir = targetDir;
81
+ monoRepo.setName(projectName);
82
+ const name = monoRepo.name;
83
+
84
+ const compose = new DockerCompose()
85
+ .setProjectName(name)
86
+ .addHeaderComment(
87
+ "Merge .cursor/mcp.json in the service command. postStartCommand runs after Cursor's first MCP snapshot.",
88
+ )
89
+ .addNetwork(name, { name: `samples-${name}` })
90
+ .addService("devcontainer", {
91
+ build: ".",
92
+ volumes: [
93
+ // Workspace-local (created by initialize.sh as the host user).
94
+ // Do NOT bind ${HOME}/.npm/... — Docker creates missing host paths as root.
95
+ "./npm-auth:/home/node/.npm-config",
96
+ "./gh-auth:/home/node/.config/gh",
97
+ "webapi-node-modules:/workspace/node_modules",
98
+ // Named volume (not a Cursor-only mount) so CLI recreates keep Up-arrow history.
99
+ `${commandHistory.volumeName}:${commandHistory.dir}`,
100
+ ],
101
+ env_file: ["./gh.env"],
102
+ environment: { NPM_CONFIG_USERCONFIG: "/home/node/.npm-config/.npmrc" },
103
+ command:
104
+ "'bash -c \"CODEBASE_RAG_WORKSPACE=/workspace node --experimental-strip-types /workspace/.devcontainer/codebase-rag-mcp.ts merge || true && exec sleep infinity\"'",
105
+ networks: [name],
106
+ })
107
+ .addVolume("webapi-node-modules")
108
+ .addVolume(commandHistory.volumeName);
109
+
110
+ const installCmd = "bash .devcontainer/post-create.sh";
111
+ const devContainer = new DevContainer()
112
+ .addExtension("biomejs.biome", "vitest.explorer")
113
+ .setInitializeCommand("bash .devcontainer/initialize.sh")
114
+ .setPostCreateCommand(installCmd)
115
+ .setUpdateContentCommand(installCmd)
116
+ .setPostStartCommand("bash .devcontainer/post-start.sh")
117
+ .useCompose();
118
+
119
+ for (const [index, apiName] of apiNames.entries()) {
120
+ const port = webapiPort(index);
121
+ devContainer.forwardPort(port);
122
+ devContainer.setPortAttributes(port, {
123
+ label: apiName === DEFAULT_WEBAPI_NAME ? "API" : apiName,
124
+ requireLocalPort: true,
125
+ });
126
+ }
127
+
128
+ // Workspace-level models (repo root)
129
+ monoRepo.addModel(compose);
130
+ monoRepo.addModel(devContainer);
131
+ monoRepo.addModel(new WebapiDevContainer());
132
+ monoRepo.addModel(new WebapiProductionDockerfile(apiNames));
133
+ monoRepo.addModel(new GithubCiWorkflows());
134
+ monoRepo.addModel(new VSCodeSettings(name));
135
+ monoRepo.addModel(new LaunchJson(apiNames));
136
+ monoRepo.addModel(new TsConfig());
137
+ monoRepo.addModel(new VitestConfig());
138
+ monoRepo.addModel(new PackageJson(`${name}.api`, { apiNames, workspaceName: name }));
139
+ monoRepo.addModel(new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""));
140
+ monoRepo.addModel(
141
+ new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""),
142
+ );
143
+ monoRepo.addModel(new Gitignore());
144
+ monoRepo.addModel(new EnvFile());
145
+ monoRepo.addFile(new DevContainerHostScripts());
146
+
147
+ // Biome formatter/linter config
148
+ monoRepo.addFile({
149
+ files: () => [
150
+ {
151
+ filePath: "biome.json",
152
+ content: JSON.stringify(
153
+ {
154
+ $schema: "https://biomejs.dev/schemas/2.0.0/schema.json",
155
+ files: {
156
+ includes: ["**/*.ts", "**/*.js", "**/*.json", "**/*.yml", "**/*.yaml"],
157
+ },
158
+ assist: { actions: { source: { organizeImports: "on" } } },
159
+ vcs: { enabled: true, clientKind: "git", useIgnoreFile: true },
160
+ formatter: {
161
+ enabled: true,
162
+ formatWithErrors: true,
163
+ indentStyle: "tab",
164
+ lineWidth: 95,
165
+ },
166
+ javascript: { parser: { unsafeParameterDecoratorsEnabled: true } },
167
+ linter: {
168
+ rules: {
169
+ style: {
170
+ useConsistentMemberAccessibility: {
171
+ level: "error",
172
+ options: { accessibility: "explicit" },
173
+ },
174
+ },
175
+ },
176
+ },
177
+ overrides: [
178
+ {
179
+ includes: ["**/*.json"],
180
+ formatter: { indentStyle: "space", indentWidth: 2 },
181
+ },
182
+ ],
183
+ },
184
+ null,
185
+ 2,
186
+ ),
187
+ },
188
+ ],
189
+ });
190
+
191
+ for (const apiName of apiNames) {
192
+ addApiProject(monoRepo, name, apiName);
193
+ }
194
+
195
+ return monoRepo;
196
+ }
197
+
198
+ function createAddWorkspace(
199
+ targetDir: string,
200
+ projectName: string,
201
+ apiNames: readonly string[],
202
+ ): MonoRepoScaffold {
203
+ if (!isDecohereWorkspace(targetDir)) {
204
+ throw new CreateCliError(
205
+ `Not a Decohere workspace: ${targetDir}. Scaffold one first with \`npx @decohere/create webapi\`.`,
206
+ );
207
+ }
208
+
209
+ const existing = listExistingApiNames(targetDir);
210
+ for (const apiName of apiNames) {
211
+ if (existing.includes(apiName)) {
212
+ throw new CreateCliError(
213
+ `API "${apiName}" already exists at ${webapiProjectDir(apiName)}.`,
214
+ );
215
+ }
216
+ }
217
+
218
+ const monoRepo = new MonoRepoScaffold();
219
+ monoRepo.targetDir = targetDir;
220
+ monoRepo.setName(projectName);
221
+ const name = monoRepo.name;
222
+
223
+ const pkg = PackageJson.fromFile(join(targetDir, "package.json"));
224
+ monoRepo.addModel(pkg);
225
+ monoRepo.addModel(
226
+ existsSync(join(targetDir, ".env"))
227
+ ? EnvFile.fromFile(join(targetDir, ".env"))
228
+ : new EnvFile(),
229
+ );
230
+ monoRepo.addModel(
231
+ existsSync(join(targetDir, "config/config.yaml"))
232
+ ? ConfigYaml.fromFile(
233
+ WELL_KNOWN_FILES.CONFIG_YAML,
234
+ "config/config.yaml",
235
+ join(targetDir, "config/config.yaml"),
236
+ )
237
+ : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""),
238
+ );
239
+ monoRepo.addModel(
240
+ existsSync(join(targetDir, "config/config.dev.yaml"))
241
+ ? ConfigYaml.fromFile(
242
+ WELL_KNOWN_FILES.CONFIG_DEV_YAML,
243
+ "config/config.dev.yaml",
244
+ join(targetDir, "config/config.dev.yaml"),
245
+ )
246
+ : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""),
247
+ );
248
+
249
+ for (const [offset, apiName] of apiNames.entries()) {
250
+ const port = webapiPort(existing.length + offset);
251
+ pkg.addScript(`start:${apiName}`, `node ${webapiReleaseEntry(apiName)}`);
252
+ pkg.addScript(
253
+ `dev:${apiName}`,
254
+ `PORT=${port} flux serve --project ${webapiPackageName(name, apiName)}`,
255
+ );
256
+ addApiProject(monoRepo, name, apiName);
257
+ }
258
+ monoRepo.addModel(new WebapiProductionDockerfile(apiNames, { namedOnly: true }));
259
+
260
+ return monoRepo;
261
+ }
262
+
263
+ function addApiProject(
264
+ monoRepo: MonoRepoScaffold,
265
+ workspaceName: string,
266
+ apiName: string,
267
+ ): void {
268
+ const apiProject = new ProjectScaffold(webapiProjectDir(apiName));
269
+ apiProject.addModel(new ApiPackageJson(workspaceName, apiName));
270
+ apiProject.addModel(new MainSourceFile(`${workspaceName}.${apiName}`));
271
+ apiProject.addModel(new ControllerSourceFile());
272
+ apiProject.addFile(new SampleConfigModel());
273
+ apiProject.addFile(new SampleServiceModel());
274
+ monoRepo.addProject(apiProject);
275
+ }
@@ -0,0 +1,35 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import type { SourceFile, SourceFileProvider } from "../../models/source-file.js";
4
+
5
+ const TEMPLATE_FILES = [
6
+ "initialize.sh",
7
+ "post-create.sh",
8
+ "post-start.sh",
9
+ "tty-prompt.sh",
10
+ "codebase-rag.env.example",
11
+ ] as const;
12
+
13
+ export function devcontainerTemplatePath(name: string): string {
14
+ return fileURLToPath(new URL(`./templates/${name}`, import.meta.url));
15
+ }
16
+
17
+ export function codebaseRagMcpSourcePath(): string {
18
+ return fileURLToPath(new URL("./codebase-rag-mcp.ts", import.meta.url));
19
+ }
20
+
21
+ /** Host + container scripts for the scaffolded Dev Container. */
22
+ export class DevContainerHostScripts implements SourceFileProvider {
23
+ public files(): SourceFile[] {
24
+ return [
25
+ ...TEMPLATE_FILES.map((name) => ({
26
+ filePath: `.devcontainer/${name}`,
27
+ content: readFileSync(devcontainerTemplatePath(name), "utf8"),
28
+ })),
29
+ {
30
+ filePath: ".devcontainer/codebase-rag-mcp.ts",
31
+ content: readFileSync(codebaseRagMcpSourcePath(), "utf8"),
32
+ },
33
+ ];
34
+ }
35
+ }