@deepstorm/cli 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +508 -24
- package/dist/registry.json +168 -0
- package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +53 -0
- package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +30 -0
- package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +58 -0
- package/dist/skills/reef-style-backend/fragments/nodejs/prettier-config.json +19 -0
- package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +166 -0
- package/dist/skills/reef-style-backend/variants/nodejs/examples/prisma-example.md +115 -0
- package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +116 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -6150,6 +6150,10 @@ function parseInitArgs(raw) {
|
|
|
6150
6150
|
if (raw.ai && typeof raw.ai === "string") opts.ai = raw.ai;
|
|
6151
6151
|
if (raw["ui-lib"] && typeof raw["ui-lib"] === "string") opts.uiLib = raw["ui-lib"];
|
|
6152
6152
|
if (raw["css"] && typeof raw["css"] === "string") opts.cssFramework = raw["css"];
|
|
6153
|
+
if (raw.nodejsOrm && typeof raw.nodejsOrm === "string") opts.nodejsOrm = raw.nodejsOrm;
|
|
6154
|
+
if (raw["nodejs-orm"] && typeof raw["nodejs-orm"] === "string") opts.nodejsOrm = raw["nodejs-orm"];
|
|
6155
|
+
if (raw.nodejsAi && typeof raw.nodejsAi === "string") opts.nodejsAi = raw.nodejsAi;
|
|
6156
|
+
if (raw["nodejs-ai"] && typeof raw["nodejs-ai"] === "string") opts.nodejsAi = raw["nodejs-ai"];
|
|
6153
6157
|
return opts;
|
|
6154
6158
|
}
|
|
6155
6159
|
var CONTEXT_MD_NAME = "context.md";
|
|
@@ -6249,10 +6253,15 @@ function initClaudeMd(targetDir, opts) {
|
|
|
6249
6253
|
if (opts.cssFramework) techLines.push(`- **CSS \u65B9\u6848**\uFF1A${opts.cssFramework}`);
|
|
6250
6254
|
}
|
|
6251
6255
|
if (opts.backend) {
|
|
6252
|
-
techLines.push(`- **\u540E\u7AEF**\uFF1A${opts.backend}`);
|
|
6253
|
-
if (opts.
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
+
techLines.push(`- **\u540E\u7AEF**\uFF1A${opts.backend === "nodejs" ? "Node.js (NestJS)" : opts.backend}`);
|
|
6257
|
+
if (opts.backend === "nodejs") {
|
|
6258
|
+
if (opts.nodejsOrm) techLines.push(`- **ORM**\uFF1A${opts.nodejsOrm}`);
|
|
6259
|
+
if (opts.nodejsAi) techLines.push(`- **AI \u6846\u67B6**\uFF1A${opts.nodejsAi}`);
|
|
6260
|
+
} else {
|
|
6261
|
+
if (opts.orm) techLines.push(`- **ORM**\uFF1A${opts.orm}`);
|
|
6262
|
+
if (opts.migration) techLines.push(`- **\u6570\u636E\u5E93\u8FC1\u79FB**\uFF1A${opts.migration}`);
|
|
6263
|
+
if (opts.ai) techLines.push(`- **AI \u6846\u67B6**\uFF1A${opts.ai}`);
|
|
6264
|
+
}
|
|
6256
6265
|
}
|
|
6257
6266
|
if (techLines.length > 0) {
|
|
6258
6267
|
lines.push("## \u6280\u672F\u6808", "");
|
|
@@ -6275,9 +6284,14 @@ function writeInitTechStack(baseDir, opts) {
|
|
|
6275
6284
|
if (opts.backend) {
|
|
6276
6285
|
config["reef.techs"] = opts.frontend ? "frontend,backend" : "backend";
|
|
6277
6286
|
config["reef.backend.language"] = opts.backend;
|
|
6278
|
-
if (opts.
|
|
6279
|
-
|
|
6280
|
-
|
|
6287
|
+
if (opts.backend === "nodejs") {
|
|
6288
|
+
if (opts.nodejsOrm) config["reef.backend.nodejs.orm"] = opts.nodejsOrm;
|
|
6289
|
+
if (opts.nodejsAi) config["reef.backend.nodejs.ai"] = opts.nodejsAi;
|
|
6290
|
+
} else {
|
|
6291
|
+
if (opts.orm) config["reef.backend.java.orm"] = opts.orm;
|
|
6292
|
+
if (opts.migration) config["reef.backend.java.dbMigration"] = opts.migration;
|
|
6293
|
+
if (opts.ai) config["reef.backend.java.ai"] = opts.ai;
|
|
6294
|
+
}
|
|
6281
6295
|
}
|
|
6282
6296
|
if (Object.keys(config).length === 0) return;
|
|
6283
6297
|
const nested = buildInitNestedConfig(config);
|
|
@@ -6304,7 +6318,7 @@ function buildInitNestedConfig(flat) {
|
|
|
6304
6318
|
return result;
|
|
6305
6319
|
}
|
|
6306
6320
|
function registerInitCommand(program2, registry2) {
|
|
6307
|
-
program2.command("init").description("\u521D\u59CB\u5316\u9879\u76EE\u811A\u624B\u67B6 \u2014 \u9009\u62E9\u6280\u672F\u6808\uFF0C\u751F\u6210\u9879\u76EE\u9AA8\u67B6").option("--name <name>", "\u9879\u76EE\u540D\u79F0").option("--frontend <framework>", "\u524D\u7AEF\u6846\u67B6\uFF08angular\uFF09").option("--backend <language>", "\u540E\u7AEF\u8BED\u8A00\uFF08java\uFF09").option("--output <dir>", "\u8F93\u51FA\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55\uFF09").option("--ui-lib <lib>", "UI \u5E93\uFF08primeng\uFF09").option("--css <framework>", "CSS \u6846\u67B6\uFF08tailwind\uFF09").option("--orm <orm>", "ORM \u6846\u67B6\uFF08hibernate\uFF09").option("--migration <tool>", "\u6570\u636E\u5E93\u8FC1\u79FB\u5DE5\u5177\uFF08liquibase\uFF09").option("--ai <framework>", "AI \u6846\u67B6\uFF08spring-ai\uFF09").action(async (options) => {
|
|
6321
|
+
program2.command("init").description("\u521D\u59CB\u5316\u9879\u76EE\u811A\u624B\u67B6 \u2014 \u9009\u62E9\u6280\u672F\u6808\uFF0C\u751F\u6210\u9879\u76EE\u9AA8\u67B6").option("--name <name>", "\u9879\u76EE\u540D\u79F0").option("--frontend <framework>", "\u524D\u7AEF\u6846\u67B6\uFF08angular\uFF09").option("--backend <language>", "\u540E\u7AEF\u8BED\u8A00\uFF08java / nodejs\uFF09").option("--output <dir>", "\u8F93\u51FA\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55\uFF09").option("--ui-lib <lib>", "UI \u5E93\uFF08primeng\uFF09").option("--css <framework>", "CSS \u6846\u67B6\uFF08tailwind\uFF09").option("--orm <orm>", "ORM \u6846\u67B6\uFF08hibernate\uFF09").option("--migration <tool>", "\u6570\u636E\u5E93\u8FC1\u79FB\u5DE5\u5177\uFF08liquibase\uFF09").option("--ai <framework>", "AI \u6846\u67B6\uFF08spring-ai\uFF09").option("--nodejs-orm <orm>", "Node.js ORM\uFF08prisma\uFF09").option("--nodejs-ai <framework>", "Node.js AI \u6846\u67B6\uFF08claude-agent-sdk\uFF09").action(async (options) => {
|
|
6308
6322
|
const args = parseInitArgs(options);
|
|
6309
6323
|
const targetDir = options.output || process.cwd();
|
|
6310
6324
|
if (args.projectName && (args.frontend || args.backend)) {
|
|
@@ -6439,6 +6453,7 @@ async function runInteractiveMode(targetDir) {
|
|
|
6439
6453
|
message: "\u9009\u62E9\u540E\u7AEF\u6846\u67B6\uFF1A",
|
|
6440
6454
|
options: [
|
|
6441
6455
|
{ value: "java", label: "Java (Spring Boot)" },
|
|
6456
|
+
{ value: "nodejs", label: "Node.js (NestJS)" },
|
|
6442
6457
|
{ value: "none", label: "\u4E0D\u9700\u8981\u540E\u7AEF" }
|
|
6443
6458
|
]
|
|
6444
6459
|
});
|
|
@@ -6487,6 +6502,34 @@ async function runInteractiveMode(targetDir) {
|
|
|
6487
6502
|
}
|
|
6488
6503
|
aiChoice = aiResult;
|
|
6489
6504
|
}
|
|
6505
|
+
let nodejsOrm;
|
|
6506
|
+
let nodejsAi;
|
|
6507
|
+
if (backendChoice === "nodejs") {
|
|
6508
|
+
const ormResult = await select2({
|
|
6509
|
+
message: "\u9009\u62E9 ORM \u6846\u67B6\uFF1A",
|
|
6510
|
+
options: [
|
|
6511
|
+
{ value: "prisma", label: "Prisma" },
|
|
6512
|
+
{ value: "none", label: "\u65E0" }
|
|
6513
|
+
]
|
|
6514
|
+
});
|
|
6515
|
+
if (isCancel8(ormResult)) {
|
|
6516
|
+
outro2("\u5DF2\u53D6\u6D88");
|
|
6517
|
+
return;
|
|
6518
|
+
}
|
|
6519
|
+
nodejsOrm = ormResult;
|
|
6520
|
+
const aiResult = await select2({
|
|
6521
|
+
message: "\u9009\u62E9 AI \u6846\u67B6\uFF1A",
|
|
6522
|
+
options: [
|
|
6523
|
+
{ value: "claude-agent-sdk", label: "Claude Agent SDK" },
|
|
6524
|
+
{ value: "none", label: "\u65E0" }
|
|
6525
|
+
]
|
|
6526
|
+
});
|
|
6527
|
+
if (isCancel8(aiResult)) {
|
|
6528
|
+
outro2("\u5DF2\u53D6\u6D88");
|
|
6529
|
+
return;
|
|
6530
|
+
}
|
|
6531
|
+
nodejsAi = aiResult;
|
|
6532
|
+
}
|
|
6490
6533
|
if ((!frontendChoice || frontendChoice === "none") && (!backendChoice || backendChoice === "none")) {
|
|
6491
6534
|
console.error("\u274C \u81F3\u5C11\u9700\u8981\u9009\u62E9\u524D\u7AEF\u6216\u540E\u7AEF\u4E4B\u4E00");
|
|
6492
6535
|
outro2("\u521D\u59CB\u5316\u5931\u8D25");
|
|
@@ -6500,7 +6543,9 @@ async function runInteractiveMode(targetDir) {
|
|
|
6500
6543
|
cssFramework: cssFramework && cssFramework !== "none" ? cssFramework : void 0,
|
|
6501
6544
|
orm: orm && orm !== "none" ? orm : void 0,
|
|
6502
6545
|
migration: migration && migration !== "none" ? migration : void 0,
|
|
6503
|
-
ai: aiChoice && aiChoice !== "none" ? aiChoice : void 0
|
|
6546
|
+
ai: aiChoice && aiChoice !== "none" ? aiChoice : void 0,
|
|
6547
|
+
nodejsOrm: nodejsOrm && nodejsOrm !== "none" ? nodejsOrm : void 0,
|
|
6548
|
+
nodejsAi: nodejsAi && nodejsAi !== "none" ? nodejsAi : void 0
|
|
6504
6549
|
};
|
|
6505
6550
|
await runInit(targetDir, opts);
|
|
6506
6551
|
outro2("\u2705 \u9879\u76EE\u5DF2\u751F\u6210\uFF01");
|
|
@@ -6521,15 +6566,20 @@ async function runInit(baseDir, opts) {
|
|
|
6521
6566
|
}
|
|
6522
6567
|
const ctx = buildContext(opts);
|
|
6523
6568
|
const hasFrontend = opts.frontend === "angular";
|
|
6524
|
-
const
|
|
6569
|
+
const hasJavaBackend = opts.backend === "java";
|
|
6570
|
+
const hasNodeBackend = opts.backend === "nodejs";
|
|
6571
|
+
const hasBackend = hasJavaBackend || hasNodeBackend;
|
|
6525
6572
|
try {
|
|
6526
6573
|
if (hasFrontend) {
|
|
6527
6574
|
renderAngularTemplate(projectDir, ctx);
|
|
6528
6575
|
}
|
|
6529
|
-
if (
|
|
6576
|
+
if (hasJavaBackend) {
|
|
6530
6577
|
renderJavaTemplate(projectDir, ctx);
|
|
6531
6578
|
}
|
|
6532
|
-
|
|
6579
|
+
if (hasNodeBackend) {
|
|
6580
|
+
renderNestJSTemplate(projectDir, ctx, opts);
|
|
6581
|
+
}
|
|
6582
|
+
renderCommonFiles(projectDir, ctx, opts);
|
|
6533
6583
|
console.log(`
|
|
6534
6584
|
\u2714 \u9879\u76EE\u5DF2\u521B\u5EFA: ${projectDir}`);
|
|
6535
6585
|
console.log("\n\u4E0B\u4E00\u6B65:");
|
|
@@ -6537,9 +6587,10 @@ async function runInit(baseDir, opts) {
|
|
|
6537
6587
|
console.log(` cd ${opts.projectName}`);
|
|
6538
6588
|
}
|
|
6539
6589
|
if (opts.frontend) console.log(` pnpm install # \u5B89\u88C5\u524D\u7AEF\u4F9D\u8D56`);
|
|
6540
|
-
if (
|
|
6590
|
+
if (hasJavaBackend) console.log(` ./gradlew build # \u6784\u5EFA\u540E\u7AEF`);
|
|
6591
|
+
if (hasNodeBackend) console.log(` pnpm install # \u5B89\u88C5\u4F9D\u8D56`);
|
|
6541
6592
|
console.log();
|
|
6542
|
-
printProjectTree(projectDir, hasFrontend,
|
|
6593
|
+
printProjectTree(projectDir, hasFrontend, hasJavaBackend, hasNodeBackend);
|
|
6543
6594
|
if (inPlace) {
|
|
6544
6595
|
initClaudeMd(baseDir, opts);
|
|
6545
6596
|
}
|
|
@@ -7037,7 +7088,371 @@ set CLASSPATH=%APP_HOME%/gradle/wrapper/gradle-wrapper.jar
|
|
|
7037
7088
|
@endlocal & exit /b %ERRORLEVEL%
|
|
7038
7089
|
`);
|
|
7039
7090
|
}
|
|
7040
|
-
function
|
|
7091
|
+
function renderNestJSTemplate(projectDir, ctx, opts) {
|
|
7092
|
+
const hasPrisma = opts.nodejsOrm === "prisma";
|
|
7093
|
+
const hasAgentSdk = opts.nodejsAi === "claude-agent-sdk";
|
|
7094
|
+
const pkgDeps = {
|
|
7095
|
+
"@nestjs/common": "^11.0.0",
|
|
7096
|
+
"@nestjs/core": "^11.0.0",
|
|
7097
|
+
"@nestjs/platform-express": "^11.0.0",
|
|
7098
|
+
"@nestjs/config": "^4.0.0",
|
|
7099
|
+
"@nestjs/swagger": "^9.0.0",
|
|
7100
|
+
"class-validator": "^0.14.0",
|
|
7101
|
+
"class-transformer": "^0.5.0",
|
|
7102
|
+
"reflect-metadata": "^0.2.0",
|
|
7103
|
+
rxjs: "^7.8.0"
|
|
7104
|
+
};
|
|
7105
|
+
const devDeps = {
|
|
7106
|
+
"@nestjs/cli": "^11.0.0",
|
|
7107
|
+
"@nestjs/schematics": "^11.0.0",
|
|
7108
|
+
"@nestjs/testing": "^11.0.0",
|
|
7109
|
+
"@types/express": "^5.0.0",
|
|
7110
|
+
"@types/jest": "^29.5.0",
|
|
7111
|
+
"@types/node": "^22.0.0",
|
|
7112
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
7113
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
7114
|
+
eslint: "^9.0.0",
|
|
7115
|
+
"eslint-config-prettier": "^10.0.0",
|
|
7116
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
7117
|
+
jest: "^29.7.0",
|
|
7118
|
+
prettier: "^3.4.0",
|
|
7119
|
+
"source-map-support": "^0.5.0",
|
|
7120
|
+
"ts-jest": "^29.0.0",
|
|
7121
|
+
"ts-loader": "^9.5.0",
|
|
7122
|
+
"ts-node": "^10.9.0",
|
|
7123
|
+
"tsconfig-paths": "^4.2.0",
|
|
7124
|
+
typescript: "^5.7.0"
|
|
7125
|
+
};
|
|
7126
|
+
if (hasPrisma) {
|
|
7127
|
+
pkgDeps["@prisma/client"] = "^6.0.0";
|
|
7128
|
+
devDeps.prisma = "^6.0.0";
|
|
7129
|
+
}
|
|
7130
|
+
if (hasAgentSdk) {
|
|
7131
|
+
pkgDeps["@anthropic-ai/sdk"] = "^0.40.0";
|
|
7132
|
+
}
|
|
7133
|
+
writeTemplate(projectDir, "package.json", JSON.stringify({
|
|
7134
|
+
name: ctx.packageName,
|
|
7135
|
+
version: "0.1.0",
|
|
7136
|
+
description: "",
|
|
7137
|
+
private: true,
|
|
7138
|
+
scripts: {
|
|
7139
|
+
build: "nest build",
|
|
7140
|
+
format: 'prettier --write "src/**/*.ts"',
|
|
7141
|
+
start: "nest start",
|
|
7142
|
+
"start:dev": "nest start --watch",
|
|
7143
|
+
"start:prod": "node dist/main",
|
|
7144
|
+
lint: 'eslint "{src,test}/**/*.ts" --fix',
|
|
7145
|
+
test: "jest",
|
|
7146
|
+
"test:watch": "jest --watch",
|
|
7147
|
+
"test:cov": "jest --coverage",
|
|
7148
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
7149
|
+
},
|
|
7150
|
+
dependencies: pkgDeps,
|
|
7151
|
+
devDependencies: devDeps,
|
|
7152
|
+
jest: {
|
|
7153
|
+
moduleFileExtensions: ["js", "json", "ts"],
|
|
7154
|
+
rootDir: "src",
|
|
7155
|
+
testRegex: ".*\\.spec\\.ts$",
|
|
7156
|
+
transform: { "^.+\\.(t|j)s$": "ts-jest" },
|
|
7157
|
+
collectCoverageFrom: ["**/*.(t|j)s"],
|
|
7158
|
+
coverageDirectory: "../coverage",
|
|
7159
|
+
testEnvironment: "node"
|
|
7160
|
+
}
|
|
7161
|
+
}, null, 2));
|
|
7162
|
+
writeTemplate(projectDir, "tsconfig.json", JSON.stringify({
|
|
7163
|
+
compilerOptions: {
|
|
7164
|
+
module: "commonjs",
|
|
7165
|
+
declaration: true,
|
|
7166
|
+
removeComments: true,
|
|
7167
|
+
emitDecoratorMetadata: true,
|
|
7168
|
+
experimentalDecorators: true,
|
|
7169
|
+
allowSyntheticDefaultImports: true,
|
|
7170
|
+
target: "ES2023",
|
|
7171
|
+
sourceMap: true,
|
|
7172
|
+
outDir: "./dist",
|
|
7173
|
+
baseUrl: "./",
|
|
7174
|
+
incremental: true,
|
|
7175
|
+
skipLibCheck: true,
|
|
7176
|
+
strict: true,
|
|
7177
|
+
strictNullChecks: true,
|
|
7178
|
+
noImplicitAny: true,
|
|
7179
|
+
strictBindCallApply: true,
|
|
7180
|
+
forceConsistentCasingInFileNames: true,
|
|
7181
|
+
noFallthroughCasesInSwitch: true,
|
|
7182
|
+
esModuleInterop: true,
|
|
7183
|
+
resolveJsonModule: true
|
|
7184
|
+
}
|
|
7185
|
+
}, null, 2));
|
|
7186
|
+
writeTemplate(projectDir, "nest-cli.json", JSON.stringify({
|
|
7187
|
+
$schema: "https://json.schemastore.org/nest-cli",
|
|
7188
|
+
collection: "@nestjs/schematics",
|
|
7189
|
+
sourceRoot: "src",
|
|
7190
|
+
compilerOptions: { deleteOutDir: true }
|
|
7191
|
+
}, null, 2));
|
|
7192
|
+
writeTemplate(projectDir, ".prettierrc", JSON.stringify({
|
|
7193
|
+
singleQuote: true,
|
|
7194
|
+
trailingComma: "all",
|
|
7195
|
+
tabWidth: 2,
|
|
7196
|
+
semi: true,
|
|
7197
|
+
printWidth: 120
|
|
7198
|
+
}, null, 2));
|
|
7199
|
+
ensureDir2(path2.join(projectDir, "src"));
|
|
7200
|
+
writeTemplate(projectDir, "src/main.ts", [
|
|
7201
|
+
"import { NestFactory } from '@nestjs/core';",
|
|
7202
|
+
"import { ValidationPipe, Logger } from '@nestjs/common';",
|
|
7203
|
+
"import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';",
|
|
7204
|
+
"import { AppModule } from './app.module';",
|
|
7205
|
+
"",
|
|
7206
|
+
"async function bootstrap() {",
|
|
7207
|
+
" const app = await NestFactory.create(AppModule);",
|
|
7208
|
+
" const logger = new Logger('Bootstrap');",
|
|
7209
|
+
"",
|
|
7210
|
+
" app.setGlobalPrefix('api/v1');",
|
|
7211
|
+
"",
|
|
7212
|
+
" app.useGlobalPipes(",
|
|
7213
|
+
" new ValidationPipe({",
|
|
7214
|
+
" whitelist: true,",
|
|
7215
|
+
" forbidNonWhitelisted: true,",
|
|
7216
|
+
" transform: true,",
|
|
7217
|
+
" }),",
|
|
7218
|
+
" );",
|
|
7219
|
+
"",
|
|
7220
|
+
" const config = new DocumentBuilder()",
|
|
7221
|
+
` .setTitle('${ctx.projectName}')`,
|
|
7222
|
+
" .setDescription('API documentation')",
|
|
7223
|
+
" .setVersion('1.0')",
|
|
7224
|
+
" .addBearerAuth()",
|
|
7225
|
+
" .build();",
|
|
7226
|
+
" const document = SwaggerModule.createDocument(app, config);",
|
|
7227
|
+
" SwaggerModule.setup('api/docs', app, document);",
|
|
7228
|
+
"",
|
|
7229
|
+
" app.enableCors({",
|
|
7230
|
+
" origin: process.env.CORS_ORIGIN || '*',",
|
|
7231
|
+
" methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',",
|
|
7232
|
+
" credentials: true,",
|
|
7233
|
+
" });",
|
|
7234
|
+
"",
|
|
7235
|
+
" const port = process.env.PORT || 3000;",
|
|
7236
|
+
" await app.listen(port);",
|
|
7237
|
+
" logger.log(`Application running on http://localhost:${port}`);",
|
|
7238
|
+
" logger.log(`Swagger docs at http://localhost:${port}/api/docs`);",
|
|
7239
|
+
"}",
|
|
7240
|
+
"bootstrap();",
|
|
7241
|
+
""
|
|
7242
|
+
].join("\n"));
|
|
7243
|
+
const appModuleContent = [
|
|
7244
|
+
"import { Module } from '@nestjs/common';",
|
|
7245
|
+
"import { ConfigModule } from '@nestjs/config';",
|
|
7246
|
+
"import { AppController } from './app.controller';",
|
|
7247
|
+
"import { AppService } from './app.service';"
|
|
7248
|
+
];
|
|
7249
|
+
const appModuleImports = [
|
|
7250
|
+
" ConfigModule.forRoot({",
|
|
7251
|
+
" isGlobal: true,",
|
|
7252
|
+
" }),"
|
|
7253
|
+
];
|
|
7254
|
+
if (hasPrisma) {
|
|
7255
|
+
appModuleContent.push("import { PrismaModule } from './prisma/prisma.module';");
|
|
7256
|
+
appModuleImports.push(" PrismaModule,");
|
|
7257
|
+
}
|
|
7258
|
+
if (hasAgentSdk) {
|
|
7259
|
+
appModuleContent.push("import { AgentModule } from './agent/agent.module';");
|
|
7260
|
+
appModuleImports.push(" AgentModule,");
|
|
7261
|
+
}
|
|
7262
|
+
appModuleContent.push("");
|
|
7263
|
+
appModuleContent.push("/**");
|
|
7264
|
+
appModuleContent.push(" * \u5E94\u7528\u6839\u6A21\u5757");
|
|
7265
|
+
appModuleContent.push(" */");
|
|
7266
|
+
appModuleContent.push("@Module({");
|
|
7267
|
+
appModuleContent.push(" imports: [");
|
|
7268
|
+
appModuleContent.push(appModuleImports.join("\n"));
|
|
7269
|
+
appModuleContent.push(" ],");
|
|
7270
|
+
appModuleContent.push(" controllers: [AppController],");
|
|
7271
|
+
appModuleContent.push(" providers: [AppService],");
|
|
7272
|
+
appModuleContent.push("})");
|
|
7273
|
+
appModuleContent.push("export class AppModule {}");
|
|
7274
|
+
writeTemplate(projectDir, "src/app.module.ts", appModuleContent.join("\n"));
|
|
7275
|
+
writeTemplate(projectDir, "src/app.controller.ts", [
|
|
7276
|
+
"import { Controller, Get } from '@nestjs/common';",
|
|
7277
|
+
"import { ApiTags, ApiOperation } from '@nestjs/swagger';",
|
|
7278
|
+
"import { AppService } from './app.service';",
|
|
7279
|
+
"",
|
|
7280
|
+
"@ApiTags('Health')",
|
|
7281
|
+
"@Controller()",
|
|
7282
|
+
"export class AppController {",
|
|
7283
|
+
" constructor(private readonly appService: AppService) {}",
|
|
7284
|
+
"",
|
|
7285
|
+
" @Get()",
|
|
7286
|
+
" @ApiOperation({ summary: '\u5065\u5EB7\u68C0\u67E5' })",
|
|
7287
|
+
" getHello(): string {",
|
|
7288
|
+
" return this.appService.getHello();",
|
|
7289
|
+
" }",
|
|
7290
|
+
"}",
|
|
7291
|
+
""
|
|
7292
|
+
].join("\n"));
|
|
7293
|
+
writeTemplate(projectDir, "src/app.service.ts", [
|
|
7294
|
+
"import { Injectable } from '@nestjs/common';",
|
|
7295
|
+
"",
|
|
7296
|
+
"@Injectable()",
|
|
7297
|
+
"export class AppService {",
|
|
7298
|
+
" getHello(): string {",
|
|
7299
|
+
` return 'Hello from ${ctx.projectName}!';`,
|
|
7300
|
+
" }",
|
|
7301
|
+
"}",
|
|
7302
|
+
""
|
|
7303
|
+
].join("\n"));
|
|
7304
|
+
if (hasPrisma) {
|
|
7305
|
+
ensureDir2(path2.join(projectDir, "prisma"));
|
|
7306
|
+
writeTemplate(projectDir, "prisma/schema.prisma", [
|
|
7307
|
+
"generator client {",
|
|
7308
|
+
' provider = "prisma-client-js"',
|
|
7309
|
+
"}",
|
|
7310
|
+
"",
|
|
7311
|
+
"datasource db {",
|
|
7312
|
+
' provider = "postgresql"',
|
|
7313
|
+
' url = env("DATABASE_URL")',
|
|
7314
|
+
"}",
|
|
7315
|
+
"",
|
|
7316
|
+
"/// \u7528\u6237",
|
|
7317
|
+
"model User {",
|
|
7318
|
+
" id Int @id @default(autoincrement())",
|
|
7319
|
+
" name String",
|
|
7320
|
+
" email String @unique",
|
|
7321
|
+
" active Boolean @default(true)",
|
|
7322
|
+
" createdAt DateTime @default(now())",
|
|
7323
|
+
" updatedAt DateTime @updatedAt",
|
|
7324
|
+
"",
|
|
7325
|
+
' @@map("users")',
|
|
7326
|
+
"}",
|
|
7327
|
+
""
|
|
7328
|
+
].join("\n"));
|
|
7329
|
+
ensureDir2(path2.join(projectDir, "src/prisma"));
|
|
7330
|
+
writeTemplate(projectDir, "src/prisma/prisma.module.ts", [
|
|
7331
|
+
"import { Global, Module } from '@nestjs/common';",
|
|
7332
|
+
"import { PrismaService } from './prisma.service';",
|
|
7333
|
+
"",
|
|
7334
|
+
"@Global()",
|
|
7335
|
+
"@Module({",
|
|
7336
|
+
" providers: [PrismaService],",
|
|
7337
|
+
" exports: [PrismaService],",
|
|
7338
|
+
"})",
|
|
7339
|
+
"export class PrismaModule {}",
|
|
7340
|
+
""
|
|
7341
|
+
].join("\n"));
|
|
7342
|
+
writeTemplate(projectDir, "src/prisma/prisma.service.ts", [
|
|
7343
|
+
"import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';",
|
|
7344
|
+
"import { PrismaClient } from '@prisma/client';",
|
|
7345
|
+
"",
|
|
7346
|
+
"@Injectable()",
|
|
7347
|
+
"export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {",
|
|
7348
|
+
" private readonly logger = new Logger(PrismaService.name);",
|
|
7349
|
+
"",
|
|
7350
|
+
" async onModuleInit() {",
|
|
7351
|
+
" await this.$connect();",
|
|
7352
|
+
" this.logger.log('Database connected');",
|
|
7353
|
+
" }",
|
|
7354
|
+
"",
|
|
7355
|
+
" async onModuleDestroy() {",
|
|
7356
|
+
" await this.$disconnect();",
|
|
7357
|
+
" this.logger.log('Database disconnected');",
|
|
7358
|
+
" }",
|
|
7359
|
+
"}",
|
|
7360
|
+
""
|
|
7361
|
+
].join("\n"));
|
|
7362
|
+
}
|
|
7363
|
+
if (hasAgentSdk) {
|
|
7364
|
+
ensureDir2(path2.join(projectDir, "src/agent/tools"));
|
|
7365
|
+
writeTemplate(projectDir, "src/agent/agent.module.ts", [
|
|
7366
|
+
"import { Module } from '@nestjs/common';",
|
|
7367
|
+
"import { AgentService } from './agent.service';",
|
|
7368
|
+
"",
|
|
7369
|
+
"@Module({",
|
|
7370
|
+
" providers: [AgentService],",
|
|
7371
|
+
" exports: [AgentService],",
|
|
7372
|
+
"})",
|
|
7373
|
+
"export class AgentModule {}",
|
|
7374
|
+
""
|
|
7375
|
+
].join("\n"));
|
|
7376
|
+
writeTemplate(projectDir, "src/agent/agent.service.ts", [
|
|
7377
|
+
"import { Injectable, Logger } from '@nestjs/common';",
|
|
7378
|
+
"import { ConfigService } from '@nestjs/config';",
|
|
7379
|
+
"",
|
|
7380
|
+
"/**",
|
|
7381
|
+
" * Claude Agent \u670D\u52A1",
|
|
7382
|
+
" *",
|
|
7383
|
+
" * \u5C01\u88C5 Claude Agent SDK\uFF0C\u63D0\u4F9B Agent \u4EA4\u4E92\u80FD\u529B\u3002",
|
|
7384
|
+
" * \u4F7F\u7528\u524D\u9700\u5728 .env \u4E2D\u914D\u7F6E ANTHROPIC_API_KEY\u3002",
|
|
7385
|
+
" */",
|
|
7386
|
+
"@Injectable()",
|
|
7387
|
+
"export class AgentService {",
|
|
7388
|
+
" private readonly logger = new Logger(AgentService.name);",
|
|
7389
|
+
"",
|
|
7390
|
+
" constructor(private readonly configService: ConfigService) {",
|
|
7391
|
+
" const apiKey = this.configService.get<string>('ANTHROPIC_API_KEY');",
|
|
7392
|
+
" if (!apiKey) {",
|
|
7393
|
+
" this.logger.warn('ANTHROPIC_API_KEY is not configured');",
|
|
7394
|
+
" }",
|
|
7395
|
+
" }",
|
|
7396
|
+
"",
|
|
7397
|
+
" async ask(question: string): Promise<string> {",
|
|
7398
|
+
' this.logger.debug(`Agent ask: "${question}"`);',
|
|
7399
|
+
" return 'Agent response placeholder -- configure ANTHROPIC_API_KEY to enable';",
|
|
7400
|
+
" }",
|
|
7401
|
+
"}",
|
|
7402
|
+
""
|
|
7403
|
+
].join("\n"));
|
|
7404
|
+
writeTemplate(projectDir, "src/agent/tools/example.tool.ts", [
|
|
7405
|
+
"import { Injectable, Logger } from '@nestjs/common';",
|
|
7406
|
+
"",
|
|
7407
|
+
"export interface ToolDefinition {",
|
|
7408
|
+
" name: string;",
|
|
7409
|
+
" description: string;",
|
|
7410
|
+
" input_schema: Record<string, unknown>;",
|
|
7411
|
+
" execute: (input: Record<string, unknown>) => Promise<unknown>;",
|
|
7412
|
+
"}",
|
|
7413
|
+
"",
|
|
7414
|
+
"@Injectable()",
|
|
7415
|
+
"export class ExampleTool implements ToolDefinition {",
|
|
7416
|
+
" private readonly logger = new Logger(ExampleTool.name);",
|
|
7417
|
+
"",
|
|
7418
|
+
" name = 'get_current_time';",
|
|
7419
|
+
" description = '\u83B7\u53D6\u5F53\u524D\u65E5\u671F\u548C\u65F6\u95F4';",
|
|
7420
|
+
" input_schema = {",
|
|
7421
|
+
" type: 'object',",
|
|
7422
|
+
" properties: {",
|
|
7423
|
+
" timezone: {",
|
|
7424
|
+
" type: 'string',",
|
|
7425
|
+
" description: '\u65F6\u533A\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4 UTC\uFF09',",
|
|
7426
|
+
" enum: ['UTC', 'Asia/Shanghai', 'America/New_York'],",
|
|
7427
|
+
" },",
|
|
7428
|
+
" },",
|
|
7429
|
+
" };",
|
|
7430
|
+
"",
|
|
7431
|
+
" async execute(input: Record<string, unknown>): Promise<unknown> {",
|
|
7432
|
+
" try {",
|
|
7433
|
+
" this.logger.debug(`Tool execute: get_current_time with input: ${JSON.stringify(input)}`);",
|
|
7434
|
+
" const now = new Date();",
|
|
7435
|
+
" return {",
|
|
7436
|
+
" success: true,",
|
|
7437
|
+
" data: {",
|
|
7438
|
+
" iso: now.toISOString(),",
|
|
7439
|
+
" timestamp: now.getTime(),",
|
|
7440
|
+
" },",
|
|
7441
|
+
" };",
|
|
7442
|
+
" } catch (error) {",
|
|
7443
|
+
" this.logger.error(`Tool execution failed: ${error}`);",
|
|
7444
|
+
" return {",
|
|
7445
|
+
" success: false,",
|
|
7446
|
+
" error: error instanceof Error ? error.message : 'Unknown error',",
|
|
7447
|
+
" };",
|
|
7448
|
+
" }",
|
|
7449
|
+
" }",
|
|
7450
|
+
"}",
|
|
7451
|
+
""
|
|
7452
|
+
].join("\n"));
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
function renderCommonFiles(projectDir, ctx, opts) {
|
|
7041
7456
|
writeTemplate(projectDir, ".gitignore", `node_modules/
|
|
7042
7457
|
.gradle/
|
|
7043
7458
|
build/
|
|
@@ -7052,7 +7467,21 @@ __pycache__/
|
|
|
7052
7467
|
.vscode/
|
|
7053
7468
|
*.iml
|
|
7054
7469
|
`);
|
|
7055
|
-
|
|
7470
|
+
const hasNodeBackend = opts?.backend === "nodejs";
|
|
7471
|
+
if (hasNodeBackend) {
|
|
7472
|
+
writeEnvFile(projectDir, `# \u6570\u636E\u5E93\u914D\u7F6E
|
|
7473
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/${ctx.packageName}
|
|
7474
|
+
|
|
7475
|
+
# Claude Agent SDK
|
|
7476
|
+
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxx
|
|
7477
|
+
AGENT_MODEL=claude-sonnet-5
|
|
7478
|
+
|
|
7479
|
+
# Server
|
|
7480
|
+
PORT=3000
|
|
7481
|
+
CORS_ORIGIN=http://localhost:4200
|
|
7482
|
+
`);
|
|
7483
|
+
} else {
|
|
7484
|
+
writeEnvFile(projectDir, `# \u6570\u636E\u5E93\u914D\u7F6E
|
|
7056
7485
|
DB_URL=jdbc:postgresql://localhost:5432/${ctx.packageName}
|
|
7057
7486
|
DB_USERNAME=postgres
|
|
7058
7487
|
DB_PASSWORD=change-me
|
|
@@ -7060,15 +7489,26 @@ DB_PASSWORD=change-me
|
|
|
7060
7489
|
# API Keys
|
|
7061
7490
|
OPENAI_API_KEY=sk-your-key-here
|
|
7062
7491
|
`);
|
|
7063
|
-
|
|
7492
|
+
}
|
|
7493
|
+
const readme = generateReadme(ctx, opts);
|
|
7064
7494
|
writeTemplate(projectDir, "README.md", readme);
|
|
7065
7495
|
}
|
|
7066
|
-
function generateReadme(ctx) {
|
|
7496
|
+
function generateReadme(ctx, opts) {
|
|
7497
|
+
const hasNodeBackend = opts?.backend === "nodejs";
|
|
7498
|
+
const hasPrisma = opts?.nodejsOrm === "prisma";
|
|
7499
|
+
const hasAgentSdk = opts?.nodejsAi === "claude-agent-sdk";
|
|
7067
7500
|
const lines = [];
|
|
7068
7501
|
lines.push(`# ${ctx.projectName}`, "");
|
|
7069
7502
|
lines.push("## \u6280\u672F\u6808", "");
|
|
7070
7503
|
if (ctx.frontend) lines.push("- **\u524D\u7AEF\uFF1A** Angular + TypeScript");
|
|
7071
|
-
if (
|
|
7504
|
+
if (hasNodeBackend) {
|
|
7505
|
+
const nodeDeps = ["NestJS + TypeScript"];
|
|
7506
|
+
if (hasPrisma) nodeDeps.push("Prisma");
|
|
7507
|
+
if (hasAgentSdk) nodeDeps.push("Claude Agent SDK");
|
|
7508
|
+
lines.push(`- **\u540E\u7AEF\uFF1A** ${nodeDeps.join(" + ")}`);
|
|
7509
|
+
} else if (ctx.backend) {
|
|
7510
|
+
lines.push("- **\u540E\u7AEF\uFF1A** Java 21 + Spring Boot 3.x + Gradle");
|
|
7511
|
+
}
|
|
7072
7512
|
lines.push("");
|
|
7073
7513
|
lines.push("## \u5FEB\u901F\u5F00\u59CB", "");
|
|
7074
7514
|
if (ctx.frontend) {
|
|
@@ -7078,7 +7518,13 @@ function generateReadme(ctx) {
|
|
|
7078
7518
|
lines.push("pnpm start");
|
|
7079
7519
|
lines.push("```", "");
|
|
7080
7520
|
}
|
|
7081
|
-
if (
|
|
7521
|
+
if (hasNodeBackend) {
|
|
7522
|
+
lines.push("### \u540E\u7AEF", "");
|
|
7523
|
+
lines.push("```bash");
|
|
7524
|
+
lines.push("pnpm install");
|
|
7525
|
+
lines.push("pnpm start:dev");
|
|
7526
|
+
lines.push("```", "");
|
|
7527
|
+
} else if (ctx.backend) {
|
|
7082
7528
|
lines.push("### \u540E\u7AEF", "");
|
|
7083
7529
|
lines.push("```bash");
|
|
7084
7530
|
lines.push("./gradlew build");
|
|
@@ -7087,7 +7533,13 @@ function generateReadme(ctx) {
|
|
|
7087
7533
|
}
|
|
7088
7534
|
lines.push("## \u9879\u76EE\u7ED3\u6784", "");
|
|
7089
7535
|
lines.push("```");
|
|
7090
|
-
if (ctx.frontend &&
|
|
7536
|
+
if (ctx.frontend && hasNodeBackend) {
|
|
7537
|
+
lines.push("\u251C\u2500\u2500 src/ # NestJS + Angular");
|
|
7538
|
+
lines.push("\u251C\u2500\u2500 angular.json # Angular \u914D\u7F6E");
|
|
7539
|
+
lines.push("\u251C\u2500\u2500 nest-cli.json # NestJS \u914D\u7F6E");
|
|
7540
|
+
lines.push("\u251C\u2500\u2500 tsconfig.json");
|
|
7541
|
+
lines.push("\u2514\u2500\u2500 package.json");
|
|
7542
|
+
} else if (ctx.frontend && ctx.backend) {
|
|
7091
7543
|
lines.push("\u251C\u2500\u2500 src/main/web/ # Angular \u524D\u7AEF");
|
|
7092
7544
|
lines.push("\u251C\u2500\u2500 src/main/java/ # Java \u540E\u7AEF");
|
|
7093
7545
|
lines.push("\u251C\u2500\u2500 src/main/resources/ # \u914D\u7F6E");
|
|
@@ -7096,6 +7548,11 @@ function generateReadme(ctx) {
|
|
|
7096
7548
|
} else if (ctx.frontend) {
|
|
7097
7549
|
lines.push("\u251C\u2500\u2500 src/main/web/ # Angular \u524D\u7AEF");
|
|
7098
7550
|
lines.push("\u2514\u2500\u2500 angular.json # Angular \u914D\u7F6E");
|
|
7551
|
+
} else if (hasNodeBackend) {
|
|
7552
|
+
lines.push("\u251C\u2500\u2500 src/ # NestJS \u540E\u7AEF");
|
|
7553
|
+
lines.push("\u251C\u2500\u2500 nest-cli.json # NestJS \u914D\u7F6E");
|
|
7554
|
+
lines.push("\u251C\u2500\u2500 tsconfig.json");
|
|
7555
|
+
lines.push("\u2514\u2500\u2500 package.json");
|
|
7099
7556
|
} else if (ctx.backend) {
|
|
7100
7557
|
lines.push("\u251C\u2500\u2500 src/main/java/ # Java \u540E\u7AEF");
|
|
7101
7558
|
lines.push("\u2514\u2500\u2500 build.gradle.kts # Gradle \u6784\u5EFA");
|
|
@@ -7127,10 +7584,10 @@ function writeEnvFile(baseDir, content) {
|
|
|
7127
7584
|
fs2.writeFileSync(envPath, content, "utf-8");
|
|
7128
7585
|
}
|
|
7129
7586
|
}
|
|
7130
|
-
function printProjectTree(projectDir, hasFrontend,
|
|
7587
|
+
function printProjectTree(projectDir, hasFrontend, hasJavaBackend, hasNodeBackend = false) {
|
|
7131
7588
|
console.log("\u76EE\u5F55\u7ED3\u6784:");
|
|
7132
7589
|
console.log(` ${path2.basename(projectDir)}/`);
|
|
7133
|
-
if (hasFrontend &&
|
|
7590
|
+
if (hasFrontend && hasJavaBackend) {
|
|
7134
7591
|
console.log(" \u251C\u2500\u2500 src/");
|
|
7135
7592
|
console.log(" \u2502 \u251C\u2500\u2500 main/");
|
|
7136
7593
|
console.log(" \u2502 \u2502 \u251C\u2500\u2500 web/ # Angular \u524D\u7AEF");
|
|
@@ -7142,11 +7599,25 @@ function printProjectTree(projectDir, hasFrontend, hasBackend) {
|
|
|
7142
7599
|
console.log(" \u251C\u2500\u2500 build.gradle.kts");
|
|
7143
7600
|
console.log(" \u251C\u2500\u2500 angular.json");
|
|
7144
7601
|
console.log(" \u2514\u2500\u2500 package.json");
|
|
7602
|
+
} else if (hasFrontend && hasNodeBackend) {
|
|
7603
|
+
console.log(" \u251C\u2500\u2500 src/");
|
|
7604
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.controller.ts");
|
|
7605
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.module.ts");
|
|
7606
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.service.ts");
|
|
7607
|
+
console.log(" \u2502 \u251C\u2500\u2500 main.ts");
|
|
7608
|
+
console.log(" \u2502 \u251C\u2500\u2500 prisma/ # Prisma ORM");
|
|
7609
|
+
console.log(" \u2502 \u2514\u2500\u2500 agent/ # Claude Agent SDK");
|
|
7610
|
+
console.log(" \u251C\u2500\u2500 prisma/");
|
|
7611
|
+
console.log(" \u2502 \u2514\u2500\u2500 schema.prisma");
|
|
7612
|
+
console.log(" \u251C\u2500\u2500 nest-cli.json");
|
|
7613
|
+
console.log(" \u251C\u2500\u2500 tsconfig.json");
|
|
7614
|
+
console.log(" \u251C\u2500\u2500 angular.json");
|
|
7615
|
+
console.log(" \u2514\u2500\u2500 package.json");
|
|
7145
7616
|
} else if (hasFrontend) {
|
|
7146
7617
|
console.log(" \u251C\u2500\u2500 src/main/web/ # Angular \u524D\u7AEF");
|
|
7147
7618
|
console.log(" \u251C\u2500\u2500 angular.json");
|
|
7148
7619
|
console.log(" \u2514\u2500\u2500 package.json");
|
|
7149
|
-
} else if (
|
|
7620
|
+
} else if (hasJavaBackend) {
|
|
7150
7621
|
console.log(" \u251C\u2500\u2500 src/");
|
|
7151
7622
|
console.log(" \u2502 \u251C\u2500\u2500 main/java/");
|
|
7152
7623
|
console.log(" \u2502 \u251C\u2500\u2500 main/resources/");
|
|
@@ -7154,6 +7625,19 @@ function printProjectTree(projectDir, hasFrontend, hasBackend) {
|
|
|
7154
7625
|
console.log(" \u2502 \u2514\u2500\u2500 test/resources/");
|
|
7155
7626
|
console.log(" \u251C\u2500\u2500 build.gradle.kts");
|
|
7156
7627
|
console.log(" \u2514\u2500\u2500 settings.gradle.kts");
|
|
7628
|
+
} else if (hasNodeBackend) {
|
|
7629
|
+
console.log(" \u251C\u2500\u2500 src/");
|
|
7630
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.controller.ts");
|
|
7631
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.module.ts");
|
|
7632
|
+
console.log(" \u2502 \u251C\u2500\u2500 app.service.ts");
|
|
7633
|
+
console.log(" \u2502 \u251C\u2500\u2500 main.ts");
|
|
7634
|
+
console.log(" \u2502 \u251C\u2500\u2500 prisma/ # Prisma ORM");
|
|
7635
|
+
console.log(" \u2502 \u2514\u2500\u2500 agent/ # Claude Agent SDK");
|
|
7636
|
+
console.log(" \u251C\u2500\u2500 prisma/");
|
|
7637
|
+
console.log(" \u2502 \u2514\u2500\u2500 schema.prisma");
|
|
7638
|
+
console.log(" \u251C\u2500\u2500 nest-cli.json");
|
|
7639
|
+
console.log(" \u251C\u2500\u2500 tsconfig.json");
|
|
7640
|
+
console.log(" \u2514\u2500\u2500 package.json");
|
|
7157
7641
|
}
|
|
7158
7642
|
}
|
|
7159
7643
|
|