@decohere/scaffold 0.0.1-dev.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commonjs/src/add-api.action.js +37 -0
- package/commonjs/src/add-api.command.js +39 -0
- package/commonjs/src/add.command.js +22 -0
- package/commonjs/src/add.module.js +24 -0
- package/commonjs/src/auth0-configure.action.js +28 -0
- package/commonjs/src/auth0-configure.command.js +24 -0
- package/commonjs/src/auth0-login.action.js +28 -0
- package/commonjs/src/auth0-login.command.js +23 -0
- package/commonjs/src/auth0.command.js +22 -0
- package/commonjs/src/auth0.module.js +28 -0
- package/commonjs/src/cli.js +7 -0
- package/commonjs/src/create.command.js +22 -0
- package/commonjs/src/create.module.js +24 -0
- package/commonjs/src/domain/prompt.js +62 -0
- package/commonjs/src/index.js +48 -0
- package/commonjs/src/models/compose.model.js +258 -0
- package/commonjs/src/models/config-yaml.model.js +86 -0
- package/commonjs/src/models/const.js +30 -0
- package/commonjs/src/models/dev-container.model.js +172 -0
- package/commonjs/src/models/docker-image.model.js +277 -0
- package/commonjs/src/models/env-file.model.js +48 -0
- package/commonjs/src/models/gitignore.model.js +48 -0
- package/commonjs/src/models/launch-json.model.js +70 -0
- package/commonjs/src/models/package-json.model.js +156 -0
- package/commonjs/src/models/project.model.js +132 -0
- package/commonjs/src/models/source-file.js +4 -0
- package/commonjs/src/models/tsconfig.model.js +32 -0
- package/commonjs/src/models/vitest-config.model.js +33 -0
- package/commonjs/src/models/vscode-settings.model.js +29 -0
- package/commonjs/src/program.js +64 -0
- package/commonjs/src/resolve-target-dir.js +17 -0
- package/commonjs/src/services/scaffold.service.js +60 -0
- package/commonjs/src/version.js +55 -0
- package/commonjs/src/webapi/api-name.js +93 -0
- package/commonjs/src/webapi/auth0-commands.js +250 -0
- package/commonjs/src/webapi/authorize-scopes.js +79 -0
- package/commonjs/src/webapi/cli-options.js +99 -0
- package/commonjs/src/webapi/const.js +54 -0
- package/commonjs/src/webapi/create-api.js +265 -0
- package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +164 -0
- package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/commonjs/src/webapi/devcontainer/host-scripts.js +50 -0
- package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/commonjs/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/commonjs/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/commonjs/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/commonjs/src/webapi/features/auth.feature.js +408 -0
- package/commonjs/src/webapi/features/auth0-cli.js +472 -0
- package/commonjs/src/webapi/features/biome-format.js +47 -0
- package/commonjs/src/webapi/features/database.feature.js +432 -0
- package/commonjs/src/webapi/features/finalize.feature.js +93 -0
- package/commonjs/src/webapi/features/postman.feature.js +322 -0
- package/commonjs/src/webapi/models/api-package-json.model.js +58 -0
- package/commonjs/src/webapi/models/auth-config.model.js +24 -0
- package/commonjs/src/webapi/models/controller-source-file.model.js +190 -0
- package/commonjs/src/webapi/models/github-ci.model.js +193 -0
- package/commonjs/src/webapi/models/main-source-file.model.js +165 -0
- package/commonjs/src/webapi/models/production-dockerfile.model.js +75 -0
- package/commonjs/src/webapi/models/sample-files.model.js +58 -0
- package/commonjs/src/webapi/models/webapi-image.model.js +25 -0
- package/commonjs/src/webapi/postman/hello-openapi.js +173 -0
- package/commonjs/src/webapi/postman/local-view.js +182 -0
- package/commonjs/src/webapi/postman/openapi-to-postman.js +200 -0
- package/commonjs/src/webapi/workspace-readme.js +109 -0
- package/commonjs/src/webapi.action.js +28 -0
- package/commonjs/src/webapi.command.js +43 -0
- package/es6/src/add-api.action.js +27 -0
- package/es6/src/add-api.command.js +29 -0
- package/es6/src/add.command.js +12 -0
- package/es6/src/add.module.js +14 -0
- package/es6/src/auth0-configure.action.js +18 -0
- package/es6/src/auth0-configure.command.js +14 -0
- package/es6/src/auth0-login.action.js +18 -0
- package/es6/src/auth0-login.command.js +13 -0
- package/es6/src/auth0.command.js +12 -0
- package/es6/src/auth0.module.js +18 -0
- package/es6/src/cli.js +3 -0
- package/es6/src/create.command.js +12 -0
- package/es6/src/create.module.js +14 -0
- package/es6/src/domain/prompt.js +41 -0
- package/es6/src/index.js +9 -0
- package/es6/src/models/compose.model.js +254 -0
- package/es6/src/models/config-yaml.model.js +74 -0
- package/es6/src/models/const.js +20 -0
- package/es6/src/models/dev-container.model.js +162 -0
- package/es6/src/models/docker-image.model.js +235 -0
- package/es6/src/models/env-file.model.js +44 -0
- package/es6/src/models/gitignore.model.js +38 -0
- package/es6/src/models/launch-json.model.js +60 -0
- package/es6/src/models/package-json.model.js +141 -0
- package/es6/src/models/project.model.js +117 -0
- package/es6/src/models/source-file.js +1 -0
- package/es6/src/models/tsconfig.model.js +22 -0
- package/es6/src/models/vitest-config.model.js +23 -0
- package/es6/src/models/vscode-settings.model.js +19 -0
- package/es6/src/program.js +46 -0
- package/es6/src/resolve-target-dir.js +7 -0
- package/es6/src/services/scaffold.service.js +50 -0
- package/es6/src/version.js +34 -0
- package/es6/src/webapi/api-name.js +57 -0
- package/es6/src/webapi/auth0-commands.js +185 -0
- package/es6/src/webapi/authorize-scopes.js +55 -0
- package/es6/src/webapi/cli-options.js +34 -0
- package/es6/src/webapi/const.js +21 -0
- package/es6/src/webapi/create-api.js +245 -0
- package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +154 -0
- package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/es6/src/webapi/devcontainer/host-scripts.js +29 -0
- package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/es6/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/es6/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/es6/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/es6/src/webapi/features/auth.feature.js +357 -0
- package/es6/src/webapi/features/auth0-cli.js +406 -0
- package/es6/src/webapi/features/biome-format.js +40 -0
- package/es6/src/webapi/features/database.feature.js +422 -0
- package/es6/src/webapi/features/finalize.feature.js +83 -0
- package/es6/src/webapi/features/postman.feature.js +256 -0
- package/es6/src/webapi/models/api-package-json.model.js +53 -0
- package/es6/src/webapi/models/auth-config.model.js +20 -0
- package/es6/src/webapi/models/controller-source-file.model.js +181 -0
- package/es6/src/webapi/models/github-ci.model.js +186 -0
- package/es6/src/webapi/models/main-source-file.model.js +161 -0
- package/es6/src/webapi/models/production-dockerfile.model.js +66 -0
- package/es6/src/webapi/models/sample-files.model.js +40 -0
- package/es6/src/webapi/models/webapi-image.model.js +18 -0
- package/es6/src/webapi/postman/hello-openapi.js +166 -0
- package/es6/src/webapi/postman/local-view.js +167 -0
- package/es6/src/webapi/postman/openapi-to-postman.js +177 -0
- package/es6/src/webapi/workspace-readme.js +88 -0
- package/es6/src/webapi.action.js +18 -0
- package/es6/src/webapi.command.js +33 -0
- package/package.json +36 -0
- package/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/types/src/add-api.action.d.ts +13 -0
- package/types/src/add-api.command.d.ts +7 -0
- package/types/src/add.command.d.ts +6 -0
- package/types/src/add.module.d.ts +14 -0
- package/types/src/auth0-configure.action.d.ts +7 -0
- package/types/src/auth0-configure.command.d.ts +6 -0
- package/types/src/auth0-login.action.d.ts +4 -0
- package/types/src/auth0-login.command.d.ts +6 -0
- package/types/src/auth0.command.d.ts +6 -0
- package/types/src/auth0.module.d.ts +18 -0
- package/types/src/cli.d.ts +2 -0
- package/types/src/create.command.d.ts +6 -0
- package/types/src/create.module.d.ts +14 -0
- package/types/src/domain/prompt.d.ts +4 -0
- package/types/src/index.d.ts +13 -0
- package/types/src/models/compose.model.d.ts +73 -0
- package/types/src/models/config-yaml.model.d.ts +27 -0
- package/types/src/models/const.d.ts +20 -0
- package/types/src/models/dev-container.model.d.ts +49 -0
- package/types/src/models/docker-image.model.d.ts +90 -0
- package/types/src/models/env-file.model.d.ts +16 -0
- package/types/src/models/gitignore.model.d.ts +9 -0
- package/types/src/models/launch-json.model.d.ts +7 -0
- package/types/src/models/package-json.model.d.ts +36 -0
- package/types/src/models/project.model.d.ts +60 -0
- package/types/src/models/source-file.d.ts +11 -0
- package/types/src/models/tsconfig.model.d.ts +5 -0
- package/types/src/models/vitest-config.model.d.ts +5 -0
- package/types/src/models/vscode-settings.model.d.ts +7 -0
- package/types/src/program.d.ts +3 -0
- package/types/src/resolve-target-dir.d.ts +5 -0
- package/types/src/services/scaffold.service.d.ts +22 -0
- package/types/src/version.d.ts +6 -0
- package/types/src/webapi/api-name.d.ts +14 -0
- package/types/src/webapi/auth0-commands.d.ts +11 -0
- package/types/src/webapi/authorize-scopes.d.ts +7 -0
- package/types/src/webapi/cli-options.d.ts +6 -0
- package/types/src/webapi/const.d.ts +19 -0
- package/types/src/webapi/create-api.d.ts +15 -0
- package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +32 -0
- package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/types/src/webapi/devcontainer/host-scripts.d.ts +7 -0
- package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/types/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/types/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/types/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/types/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/types/src/webapi/features/auth.feature.d.ts +10 -0
- package/types/src/webapi/features/auth0-cli.d.ts +84 -0
- package/types/src/webapi/features/biome-format.d.ts +5 -0
- package/types/src/webapi/features/database.feature.d.ts +7 -0
- package/types/src/webapi/features/finalize.feature.d.ts +2 -0
- package/types/src/webapi/features/postman.feature.d.ts +16 -0
- package/types/src/webapi/models/api-package-json.model.d.ts +18 -0
- package/types/src/webapi/models/auth-config.model.d.ts +26 -0
- package/types/src/webapi/models/controller-source-file.model.d.ts +46 -0
- package/types/src/webapi/models/github-ci.model.d.ts +9 -0
- package/types/src/webapi/models/main-source-file.model.d.ts +54 -0
- package/types/src/webapi/models/production-dockerfile.model.d.ts +18 -0
- package/types/src/webapi/models/sample-files.model.d.ts +7 -0
- package/types/src/webapi/models/webapi-image.model.d.ts +12 -0
- package/types/src/webapi/postman/hello-openapi.d.ts +19 -0
- package/types/src/webapi/postman/local-view.d.ts +17 -0
- package/types/src/webapi/postman/openapi-to-postman.d.ts +62 -0
- package/types/src/webapi/workspace-readme.d.ts +18 -0
- package/types/src/webapi.action.d.ts +14 -0
- package/types/src/webapi.command.d.ts +11 -0
|
@@ -0,0 +1,245 @@
|
|
|
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, DockerfileModel, withWorkspaceNodeModulesOwnership } 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, packageScript } 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 { CreateCliError, isDecohereWorkspace, listExistingApiNames, parseApiNames } from "./api-name.js";
|
|
18
|
+
import { DEFAULT_WEBAPI_NAME, webapiPackageName, webapiPort, webapiProjectDir, webapiReleaseEntry } from "./const.js";
|
|
19
|
+
import { DevContainerHostScripts } from "./devcontainer/host-scripts.js";
|
|
20
|
+
import { AuthFeature } from "./features/auth.feature.js";
|
|
21
|
+
import { DatabaseFeature } from "./features/database.feature.js";
|
|
22
|
+
import { FinalizeFeature } from "./features/finalize.feature.js";
|
|
23
|
+
import { PostmanFeature } from "./features/postman.feature.js";
|
|
24
|
+
import { ApiPackageJson } from "./models/api-package-json.model.js";
|
|
25
|
+
import { ControllerSourceFile } from "./models/controller-source-file.model.js";
|
|
26
|
+
import { GithubCiWorkflows } from "./models/github-ci.model.js";
|
|
27
|
+
import { MainSourceFile } from "./models/main-source-file.model.js";
|
|
28
|
+
import { WebapiProductionDockerfile } from "./models/production-dockerfile.model.js";
|
|
29
|
+
import { SampleConfigModel, SampleServiceModel } from "./models/sample-files.model.js";
|
|
30
|
+
import { WebapiDevContainer } from "./models/webapi-image.model.js";
|
|
31
|
+
export { WEBAPI_PROJECT_DIR, WEBAPI_RELEASE_ENTRY } from "./const.js";
|
|
32
|
+
const features = [
|
|
33
|
+
DatabaseFeature,
|
|
34
|
+
AuthFeature,
|
|
35
|
+
PostmanFeature,
|
|
36
|
+
FinalizeFeature
|
|
37
|
+
];
|
|
38
|
+
export async function scaffoldApi(cliOptions) {
|
|
39
|
+
const targetDir = resolve(cliOptions.d ?? ".");
|
|
40
|
+
const projectName = cliOptions.projectName?.trim() || process.env.DECOHERE_PROJECT_NAME?.trim() || basename(targetDir);
|
|
41
|
+
const names = parseApiNames(cliOptions.names);
|
|
42
|
+
const workspace = cliOptions.add ? createAddWorkspace(targetDir, projectName, names) : createWorkspace(targetDir, projectName, names);
|
|
43
|
+
await ScaffoldService.scaffold(workspace, {
|
|
44
|
+
...cliOptions,
|
|
45
|
+
names
|
|
46
|
+
}, features);
|
|
47
|
+
}
|
|
48
|
+
function createWorkspace(targetDir, projectName, apiNames) {
|
|
49
|
+
const monoRepo = new MonoRepoScaffold();
|
|
50
|
+
monoRepo.targetDir = targetDir;
|
|
51
|
+
monoRepo.setName(projectName);
|
|
52
|
+
const name = monoRepo.name;
|
|
53
|
+
// Project-named root so Cursor Agents (and other tools) label the workspace by name.
|
|
54
|
+
const workspaceRoot = `/${name}`;
|
|
55
|
+
const compose = new DockerCompose().setProjectName(name).addHeaderComment("Merge .cursor/mcp.json in the service command. postStartCommand runs after Cursor's first MCP snapshot.").addNetwork(name, {
|
|
56
|
+
name: `samples-${name}`
|
|
57
|
+
}).addService("devcontainer", {
|
|
58
|
+
build: ".",
|
|
59
|
+
volumes: [
|
|
60
|
+
// Repo bind in Compose (survives CLI recreates; Cursor-only mounts do not).
|
|
61
|
+
`..:${workspaceRoot}`,
|
|
62
|
+
// Workspace-local (created by initialize.sh as the host user).
|
|
63
|
+
// Do NOT bind ${HOME}/.npm/... — Docker creates missing host paths as root.
|
|
64
|
+
"./npm-auth:/home/node/.npm-config",
|
|
65
|
+
"./gh-auth:/home/node/.config/gh",
|
|
66
|
+
`webapi-node-modules:${workspaceRoot}/node_modules`,
|
|
67
|
+
// Named volume (not a Cursor-only mount) so CLI recreates keep Up-arrow history.
|
|
68
|
+
`${commandHistory.volumeName}:${commandHistory.dir}`
|
|
69
|
+
],
|
|
70
|
+
env_file: [
|
|
71
|
+
"./gh.env"
|
|
72
|
+
],
|
|
73
|
+
environment: {
|
|
74
|
+
NPM_CONFIG_USERCONFIG: "/home/node/.npm-config/.npmrc"
|
|
75
|
+
},
|
|
76
|
+
command: `'bash -c "CODEBASE_RAG_WORKSPACE=${workspaceRoot} node --experimental-strip-types ${workspaceRoot}/.devcontainer/codebase-rag-mcp.ts merge || true && exec sleep infinity"'`,
|
|
77
|
+
networks: [
|
|
78
|
+
name
|
|
79
|
+
]
|
|
80
|
+
}).addVolume("webapi-node-modules").addVolume(commandHistory.volumeName);
|
|
81
|
+
const installCmd = "bash .devcontainer/post-create.sh";
|
|
82
|
+
const devContainer = new DevContainer().setWorkspaceFolder(workspaceRoot).addExtension("biomejs.biome", "vitest.explorer").setInitializeCommand("bash .devcontainer/initialize.sh").setPostCreateCommand(installCmd).setUpdateContentCommand(installCmd).setPostStartCommand("bash .devcontainer/post-start.sh").useCompose();
|
|
83
|
+
forwardApiPorts(devContainer, apiNames, 0);
|
|
84
|
+
// Workspace-level models (repo root)
|
|
85
|
+
monoRepo.addModel(compose);
|
|
86
|
+
monoRepo.addModel(devContainer);
|
|
87
|
+
const appDevImage = new WebapiDevContainer();
|
|
88
|
+
appDevImage.addLayer(withWorkspaceNodeModulesOwnership({
|
|
89
|
+
workspaceDir: workspaceRoot
|
|
90
|
+
}));
|
|
91
|
+
monoRepo.addModel(appDevImage);
|
|
92
|
+
monoRepo.addModel(new WebapiProductionDockerfile(apiNames));
|
|
93
|
+
monoRepo.addModel(new GithubCiWorkflows());
|
|
94
|
+
monoRepo.addModel(new VSCodeSettings(name));
|
|
95
|
+
monoRepo.addModel(new LaunchJson(apiNames));
|
|
96
|
+
monoRepo.addModel(new TsConfig());
|
|
97
|
+
monoRepo.addModel(new VitestConfig());
|
|
98
|
+
monoRepo.addModel(new PackageJson(`${name}.api`, {
|
|
99
|
+
apiNames,
|
|
100
|
+
workspaceName: name
|
|
101
|
+
}));
|
|
102
|
+
monoRepo.addModel(new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""));
|
|
103
|
+
monoRepo.addModel(new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""));
|
|
104
|
+
monoRepo.addModel(new Gitignore());
|
|
105
|
+
monoRepo.addModel(new EnvFile());
|
|
106
|
+
monoRepo.addFile(new DevContainerHostScripts());
|
|
107
|
+
// Biome formatter/linter config
|
|
108
|
+
monoRepo.addFile({
|
|
109
|
+
files: ()=>[
|
|
110
|
+
{
|
|
111
|
+
filePath: "biome.json",
|
|
112
|
+
content: JSON.stringify({
|
|
113
|
+
$schema: "https://biomejs.dev/schemas/2.0.0/schema.json",
|
|
114
|
+
files: {
|
|
115
|
+
includes: [
|
|
116
|
+
"**/*.ts",
|
|
117
|
+
"**/*.js",
|
|
118
|
+
"**/*.json",
|
|
119
|
+
"**/*.yml",
|
|
120
|
+
"**/*.yaml"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
assist: {
|
|
124
|
+
actions: {
|
|
125
|
+
source: {
|
|
126
|
+
organizeImports: "on"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
vcs: {
|
|
131
|
+
enabled: true,
|
|
132
|
+
clientKind: "git",
|
|
133
|
+
useIgnoreFile: true
|
|
134
|
+
},
|
|
135
|
+
formatter: {
|
|
136
|
+
enabled: true,
|
|
137
|
+
formatWithErrors: true,
|
|
138
|
+
indentStyle: "tab",
|
|
139
|
+
lineWidth: 95
|
|
140
|
+
},
|
|
141
|
+
javascript: {
|
|
142
|
+
parser: {
|
|
143
|
+
unsafeParameterDecoratorsEnabled: true
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
linter: {
|
|
147
|
+
rules: {
|
|
148
|
+
style: {
|
|
149
|
+
useConsistentMemberAccessibility: {
|
|
150
|
+
level: "error",
|
|
151
|
+
options: {
|
|
152
|
+
accessibility: "explicit"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
overrides: [
|
|
159
|
+
{
|
|
160
|
+
includes: [
|
|
161
|
+
"**/*.json"
|
|
162
|
+
],
|
|
163
|
+
formatter: {
|
|
164
|
+
indentStyle: "space",
|
|
165
|
+
indentWidth: 2
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}, null, 2)
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
for (const apiName of apiNames){
|
|
174
|
+
addApiProject(monoRepo, name, apiName);
|
|
175
|
+
}
|
|
176
|
+
return monoRepo;
|
|
177
|
+
}
|
|
178
|
+
function createAddWorkspace(targetDir, projectName, apiNames) {
|
|
179
|
+
if (!isDecohereWorkspace(targetDir)) {
|
|
180
|
+
throw new CreateCliError(`Not a Decohere workspace: ${targetDir}. Scaffold one first with \`npx @decohere/create webapi\`.`);
|
|
181
|
+
}
|
|
182
|
+
const existing = listExistingApiNames(targetDir);
|
|
183
|
+
for (const apiName of apiNames){
|
|
184
|
+
if (existing.includes(apiName)) {
|
|
185
|
+
throw new CreateCliError(`API "${apiName}" already exists at ${webapiProjectDir(apiName)}.`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const monoRepo = new MonoRepoScaffold();
|
|
189
|
+
monoRepo.targetDir = targetDir;
|
|
190
|
+
monoRepo.setName(projectName);
|
|
191
|
+
const name = monoRepo.name;
|
|
192
|
+
const pkg = PackageJson.fromFile(join(targetDir, "package.json"));
|
|
193
|
+
monoRepo.addModel(pkg);
|
|
194
|
+
monoRepo.addModel(existsSync(join(targetDir, ".env")) ? EnvFile.fromFile(join(targetDir, ".env")) : new EnvFile());
|
|
195
|
+
monoRepo.addModel(existsSync(join(targetDir, "config/config.yaml")) ? ConfigYaml.fromFile(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", join(targetDir, "config/config.yaml")) : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""));
|
|
196
|
+
monoRepo.addModel(existsSync(join(targetDir, "config/config.dev.yaml")) ? ConfigYaml.fromFile(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", join(targetDir, "config/config.dev.yaml")) : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""));
|
|
197
|
+
// Load the workspace files features merge into, so e.g. --database on a workspace
|
|
198
|
+
// created without one adds the Postgres service instead of only the db:* scripts.
|
|
199
|
+
const compose = loadIfExists(targetDir, ".devcontainer/docker-compose.yml", (path)=>DockerCompose.fromFile(path));
|
|
200
|
+
if (compose) monoRepo.addModel(compose);
|
|
201
|
+
const devContainer = loadIfExists(targetDir, ".devcontainer/devcontainer.json", (path)=>DevContainer.fromFile(path));
|
|
202
|
+
if (devContainer) {
|
|
203
|
+
forwardApiPorts(devContainer, apiNames, existing.length);
|
|
204
|
+
monoRepo.addModel(devContainer);
|
|
205
|
+
}
|
|
206
|
+
const devImage = loadIfExists(targetDir, ".devcontainer/Dockerfile", (path)=>DockerfileModel.fromFile(path, ".devcontainer/Dockerfile"));
|
|
207
|
+
if (devImage) monoRepo.addModel(devImage);
|
|
208
|
+
const gitignore = loadIfExists(targetDir, ".gitignore", (path)=>Gitignore.fromFile(path));
|
|
209
|
+
if (gitignore) monoRepo.addModel(gitignore);
|
|
210
|
+
if (!pkg.hasScript("package")) {
|
|
211
|
+
pkg.addScript("package", "pnpm run build && forge package");
|
|
212
|
+
}
|
|
213
|
+
for (const [offset, apiName] of apiNames.entries()){
|
|
214
|
+
const port = webapiPort(existing.length + offset);
|
|
215
|
+
pkg.addScript(`start:${apiName}`, `node ${webapiReleaseEntry(apiName)}`);
|
|
216
|
+
pkg.addScript(`package:${apiName}`, packageScript(name, apiName));
|
|
217
|
+
pkg.addScript(`dev:${apiName}`, `PORT=${port} flux serve --env-file-if-exists .env --project ${webapiPackageName(name, apiName)}`);
|
|
218
|
+
addApiProject(monoRepo, name, apiName);
|
|
219
|
+
}
|
|
220
|
+
monoRepo.addModel(new WebapiProductionDockerfile(apiNames));
|
|
221
|
+
return monoRepo;
|
|
222
|
+
}
|
|
223
|
+
function addApiProject(monoRepo, workspaceName, apiName) {
|
|
224
|
+
const apiProject = new ProjectScaffold(webapiProjectDir(apiName));
|
|
225
|
+
apiProject.addModel(new ApiPackageJson(workspaceName, apiName));
|
|
226
|
+
apiProject.addModel(new MainSourceFile(`${workspaceName}.${apiName}`));
|
|
227
|
+
apiProject.addModel(new ControllerSourceFile());
|
|
228
|
+
apiProject.addFile(new SampleConfigModel());
|
|
229
|
+
apiProject.addFile(new SampleServiceModel());
|
|
230
|
+
monoRepo.addProject(apiProject);
|
|
231
|
+
}
|
|
232
|
+
function forwardApiPorts(devContainer, apiNames, firstIndex) {
|
|
233
|
+
for (const [offset, apiName] of apiNames.entries()){
|
|
234
|
+
const port = webapiPort(firstIndex + offset);
|
|
235
|
+
devContainer.forwardPort(port);
|
|
236
|
+
devContainer.setPortAttributes(port, {
|
|
237
|
+
label: apiName === DEFAULT_WEBAPI_NAME ? "API" : apiName,
|
|
238
|
+
requireLocalPort: true
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function loadIfExists(targetDir, relativePath, load) {
|
|
243
|
+
const absolutePath = join(targetDir, relativePath);
|
|
244
|
+
return existsSync(absolutePath) ? load(absolutePath) : undefined;
|
|
245
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function loadDotenv(path, env) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = readFileSync(path, "utf8");
|
|
11
|
+
} catch {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const line of raw.split(/\r?\n/)){
|
|
15
|
+
const trimmed = line.trim();
|
|
16
|
+
if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
|
|
17
|
+
const eq = trimmed.indexOf("=");
|
|
18
|
+
const key = trimmed.slice(0, eq).trim();
|
|
19
|
+
const value = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
20
|
+
if (key && env[key] === undefined) env[key] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function seedFromMcpJson(raw) {
|
|
24
|
+
let data;
|
|
25
|
+
try {
|
|
26
|
+
data = JSON.parse(raw);
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (!isRecord(data)) return null;
|
|
31
|
+
const servers = data.mcpServers;
|
|
32
|
+
if (!isRecord(servers)) return null;
|
|
33
|
+
const server = servers["codebase-rag"];
|
|
34
|
+
if (!isRecord(server)) return null;
|
|
35
|
+
const url = typeof server.url === "string" ? server.url.trim() : "";
|
|
36
|
+
const headers = isRecord(server.headers) ? server.headers : {};
|
|
37
|
+
const auth = typeof headers.Authorization === "string" ? headers.Authorization.trim() : "";
|
|
38
|
+
const token = auth.toLowerCase().startsWith("bearer ") ? auth.slice(7).trim() : "";
|
|
39
|
+
if (!url.startsWith("http") || token.length === 0) return null;
|
|
40
|
+
return {
|
|
41
|
+
url,
|
|
42
|
+
token
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function mergeIntoMcpJson(input) {
|
|
46
|
+
const { mcpPath, url, token, hostRoot } = input;
|
|
47
|
+
if (!url || !token) {
|
|
48
|
+
return {
|
|
49
|
+
skipped: "no URL/token"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const xRoot = hostRoot || "${workspaceFolder}";
|
|
53
|
+
mkdirSync(dirname(mcpPath), {
|
|
54
|
+
recursive: true
|
|
55
|
+
});
|
|
56
|
+
let data = {
|
|
57
|
+
mcpServers: {}
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
if (statSync(mcpPath).size > 0) {
|
|
61
|
+
const loaded = JSON.parse(readFileSync(mcpPath, "utf8"));
|
|
62
|
+
if (isRecord(loaded)) data = loaded;
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
const code = isRecord(err) && typeof err.code === "string" ? err.code : "";
|
|
66
|
+
if (code !== "ENOENT") {
|
|
67
|
+
console.log("codebase-rag MCP: existing mcp.json is invalid JSON; replacing rag entry only after backup");
|
|
68
|
+
renameSync(mcpPath, `${mcpPath}.bak`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const servers = isRecord(data.mcpServers) ? data.mcpServers : {};
|
|
72
|
+
data.mcpServers = servers;
|
|
73
|
+
servers["codebase-rag"] = {
|
|
74
|
+
url,
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: `Bearer ${token}`,
|
|
77
|
+
"X-Codebase-Root": xRoot
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
writeFileSync(mcpPath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
81
|
+
try {
|
|
82
|
+
chmodSync(mcpPath, 0o600);
|
|
83
|
+
} catch {
|
|
84
|
+
// memfs and some hosts omit chmod
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
path: mcpPath,
|
|
88
|
+
root: xRoot
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function workspaceRoot(env = process.env) {
|
|
92
|
+
const fromEnv = env.CODEBASE_RAG_WORKSPACE?.trim();
|
|
93
|
+
if (fromEnv) return fromEnv;
|
|
94
|
+
// Scaffolded copy lives at <repo>/.devcontainer/codebase-rag-mcp.ts
|
|
95
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
96
|
+
}
|
|
97
|
+
function mergeFromEnv(env = process.env) {
|
|
98
|
+
const root = workspaceRoot(env);
|
|
99
|
+
const cursorDir = join(root, ".cursor");
|
|
100
|
+
loadDotenv(join(cursorDir, "codebase-rag.env"), env);
|
|
101
|
+
const url = (env.CODEBASE_RAG_MCP_URL ?? "").trim();
|
|
102
|
+
const token = (env.CODEBASE_RAG_MCP_TOKEN ?? "").trim();
|
|
103
|
+
const hostRoot = (env.CODEBASE_RAG_MCP_ROOT ?? "").trim() || root;
|
|
104
|
+
const result = mergeIntoMcpJson({
|
|
105
|
+
mcpPath: join(cursorDir, "mcp.json"),
|
|
106
|
+
url,
|
|
107
|
+
token,
|
|
108
|
+
hostRoot
|
|
109
|
+
});
|
|
110
|
+
if (result.skipped != null) {
|
|
111
|
+
console.log(`codebase-rag MCP: skipped (${result.skipped})`);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
console.log(`codebase-rag MCP: wrote ${result.path} url=${url} root=${result.root}`);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
function seedPrint(mcpPath) {
|
|
118
|
+
let raw;
|
|
119
|
+
try {
|
|
120
|
+
raw = readFileSync(mcpPath, "utf8");
|
|
121
|
+
} catch {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
const creds = seedFromMcpJson(raw);
|
|
125
|
+
if (creds == null) return 1;
|
|
126
|
+
console.log(creds.url);
|
|
127
|
+
console.log(creds.token);
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
function main(argv = process.argv.slice(2)) {
|
|
131
|
+
const command = argv[0] ?? "merge";
|
|
132
|
+
if (command === "seed-print") {
|
|
133
|
+
const mcpPath = argv[1];
|
|
134
|
+
if (mcpPath == null || mcpPath.length === 0) return 1;
|
|
135
|
+
return seedPrint(mcpPath);
|
|
136
|
+
}
|
|
137
|
+
if (command === "merge") {
|
|
138
|
+
return mergeFromEnv();
|
|
139
|
+
}
|
|
140
|
+
console.error(`codebase-rag MCP: unknown command ${command}`);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
const invoked = (process.argv[1] ?? "").replaceAll("\\", "/");
|
|
144
|
+
if (invoked.endsWith("/codebase-rag-mcp.ts") || invoked.endsWith("/codebase-rag-mcp.js")) {
|
|
145
|
+
process.exit(main());
|
|
146
|
+
}
|
|
147
|
+
export const codebaseRagMcp = {
|
|
148
|
+
loadDotenv,
|
|
149
|
+
seedFromMcpJson,
|
|
150
|
+
mergeIntoMcpJson,
|
|
151
|
+
mergeFromEnv,
|
|
152
|
+
seedPrint,
|
|
153
|
+
main
|
|
154
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chmodSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
renameSync,
|
|
6
|
+
statSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from "node:fs";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
|
|
12
|
+
export type CodebaseRagCredentials = {
|
|
13
|
+
url: string;
|
|
14
|
+
token: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type McpJson = {
|
|
18
|
+
mcpServers?: Record<string, unknown>;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
23
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function loadDotenv(path: string, env: NodeJS.ProcessEnv): void {
|
|
27
|
+
let raw: string;
|
|
28
|
+
try {
|
|
29
|
+
raw = readFileSync(path, "utf8");
|
|
30
|
+
} catch {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
|
|
36
|
+
const eq = trimmed.indexOf("=");
|
|
37
|
+
const key = trimmed.slice(0, eq).trim();
|
|
38
|
+
const value = trimmed
|
|
39
|
+
.slice(eq + 1)
|
|
40
|
+
.trim()
|
|
41
|
+
.replace(/^["']|["']$/g, "");
|
|
42
|
+
if (key && env[key] === undefined) env[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function seedFromMcpJson(raw: string): CodebaseRagCredentials | null {
|
|
47
|
+
let data: unknown;
|
|
48
|
+
try {
|
|
49
|
+
data = JSON.parse(raw);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!isRecord(data)) return null;
|
|
54
|
+
const servers = data.mcpServers;
|
|
55
|
+
if (!isRecord(servers)) return null;
|
|
56
|
+
const server = servers["codebase-rag"];
|
|
57
|
+
if (!isRecord(server)) return null;
|
|
58
|
+
const url = typeof server.url === "string" ? server.url.trim() : "";
|
|
59
|
+
const headers = isRecord(server.headers) ? server.headers : {};
|
|
60
|
+
const auth = typeof headers.Authorization === "string" ? headers.Authorization.trim() : "";
|
|
61
|
+
const token = auth.toLowerCase().startsWith("bearer ") ? auth.slice(7).trim() : "";
|
|
62
|
+
if (!url.startsWith("http") || token.length === 0) return null;
|
|
63
|
+
return { url, token };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function mergeIntoMcpJson(input: {
|
|
67
|
+
mcpPath: string;
|
|
68
|
+
url: string;
|
|
69
|
+
token: string;
|
|
70
|
+
hostRoot: string;
|
|
71
|
+
}): { skipped?: string; path?: string; root?: string } {
|
|
72
|
+
const { mcpPath, url, token, hostRoot } = input;
|
|
73
|
+
if (!url || !token) {
|
|
74
|
+
return { skipped: "no URL/token" };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const xRoot = hostRoot || "${workspaceFolder}";
|
|
78
|
+
mkdirSync(dirname(mcpPath), { recursive: true });
|
|
79
|
+
|
|
80
|
+
let data: McpJson = { mcpServers: {} };
|
|
81
|
+
try {
|
|
82
|
+
if (statSync(mcpPath).size > 0) {
|
|
83
|
+
const loaded: unknown = JSON.parse(readFileSync(mcpPath, "utf8"));
|
|
84
|
+
if (isRecord(loaded)) data = loaded as McpJson;
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
const code = isRecord(err) && typeof err.code === "string" ? err.code : "";
|
|
88
|
+
if (code !== "ENOENT") {
|
|
89
|
+
console.log(
|
|
90
|
+
"codebase-rag MCP: existing mcp.json is invalid JSON; replacing rag entry only after backup",
|
|
91
|
+
);
|
|
92
|
+
renameSync(mcpPath, `${mcpPath}.bak`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const servers = isRecord(data.mcpServers) ? data.mcpServers : {};
|
|
97
|
+
data.mcpServers = servers;
|
|
98
|
+
servers["codebase-rag"] = {
|
|
99
|
+
url,
|
|
100
|
+
headers: {
|
|
101
|
+
Authorization: `Bearer ${token}`,
|
|
102
|
+
"X-Codebase-Root": xRoot,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
writeFileSync(mcpPath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
106
|
+
try {
|
|
107
|
+
chmodSync(mcpPath, 0o600);
|
|
108
|
+
} catch {
|
|
109
|
+
// memfs and some hosts omit chmod
|
|
110
|
+
}
|
|
111
|
+
return { path: mcpPath, root: xRoot };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function workspaceRoot(env: NodeJS.ProcessEnv = process.env): string {
|
|
115
|
+
const fromEnv = env.CODEBASE_RAG_WORKSPACE?.trim();
|
|
116
|
+
if (fromEnv) return fromEnv;
|
|
117
|
+
// Scaffolded copy lives at <repo>/.devcontainer/codebase-rag-mcp.ts
|
|
118
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function mergeFromEnv(env: NodeJS.ProcessEnv = process.env): number {
|
|
122
|
+
const root = workspaceRoot(env);
|
|
123
|
+
const cursorDir = join(root, ".cursor");
|
|
124
|
+
loadDotenv(join(cursorDir, "codebase-rag.env"), env);
|
|
125
|
+
const url = (env.CODEBASE_RAG_MCP_URL ?? "").trim();
|
|
126
|
+
const token = (env.CODEBASE_RAG_MCP_TOKEN ?? "").trim();
|
|
127
|
+
const hostRoot = (env.CODEBASE_RAG_MCP_ROOT ?? "").trim() || root;
|
|
128
|
+
const result = mergeIntoMcpJson({
|
|
129
|
+
mcpPath: join(cursorDir, "mcp.json"),
|
|
130
|
+
url,
|
|
131
|
+
token,
|
|
132
|
+
hostRoot,
|
|
133
|
+
});
|
|
134
|
+
if (result.skipped != null) {
|
|
135
|
+
console.log(`codebase-rag MCP: skipped (${result.skipped})`);
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
console.log(`codebase-rag MCP: wrote ${result.path} url=${url} root=${result.root}`);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function seedPrint(mcpPath: string): number {
|
|
143
|
+
let raw: string;
|
|
144
|
+
try {
|
|
145
|
+
raw = readFileSync(mcpPath, "utf8");
|
|
146
|
+
} catch {
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
const creds = seedFromMcpJson(raw);
|
|
150
|
+
if (creds == null) return 1;
|
|
151
|
+
console.log(creds.url);
|
|
152
|
+
console.log(creds.token);
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function main(argv = process.argv.slice(2)): number {
|
|
157
|
+
const command = argv[0] ?? "merge";
|
|
158
|
+
if (command === "seed-print") {
|
|
159
|
+
const mcpPath = argv[1];
|
|
160
|
+
if (mcpPath == null || mcpPath.length === 0) return 1;
|
|
161
|
+
return seedPrint(mcpPath);
|
|
162
|
+
}
|
|
163
|
+
if (command === "merge") {
|
|
164
|
+
return mergeFromEnv();
|
|
165
|
+
}
|
|
166
|
+
console.error(`codebase-rag MCP: unknown command ${command}`);
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const invoked = (process.argv[1] ?? "").replaceAll("\\", "/");
|
|
171
|
+
if (invoked.endsWith("/codebase-rag-mcp.ts") || invoked.endsWith("/codebase-rag-mcp.js")) {
|
|
172
|
+
process.exit(main());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const codebaseRagMcp = {
|
|
176
|
+
loadDotenv,
|
|
177
|
+
seedFromMcpJson,
|
|
178
|
+
mergeIntoMcpJson,
|
|
179
|
+
mergeFromEnv,
|
|
180
|
+
seedPrint,
|
|
181
|
+
main,
|
|
182
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
const TEMPLATE_FILES = [
|
|
4
|
+
"initialize.sh",
|
|
5
|
+
"post-create.sh",
|
|
6
|
+
"post-start.sh",
|
|
7
|
+
"tty-prompt.sh",
|
|
8
|
+
"codebase-rag.env.example"
|
|
9
|
+
];
|
|
10
|
+
export function devcontainerTemplatePath(name) {
|
|
11
|
+
return fileURLToPath(new URL(`./templates/${name}`, import.meta.url));
|
|
12
|
+
}
|
|
13
|
+
export function codebaseRagMcpSourcePath() {
|
|
14
|
+
return fileURLToPath(new URL("./codebase-rag-mcp.ts", import.meta.url));
|
|
15
|
+
}
|
|
16
|
+
/** Host + container scripts for the scaffolded Dev Container. */ export class DevContainerHostScripts {
|
|
17
|
+
files() {
|
|
18
|
+
return [
|
|
19
|
+
...TEMPLATE_FILES.map((name)=>({
|
|
20
|
+
filePath: `.devcontainer/${name}`,
|
|
21
|
+
content: readFileSync(devcontainerTemplatePath(name), "utf8")
|
|
22
|
+
})),
|
|
23
|
+
{
|
|
24
|
+
filePath: ".devcontainer/codebase-rag-mcp.ts",
|
|
25
|
+
content: readFileSync(codebaseRagMcpSourcePath(), "utf8")
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
}
|