@deepstorm/cli 0.11.0 → 0.11.1
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/README.md +8 -8
- package/dist/build-registry.js +11 -5
- package/dist/cli.js +839 -585
- package/dist/mcp/code-hosting/github.json +14 -1
- package/dist/mcp/docs-reference/context7.json +1 -10
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
- package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
- package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
- package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
- package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
- package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
- package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
- package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
- package/dist/skills/atoll-ops/SKILL.md +4 -0
- package/dist/skills/reef-commit/SKILL.md +9 -5
- package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
- package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
- package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
- package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
- package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
- package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
- package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
- package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
- package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
- package/dist/skills/reef-harden/EXAMPLES.md +12 -10
- package/dist/skills/reef-harden/SKILL.md +6 -0
- package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
- package/dist/skills/reef-pr/SKILL.md +7 -0
- package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
- package/dist/skills/reef-scope/SKILL.md +6 -6
- package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
- package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
- package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
- package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
- package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
- package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
- package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
- package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
- package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
- package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
- package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
- package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
- package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
- package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
- package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
- package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
- package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
- package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
- package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
- package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
- package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
- package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
- package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
- package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
- package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
- package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
- package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
- package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
- package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
- package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
- package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
- package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
- package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
- package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
- package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
- package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
- package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
- package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
- package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
- package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
- package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
- package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
- package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
- package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
- package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
- package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
- package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
- package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
- package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
- package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
- package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
- package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
- package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
- package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
- package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
- package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
- package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
- package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
- package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
- package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
- package/dist/skills/reef-testcase/SKILL.md +19 -19
- package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
- package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
- package/dist/skills/sweep-explore/SKILL.md +129 -100
- package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
- package/dist/skills/sweep-init/SKILL.md +4 -0
- package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
- package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
- package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
- package/dist/skills/sweep-record/SKILL.md +38 -15
- package/dist/skills/sweep-run/SKILL.md +59 -50
- package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
- package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
- package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
- package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
- package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
- package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
- package/dist/skills/tide-discuss/references/checklists.md +32 -32
- package/dist/skills/tide-discuss/references/data-format.md +85 -77
- package/dist/skills/tide-discuss/references/prd-template.md +21 -19
- package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
- package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
- package/package.json +4 -3
package/dist/cli.js
CHANGED
|
@@ -5931,9 +5931,7 @@ var RegistryReader = class {
|
|
|
5931
5931
|
}
|
|
5932
5932
|
/** 按 configKey + configValue 匹配 skill,返回 skill ID 列表 */
|
|
5933
5933
|
findSkillIds(configKey, configValue) {
|
|
5934
|
-
return Object.entries(this.registry.skills).filter(
|
|
5935
|
-
([, s]) => s.configKey === configKey && s.configValue === configValue
|
|
5936
|
-
).map(([id]) => id);
|
|
5934
|
+
return Object.entries(this.registry.skills).filter(([, s]) => s.configKey === configKey && s.configValue === configValue).map(([id]) => id);
|
|
5937
5935
|
}
|
|
5938
5936
|
/** 获取所有工具名称列表 */
|
|
5939
5937
|
getTools() {
|
|
@@ -5953,9 +5951,7 @@ var RegistryReader = class {
|
|
|
5953
5951
|
}
|
|
5954
5952
|
/** 获取指定工具的所有 skill */
|
|
5955
5953
|
getToolSkills(toolName) {
|
|
5956
|
-
return Object.values(this.registry.skills).filter(
|
|
5957
|
-
(s) => s.tool === toolName
|
|
5958
|
-
);
|
|
5954
|
+
return Object.values(this.registry.skills).filter((s) => s.tool === toolName);
|
|
5959
5955
|
}
|
|
5960
5956
|
/** 获取指定工具的 agent 文件名列表 */
|
|
5961
5957
|
getToolAgents(toolName) {
|
|
@@ -6001,10 +5997,7 @@ function deepMerge(target, source) {
|
|
|
6001
5997
|
const val = source[key];
|
|
6002
5998
|
const existing = result[key];
|
|
6003
5999
|
if (isPlainObject(existing) && isPlainObject(val)) {
|
|
6004
|
-
result[key] = deepMerge(
|
|
6005
|
-
existing,
|
|
6006
|
-
val
|
|
6007
|
-
);
|
|
6000
|
+
result[key] = deepMerge(existing, val);
|
|
6008
6001
|
} else {
|
|
6009
6002
|
result[key] = val;
|
|
6010
6003
|
}
|
|
@@ -6232,7 +6225,10 @@ function initContextMap(targetDir, opts) {
|
|
|
6232
6225
|
ensureDir2(deepstormDir);
|
|
6233
6226
|
const backendLang = opts.backend || "none";
|
|
6234
6227
|
const frontendFramework = opts.frontend || "none";
|
|
6235
|
-
const content = CONTEXT_MD_TEMPLATE.replace("{backend.language}", backendLang).replace(
|
|
6228
|
+
const content = CONTEXT_MD_TEMPLATE.replace("{backend.language}", backendLang).replace(
|
|
6229
|
+
"{frontend.framework}",
|
|
6230
|
+
frontendFramework
|
|
6231
|
+
);
|
|
6236
6232
|
fs2.writeFileSync(contextPath, content, "utf-8");
|
|
6237
6233
|
console.log("\u2714 \u5DF2\u521B\u5EFA .deepstorm/context.md \u9879\u76EE\u4E0A\u4E0B\u6587\u5730\u56FE");
|
|
6238
6234
|
}
|
|
@@ -6242,10 +6238,7 @@ function initClaudeMd(targetDir, opts) {
|
|
|
6242
6238
|
if (fs2.existsSync(claudeMdPath)) return;
|
|
6243
6239
|
ensureDir2(claudeDir);
|
|
6244
6240
|
const projectName = opts.projectName || "unknown";
|
|
6245
|
-
const lines = [
|
|
6246
|
-
`# ${projectName}`,
|
|
6247
|
-
""
|
|
6248
|
-
];
|
|
6241
|
+
const lines = [`# ${projectName}`, ""];
|
|
6249
6242
|
const techLines = [];
|
|
6250
6243
|
if (opts.frontend) {
|
|
6251
6244
|
techLines.push(`- **\u524D\u7AEF**\uFF1A${opts.frontend}`);
|
|
@@ -6342,7 +6335,6 @@ async function promptContinueSetup(targetDir, projectName, registry2) {
|
|
|
6342
6335
|
if (!registry2) return;
|
|
6343
6336
|
if (!registry2.tools || Object.keys(registry2.tools).length === 0) return;
|
|
6344
6337
|
const { confirm: confirm6, isCancel: isCancel8, outro: outro2 } = await import("@clack/prompts");
|
|
6345
|
-
const projectPath = path2.join(targetDir, projectName);
|
|
6346
6338
|
const shouldContinue = await confirm6({
|
|
6347
6339
|
message: `\u662F\u5426\u7EE7\u7EED\u5B89\u88C5 DeepStorm \u5F00\u53D1\u73AF\u5883\uFF08skills + MCP \u670D\u52A1\uFF09\uFF1F`,
|
|
6348
6340
|
initialValue: true
|
|
@@ -6568,7 +6560,6 @@ async function runInit(baseDir, opts) {
|
|
|
6568
6560
|
const hasFrontend = opts.frontend === "angular";
|
|
6569
6561
|
const hasJavaBackend = opts.backend === "java";
|
|
6570
6562
|
const hasNodeBackend = opts.backend === "nodejs";
|
|
6571
|
-
const hasBackend = hasJavaBackend || hasNodeBackend;
|
|
6572
6563
|
try {
|
|
6573
6564
|
const isMonorepo = hasFrontend && hasNodeBackend;
|
|
6574
6565
|
if (isMonorepo) {
|
|
@@ -6618,89 +6609,130 @@ function renderAngularTemplate(projectDir, ctx, subPkg = false) {
|
|
|
6618
6609
|
const hasPrimeng = ctx.uiLib === "primeng";
|
|
6619
6610
|
const hasTailwind = ctx.cssFramework === "tailwind";
|
|
6620
6611
|
const webRoot = subPkg ? "src" : "src/main/web";
|
|
6621
|
-
writeTemplate(
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6612
|
+
writeTemplate(
|
|
6613
|
+
projectDir,
|
|
6614
|
+
"angular.json",
|
|
6615
|
+
JSON.stringify(
|
|
6616
|
+
{
|
|
6617
|
+
$schema: "./node_modules/@angular/cli/lib/config/schema.json",
|
|
6618
|
+
version: 1,
|
|
6619
|
+
newProjectRoot: "projects",
|
|
6620
|
+
projects: {
|
|
6621
|
+
[ctx.packageName]: {
|
|
6622
|
+
projectType: "application",
|
|
6623
|
+
root: "",
|
|
6624
|
+
sourceRoot: webRoot,
|
|
6625
|
+
prefix: "app",
|
|
6626
|
+
architect: {
|
|
6627
|
+
build: {
|
|
6628
|
+
builder: "@angular-devkit/build-angular:application",
|
|
6629
|
+
options: {
|
|
6630
|
+
outputPath: "build",
|
|
6631
|
+
index: `${webRoot}/index.html`,
|
|
6632
|
+
browser: `${webRoot}/main.ts`,
|
|
6633
|
+
polyfills: ["zone.js"],
|
|
6634
|
+
tsConfig: "tsconfig.app.json",
|
|
6635
|
+
assets: [{ glob: "**/*", input: "public" }],
|
|
6636
|
+
styles: getAngularStyles(hasPrimeng, webRoot),
|
|
6637
|
+
scripts: []
|
|
6638
|
+
},
|
|
6639
|
+
configurations: {
|
|
6640
|
+
production: { budgets: [], outputHashing: "all" },
|
|
6641
|
+
development: { optimization: false, extractLicenses: false, sourceMap: true }
|
|
6642
|
+
},
|
|
6643
|
+
defaultConfiguration: "production"
|
|
6644
|
+
},
|
|
6645
|
+
serve: {
|
|
6646
|
+
builder: "@angular-devkit/build-angular:dev-server",
|
|
6647
|
+
configurations: {
|
|
6648
|
+
production: { buildTarget: `${ctx.packageName}:build:production` },
|
|
6649
|
+
development: { buildTarget: `${ctx.packageName}:build:development` }
|
|
6650
|
+
},
|
|
6651
|
+
defaultConfiguration: "development",
|
|
6652
|
+
options: { proxyConfig: "proxy.conf.json" }
|
|
6653
|
+
},
|
|
6654
|
+
test: {
|
|
6655
|
+
builder: "@angular-devkit/build-angular:karma",
|
|
6656
|
+
options: {
|
|
6657
|
+
polyfills: ["zone.js", "zone.js/testing"],
|
|
6658
|
+
tsConfig: "tsconfig.spec.json",
|
|
6659
|
+
assets: [{ glob: "**/*", input: "public" }],
|
|
6660
|
+
styles: getAngularStyles(hasPrimeng, webRoot),
|
|
6661
|
+
scripts: []
|
|
6662
|
+
}
|
|
6663
|
+
}
|
|
6664
|
+
}
|
|
6659
6665
|
}
|
|
6660
6666
|
}
|
|
6661
|
-
}
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6667
|
+
},
|
|
6668
|
+
null,
|
|
6669
|
+
2
|
|
6670
|
+
)
|
|
6671
|
+
);
|
|
6672
|
+
writeTemplate(
|
|
6673
|
+
projectDir,
|
|
6674
|
+
"tsconfig.json",
|
|
6675
|
+
JSON.stringify(
|
|
6676
|
+
{
|
|
6677
|
+
compileOnSave: false,
|
|
6678
|
+
compilerOptions: {
|
|
6679
|
+
baseUrl: "./",
|
|
6680
|
+
outDir: "./dist",
|
|
6681
|
+
forceConsistentCasingInFileNames: true,
|
|
6682
|
+
strict: true,
|
|
6683
|
+
noImplicitOverride: true,
|
|
6684
|
+
noPropertyAccessFromIndexSignature: true,
|
|
6685
|
+
noImplicitReturns: true,
|
|
6686
|
+
noFallthroughCasesInSwitch: true,
|
|
6687
|
+
sourceMap: true,
|
|
6688
|
+
declaration: false,
|
|
6689
|
+
downlevelIteration: true,
|
|
6690
|
+
experimentalDecorators: true,
|
|
6691
|
+
moduleResolution: "bundler",
|
|
6692
|
+
importHelpers: true,
|
|
6693
|
+
target: "ES2022",
|
|
6694
|
+
module: "ES2022",
|
|
6695
|
+
lib: ["ES2022", "dom"],
|
|
6696
|
+
skipLibCheck: true
|
|
6697
|
+
},
|
|
6698
|
+
angularCompilerOptions: {
|
|
6699
|
+
enableI18nLegacyMessageIdFormat: false,
|
|
6700
|
+
strictInjectionParameters: true,
|
|
6701
|
+
strictInputAccessModifiers: true,
|
|
6702
|
+
strictTemplates: true
|
|
6703
|
+
}
|
|
6704
|
+
},
|
|
6705
|
+
null,
|
|
6706
|
+
2
|
|
6707
|
+
)
|
|
6708
|
+
);
|
|
6709
|
+
writeTemplate(
|
|
6710
|
+
projectDir,
|
|
6711
|
+
"tsconfig.app.json",
|
|
6712
|
+
JSON.stringify(
|
|
6713
|
+
{
|
|
6714
|
+
extends: "./tsconfig.json",
|
|
6715
|
+
compilerOptions: { outDir: "./out-tsc/app", types: [] },
|
|
6716
|
+
files: [`${webRoot}/main.ts`],
|
|
6717
|
+
include: ["src/**/*.d.ts"]
|
|
6718
|
+
},
|
|
6719
|
+
null,
|
|
6720
|
+
2
|
|
6721
|
+
)
|
|
6722
|
+
);
|
|
6723
|
+
writeTemplate(
|
|
6724
|
+
projectDir,
|
|
6725
|
+
"tsconfig.spec.json",
|
|
6726
|
+
JSON.stringify(
|
|
6727
|
+
{
|
|
6728
|
+
extends: "./tsconfig.json",
|
|
6729
|
+
compilerOptions: { outDir: "./out-tsc/spec", types: ["jasmine"] },
|
|
6730
|
+
include: ["src/**/*.spec.ts", "src/**/*.d.ts"]
|
|
6731
|
+
},
|
|
6732
|
+
null,
|
|
6733
|
+
2
|
|
6734
|
+
)
|
|
6735
|
+
);
|
|
6704
6736
|
const pkgDeps = {
|
|
6705
6737
|
"@angular/animations": "^21.0.0",
|
|
6706
6738
|
"@angular/common": "^21.0.0",
|
|
@@ -6709,45 +6741,64 @@ function renderAngularTemplate(projectDir, ctx, subPkg = false) {
|
|
|
6709
6741
|
"@angular/forms": "^21.0.0",
|
|
6710
6742
|
"@angular/platform-browser": "^21.0.0",
|
|
6711
6743
|
"@angular/router": "^21.0.0",
|
|
6712
|
-
|
|
6713
|
-
|
|
6744
|
+
rxjs: "~7.8.0",
|
|
6745
|
+
tslib: "^2.3.0",
|
|
6714
6746
|
"zone.js": "~0.15.0"
|
|
6715
6747
|
};
|
|
6716
6748
|
const devDeps = {
|
|
6717
6749
|
"@angular-devkit/build-angular": "^21.0.0",
|
|
6718
6750
|
"@angular/cli": "^21.0.0",
|
|
6719
6751
|
"@angular/compiler-cli": "^21.0.0",
|
|
6720
|
-
|
|
6752
|
+
typescript: "~5.7.0"
|
|
6721
6753
|
};
|
|
6722
6754
|
if (hasPrimeng) {
|
|
6723
6755
|
pkgDeps["primeng"] = "^21.0.0";
|
|
6724
6756
|
pkgDeps["@primeng/themes"] = "^21.0.0";
|
|
6725
6757
|
pkgDeps["@primeuix/themes"] = "^2.0.0";
|
|
6726
6758
|
}
|
|
6727
|
-
writeTemplate(
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6759
|
+
writeTemplate(
|
|
6760
|
+
projectDir,
|
|
6761
|
+
"package.json",
|
|
6762
|
+
JSON.stringify(
|
|
6763
|
+
{
|
|
6764
|
+
name: ctx.packageName,
|
|
6765
|
+
version: "1.0.0-dev",
|
|
6766
|
+
private: true,
|
|
6767
|
+
packageManager: "pnpm@10.0.0",
|
|
6768
|
+
scripts: {
|
|
6769
|
+
ng: "ng",
|
|
6770
|
+
start: "ng serve",
|
|
6771
|
+
build: "ng build",
|
|
6772
|
+
watch: "ng build --watch --configuration development",
|
|
6773
|
+
test: "ng test",
|
|
6774
|
+
lint: "ng lint",
|
|
6775
|
+
typecheck: "tsc --build --noEmit"
|
|
6776
|
+
},
|
|
6777
|
+
dependencies: pkgDeps,
|
|
6778
|
+
devDependencies: devDeps
|
|
6779
|
+
},
|
|
6780
|
+
null,
|
|
6781
|
+
2
|
|
6782
|
+
)
|
|
6783
|
+
);
|
|
6784
|
+
writeTemplate(
|
|
6785
|
+
projectDir,
|
|
6786
|
+
"proxy.conf.json",
|
|
6787
|
+
JSON.stringify(
|
|
6788
|
+
{
|
|
6789
|
+
"/api": {
|
|
6790
|
+
target: "http://localhost:8080",
|
|
6791
|
+
secure: false
|
|
6792
|
+
}
|
|
6793
|
+
},
|
|
6794
|
+
null,
|
|
6795
|
+
2
|
|
6796
|
+
)
|
|
6797
|
+
);
|
|
6798
|
+
writeTemplate(
|
|
6799
|
+
projectDir,
|
|
6800
|
+
"eslint.config.mjs",
|
|
6801
|
+
`import globals from "globals";
|
|
6751
6802
|
import pluginJs from "@eslint/js";
|
|
6752
6803
|
import tseslint from "typescript-eslint";
|
|
6753
6804
|
|
|
@@ -6757,10 +6808,14 @@ export default [
|
|
|
6757
6808
|
pluginJs.configs.recommended,
|
|
6758
6809
|
...tseslint.configs.recommended,
|
|
6759
6810
|
];
|
|
6760
|
-
`
|
|
6811
|
+
`
|
|
6812
|
+
);
|
|
6761
6813
|
ensureDir2(path2.join(projectDir, "public"));
|
|
6762
6814
|
ensureDir2(path2.join(projectDir, webRoot, "app"));
|
|
6763
|
-
writeTemplate(
|
|
6815
|
+
writeTemplate(
|
|
6816
|
+
projectDir,
|
|
6817
|
+
`${webRoot}/index.html`,
|
|
6818
|
+
`<!doctype html>
|
|
6764
6819
|
<html lang="zh-CN">
|
|
6765
6820
|
<head>
|
|
6766
6821
|
<meta charset="utf-8">
|
|
@@ -6773,20 +6828,28 @@ export default [
|
|
|
6773
6828
|
<app-root></app-root>
|
|
6774
6829
|
</body>
|
|
6775
6830
|
</html>
|
|
6776
|
-
`
|
|
6777
|
-
|
|
6831
|
+
`
|
|
6832
|
+
);
|
|
6833
|
+
writeTemplate(
|
|
6834
|
+
projectDir,
|
|
6835
|
+
`${webRoot}/main.ts`,
|
|
6836
|
+
`import { bootstrapApplication } from '@angular/platform-browser';
|
|
6778
6837
|
import { appConfig } from './app/app.config';
|
|
6779
6838
|
import { App } from './app/app';
|
|
6780
6839
|
|
|
6781
6840
|
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
|
|
6782
|
-
`
|
|
6841
|
+
`
|
|
6842
|
+
);
|
|
6783
6843
|
const stylesContent = hasTailwind ? `@import "tailwindcss";
|
|
6784
6844
|
|
|
6785
6845
|
/* \u5168\u5C40\u6837\u5F0F */
|
|
6786
6846
|
` : `/* \u5168\u5C40\u6837\u5F0F */
|
|
6787
6847
|
`;
|
|
6788
6848
|
writeTemplate(projectDir, `${webRoot}/styles.css`, stylesContent);
|
|
6789
|
-
writeTemplate(
|
|
6849
|
+
writeTemplate(
|
|
6850
|
+
projectDir,
|
|
6851
|
+
`${webRoot}/app/app.ts`,
|
|
6852
|
+
`import { Component } from '@angular/core';
|
|
6790
6853
|
import { RouterOutlet } from '@angular/router';
|
|
6791
6854
|
|
|
6792
6855
|
@Component({
|
|
@@ -6796,8 +6859,12 @@ import { RouterOutlet } from '@angular/router';
|
|
|
6796
6859
|
template: \`<router-outlet></router-outlet>\`,
|
|
6797
6860
|
})
|
|
6798
6861
|
export class App {}
|
|
6799
|
-
`
|
|
6800
|
-
|
|
6862
|
+
`
|
|
6863
|
+
);
|
|
6864
|
+
writeTemplate(
|
|
6865
|
+
projectDir,
|
|
6866
|
+
`${webRoot}/app/app.config.ts`,
|
|
6867
|
+
`import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
|
6801
6868
|
import { provideRouter } from '@angular/router';
|
|
6802
6869
|
import { routes } from './app.routes';
|
|
6803
6870
|
|
|
@@ -6807,15 +6874,28 @@ export const appConfig: ApplicationConfig = {
|
|
|
6807
6874
|
provideRouter(routes),
|
|
6808
6875
|
],
|
|
6809
6876
|
};
|
|
6810
|
-
`
|
|
6811
|
-
|
|
6877
|
+
`
|
|
6878
|
+
);
|
|
6879
|
+
writeTemplate(
|
|
6880
|
+
projectDir,
|
|
6881
|
+
`${webRoot}/app/app.routes.ts`,
|
|
6882
|
+
`import { Routes } from '@angular/router';
|
|
6812
6883
|
|
|
6813
6884
|
export const routes: Routes = [];
|
|
6814
|
-
`
|
|
6885
|
+
`
|
|
6886
|
+
);
|
|
6815
6887
|
if (hasTailwind) {
|
|
6816
|
-
writeTemplate(
|
|
6817
|
-
|
|
6818
|
-
|
|
6888
|
+
writeTemplate(
|
|
6889
|
+
projectDir,
|
|
6890
|
+
"postcss.config.json",
|
|
6891
|
+
JSON.stringify(
|
|
6892
|
+
{
|
|
6893
|
+
plugins: { "@tailwindcss/postcss": {} }
|
|
6894
|
+
},
|
|
6895
|
+
null,
|
|
6896
|
+
2
|
|
6897
|
+
)
|
|
6898
|
+
);
|
|
6819
6899
|
}
|
|
6820
6900
|
}
|
|
6821
6901
|
function getAngularStyles(hasPrimeng, webRoot) {
|
|
@@ -6827,40 +6907,56 @@ function getAngularStyles(hasPrimeng, webRoot) {
|
|
|
6827
6907
|
return styles;
|
|
6828
6908
|
}
|
|
6829
6909
|
function renderMonorepoRoot(projectDir, ctx) {
|
|
6830
|
-
writeTemplate(
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6910
|
+
writeTemplate(
|
|
6911
|
+
projectDir,
|
|
6912
|
+
"package.json",
|
|
6913
|
+
JSON.stringify(
|
|
6914
|
+
{
|
|
6915
|
+
name: ctx.packageName,
|
|
6916
|
+
version: "0.1.0",
|
|
6917
|
+
private: true,
|
|
6918
|
+
description: "",
|
|
6919
|
+
scripts: {
|
|
6920
|
+
dev: "pnpm --filter server dev & pnpm --filter client dev",
|
|
6921
|
+
build: "pnpm --filter server build",
|
|
6922
|
+
lint: "pnpm --filter server lint",
|
|
6923
|
+
format: "pnpm --filter server format",
|
|
6924
|
+
test: "pnpm --filter server test"
|
|
6925
|
+
}
|
|
6926
|
+
},
|
|
6927
|
+
null,
|
|
6928
|
+
2
|
|
6929
|
+
)
|
|
6930
|
+
);
|
|
6931
|
+
writeTemplate(
|
|
6932
|
+
projectDir,
|
|
6933
|
+
"pnpm-workspace.yaml",
|
|
6934
|
+
`packages:
|
|
6844
6935
|
- "server"
|
|
6845
6936
|
- "client"
|
|
6846
|
-
`
|
|
6937
|
+
`
|
|
6938
|
+
);
|
|
6847
6939
|
}
|
|
6848
6940
|
function renderJavaTemplate(projectDir, ctx) {
|
|
6849
6941
|
const hasOrm = ctx.orm === "hibernate";
|
|
6850
6942
|
const hasLiquibase = ctx.migration === "liquibase";
|
|
6851
6943
|
const hasSpringAi = ctx.ai === "spring-ai";
|
|
6852
|
-
writeTemplate(
|
|
6853
|
-
|
|
6854
|
-
|
|
6944
|
+
writeTemplate(
|
|
6945
|
+
projectDir,
|
|
6946
|
+
"settings.gradle.kts",
|
|
6947
|
+
`rootProject.name = "${ctx.packageName}"
|
|
6948
|
+
`
|
|
6949
|
+
);
|
|
6950
|
+
writeTemplate(
|
|
6951
|
+
projectDir,
|
|
6952
|
+
"gradle.properties",
|
|
6953
|
+
`# Gradle JVM \u53C2\u6570
|
|
6855
6954
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
6856
6955
|
# \u5E76\u884C\u6784\u5EFA
|
|
6857
6956
|
org.gradle.parallel=true
|
|
6858
|
-
`
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
"org.springframework.boot",
|
|
6862
|
-
"io.spring.dependency-management"
|
|
6863
|
-
];
|
|
6957
|
+
`
|
|
6958
|
+
);
|
|
6959
|
+
const plugins = ["java", "org.springframework.boot", "io.spring.dependency-management"];
|
|
6864
6960
|
const gradleDeps = [
|
|
6865
6961
|
'implementation("org.springframework.boot:spring-boot-starter-web")',
|
|
6866
6962
|
'implementation("org.springframework.boot:spring-boot-starter-validation")',
|
|
@@ -6877,7 +6973,10 @@ org.gradle.parallel=true
|
|
|
6877
6973
|
gradleDeps.push('implementation("org.springframework.ai:spring-ai-openai-spring-boot-starter")');
|
|
6878
6974
|
}
|
|
6879
6975
|
const reposExtra = hasSpringAi ? '\n maven { url = uri("https://repo.spring.io/milestone") }' : "";
|
|
6880
|
-
writeTemplate(
|
|
6976
|
+
writeTemplate(
|
|
6977
|
+
projectDir,
|
|
6978
|
+
"build.gradle.kts",
|
|
6979
|
+
`plugins {
|
|
6881
6980
|
${plugins.map((p7) => `id("${p7}") version "3.4.0"`).join("\n ")}${hasLiquibase ? `
|
|
6882
6981
|
id("org.liquibase.gradle") version "2.2.2"` : ""}
|
|
6883
6982
|
}
|
|
@@ -6906,11 +7005,15 @@ dependencies {
|
|
|
6906
7005
|
tasks.withType<Test> {
|
|
6907
7006
|
useJUnitPlatform()
|
|
6908
7007
|
}
|
|
6909
|
-
`
|
|
7008
|
+
`
|
|
7009
|
+
);
|
|
6910
7010
|
const appPackage = ctx.groupId.replace(/[.-]/g, ".");
|
|
6911
7011
|
const appDir = `src/main/java/${appPackage.replace(/\./g, "/")}`;
|
|
6912
7012
|
ensureDir2(path2.join(projectDir, appDir));
|
|
6913
|
-
writeTemplate(
|
|
7013
|
+
writeTemplate(
|
|
7014
|
+
projectDir,
|
|
7015
|
+
`${appDir}/Application.java`,
|
|
7016
|
+
`package ${appPackage};
|
|
6914
7017
|
|
|
6915
7018
|
import org.springframework.boot.SpringApplication;
|
|
6916
7019
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
@@ -6922,10 +7025,14 @@ public class Application {
|
|
|
6922
7025
|
SpringApplication.run(Application.class, args);
|
|
6923
7026
|
}
|
|
6924
7027
|
}
|
|
6925
|
-
`
|
|
7028
|
+
`
|
|
7029
|
+
);
|
|
6926
7030
|
const controllerDir = `${appDir}/controller`;
|
|
6927
7031
|
ensureDir2(path2.join(projectDir, controllerDir));
|
|
6928
|
-
writeTemplate(
|
|
7032
|
+
writeTemplate(
|
|
7033
|
+
projectDir,
|
|
7034
|
+
`${controllerDir}/HealthController.java`,
|
|
7035
|
+
`package ${appPackage}.controller;
|
|
6929
7036
|
|
|
6930
7037
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
6931
7038
|
import org.springframework.web.bind.annotation.RestController;
|
|
@@ -6938,7 +7045,8 @@ public class HealthController {
|
|
|
6938
7045
|
return "OK";
|
|
6939
7046
|
}
|
|
6940
7047
|
}
|
|
6941
|
-
`
|
|
7048
|
+
`
|
|
7049
|
+
);
|
|
6942
7050
|
const serviceDir = `${appDir}/service`;
|
|
6943
7051
|
ensureDir2(path2.join(projectDir, serviceDir));
|
|
6944
7052
|
if (hasOrm) {
|
|
@@ -6946,7 +7054,10 @@ public class HealthController {
|
|
|
6946
7054
|
ensureDir2(path2.join(projectDir, repositoryDir));
|
|
6947
7055
|
const entityDir = `${appDir}/entity`;
|
|
6948
7056
|
ensureDir2(path2.join(projectDir, entityDir));
|
|
6949
|
-
writeTemplate(
|
|
7057
|
+
writeTemplate(
|
|
7058
|
+
projectDir,
|
|
7059
|
+
`${entityDir}/BaseEntity.java`,
|
|
7060
|
+
`package ${appPackage}.entity;
|
|
6950
7061
|
|
|
6951
7062
|
import jakarta.persistence.GeneratedValue;
|
|
6952
7063
|
import jakarta.persistence.GenerationType;
|
|
@@ -6971,7 +7082,8 @@ public abstract class BaseEntity {
|
|
|
6971
7082
|
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
|
6972
7083
|
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
|
6973
7084
|
}
|
|
6974
|
-
`
|
|
7085
|
+
`
|
|
7086
|
+
);
|
|
6975
7087
|
}
|
|
6976
7088
|
ensureDir2(path2.join(projectDir, "src/main/resources"));
|
|
6977
7089
|
const datasourceConfig = hasOrm ? `
|
|
@@ -6993,19 +7105,26 @@ spring:
|
|
|
6993
7105
|
liquibase:
|
|
6994
7106
|
change-log: classpath:db/changelog/db.changelog-master.xml
|
|
6995
7107
|
` : "";
|
|
6996
|
-
writeTemplate(
|
|
7108
|
+
writeTemplate(
|
|
7109
|
+
projectDir,
|
|
7110
|
+
"src/main/resources/application.yml",
|
|
7111
|
+
`server:
|
|
6997
7112
|
port: 8080
|
|
6998
7113
|
${datasourceConfig}${liquibaseConfig}
|
|
6999
7114
|
logging:
|
|
7000
7115
|
level:
|
|
7001
7116
|
root: INFO
|
|
7002
7117
|
${ctx.packageName}: DEBUG
|
|
7003
|
-
`
|
|
7118
|
+
`
|
|
7119
|
+
);
|
|
7004
7120
|
if (hasLiquibase) {
|
|
7005
7121
|
const now = /* @__PURE__ */ new Date();
|
|
7006
7122
|
const ts = now.toISOString().replace(/\D/g, "").slice(0, 12);
|
|
7007
7123
|
ensureDir2(path2.join(projectDir, "src/main/resources/db/changelog"));
|
|
7008
|
-
writeTemplate(
|
|
7124
|
+
writeTemplate(
|
|
7125
|
+
projectDir,
|
|
7126
|
+
"src/main/resources/db/changelog/db.changelog-master.xml",
|
|
7127
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
7009
7128
|
<databaseChangeLog
|
|
7010
7129
|
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
|
7011
7130
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
@@ -7018,12 +7137,16 @@ logging:
|
|
|
7018
7137
|
</createTable>
|
|
7019
7138
|
</changeSet>
|
|
7020
7139
|
</databaseChangeLog>
|
|
7021
|
-
`
|
|
7140
|
+
`
|
|
7141
|
+
);
|
|
7022
7142
|
}
|
|
7023
7143
|
const testDir = `src/test/java/${appPackage.replace(/\./g, "/")}`;
|
|
7024
7144
|
ensureDir2(path2.join(projectDir, testDir));
|
|
7025
7145
|
ensureDir2(path2.join(projectDir, "src/test/resources"));
|
|
7026
|
-
writeTemplate(
|
|
7146
|
+
writeTemplate(
|
|
7147
|
+
projectDir,
|
|
7148
|
+
`${testDir}/ApplicationTests.java`,
|
|
7149
|
+
`package ${appPackage};
|
|
7027
7150
|
|
|
7028
7151
|
import org.junit.jupiter.api.Test;
|
|
7029
7152
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
@@ -7035,19 +7158,31 @@ class ApplicationTests {
|
|
|
7035
7158
|
void contextLoads() {
|
|
7036
7159
|
}
|
|
7037
7160
|
}
|
|
7038
|
-
`
|
|
7039
|
-
|
|
7040
|
-
|
|
7161
|
+
`
|
|
7162
|
+
);
|
|
7163
|
+
writeTemplate(
|
|
7164
|
+
projectDir,
|
|
7165
|
+
"src/test/resources/junit-platform.properties",
|
|
7166
|
+
`junit.jupiter.testinstance.lifecycle.default = per_class
|
|
7167
|
+
`
|
|
7168
|
+
);
|
|
7041
7169
|
ensureDir2(path2.join(projectDir, "gradle/wrapper"));
|
|
7042
|
-
writeTemplate(
|
|
7170
|
+
writeTemplate(
|
|
7171
|
+
projectDir,
|
|
7172
|
+
"gradle/wrapper/gradle-wrapper.properties",
|
|
7173
|
+
`distributionBase=GRADLE_USER_HOME
|
|
7043
7174
|
distributionPath=wrapper/dists
|
|
7044
7175
|
distributionUrl=https\\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
|
7045
7176
|
networkTimeout=10000
|
|
7046
7177
|
validateDistributionUrl=true
|
|
7047
7178
|
zipStoreBase=GRADLE_USER_HOME
|
|
7048
7179
|
zipStorePath=wrapper/dists
|
|
7049
|
-
`
|
|
7050
|
-
|
|
7180
|
+
`
|
|
7181
|
+
);
|
|
7182
|
+
writeTemplate(
|
|
7183
|
+
projectDir,
|
|
7184
|
+
"gradlew",
|
|
7185
|
+
`#!/bin/sh
|
|
7051
7186
|
|
|
7052
7187
|
#
|
|
7053
7188
|
# Gradle start up script for POSIX generated by Gradle.
|
|
@@ -7105,8 +7240,12 @@ else
|
|
|
7105
7240
|
fi
|
|
7106
7241
|
|
|
7107
7242
|
exec "$JAVACMD" $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
7108
|
-
`
|
|
7109
|
-
|
|
7243
|
+
`
|
|
7244
|
+
);
|
|
7245
|
+
writeTemplate(
|
|
7246
|
+
projectDir,
|
|
7247
|
+
"gradlew.bat",
|
|
7248
|
+
`@rem
|
|
7110
7249
|
@rem Gradle startup script for Windows
|
|
7111
7250
|
@rem
|
|
7112
7251
|
@if "%DEBUG%"=="" @echo off
|
|
@@ -7119,7 +7258,8 @@ set CLASSPATH=%APP_HOME%/gradle/wrapper/gradle-wrapper.jar
|
|
|
7119
7258
|
"%JAVA_HOME%/bin/java.exe" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
7120
7259
|
:end
|
|
7121
7260
|
@endlocal & exit /b %ERRORLEVEL%
|
|
7122
|
-
`
|
|
7261
|
+
`
|
|
7262
|
+
);
|
|
7123
7263
|
}
|
|
7124
7264
|
function renderNestJSTemplate(projectDir, ctx, opts) {
|
|
7125
7265
|
const hasPrisma = opts.nodejsOrm === "prisma";
|
|
@@ -7163,127 +7303,159 @@ function renderNestJSTemplate(projectDir, ctx, opts) {
|
|
|
7163
7303
|
if (hasAgentSdk) {
|
|
7164
7304
|
pkgDeps["@anthropic-ai/sdk"] = "^0.40.0";
|
|
7165
7305
|
}
|
|
7166
|
-
writeTemplate(
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7306
|
+
writeTemplate(
|
|
7307
|
+
projectDir,
|
|
7308
|
+
"package.json",
|
|
7309
|
+
JSON.stringify(
|
|
7310
|
+
{
|
|
7311
|
+
name: ctx.packageName,
|
|
7312
|
+
version: "0.1.0",
|
|
7313
|
+
description: "",
|
|
7314
|
+
private: true,
|
|
7315
|
+
scripts: {
|
|
7316
|
+
build: "nest build",
|
|
7317
|
+
format: 'prettier --write "src/**/*.ts"',
|
|
7318
|
+
start: "nest start",
|
|
7319
|
+
"start:dev": "nest start --watch",
|
|
7320
|
+
"start:prod": "node dist/main",
|
|
7321
|
+
lint: 'eslint "{src,test}/**/*.ts" --fix',
|
|
7322
|
+
test: "jest",
|
|
7323
|
+
"test:watch": "jest --watch",
|
|
7324
|
+
"test:cov": "jest --coverage",
|
|
7325
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
7326
|
+
},
|
|
7327
|
+
dependencies: pkgDeps,
|
|
7328
|
+
devDependencies: devDeps,
|
|
7329
|
+
jest: {
|
|
7330
|
+
moduleFileExtensions: ["js", "json", "ts"],
|
|
7331
|
+
rootDir: "src",
|
|
7332
|
+
testRegex: ".*\\.spec\\.ts$",
|
|
7333
|
+
transform: { "^.+\\.(t|j)s$": "ts-jest" },
|
|
7334
|
+
collectCoverageFrom: ["**/*.(t|j)s"],
|
|
7335
|
+
coverageDirectory: "../coverage",
|
|
7336
|
+
testEnvironment: "node"
|
|
7337
|
+
}
|
|
7338
|
+
},
|
|
7339
|
+
null,
|
|
7340
|
+
2
|
|
7341
|
+
)
|
|
7342
|
+
);
|
|
7343
|
+
writeTemplate(
|
|
7344
|
+
projectDir,
|
|
7345
|
+
"tsconfig.json",
|
|
7346
|
+
JSON.stringify(
|
|
7347
|
+
{
|
|
7348
|
+
compilerOptions: {
|
|
7349
|
+
module: "commonjs",
|
|
7350
|
+
declaration: true,
|
|
7351
|
+
removeComments: true,
|
|
7352
|
+
emitDecoratorMetadata: true,
|
|
7353
|
+
experimentalDecorators: true,
|
|
7354
|
+
allowSyntheticDefaultImports: true,
|
|
7355
|
+
target: "ES2023",
|
|
7356
|
+
sourceMap: true,
|
|
7357
|
+
outDir: "./dist",
|
|
7358
|
+
baseUrl: "./",
|
|
7359
|
+
incremental: true,
|
|
7360
|
+
skipLibCheck: true,
|
|
7361
|
+
strict: true,
|
|
7362
|
+
strictNullChecks: true,
|
|
7363
|
+
noImplicitAny: true,
|
|
7364
|
+
strictBindCallApply: true,
|
|
7365
|
+
forceConsistentCasingInFileNames: true,
|
|
7366
|
+
noFallthroughCasesInSwitch: true,
|
|
7367
|
+
esModuleInterop: true,
|
|
7368
|
+
resolveJsonModule: true
|
|
7369
|
+
}
|
|
7370
|
+
},
|
|
7371
|
+
null,
|
|
7372
|
+
2
|
|
7373
|
+
)
|
|
7374
|
+
);
|
|
7375
|
+
writeTemplate(
|
|
7376
|
+
projectDir,
|
|
7377
|
+
"nest-cli.json",
|
|
7378
|
+
JSON.stringify(
|
|
7379
|
+
{
|
|
7380
|
+
$schema: "https://json.schemastore.org/nest-cli",
|
|
7381
|
+
collection: "@nestjs/schematics",
|
|
7382
|
+
sourceRoot: "src",
|
|
7383
|
+
compilerOptions: { deleteOutDir: true }
|
|
7384
|
+
},
|
|
7385
|
+
null,
|
|
7386
|
+
2
|
|
7387
|
+
)
|
|
7388
|
+
);
|
|
7389
|
+
writeTemplate(
|
|
7390
|
+
projectDir,
|
|
7391
|
+
".prettierrc",
|
|
7392
|
+
JSON.stringify(
|
|
7393
|
+
{
|
|
7394
|
+
singleQuote: true,
|
|
7395
|
+
trailingComma: "all",
|
|
7396
|
+
tabWidth: 2,
|
|
7397
|
+
semi: true,
|
|
7398
|
+
printWidth: 120
|
|
7399
|
+
},
|
|
7400
|
+
null,
|
|
7401
|
+
2
|
|
7402
|
+
)
|
|
7403
|
+
);
|
|
7232
7404
|
ensureDir2(path2.join(projectDir, "src"));
|
|
7233
|
-
writeTemplate(
|
|
7234
|
-
|
|
7235
|
-
"
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
"
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
"
|
|
7267
|
-
"
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7405
|
+
writeTemplate(
|
|
7406
|
+
projectDir,
|
|
7407
|
+
"src/main.ts",
|
|
7408
|
+
[
|
|
7409
|
+
"import { NestFactory } from '@nestjs/core';",
|
|
7410
|
+
"import { ValidationPipe, Logger } from '@nestjs/common';",
|
|
7411
|
+
"import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';",
|
|
7412
|
+
"import { AppModule } from './app.module';",
|
|
7413
|
+
"",
|
|
7414
|
+
"async function bootstrap() {",
|
|
7415
|
+
" const app = await NestFactory.create(AppModule);",
|
|
7416
|
+
" const logger = new Logger('Bootstrap');",
|
|
7417
|
+
"",
|
|
7418
|
+
" app.setGlobalPrefix('api/v1');",
|
|
7419
|
+
"",
|
|
7420
|
+
" app.useGlobalPipes(",
|
|
7421
|
+
" new ValidationPipe({",
|
|
7422
|
+
" whitelist: true,",
|
|
7423
|
+
" forbidNonWhitelisted: true,",
|
|
7424
|
+
" transform: true,",
|
|
7425
|
+
" }),",
|
|
7426
|
+
" );",
|
|
7427
|
+
"",
|
|
7428
|
+
" const config = new DocumentBuilder()",
|
|
7429
|
+
` .setTitle('${ctx.projectName}')`,
|
|
7430
|
+
" .setDescription('API documentation')",
|
|
7431
|
+
" .setVersion('1.0')",
|
|
7432
|
+
" .addBearerAuth()",
|
|
7433
|
+
" .build();",
|
|
7434
|
+
" const document = SwaggerModule.createDocument(app, config);",
|
|
7435
|
+
" SwaggerModule.setup('api/docs', app, document);",
|
|
7436
|
+
"",
|
|
7437
|
+
" app.enableCors({",
|
|
7438
|
+
" origin: process.env.CORS_ORIGIN || '*',",
|
|
7439
|
+
" methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',",
|
|
7440
|
+
" credentials: true,",
|
|
7441
|
+
" });",
|
|
7442
|
+
"",
|
|
7443
|
+
" const port = process.env.PORT || 3000;",
|
|
7444
|
+
" await app.listen(port);",
|
|
7445
|
+
" logger.log(`Application running on http://localhost:${port}`);",
|
|
7446
|
+
" logger.log(`Swagger docs at http://localhost:${port}/api/docs`);",
|
|
7447
|
+
"}",
|
|
7448
|
+
"bootstrap();",
|
|
7449
|
+
""
|
|
7450
|
+
].join("\n")
|
|
7451
|
+
);
|
|
7276
7452
|
const appModuleContent = [
|
|
7277
7453
|
"import { Module } from '@nestjs/common';",
|
|
7278
7454
|
"import { ConfigModule } from '@nestjs/config';",
|
|
7279
7455
|
"import { AppController } from './app.controller';",
|
|
7280
7456
|
"import { AppService } from './app.service';"
|
|
7281
7457
|
];
|
|
7282
|
-
const appModuleImports = [
|
|
7283
|
-
" ConfigModule.forRoot({",
|
|
7284
|
-
" isGlobal: true,",
|
|
7285
|
-
" }),"
|
|
7286
|
-
];
|
|
7458
|
+
const appModuleImports = [" ConfigModule.forRoot({", " isGlobal: true,", " }),"];
|
|
7287
7459
|
if (hasPrisma) {
|
|
7288
7460
|
appModuleContent.push("import { PrismaModule } from './prisma/prisma.module';");
|
|
7289
7461
|
appModuleImports.push(" PrismaModule,");
|
|
@@ -7305,188 +7477,223 @@ function renderNestJSTemplate(projectDir, ctx, opts) {
|
|
|
7305
7477
|
appModuleContent.push("})");
|
|
7306
7478
|
appModuleContent.push("export class AppModule {}");
|
|
7307
7479
|
writeTemplate(projectDir, "src/app.module.ts", appModuleContent.join("\n"));
|
|
7308
|
-
writeTemplate(
|
|
7309
|
-
|
|
7310
|
-
"
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
"export class AppController {",
|
|
7316
|
-
" constructor(private readonly appService: AppService) {}",
|
|
7317
|
-
"",
|
|
7318
|
-
" @Get()",
|
|
7319
|
-
" @ApiOperation({ summary: '\u5065\u5EB7\u68C0\u67E5' })",
|
|
7320
|
-
" getHello(): string {",
|
|
7321
|
-
" return this.appService.getHello();",
|
|
7322
|
-
" }",
|
|
7323
|
-
"}",
|
|
7324
|
-
""
|
|
7325
|
-
].join("\n"));
|
|
7326
|
-
writeTemplate(projectDir, "src/app.service.ts", [
|
|
7327
|
-
"import { Injectable } from '@nestjs/common';",
|
|
7328
|
-
"",
|
|
7329
|
-
"@Injectable()",
|
|
7330
|
-
"export class AppService {",
|
|
7331
|
-
" getHello(): string {",
|
|
7332
|
-
` return 'Hello from ${ctx.projectName}!';`,
|
|
7333
|
-
" }",
|
|
7334
|
-
"}",
|
|
7335
|
-
""
|
|
7336
|
-
].join("\n"));
|
|
7337
|
-
if (hasPrisma) {
|
|
7338
|
-
ensureDir2(path2.join(projectDir, "prisma"));
|
|
7339
|
-
writeTemplate(projectDir, "prisma/schema.prisma", [
|
|
7340
|
-
"generator client {",
|
|
7341
|
-
' provider = "prisma-client-js"',
|
|
7342
|
-
"}",
|
|
7480
|
+
writeTemplate(
|
|
7481
|
+
projectDir,
|
|
7482
|
+
"src/app.controller.ts",
|
|
7483
|
+
[
|
|
7484
|
+
"import { Controller, Get } from '@nestjs/common';",
|
|
7485
|
+
"import { ApiTags, ApiOperation } from '@nestjs/swagger';",
|
|
7486
|
+
"import { AppService } from './app.service';",
|
|
7343
7487
|
"",
|
|
7344
|
-
"
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
"}",
|
|
7488
|
+
"@ApiTags('Health')",
|
|
7489
|
+
"@Controller()",
|
|
7490
|
+
"export class AppController {",
|
|
7491
|
+
" constructor(private readonly appService: AppService) {}",
|
|
7348
7492
|
"",
|
|
7349
|
-
"
|
|
7350
|
-
"
|
|
7351
|
-
"
|
|
7352
|
-
"
|
|
7353
|
-
"
|
|
7354
|
-
" active Boolean @default(true)",
|
|
7355
|
-
" createdAt DateTime @default(now())",
|
|
7356
|
-
" updatedAt DateTime @updatedAt",
|
|
7357
|
-
"",
|
|
7358
|
-
' @@map("users")',
|
|
7493
|
+
" @Get()",
|
|
7494
|
+
" @ApiOperation({ summary: '\u5065\u5EB7\u68C0\u67E5' })",
|
|
7495
|
+
" getHello(): string {",
|
|
7496
|
+
" return this.appService.getHello();",
|
|
7497
|
+
" }",
|
|
7359
7498
|
"}",
|
|
7360
7499
|
""
|
|
7361
|
-
].join("\n")
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
"@
|
|
7368
|
-
"@Module({",
|
|
7369
|
-
" providers: [PrismaService],",
|
|
7370
|
-
" exports: [PrismaService],",
|
|
7371
|
-
"})",
|
|
7372
|
-
"export class PrismaModule {}",
|
|
7373
|
-
""
|
|
7374
|
-
].join("\n"));
|
|
7375
|
-
writeTemplate(projectDir, "src/prisma/prisma.service.ts", [
|
|
7376
|
-
"import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';",
|
|
7377
|
-
"import { PrismaClient } from '@prisma/client';",
|
|
7500
|
+
].join("\n")
|
|
7501
|
+
);
|
|
7502
|
+
writeTemplate(
|
|
7503
|
+
projectDir,
|
|
7504
|
+
"src/app.service.ts",
|
|
7505
|
+
[
|
|
7506
|
+
"import { Injectable } from '@nestjs/common';",
|
|
7378
7507
|
"",
|
|
7379
7508
|
"@Injectable()",
|
|
7380
|
-
"export class
|
|
7381
|
-
"
|
|
7382
|
-
|
|
7383
|
-
" async onModuleInit() {",
|
|
7384
|
-
" await this.$connect();",
|
|
7385
|
-
" this.logger.log('Database connected');",
|
|
7386
|
-
" }",
|
|
7387
|
-
"",
|
|
7388
|
-
" async onModuleDestroy() {",
|
|
7389
|
-
" await this.$disconnect();",
|
|
7390
|
-
" this.logger.log('Database disconnected');",
|
|
7509
|
+
"export class AppService {",
|
|
7510
|
+
" getHello(): string {",
|
|
7511
|
+
` return 'Hello from ${ctx.projectName}!';`,
|
|
7391
7512
|
" }",
|
|
7392
7513
|
"}",
|
|
7393
7514
|
""
|
|
7394
|
-
].join("\n")
|
|
7515
|
+
].join("\n")
|
|
7516
|
+
);
|
|
7517
|
+
if (hasPrisma) {
|
|
7518
|
+
ensureDir2(path2.join(projectDir, "prisma"));
|
|
7519
|
+
writeTemplate(
|
|
7520
|
+
projectDir,
|
|
7521
|
+
"prisma/schema.prisma",
|
|
7522
|
+
[
|
|
7523
|
+
"generator client {",
|
|
7524
|
+
' provider = "prisma-client-js"',
|
|
7525
|
+
"}",
|
|
7526
|
+
"",
|
|
7527
|
+
"datasource db {",
|
|
7528
|
+
' provider = "postgresql"',
|
|
7529
|
+
' url = env("DATABASE_URL")',
|
|
7530
|
+
"}",
|
|
7531
|
+
"",
|
|
7532
|
+
"/// \u7528\u6237",
|
|
7533
|
+
"model User {",
|
|
7534
|
+
" id Int @id @default(autoincrement())",
|
|
7535
|
+
" name String",
|
|
7536
|
+
" email String @unique",
|
|
7537
|
+
" active Boolean @default(true)",
|
|
7538
|
+
" createdAt DateTime @default(now())",
|
|
7539
|
+
" updatedAt DateTime @updatedAt",
|
|
7540
|
+
"",
|
|
7541
|
+
' @@map("users")',
|
|
7542
|
+
"}",
|
|
7543
|
+
""
|
|
7544
|
+
].join("\n")
|
|
7545
|
+
);
|
|
7546
|
+
ensureDir2(path2.join(projectDir, "src/prisma"));
|
|
7547
|
+
writeTemplate(
|
|
7548
|
+
projectDir,
|
|
7549
|
+
"src/prisma/prisma.module.ts",
|
|
7550
|
+
[
|
|
7551
|
+
"import { Global, Module } from '@nestjs/common';",
|
|
7552
|
+
"import { PrismaService } from './prisma.service';",
|
|
7553
|
+
"",
|
|
7554
|
+
"@Global()",
|
|
7555
|
+
"@Module({",
|
|
7556
|
+
" providers: [PrismaService],",
|
|
7557
|
+
" exports: [PrismaService],",
|
|
7558
|
+
"})",
|
|
7559
|
+
"export class PrismaModule {}",
|
|
7560
|
+
""
|
|
7561
|
+
].join("\n")
|
|
7562
|
+
);
|
|
7563
|
+
writeTemplate(
|
|
7564
|
+
projectDir,
|
|
7565
|
+
"src/prisma/prisma.service.ts",
|
|
7566
|
+
[
|
|
7567
|
+
"import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';",
|
|
7568
|
+
"import { PrismaClient } from '@prisma/client';",
|
|
7569
|
+
"",
|
|
7570
|
+
"@Injectable()",
|
|
7571
|
+
"export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {",
|
|
7572
|
+
" private readonly logger = new Logger(PrismaService.name);",
|
|
7573
|
+
"",
|
|
7574
|
+
" async onModuleInit() {",
|
|
7575
|
+
" await this.$connect();",
|
|
7576
|
+
" this.logger.log('Database connected');",
|
|
7577
|
+
" }",
|
|
7578
|
+
"",
|
|
7579
|
+
" async onModuleDestroy() {",
|
|
7580
|
+
" await this.$disconnect();",
|
|
7581
|
+
" this.logger.log('Database disconnected');",
|
|
7582
|
+
" }",
|
|
7583
|
+
"}",
|
|
7584
|
+
""
|
|
7585
|
+
].join("\n")
|
|
7586
|
+
);
|
|
7395
7587
|
}
|
|
7396
7588
|
if (hasAgentSdk) {
|
|
7397
7589
|
ensureDir2(path2.join(projectDir, "src/agent/tools"));
|
|
7398
|
-
writeTemplate(
|
|
7399
|
-
|
|
7400
|
-
"
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
"
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
"
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
"
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
"
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
"
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7590
|
+
writeTemplate(
|
|
7591
|
+
projectDir,
|
|
7592
|
+
"src/agent/agent.module.ts",
|
|
7593
|
+
[
|
|
7594
|
+
"import { Module } from '@nestjs/common';",
|
|
7595
|
+
"import { AgentService } from './agent.service';",
|
|
7596
|
+
"",
|
|
7597
|
+
"@Module({",
|
|
7598
|
+
" providers: [AgentService],",
|
|
7599
|
+
" exports: [AgentService],",
|
|
7600
|
+
"})",
|
|
7601
|
+
"export class AgentModule {}",
|
|
7602
|
+
""
|
|
7603
|
+
].join("\n")
|
|
7604
|
+
);
|
|
7605
|
+
writeTemplate(
|
|
7606
|
+
projectDir,
|
|
7607
|
+
"src/agent/agent.service.ts",
|
|
7608
|
+
[
|
|
7609
|
+
"import { Injectable, Logger } from '@nestjs/common';",
|
|
7610
|
+
"import { ConfigService } from '@nestjs/config';",
|
|
7611
|
+
"",
|
|
7612
|
+
"/**",
|
|
7613
|
+
" * Claude Agent \u670D\u52A1",
|
|
7614
|
+
" *",
|
|
7615
|
+
" * \u5C01\u88C5 Claude Agent SDK\uFF0C\u63D0\u4F9B Agent \u4EA4\u4E92\u80FD\u529B\u3002",
|
|
7616
|
+
" * \u4F7F\u7528\u524D\u9700\u5728 .env \u4E2D\u914D\u7F6E ANTHROPIC_API_KEY\u3002",
|
|
7617
|
+
" */",
|
|
7618
|
+
"@Injectable()",
|
|
7619
|
+
"export class AgentService {",
|
|
7620
|
+
" private readonly logger = new Logger(AgentService.name);",
|
|
7621
|
+
"",
|
|
7622
|
+
" constructor(private readonly configService: ConfigService) {",
|
|
7623
|
+
" const apiKey = this.configService.get<string>('ANTHROPIC_API_KEY');",
|
|
7624
|
+
" if (!apiKey) {",
|
|
7625
|
+
" this.logger.warn('ANTHROPIC_API_KEY is not configured');",
|
|
7626
|
+
" }",
|
|
7627
|
+
" }",
|
|
7628
|
+
"",
|
|
7629
|
+
" async ask(question: string): Promise<string> {",
|
|
7630
|
+
' this.logger.debug(`Agent ask: "${question}"`);',
|
|
7631
|
+
" return 'Agent response placeholder -- configure ANTHROPIC_API_KEY to enable';",
|
|
7632
|
+
" }",
|
|
7633
|
+
"}",
|
|
7634
|
+
""
|
|
7635
|
+
].join("\n")
|
|
7636
|
+
);
|
|
7637
|
+
writeTemplate(
|
|
7638
|
+
projectDir,
|
|
7639
|
+
"src/agent/tools/example.tool.ts",
|
|
7640
|
+
[
|
|
7641
|
+
"import { Injectable, Logger } from '@nestjs/common';",
|
|
7642
|
+
"",
|
|
7643
|
+
"export interface ToolDefinition {",
|
|
7644
|
+
" name: string;",
|
|
7645
|
+
" description: string;",
|
|
7646
|
+
" input_schema: Record<string, unknown>;",
|
|
7647
|
+
" execute: (input: Record<string, unknown>) => Promise<unknown>;",
|
|
7648
|
+
"}",
|
|
7649
|
+
"",
|
|
7650
|
+
"@Injectable()",
|
|
7651
|
+
"export class ExampleTool implements ToolDefinition {",
|
|
7652
|
+
" private readonly logger = new Logger(ExampleTool.name);",
|
|
7653
|
+
"",
|
|
7654
|
+
" name = 'get_current_time';",
|
|
7655
|
+
" description = '\u83B7\u53D6\u5F53\u524D\u65E5\u671F\u548C\u65F6\u95F4';",
|
|
7656
|
+
" input_schema = {",
|
|
7657
|
+
" type: 'object',",
|
|
7658
|
+
" properties: {",
|
|
7659
|
+
" timezone: {",
|
|
7660
|
+
" type: 'string',",
|
|
7661
|
+
" description: '\u65F6\u533A\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4 UTC\uFF09',",
|
|
7662
|
+
" enum: ['UTC', 'Asia/Shanghai', 'America/New_York'],",
|
|
7663
|
+
" },",
|
|
7664
|
+
" },",
|
|
7665
|
+
" };",
|
|
7666
|
+
"",
|
|
7667
|
+
" async execute(input: Record<string, unknown>): Promise<unknown> {",
|
|
7668
|
+
" try {",
|
|
7669
|
+
" this.logger.debug(`Tool execute: get_current_time with input: ${JSON.stringify(input)}`);",
|
|
7670
|
+
" const now = new Date();",
|
|
7671
|
+
" return {",
|
|
7672
|
+
" success: true,",
|
|
7673
|
+
" data: {",
|
|
7674
|
+
" iso: now.toISOString(),",
|
|
7675
|
+
" timestamp: now.getTime(),",
|
|
7676
|
+
" },",
|
|
7677
|
+
" };",
|
|
7678
|
+
" } catch (error) {",
|
|
7679
|
+
" this.logger.error(`Tool execution failed: ${error}`);",
|
|
7680
|
+
" return {",
|
|
7681
|
+
" success: false,",
|
|
7682
|
+
" error: error instanceof Error ? error.message : 'Unknown error',",
|
|
7683
|
+
" };",
|
|
7684
|
+
" }",
|
|
7685
|
+
" }",
|
|
7686
|
+
"}",
|
|
7687
|
+
""
|
|
7688
|
+
].join("\n")
|
|
7689
|
+
);
|
|
7486
7690
|
}
|
|
7487
7691
|
}
|
|
7488
7692
|
function renderCommonFiles(projectDir, ctx, opts) {
|
|
7489
|
-
writeTemplate(
|
|
7693
|
+
writeTemplate(
|
|
7694
|
+
projectDir,
|
|
7695
|
+
".gitignore",
|
|
7696
|
+
`node_modules/
|
|
7490
7697
|
.gradle/
|
|
7491
7698
|
build/
|
|
7492
7699
|
target/
|
|
@@ -7499,10 +7706,13 @@ __pycache__/
|
|
|
7499
7706
|
.idea/
|
|
7500
7707
|
.vscode/
|
|
7501
7708
|
*.iml
|
|
7502
|
-
`
|
|
7709
|
+
`
|
|
7710
|
+
);
|
|
7503
7711
|
const hasNodeBackend = opts?.backend === "nodejs";
|
|
7504
7712
|
if (hasNodeBackend) {
|
|
7505
|
-
writeEnvFile(
|
|
7713
|
+
writeEnvFile(
|
|
7714
|
+
projectDir,
|
|
7715
|
+
`# \u6570\u636E\u5E93\u914D\u7F6E
|
|
7506
7716
|
DATABASE_URL=postgresql://user:password@localhost:5432/${ctx.packageName}
|
|
7507
7717
|
|
|
7508
7718
|
# Claude Agent SDK
|
|
@@ -7512,16 +7722,20 @@ AGENT_MODEL=claude-sonnet-5
|
|
|
7512
7722
|
# Server
|
|
7513
7723
|
PORT=3000
|
|
7514
7724
|
CORS_ORIGIN=http://localhost:4200
|
|
7515
|
-
`
|
|
7725
|
+
`
|
|
7726
|
+
);
|
|
7516
7727
|
} else {
|
|
7517
|
-
writeEnvFile(
|
|
7728
|
+
writeEnvFile(
|
|
7729
|
+
projectDir,
|
|
7730
|
+
`# \u6570\u636E\u5E93\u914D\u7F6E
|
|
7518
7731
|
DB_URL=jdbc:postgresql://localhost:5432/${ctx.packageName}
|
|
7519
7732
|
DB_USERNAME=postgres
|
|
7520
7733
|
DB_PASSWORD=change-me
|
|
7521
7734
|
|
|
7522
7735
|
# API Keys
|
|
7523
7736
|
OPENAI_API_KEY=sk-your-key-here
|
|
7524
|
-
`
|
|
7737
|
+
`
|
|
7738
|
+
);
|
|
7525
7739
|
}
|
|
7526
7740
|
const readme = generateReadme(ctx, opts);
|
|
7527
7741
|
writeTemplate(projectDir, "README.md", readme);
|
|
@@ -7743,22 +7957,22 @@ function installGrillMe(targetDir) {
|
|
|
7743
7957
|
const skillDir = path3.join(targetDir, ".claude", "skills", "grill-me");
|
|
7744
7958
|
fs3.mkdirSync(skillDir, { recursive: true });
|
|
7745
7959
|
try {
|
|
7746
|
-
(0, import_node_child_process.execSync)(
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
);
|
|
7960
|
+
(0, import_node_child_process.execSync)("curl -fsSL https://raw.githubusercontent.com/mattpocock/skills/main/grill-me/SKILL.md -o SKILL.md", {
|
|
7961
|
+
...EXEC_OPTIONS,
|
|
7962
|
+
cwd: skillDir
|
|
7963
|
+
});
|
|
7750
7964
|
console.log("\u2714 grill-me skill \u5DF2\u5B89\u88C5");
|
|
7751
7965
|
} catch {
|
|
7752
7966
|
console.log("\u26A0 grill-me \u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5 https://github.com/mattpocock/skills");
|
|
7753
7967
|
}
|
|
7754
7968
|
}
|
|
7755
|
-
function isPlaywrightInstalled(
|
|
7969
|
+
function isPlaywrightInstalled() {
|
|
7756
7970
|
const result = execSafe("npx playwright install --dry-run");
|
|
7757
7971
|
return result.success && !result.output.toLowerCase().includes("to install");
|
|
7758
7972
|
}
|
|
7759
|
-
function installPlaywright(config,
|
|
7973
|
+
function installPlaywright(config, _targetDir) {
|
|
7760
7974
|
if (config["sweep.e2eFramework"] !== "playwright") return;
|
|
7761
|
-
if (isPlaywrightInstalled(
|
|
7975
|
+
if (isPlaywrightInstalled()) {
|
|
7762
7976
|
console.log("\u2139 Playwright \u6D4F\u89C8\u5668\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5B89\u88C5");
|
|
7763
7977
|
return;
|
|
7764
7978
|
}
|
|
@@ -7867,8 +8081,8 @@ function filterExistingKeys(content, existingKeys) {
|
|
|
7867
8081
|
const lines = content.split("\n");
|
|
7868
8082
|
const result = [];
|
|
7869
8083
|
let skipUntilDecor = false;
|
|
7870
|
-
for (
|
|
7871
|
-
const trimmed =
|
|
8084
|
+
for (const line of lines) {
|
|
8085
|
+
const trimmed = line.trim();
|
|
7872
8086
|
if (trimmed.includes("=") && !trimmed.startsWith("#")) {
|
|
7873
8087
|
const key = trimmed.slice(0, trimmed.indexOf("=")).trim();
|
|
7874
8088
|
if (existingKeys.has(key)) {
|
|
@@ -7877,20 +8091,20 @@ function filterExistingKeys(content, existingKeys) {
|
|
|
7877
8091
|
}
|
|
7878
8092
|
}
|
|
7879
8093
|
if (skipUntilDecor) {
|
|
7880
|
-
if (
|
|
8094
|
+
if (line.match(/^#\s*[═━]/)) {
|
|
7881
8095
|
skipUntilDecor = false;
|
|
7882
|
-
result.push(
|
|
8096
|
+
result.push(line);
|
|
7883
8097
|
}
|
|
7884
8098
|
continue;
|
|
7885
8099
|
}
|
|
7886
|
-
result.push(
|
|
8100
|
+
result.push(line);
|
|
7887
8101
|
}
|
|
7888
8102
|
return result.join("\n").trimEnd();
|
|
7889
8103
|
}
|
|
7890
8104
|
|
|
7891
8105
|
// src/wizard/wizard-flow.ts
|
|
7892
|
-
var p4 = __toESM(require("@clack/prompts"));
|
|
7893
8106
|
var fs8 = __toESM(require("node:fs"));
|
|
8107
|
+
var p4 = __toESM(require("@clack/prompts"));
|
|
7894
8108
|
|
|
7895
8109
|
// src/wizard/tool-select.ts
|
|
7896
8110
|
var p = __toESM(require("@clack/prompts"));
|
|
@@ -8123,9 +8337,7 @@ async function renderAsSingleGroup(questions, multiselectKey, selectedTechs, con
|
|
|
8123
8337
|
const hasOptionDependsOn = opts.some((o) => o.dependsOn);
|
|
8124
8338
|
if (hasOptionDependsOn) {
|
|
8125
8339
|
groupPrompts[sub.key] = ({ results }) => {
|
|
8126
|
-
const filtered = opts.filter(
|
|
8127
|
-
(o) => !o.dependsOn || Object.values(results).includes(o.dependsOn)
|
|
8128
|
-
);
|
|
8340
|
+
const filtered = opts.filter((o) => !o.dependsOn || Object.values(results).includes(o.dependsOn));
|
|
8129
8341
|
return p3.select({
|
|
8130
8342
|
message: sub.label,
|
|
8131
8343
|
options: filtered.map((o) => ({
|
|
@@ -8220,13 +8432,7 @@ async function runToolWizard(wizard, configuredKeys) {
|
|
|
8220
8432
|
);
|
|
8221
8433
|
if (hasTabs) {
|
|
8222
8434
|
const selectedTechs = (config[question.key] || "").split(",").map((v) => v.trim()).filter(Boolean);
|
|
8223
|
-
await renderAsSingleGroup(
|
|
8224
|
-
wizard.questions,
|
|
8225
|
-
question.key,
|
|
8226
|
-
selectedTechs,
|
|
8227
|
-
config,
|
|
8228
|
-
configuredKeys
|
|
8229
|
-
);
|
|
8435
|
+
await renderAsSingleGroup(wizard.questions, question.key, selectedTechs, config, configuredKeys);
|
|
8230
8436
|
break;
|
|
8231
8437
|
}
|
|
8232
8438
|
} else if (question.dependsOn?.contains) {
|
|
@@ -8604,7 +8810,7 @@ function printMcpEnvStatus(mcpTools, installedMcpServices, examplesDir, targetDi
|
|
|
8604
8810
|
}
|
|
8605
8811
|
}
|
|
8606
8812
|
async function printGuide(options) {
|
|
8607
|
-
const { installedSkills,
|
|
8813
|
+
const { installedSkills, mcpTools, mcpEnvStubs } = options;
|
|
8608
8814
|
console.log("");
|
|
8609
8815
|
console.log(" \u2714 \u914D\u7F6E\u5DF2\u4FDD\u5B58\uFF08DeepStorm \u2192 .deepstorm/settings.json\uFF0CClaude Code \u2192 .claude/settings.json\uFF09");
|
|
8610
8816
|
if (mcpTools && mcpTools.length > 0) {
|
|
@@ -8721,9 +8927,7 @@ function renderTemplate(tmplPath, variables, outputPath) {
|
|
|
8721
8927
|
function copyVariants(sourceVariantsDir, selectedValue, targetDir, clean = false) {
|
|
8722
8928
|
const variantDir = path8.join(sourceVariantsDir, selectedValue);
|
|
8723
8929
|
if (!fs12.existsSync(variantDir)) {
|
|
8724
|
-
console.warn(
|
|
8725
|
-
`[template] \u26A0 \u53D8\u4F53\u76EE\u5F55\u4E0D\u5B58\u5728: ${variantDir}\uFF08\u76F8\u5BF9\u4E8E ${sourceVariantsDir}\uFF09\uFF0C\u8DF3\u8FC7`
|
|
8726
|
-
);
|
|
8930
|
+
console.warn(`[template] \u26A0 \u53D8\u4F53\u76EE\u5F55\u4E0D\u5B58\u5728: ${variantDir}\uFF08\u76F8\u5BF9\u4E8E ${sourceVariantsDir}\uFF09\uFF0C\u8DF3\u8FC7`);
|
|
8727
8931
|
return;
|
|
8728
8932
|
}
|
|
8729
8933
|
if (clean && fs12.existsSync(targetDir)) {
|
|
@@ -8758,10 +8962,10 @@ async function runSetup(reader, targetDir, cliDir2, options, registry2) {
|
|
|
8758
8962
|
cleanInstalled(targetDir);
|
|
8759
8963
|
console.log("\u2714 \u65E7\u5B89\u88C5\u5DF2\u6E05\u7406");
|
|
8760
8964
|
}
|
|
8761
|
-
let tools
|
|
8762
|
-
let config
|
|
8965
|
+
let tools;
|
|
8966
|
+
let config;
|
|
8763
8967
|
let selectedMcpTools = [];
|
|
8764
|
-
let templateVariables
|
|
8968
|
+
let templateVariables;
|
|
8765
8969
|
let enabledMcpJsonServers = [];
|
|
8766
8970
|
const examplesDir = path9.join(cliDir2, "env-examples");
|
|
8767
8971
|
const installedSkillIds = [];
|
|
@@ -8799,7 +9003,16 @@ async function runSetup(reader, targetDir, cliDir2, options, registry2) {
|
|
|
8799
9003
|
}
|
|
8800
9004
|
installMcpSkills(tools, reader, cliDir2, targetDir, installedSkillIds, selectedMcpTools);
|
|
8801
9005
|
for (const tool of tools) {
|
|
8802
|
-
const ids = renderToolAssets(
|
|
9006
|
+
const ids = renderToolAssets(
|
|
9007
|
+
tool,
|
|
9008
|
+
reader,
|
|
9009
|
+
cliDir2,
|
|
9010
|
+
targetDir,
|
|
9011
|
+
templateVariables,
|
|
9012
|
+
config,
|
|
9013
|
+
registry2,
|
|
9014
|
+
selectedMcpTools
|
|
9015
|
+
);
|
|
8803
9016
|
installedSkillIds.push(...ids);
|
|
8804
9017
|
}
|
|
8805
9018
|
if (shouldInstallGlobalHooks(tools, reader)) {
|
|
@@ -8832,8 +9045,8 @@ async function runSetup(reader, targetDir, cliDir2, options, registry2) {
|
|
|
8832
9045
|
deepstormConfig.installedMcpServers = [.../* @__PURE__ */ new Set([...existingMcp, ...selectedMcpTools])];
|
|
8833
9046
|
}
|
|
8834
9047
|
writeDeepStormConfig(targetDir, deepstormConfig);
|
|
8835
|
-
const frontend =
|
|
8836
|
-
const backend =
|
|
9048
|
+
const frontend = deepstormConfig.reef?.frontend?.framework ?? void 0;
|
|
9049
|
+
const backend = deepstormConfig.reef?.backend?.language ?? void 0;
|
|
8837
9050
|
initContextMap(targetDir, { frontend, backend, projectName: "" });
|
|
8838
9051
|
const claudeSettingsPath = path9.join(targetDir, ".claude", "settings.json");
|
|
8839
9052
|
if (enabledMcpJsonServers.length > 0) {
|
|
@@ -8924,11 +9137,7 @@ function renderToolAssets(tool, reader, cliDir2, targetDir, templateVariables, c
|
|
|
8924
9137
|
registry2.mcpTools ?? {}
|
|
8925
9138
|
);
|
|
8926
9139
|
ensureDir3(targetDirPath);
|
|
8927
|
-
renderTemplate(
|
|
8928
|
-
tmplPath,
|
|
8929
|
-
enrichedVars,
|
|
8930
|
-
path9.join(targetDirPath, "SKILL.md")
|
|
8931
|
-
);
|
|
9140
|
+
renderTemplate(tmplPath, enrichedVars, path9.join(targetDirPath, "SKILL.md"));
|
|
8932
9141
|
copyVariantsForConfig(variantsDir, config, targetDirPath, skill.configKey);
|
|
8933
9142
|
copyFragmentsForSkill(skillId, srcDir, config, registry2, targetDirPath);
|
|
8934
9143
|
copyReferencesForSkill(srcDir, targetDirPath);
|
|
@@ -8953,11 +9162,7 @@ function renderToolAssets(tool, reader, cliDir2, targetDir, templateVariables, c
|
|
|
8953
9162
|
const tmplSrcPath = path9.join(agentsSrcDir, agentFile.replace(/\.md$/, ".md.tmpl"));
|
|
8954
9163
|
if (fs13.existsSync(tmplSrcPath)) {
|
|
8955
9164
|
const outputName = agentFile.replace(/\.tmpl$/, "");
|
|
8956
|
-
renderTemplate(
|
|
8957
|
-
tmplSrcPath,
|
|
8958
|
-
templateVariables,
|
|
8959
|
-
path9.join(targetAgentsDir, outputName)
|
|
8960
|
-
);
|
|
9165
|
+
renderTemplate(tmplSrcPath, templateVariables, path9.join(targetAgentsDir, outputName));
|
|
8961
9166
|
}
|
|
8962
9167
|
continue;
|
|
8963
9168
|
}
|
|
@@ -8976,11 +9181,7 @@ function renderToolAssets(tool, reader, cliDir2, targetDir, templateVariables, c
|
|
|
8976
9181
|
} else {
|
|
8977
9182
|
const tmplPath = srcPath + ".tmpl";
|
|
8978
9183
|
if (fs13.existsSync(tmplPath)) {
|
|
8979
|
-
renderTemplate(
|
|
8980
|
-
tmplPath,
|
|
8981
|
-
templateVariables,
|
|
8982
|
-
path9.join(targetHooksDir, hookFile)
|
|
8983
|
-
);
|
|
9184
|
+
renderTemplate(tmplPath, templateVariables, path9.join(targetHooksDir, hookFile));
|
|
8984
9185
|
}
|
|
8985
9186
|
}
|
|
8986
9187
|
}
|
|
@@ -9081,11 +9282,7 @@ function copyFragmentsForSkill(skillId, srcDir, config, registry2, targetDir) {
|
|
|
9081
9282
|
for (const file of exampleFiles) {
|
|
9082
9283
|
if (file === ".DS_Store") continue;
|
|
9083
9284
|
ensureDir3(targetExamplesDir);
|
|
9084
|
-
fs13.cpSync(
|
|
9085
|
-
path9.join(srcExamples, file),
|
|
9086
|
-
path9.join(targetExamplesDir, `${value}-${file}`),
|
|
9087
|
-
{ force: true }
|
|
9088
|
-
);
|
|
9285
|
+
fs13.cpSync(path9.join(srcExamples, file), path9.join(targetExamplesDir, `${value}-${file}`), { force: true });
|
|
9089
9286
|
}
|
|
9090
9287
|
}
|
|
9091
9288
|
const allFiles = fs13.readdirSync(srcPath);
|
|
@@ -9305,11 +9502,7 @@ async function buildPlugin(config) {
|
|
|
9305
9502
|
}
|
|
9306
9503
|
}
|
|
9307
9504
|
if (Object.keys(mcpServers).length > 0) {
|
|
9308
|
-
fs14.writeFileSync(
|
|
9309
|
-
path10.join(outputDir, ".mcp.json"),
|
|
9310
|
-
JSON.stringify({ mcpServers }, null, 2) + "\n",
|
|
9311
|
-
"utf-8"
|
|
9312
|
-
);
|
|
9505
|
+
fs14.writeFileSync(path10.join(outputDir, ".mcp.json"), JSON.stringify({ mcpServers }, null, 2) + "\n", "utf-8");
|
|
9313
9506
|
}
|
|
9314
9507
|
}
|
|
9315
9508
|
if (selectedMcpTools.length > 0) {
|
|
@@ -9590,7 +9783,7 @@ function collectLeafPaths(props, prefix, keys) {
|
|
|
9590
9783
|
if (!props) return;
|
|
9591
9784
|
for (const [key, value] of Object.entries(props)) {
|
|
9592
9785
|
const fullPath = prefix ? `${prefix}.${key}` : key;
|
|
9593
|
-
if (value.properties
|
|
9786
|
+
if (value.properties) {
|
|
9594
9787
|
collectLeafPaths(value.properties, fullPath, keys);
|
|
9595
9788
|
} else {
|
|
9596
9789
|
keys.add(fullPath);
|
|
@@ -9656,9 +9849,7 @@ async function setConfigValue(targetDir, key, value, registry2) {
|
|
|
9656
9849
|
if (affected.length === 0) {
|
|
9657
9850
|
return;
|
|
9658
9851
|
}
|
|
9659
|
-
const assetNames = affected.map(
|
|
9660
|
-
(t) => t.replace(/\/SKILL\.md\.tmpl$/, "").replace(/\/[^/]+\.md\.tmpl$/, "")
|
|
9661
|
-
);
|
|
9852
|
+
const assetNames = affected.map((t) => t.replace(/\/SKILL\.md\.tmpl$/, "").replace(/\/[^/]+\.md\.tmpl$/, ""));
|
|
9662
9853
|
console.log("");
|
|
9663
9854
|
console.log("\u68C0\u6D4B\u5230\u914D\u7F6E\u53D8\u66F4\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\u4EE5\u4E0B\u5185\u5BB9\uFF1A");
|
|
9664
9855
|
for (const name of assetNames) {
|
|
@@ -9750,19 +9941,12 @@ function refreshConfig(cliDir2, targetDir, registry2) {
|
|
|
9750
9941
|
const targetSkillDir = path15.join(targetDotClaudeDir, "skills", skillId);
|
|
9751
9942
|
const outputPath = path15.join(targetSkillDir, "SKILL.md");
|
|
9752
9943
|
try {
|
|
9753
|
-
const enrichedVars = injectSkillCapabilities(
|
|
9754
|
-
tmplPath,
|
|
9755
|
-
{},
|
|
9756
|
-
installedMcpServers,
|
|
9757
|
-
registry2.mcpTools ?? {}
|
|
9758
|
-
);
|
|
9944
|
+
const enrichedVars = injectSkillCapabilities(tmplPath, {}, installedMcpServers, registry2.mcpTools ?? {});
|
|
9759
9945
|
fs19.mkdirSync(targetSkillDir, { recursive: true });
|
|
9760
9946
|
renderTemplate(tmplPath, enrichedVars, outputPath);
|
|
9761
9947
|
result.refreshed.push(skillId);
|
|
9762
9948
|
} catch (err) {
|
|
9763
|
-
result.errors.push(
|
|
9764
|
-
`\u5237\u65B0 skill "${skillId}" \u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
9765
|
-
);
|
|
9949
|
+
result.errors.push(`\u5237\u65B0 skill "${skillId}" \u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`);
|
|
9766
9950
|
}
|
|
9767
9951
|
}
|
|
9768
9952
|
const mcpCapabilities = buildUnifiedMcpCapabilities2(cliDir2, installedMcpServers, registry2.mcpTools ?? {});
|
|
@@ -9844,7 +10028,7 @@ function registerConfigCommand(program2, registry2) {
|
|
|
9844
10028
|
// src/commands/template-list.ts
|
|
9845
10029
|
function listTemplates(registry2, tool) {
|
|
9846
10030
|
const reader = new RegistryReader(registry2);
|
|
9847
|
-
const skills = tool ? reader.getToolSkills(tool) : Object.entries(registry2.skills).map(([id, entry]) => ({ id, ...entry }));
|
|
10031
|
+
const skills = tool ? reader.getToolSkills(tool).map((s) => ({ ...s, id: "" })) : Object.entries(registry2.skills).map(([id, entry]) => ({ id, ...entry }));
|
|
9848
10032
|
if (skills.length === 0) {
|
|
9849
10033
|
console.log("\u6CA1\u6709\u627E\u5230\u53EF\u7528\u7684\u6A21\u677F");
|
|
9850
10034
|
return;
|
|
@@ -9852,7 +10036,7 @@ function listTemplates(registry2, tool) {
|
|
|
9852
10036
|
console.log("\u53EF\u7528\u7684\u6A21\u677F:");
|
|
9853
10037
|
console.log("");
|
|
9854
10038
|
for (const skill of skills) {
|
|
9855
|
-
const id =
|
|
10039
|
+
const id = skill.id;
|
|
9856
10040
|
const toolName = skill.tool || "";
|
|
9857
10041
|
const toolLabel = toolName.charAt(0).toUpperCase() + toolName.slice(1);
|
|
9858
10042
|
const displayName = skill.name || id;
|
|
@@ -9939,10 +10123,7 @@ var fs22 = __toESM(require("node:fs"));
|
|
|
9939
10123
|
var path18 = __toESM(require("node:path"));
|
|
9940
10124
|
function getCliVersion() {
|
|
9941
10125
|
try {
|
|
9942
|
-
const paths = [
|
|
9943
|
-
path18.resolve(__dirname, "package.json"),
|
|
9944
|
-
path18.resolve(__dirname, "..", "package.json")
|
|
9945
|
-
];
|
|
10126
|
+
const paths = [path18.resolve(__dirname, "package.json"), path18.resolve(__dirname, "..", "package.json")];
|
|
9946
10127
|
for (const pkgPath of paths) {
|
|
9947
10128
|
if (fs22.existsSync(pkgPath)) {
|
|
9948
10129
|
const pkg = JSON.parse(fs22.readFileSync(pkgPath, "utf-8"));
|
|
@@ -9999,11 +10180,7 @@ function loadChecksums(targetDir) {
|
|
|
9999
10180
|
function saveChecksums(targetDir, checksums) {
|
|
10000
10181
|
const dir = path19.join(targetDir, ".claude");
|
|
10001
10182
|
ensureDir3(dir);
|
|
10002
|
-
fs23.writeFileSync(
|
|
10003
|
-
path19.join(dir, CHECKSUM_FILE),
|
|
10004
|
-
JSON.stringify(checksums, null, 2) + "\n",
|
|
10005
|
-
"utf-8"
|
|
10006
|
-
);
|
|
10183
|
+
fs23.writeFileSync(path19.join(dir, CHECKSUM_FILE), JSON.stringify(checksums, null, 2) + "\n", "utf-8");
|
|
10007
10184
|
}
|
|
10008
10185
|
function backupFile(filePath) {
|
|
10009
10186
|
try {
|
|
@@ -10261,8 +10438,10 @@ function upgradeTemplates(cliDir2, targetDir, skillIds) {
|
|
|
10261
10438
|
const count = report.syncedSkills.length;
|
|
10262
10439
|
const agentCount = report.syncedAgents.length;
|
|
10263
10440
|
const hookCount = report.syncedHooks.length;
|
|
10264
|
-
console.log(
|
|
10265
|
-
|
|
10441
|
+
console.log(
|
|
10442
|
+
`
|
|
10443
|
+
\u2714 \u540C\u6B65\u5B8C\u6210\uFF1A${count} \u4E2A skill${agentCount > 0 ? `\u3001${agentCount} \u4E2A agent` : ""}${hookCount > 0 ? `\u3001${hookCount} \u4E2A hook` : ""}`
|
|
10444
|
+
);
|
|
10266
10445
|
if (report.backedUpFiles.length > 0) {
|
|
10267
10446
|
console.log(` \u5DF2\u5907\u4EFD ${report.backedUpFiles.length} \u4E2A\u4FEE\u6539\u8FC7\u7684\u6587\u4EF6`);
|
|
10268
10447
|
}
|
|
@@ -10448,7 +10627,11 @@ function migrateOldDataSources(targetDir) {
|
|
|
10448
10627
|
}
|
|
10449
10628
|
const cleaned = remainingLines.join("\n").trimEnd();
|
|
10450
10629
|
if (cleaned === "") {
|
|
10451
|
-
fs24.writeFileSync(
|
|
10630
|
+
fs24.writeFileSync(
|
|
10631
|
+
envPath,
|
|
10632
|
+
"# \u73AF\u5883 baseURL \u914D\u7F6E\u5DF2\u8FC1\u79FB\u81F3 .deepstorm/settings.json\n# \u8BF7\u52FF\u5728\u6B64\u5904\u91CD\u590D\u5B9A\u4E49 BASE_URL_* \u914D\u7F6E\n",
|
|
10633
|
+
"utf-8"
|
|
10634
|
+
);
|
|
10452
10635
|
} else if (hasDefaultEnv || Object.keys(baseUrlVars).length > 0) {
|
|
10453
10636
|
fs24.writeFileSync(envPath, cleaned + "\n", "utf-8");
|
|
10454
10637
|
}
|
|
@@ -10510,7 +10693,7 @@ function registerPilotCommands(program2) {
|
|
|
10510
10693
|
// src/record/browser-recorder.ts
|
|
10511
10694
|
var path22 = __toESM(require("node:path"));
|
|
10512
10695
|
var fs26 = __toESM(require("node:fs"));
|
|
10513
|
-
var
|
|
10696
|
+
var import_node_child_process3 = require("node:child_process");
|
|
10514
10697
|
|
|
10515
10698
|
// src/record/recorder.ts
|
|
10516
10699
|
var path21 = __toESM(require("node:path"));
|
|
@@ -10528,8 +10711,7 @@ function dedupEvents(events) {
|
|
|
10528
10711
|
if (events.length === 0) return [];
|
|
10529
10712
|
const result = [];
|
|
10530
10713
|
const inputElements = /* @__PURE__ */ new Map();
|
|
10531
|
-
for (
|
|
10532
|
-
const current = events[i];
|
|
10714
|
+
for (const current of events) {
|
|
10533
10715
|
if (current.type === "input" || current.type === "select") {
|
|
10534
10716
|
const key = eventGroupKey(current);
|
|
10535
10717
|
const dedupKey = `${key.cssSelector}|${key.type}`;
|
|
@@ -10586,6 +10768,82 @@ function getNextSeq(datePrefix) {
|
|
|
10586
10768
|
}
|
|
10587
10769
|
|
|
10588
10770
|
// src/record/browser-recorder.ts
|
|
10771
|
+
var playwrightModule = null;
|
|
10772
|
+
async function getPlaywright() {
|
|
10773
|
+
if (!playwrightModule) {
|
|
10774
|
+
playwrightModule = await import("playwright");
|
|
10775
|
+
}
|
|
10776
|
+
return playwrightModule;
|
|
10777
|
+
}
|
|
10778
|
+
function isPlaywrightPackageInstalled() {
|
|
10779
|
+
try {
|
|
10780
|
+
require.resolve("playwright");
|
|
10781
|
+
return true;
|
|
10782
|
+
} catch {
|
|
10783
|
+
return false;
|
|
10784
|
+
}
|
|
10785
|
+
}
|
|
10786
|
+
async function ensurePlaywrightPackage() {
|
|
10787
|
+
if (isPlaywrightPackageInstalled()) return;
|
|
10788
|
+
console.log("\u{1F4E6} \u672A\u68C0\u6D4B\u5230 Playwright\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5...");
|
|
10789
|
+
const targetDir = process.cwd();
|
|
10790
|
+
try {
|
|
10791
|
+
(0, import_node_child_process3.execSync)("npm install playwright@latest --no-save", {
|
|
10792
|
+
cwd: targetDir,
|
|
10793
|
+
stdio: "inherit",
|
|
10794
|
+
env: { ...process.env, NODE_ENV: void 0 }
|
|
10795
|
+
});
|
|
10796
|
+
} catch {
|
|
10797
|
+
console.log("npm install \u5931\u8D25\uFF0C\u5C1D\u8BD5\u901A\u8FC7 npx \u5B89\u88C5...");
|
|
10798
|
+
(0, import_node_child_process3.execSync)("npx --yes playwright@latest install --dry-run", {
|
|
10799
|
+
stdio: "inherit"
|
|
10800
|
+
});
|
|
10801
|
+
}
|
|
10802
|
+
if (!isPlaywrightPackageInstalled()) {
|
|
10803
|
+
console.error("\u274C Playwright \u81EA\u52A8\u5B89\u88C5\u5931\u8D25\u3002\u8BF7\u624B\u52A8\u6267\u884C:");
|
|
10804
|
+
console.error(" npm install playwright");
|
|
10805
|
+
process.exit(1);
|
|
10806
|
+
}
|
|
10807
|
+
console.log("\u2705 Playwright \u5B89\u88C5\u6210\u529F");
|
|
10808
|
+
}
|
|
10809
|
+
async function isPlaywrightBrowserAvailable() {
|
|
10810
|
+
try {
|
|
10811
|
+
const pw = await getPlaywright();
|
|
10812
|
+
const browser = await pw.chromium.launch({ headless: true });
|
|
10813
|
+
await browser.close();
|
|
10814
|
+
return true;
|
|
10815
|
+
} catch {
|
|
10816
|
+
return false;
|
|
10817
|
+
}
|
|
10818
|
+
}
|
|
10819
|
+
async function ensurePlaywrightBrowsers() {
|
|
10820
|
+
if (await isPlaywrightBrowserAvailable()) return;
|
|
10821
|
+
console.log("\u{1F310} \u672A\u68C0\u6D4B\u5230 Playwright Chromium \u6D4F\u89C8\u5668\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5...");
|
|
10822
|
+
try {
|
|
10823
|
+
const pw = await getPlaywright();
|
|
10824
|
+
await pw.chromium.launch({ headless: true, executablePath: void 0 });
|
|
10825
|
+
} catch {
|
|
10826
|
+
try {
|
|
10827
|
+
(0, import_node_child_process3.execSync)("npx playwright install chromium", {
|
|
10828
|
+
stdio: "inherit",
|
|
10829
|
+
env: { ...process.env, PLAYWRIGHT_BROWSERS_PATH: "0" }
|
|
10830
|
+
});
|
|
10831
|
+
} catch {
|
|
10832
|
+
console.error("\u274C \u6D4F\u89C8\u5668\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\u3002\u8BF7\u624B\u52A8\u6267\u884C:");
|
|
10833
|
+
console.error(" npx playwright install chromium");
|
|
10834
|
+
console.error("");
|
|
10835
|
+
console.error(" \u6216\u6307\u5B9A\u5DF2\u5B89\u88C5\u7684\u6D4F\u89C8\u5668\u8DEF\u5F84:");
|
|
10836
|
+
console.error(" export PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/path/to/chrome");
|
|
10837
|
+
process.exit(1);
|
|
10838
|
+
}
|
|
10839
|
+
}
|
|
10840
|
+
if (await isPlaywrightBrowserAvailable()) {
|
|
10841
|
+
console.log("\u2705 \u6D4F\u89C8\u5668\u5B89\u88C5\u6210\u529F");
|
|
10842
|
+
} else {
|
|
10843
|
+
console.error("\u274C \u6D4F\u89C8\u5668\u5B89\u88C5\u540E\u4ECD\u7136\u4E0D\u53EF\u7528\uFF0C\u8BF7\u624B\u52A8\u6267\u884C: npx playwright install chromium");
|
|
10844
|
+
process.exit(1);
|
|
10845
|
+
}
|
|
10846
|
+
}
|
|
10589
10847
|
async function recordBrowserSession(url) {
|
|
10590
10848
|
let targetUrl;
|
|
10591
10849
|
try {
|
|
@@ -10593,12 +10851,11 @@ async function recordBrowserSession(url) {
|
|
|
10593
10851
|
} catch {
|
|
10594
10852
|
throw new Error(`\u65E0\u6548\u7684 URL: ${url}`);
|
|
10595
10853
|
}
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
}
|
|
10854
|
+
await ensurePlaywrightPackage();
|
|
10855
|
+
await ensurePlaywrightBrowsers();
|
|
10856
|
+
const pw = await getPlaywright();
|
|
10600
10857
|
const startTime = Date.now();
|
|
10601
|
-
const browser = await
|
|
10858
|
+
const browser = await pw.chromium.launch({ headless: false });
|
|
10602
10859
|
const context = await browser.newContext();
|
|
10603
10860
|
const page = await context.newPage();
|
|
10604
10861
|
const events = [];
|
|
@@ -10769,8 +11026,13 @@ async function recordBrowserSession(url) {
|
|
|
10769
11026
|
})();`);
|
|
10770
11027
|
console.log("\u{1F3A5} \u5F55\u5236\u4E2D... \u6309 Ctrl+D \u505C\u6B62");
|
|
10771
11028
|
const stopPromise = new Promise((resolve4) => {
|
|
10772
|
-
|
|
10773
|
-
|
|
11029
|
+
let rawModeSupported = false;
|
|
11030
|
+
try {
|
|
11031
|
+
process.stdin.setRawMode?.(true);
|
|
11032
|
+
rawModeSupported = true;
|
|
11033
|
+
} catch {
|
|
11034
|
+
console.log("\u24D8 \u5F53\u524D\u7EC8\u7AEF\u4E0D\u652F\u6301 raw mode\uFF0C\u8BF7\u5173\u95ED\u6D4F\u89C8\u5668\u7A97\u53E3\u505C\u6B62\u5F55\u5236");
|
|
11035
|
+
}
|
|
10774
11036
|
process.stdin.resume();
|
|
10775
11037
|
process.stdin.on("data", (chunk) => {
|
|
10776
11038
|
if (chunk.length === 1 && chunk[0] === 4) {
|
|
@@ -10783,7 +11045,12 @@ async function recordBrowserSession(url) {
|
|
|
10783
11045
|
resolve4();
|
|
10784
11046
|
});
|
|
10785
11047
|
function cleanup() {
|
|
10786
|
-
|
|
11048
|
+
if (rawModeSupported) {
|
|
11049
|
+
try {
|
|
11050
|
+
process.stdin.setRawMode?.(false);
|
|
11051
|
+
} catch {
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
10787
11054
|
process.stdin.pause();
|
|
10788
11055
|
}
|
|
10789
11056
|
});
|
|
@@ -10798,7 +11065,10 @@ async function recordBrowserSession(url) {
|
|
|
10798
11065
|
console.error("\n\u6D4F\u89C8\u5668\u8FDE\u63A5\u65AD\u5F00\uFF0C\u5F55\u5236\u5DF2\u7EC8\u6B62");
|
|
10799
11066
|
throw err;
|
|
10800
11067
|
} finally {
|
|
10801
|
-
|
|
11068
|
+
try {
|
|
11069
|
+
process.stdin.setRawMode?.(false);
|
|
11070
|
+
} catch {
|
|
11071
|
+
}
|
|
10802
11072
|
process.stdin.pause();
|
|
10803
11073
|
}
|
|
10804
11074
|
const duration = Date.now() - startTime;
|
|
@@ -10839,20 +11109,6 @@ async function recordBrowserSession(url) {
|
|
|
10839
11109
|
console.log(` \u6587\u4EF6\u8DEF\u5F84: ${filePath}`);
|
|
10840
11110
|
return filePath;
|
|
10841
11111
|
}
|
|
10842
|
-
async function isPlaywrightAvailable() {
|
|
10843
|
-
try {
|
|
10844
|
-
const { execSync: execSync3 } = await import("node:child_process");
|
|
10845
|
-
execSync3(
|
|
10846
|
-
"npx playwright install --dry-run 2>/dev/null || npx playwright --version 2>/dev/null",
|
|
10847
|
-
{ stdio: "ignore" }
|
|
10848
|
-
);
|
|
10849
|
-
const browser = await import_playwright.chromium.launch({ headless: true });
|
|
10850
|
-
await browser.close();
|
|
10851
|
-
return true;
|
|
10852
|
-
} catch {
|
|
10853
|
-
return false;
|
|
10854
|
-
}
|
|
10855
|
-
}
|
|
10856
11112
|
|
|
10857
11113
|
// src/commands/record.ts
|
|
10858
11114
|
function registerRecordCommand(program2) {
|
|
@@ -10930,9 +11186,7 @@ function runDoctor(targetDir) {
|
|
|
10930
11186
|
}
|
|
10931
11187
|
const skillsDir = path23.join(targetDir, ".claude", "skills");
|
|
10932
11188
|
if (fs27.existsSync(skillsDir)) {
|
|
10933
|
-
const skillDirs = fs27.readdirSync(skillsDir).filter(
|
|
10934
|
-
(n) => fs27.statSync(path23.join(skillsDir, n)).isDirectory()
|
|
10935
|
-
);
|
|
11189
|
+
const skillDirs = fs27.readdirSync(skillsDir).filter((n) => fs27.statSync(path23.join(skillsDir, n)).isDirectory());
|
|
10936
11190
|
let validCount = 0;
|
|
10937
11191
|
let invalidCount = 0;
|
|
10938
11192
|
for (const skillName of skillDirs) {
|