@deepstorm/cli 0.10.2 → 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 +1256 -634
- 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/registry.json +10 -0
- 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 +824 -0
- package/dist/skills/sweep-explore/references/explore-flow-template.md +61 -0
- 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 +358 -0
- 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 +5 -3
package/dist/cli.js
CHANGED
|
@@ -1187,13 +1187,13 @@ var require_ast = __commonJS({
|
|
|
1187
1187
|
helperExpression: function helperExpression(node) {
|
|
1188
1188
|
return node.type === "SubExpression" || (node.type === "MustacheStatement" || node.type === "BlockStatement") && !!(node.params && node.params.length || node.hash);
|
|
1189
1189
|
},
|
|
1190
|
-
scopedId: function scopedId(
|
|
1191
|
-
return /^\.|this\b/.test(
|
|
1190
|
+
scopedId: function scopedId(path26) {
|
|
1191
|
+
return /^\.|this\b/.test(path26.original);
|
|
1192
1192
|
},
|
|
1193
1193
|
// an ID is simple if it only has one part, and that part is not
|
|
1194
1194
|
// `..` or `this`.
|
|
1195
|
-
simpleId: function simpleId(
|
|
1196
|
-
return
|
|
1195
|
+
simpleId: function simpleId(path26) {
|
|
1196
|
+
return path26.parts.length === 1 && !AST.helpers.scopedId(path26) && !path26.depth;
|
|
1197
1197
|
}
|
|
1198
1198
|
}
|
|
1199
1199
|
};
|
|
@@ -2263,12 +2263,12 @@ var require_helpers2 = __commonJS({
|
|
|
2263
2263
|
loc
|
|
2264
2264
|
};
|
|
2265
2265
|
}
|
|
2266
|
-
function prepareMustache(
|
|
2266
|
+
function prepareMustache(path26, params, hash, open, strip, locInfo) {
|
|
2267
2267
|
var escapeFlag = open.charAt(3) || open.charAt(2), escaped = escapeFlag !== "{" && escapeFlag !== "&";
|
|
2268
2268
|
var decorator = /\*/.test(open);
|
|
2269
2269
|
return {
|
|
2270
2270
|
type: decorator ? "Decorator" : "MustacheStatement",
|
|
2271
|
-
path:
|
|
2271
|
+
path: path26,
|
|
2272
2272
|
params,
|
|
2273
2273
|
hash,
|
|
2274
2274
|
escaped,
|
|
@@ -2586,9 +2586,9 @@ var require_compiler = __commonJS({
|
|
|
2586
2586
|
},
|
|
2587
2587
|
DecoratorBlock: function DecoratorBlock(decorator) {
|
|
2588
2588
|
var program2 = decorator.program && this.compileProgram(decorator.program);
|
|
2589
|
-
var params = this.setupFullMustacheParams(decorator, program2, void 0),
|
|
2589
|
+
var params = this.setupFullMustacheParams(decorator, program2, void 0), path26 = decorator.path;
|
|
2590
2590
|
this.useDecorators = true;
|
|
2591
|
-
this.opcode("registerDecorator", params.length,
|
|
2591
|
+
this.opcode("registerDecorator", params.length, path26.original);
|
|
2592
2592
|
},
|
|
2593
2593
|
PartialStatement: function PartialStatement(partial) {
|
|
2594
2594
|
this.usePartial = true;
|
|
@@ -2652,46 +2652,46 @@ var require_compiler = __commonJS({
|
|
|
2652
2652
|
}
|
|
2653
2653
|
},
|
|
2654
2654
|
ambiguousSexpr: function ambiguousSexpr(sexpr, program2, inverse) {
|
|
2655
|
-
var
|
|
2656
|
-
this.opcode("getContext",
|
|
2655
|
+
var path26 = sexpr.path, name = path26.parts[0], isBlock = program2 != null || inverse != null;
|
|
2656
|
+
this.opcode("getContext", path26.depth);
|
|
2657
2657
|
this.opcode("pushProgram", program2);
|
|
2658
2658
|
this.opcode("pushProgram", inverse);
|
|
2659
|
-
|
|
2660
|
-
this.accept(
|
|
2659
|
+
path26.strict = true;
|
|
2660
|
+
this.accept(path26);
|
|
2661
2661
|
this.opcode("invokeAmbiguous", name, isBlock);
|
|
2662
2662
|
},
|
|
2663
2663
|
simpleSexpr: function simpleSexpr(sexpr) {
|
|
2664
|
-
var
|
|
2665
|
-
|
|
2666
|
-
this.accept(
|
|
2664
|
+
var path26 = sexpr.path;
|
|
2665
|
+
path26.strict = true;
|
|
2666
|
+
this.accept(path26);
|
|
2667
2667
|
this.opcode("resolvePossibleLambda");
|
|
2668
2668
|
},
|
|
2669
2669
|
helperSexpr: function helperSexpr(sexpr, program2, inverse) {
|
|
2670
|
-
var params = this.setupFullMustacheParams(sexpr, program2, inverse),
|
|
2670
|
+
var params = this.setupFullMustacheParams(sexpr, program2, inverse), path26 = sexpr.path, name = path26.parts[0];
|
|
2671
2671
|
if (this.options.knownHelpers[name]) {
|
|
2672
2672
|
this.opcode("invokeKnownHelper", params.length, name);
|
|
2673
2673
|
} else if (this.options.knownHelpersOnly) {
|
|
2674
2674
|
throw new _exception2["default"]("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
|
|
2675
2675
|
} else {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
this.accept(
|
|
2679
|
-
this.opcode("invokeHelper", params.length,
|
|
2676
|
+
path26.strict = true;
|
|
2677
|
+
path26.falsy = true;
|
|
2678
|
+
this.accept(path26);
|
|
2679
|
+
this.opcode("invokeHelper", params.length, path26.original, _ast2["default"].helpers.simpleId(path26));
|
|
2680
2680
|
}
|
|
2681
2681
|
},
|
|
2682
|
-
PathExpression: function PathExpression(
|
|
2683
|
-
this.addDepth(
|
|
2684
|
-
this.opcode("getContext",
|
|
2685
|
-
var name =
|
|
2682
|
+
PathExpression: function PathExpression(path26) {
|
|
2683
|
+
this.addDepth(path26.depth);
|
|
2684
|
+
this.opcode("getContext", path26.depth);
|
|
2685
|
+
var name = path26.parts[0], scoped = _ast2["default"].helpers.scopedId(path26), blockParamId = !path26.depth && !scoped && this.blockParamIndex(name);
|
|
2686
2686
|
if (blockParamId) {
|
|
2687
|
-
this.opcode("lookupBlockParam", blockParamId,
|
|
2687
|
+
this.opcode("lookupBlockParam", blockParamId, path26.parts);
|
|
2688
2688
|
} else if (!name) {
|
|
2689
2689
|
this.opcode("pushContext");
|
|
2690
|
-
} else if (
|
|
2690
|
+
} else if (path26.data) {
|
|
2691
2691
|
this.options.data = true;
|
|
2692
|
-
this.opcode("lookupData",
|
|
2692
|
+
this.opcode("lookupData", path26.depth, path26.parts, path26.strict);
|
|
2693
2693
|
} else {
|
|
2694
|
-
this.opcode("lookupOnContext",
|
|
2694
|
+
this.opcode("lookupOnContext", path26.parts, path26.falsy, path26.strict, scoped);
|
|
2695
2695
|
}
|
|
2696
2696
|
},
|
|
2697
2697
|
StringLiteral: function StringLiteral(string) {
|
|
@@ -3041,16 +3041,16 @@ var require_util = __commonJS({
|
|
|
3041
3041
|
}
|
|
3042
3042
|
exports2.urlGenerate = urlGenerate;
|
|
3043
3043
|
function normalize(aPath) {
|
|
3044
|
-
var
|
|
3044
|
+
var path26 = aPath;
|
|
3045
3045
|
var url = urlParse(aPath);
|
|
3046
3046
|
if (url) {
|
|
3047
3047
|
if (!url.path) {
|
|
3048
3048
|
return aPath;
|
|
3049
3049
|
}
|
|
3050
|
-
|
|
3050
|
+
path26 = url.path;
|
|
3051
3051
|
}
|
|
3052
|
-
var isAbsolute = exports2.isAbsolute(
|
|
3053
|
-
var parts =
|
|
3052
|
+
var isAbsolute = exports2.isAbsolute(path26);
|
|
3053
|
+
var parts = path26.split(/\/+/);
|
|
3054
3054
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
3055
3055
|
part = parts[i];
|
|
3056
3056
|
if (part === ".") {
|
|
@@ -3067,18 +3067,18 @@ var require_util = __commonJS({
|
|
|
3067
3067
|
}
|
|
3068
3068
|
}
|
|
3069
3069
|
}
|
|
3070
|
-
|
|
3071
|
-
if (
|
|
3072
|
-
|
|
3070
|
+
path26 = parts.join("/");
|
|
3071
|
+
if (path26 === "") {
|
|
3072
|
+
path26 = isAbsolute ? "/" : ".";
|
|
3073
3073
|
}
|
|
3074
3074
|
if (url) {
|
|
3075
|
-
url.path =
|
|
3075
|
+
url.path = path26;
|
|
3076
3076
|
return urlGenerate(url);
|
|
3077
3077
|
}
|
|
3078
|
-
return
|
|
3078
|
+
return path26;
|
|
3079
3079
|
}
|
|
3080
3080
|
exports2.normalize = normalize;
|
|
3081
|
-
function
|
|
3081
|
+
function join24(aRoot, aPath) {
|
|
3082
3082
|
if (aRoot === "") {
|
|
3083
3083
|
aRoot = ".";
|
|
3084
3084
|
}
|
|
@@ -3110,7 +3110,7 @@ var require_util = __commonJS({
|
|
|
3110
3110
|
}
|
|
3111
3111
|
return joined;
|
|
3112
3112
|
}
|
|
3113
|
-
exports2.join =
|
|
3113
|
+
exports2.join = join24;
|
|
3114
3114
|
exports2.isAbsolute = function(aPath) {
|
|
3115
3115
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
3116
3116
|
};
|
|
@@ -3283,7 +3283,7 @@ var require_util = __commonJS({
|
|
|
3283
3283
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
3284
3284
|
}
|
|
3285
3285
|
}
|
|
3286
|
-
sourceURL =
|
|
3286
|
+
sourceURL = join24(urlGenerate(parsed), sourceURL);
|
|
3287
3287
|
}
|
|
3288
3288
|
return normalize(sourceURL);
|
|
3289
3289
|
}
|
|
@@ -5858,8 +5858,8 @@ var require_printer = __commonJS({
|
|
|
5858
5858
|
return this.accept(sexpr.path) + " " + params + hash;
|
|
5859
5859
|
};
|
|
5860
5860
|
PrintVisitor.prototype.PathExpression = function(id) {
|
|
5861
|
-
var
|
|
5862
|
-
return (id.data ? "@" : "") + "PATH:" +
|
|
5861
|
+
var path26 = id.parts.join("/");
|
|
5862
|
+
return (id.data ? "@" : "") + "PATH:" + path26;
|
|
5863
5863
|
};
|
|
5864
5864
|
PrintVisitor.prototype.StringLiteral = function(string) {
|
|
5865
5865
|
return '"' + string.value + '"';
|
|
@@ -5898,8 +5898,8 @@ var require_lib = __commonJS({
|
|
|
5898
5898
|
handlebars.print = printer.print;
|
|
5899
5899
|
module2.exports = handlebars;
|
|
5900
5900
|
function extension(module3, filename) {
|
|
5901
|
-
var
|
|
5902
|
-
var templateString =
|
|
5901
|
+
var fs30 = require("fs");
|
|
5902
|
+
var templateString = fs30.readFileSync(filename, "utf8");
|
|
5903
5903
|
module3.exports = handlebars.compile(templateString);
|
|
5904
5904
|
}
|
|
5905
5905
|
if (typeof require !== "undefined" && require.extensions) {
|
|
@@ -5911,8 +5911,8 @@ var require_lib = __commonJS({
|
|
|
5911
5911
|
|
|
5912
5912
|
// src/index.ts
|
|
5913
5913
|
var import_commander = require("commander");
|
|
5914
|
-
var
|
|
5915
|
-
var
|
|
5914
|
+
var fs29 = __toESM(require("node:fs"));
|
|
5915
|
+
var path25 = __toESM(require("node:path"));
|
|
5916
5916
|
|
|
5917
5917
|
// src/commands/setup.ts
|
|
5918
5918
|
var path9 = __toESM(require("node:path"));
|
|
@@ -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
|
}
|
|
@@ -10507,13 +10690,453 @@ function registerPilotCommands(program2) {
|
|
|
10507
10690
|
(0, import_pilot.registerPilotCommands)(program2);
|
|
10508
10691
|
}
|
|
10509
10692
|
|
|
10510
|
-
// src/
|
|
10511
|
-
var
|
|
10693
|
+
// src/record/browser-recorder.ts
|
|
10694
|
+
var path22 = __toESM(require("node:path"));
|
|
10695
|
+
var fs26 = __toESM(require("node:fs"));
|
|
10696
|
+
var import_node_child_process3 = require("node:child_process");
|
|
10697
|
+
|
|
10698
|
+
// src/record/recorder.ts
|
|
10512
10699
|
var path21 = __toESM(require("node:path"));
|
|
10700
|
+
var fs25 = __toESM(require("node:fs"));
|
|
10701
|
+
function filterNoiseEvents(events) {
|
|
10702
|
+
const noiseTypes = [];
|
|
10703
|
+
const noiseSet = new Set(noiseTypes);
|
|
10704
|
+
return events.filter((e) => !noiseSet.has(e.type));
|
|
10705
|
+
}
|
|
10706
|
+
function eventGroupKey(e) {
|
|
10707
|
+
const selector = e.data?.cssSelector || "";
|
|
10708
|
+
return { cssSelector: selector, type: e.type };
|
|
10709
|
+
}
|
|
10710
|
+
function dedupEvents(events) {
|
|
10711
|
+
if (events.length === 0) return [];
|
|
10712
|
+
const result = [];
|
|
10713
|
+
const inputElements = /* @__PURE__ */ new Map();
|
|
10714
|
+
for (const current of events) {
|
|
10715
|
+
if (current.type === "input" || current.type === "select") {
|
|
10716
|
+
const key = eventGroupKey(current);
|
|
10717
|
+
const dedupKey = `${key.cssSelector}|${key.type}`;
|
|
10718
|
+
inputElements.set(dedupKey, current);
|
|
10719
|
+
continue;
|
|
10720
|
+
}
|
|
10721
|
+
if (current.type === "click") {
|
|
10722
|
+
const lastEvent = result.length > 0 ? result[result.length - 1] : null;
|
|
10723
|
+
if (lastEvent && lastEvent.type === "click") {
|
|
10724
|
+
const currentKey = eventGroupKey(current);
|
|
10725
|
+
const lastKey = eventGroupKey(lastEvent);
|
|
10726
|
+
const sameElement = currentKey.cssSelector === lastKey.cssSelector;
|
|
10727
|
+
const withinThreshold = current.ts - lastEvent.ts <= 500;
|
|
10728
|
+
if (sameElement && withinThreshold) {
|
|
10729
|
+
continue;
|
|
10730
|
+
}
|
|
10731
|
+
}
|
|
10732
|
+
}
|
|
10733
|
+
result.push(current);
|
|
10734
|
+
}
|
|
10735
|
+
inputElements.forEach((event) => {
|
|
10736
|
+
result.push(event);
|
|
10737
|
+
});
|
|
10738
|
+
result.sort((a, b) => a.ts - b.ts);
|
|
10739
|
+
return result;
|
|
10740
|
+
}
|
|
10741
|
+
function serializeRecording(data) {
|
|
10742
|
+
return JSON.stringify(data, null, 2);
|
|
10743
|
+
}
|
|
10744
|
+
function buildRecordingFileName(seq = 1) {
|
|
10745
|
+
const now = /* @__PURE__ */ new Date();
|
|
10746
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
10747
|
+
const dateTime = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
10748
|
+
const seqStr = seq > 1 ? `-${seq}` : "";
|
|
10749
|
+
return `${dateTime}${seqStr}.recording.json`;
|
|
10750
|
+
}
|
|
10751
|
+
function recordingsDir() {
|
|
10752
|
+
return path21.join(process.cwd(), ".deepstorm", "recordings");
|
|
10753
|
+
}
|
|
10754
|
+
function getNextSeq(datePrefix) {
|
|
10755
|
+
const dir = recordingsDir();
|
|
10756
|
+
if (!fs25.existsSync(dir)) return 1;
|
|
10757
|
+
const files = fs25.readdirSync(dir).filter((f) => f.startsWith(datePrefix));
|
|
10758
|
+
if (files.length === 0) return 1;
|
|
10759
|
+
let maxSeq = 0;
|
|
10760
|
+
for (const f of files) {
|
|
10761
|
+
const match = f.match(/(?:-(\d+))?\.recording\.json$/);
|
|
10762
|
+
if (match) {
|
|
10763
|
+
const s = match[1] ? parseInt(match[1], 10) : 1;
|
|
10764
|
+
maxSeq = Math.max(maxSeq, s);
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
return maxSeq + 1;
|
|
10768
|
+
}
|
|
10769
|
+
|
|
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
|
+
}
|
|
10847
|
+
async function recordBrowserSession(url) {
|
|
10848
|
+
let targetUrl;
|
|
10849
|
+
try {
|
|
10850
|
+
targetUrl = new URL(url);
|
|
10851
|
+
} catch {
|
|
10852
|
+
throw new Error(`\u65E0\u6548\u7684 URL: ${url}`);
|
|
10853
|
+
}
|
|
10854
|
+
await ensurePlaywrightPackage();
|
|
10855
|
+
await ensurePlaywrightBrowsers();
|
|
10856
|
+
const pw = await getPlaywright();
|
|
10857
|
+
const startTime = Date.now();
|
|
10858
|
+
const browser = await pw.chromium.launch({ headless: false });
|
|
10859
|
+
const context = await browser.newContext();
|
|
10860
|
+
const page = await context.newPage();
|
|
10861
|
+
const events = [];
|
|
10862
|
+
const requestMethods = /* @__PURE__ */ new Map();
|
|
10863
|
+
const cdpSession = await context.newCDPSession(page);
|
|
10864
|
+
cdpSession.on("Network.requestWillBeSent", (params) => {
|
|
10865
|
+
const { request, type, requestId } = params;
|
|
10866
|
+
requestMethods.set(requestId, request.method);
|
|
10867
|
+
if (type === "XHR" || type === "Fetch") {
|
|
10868
|
+
events.push({
|
|
10869
|
+
ts: Date.now() - startTime,
|
|
10870
|
+
type: "network",
|
|
10871
|
+
data: {
|
|
10872
|
+
url: request.url,
|
|
10873
|
+
method: request.method,
|
|
10874
|
+
type: "request"
|
|
10875
|
+
}
|
|
10876
|
+
});
|
|
10877
|
+
}
|
|
10878
|
+
});
|
|
10879
|
+
cdpSession.on("Network.responseReceived", (params) => {
|
|
10880
|
+
const { response, type, requestId } = params;
|
|
10881
|
+
const method = requestMethods.get(requestId) ?? "GET";
|
|
10882
|
+
if (type === "XHR" || type === "Fetch") {
|
|
10883
|
+
events.push({
|
|
10884
|
+
ts: Date.now() - startTime,
|
|
10885
|
+
type: "network",
|
|
10886
|
+
data: {
|
|
10887
|
+
url: response.url,
|
|
10888
|
+
method,
|
|
10889
|
+
statusCode: response.status,
|
|
10890
|
+
type: "response"
|
|
10891
|
+
}
|
|
10892
|
+
});
|
|
10893
|
+
}
|
|
10894
|
+
});
|
|
10895
|
+
cdpSession.on("Page.frameNavigated", (params) => {
|
|
10896
|
+
const { frame } = params;
|
|
10897
|
+
if (frame.parentId === void 0 || frame.parentId === null) {
|
|
10898
|
+
events.push({
|
|
10899
|
+
ts: Date.now() - startTime,
|
|
10900
|
+
type: "navigation",
|
|
10901
|
+
data: {
|
|
10902
|
+
url: frame.url,
|
|
10903
|
+
title: frame.name || frame.url,
|
|
10904
|
+
type: "full"
|
|
10905
|
+
}
|
|
10906
|
+
});
|
|
10907
|
+
}
|
|
10908
|
+
});
|
|
10909
|
+
cdpSession.on("Page.navigatedWithinDocument", (params) => {
|
|
10910
|
+
events.push({
|
|
10911
|
+
ts: Date.now() - startTime,
|
|
10912
|
+
type: "navigation",
|
|
10913
|
+
data: {
|
|
10914
|
+
url: params.url,
|
|
10915
|
+
type: "spa"
|
|
10916
|
+
}
|
|
10917
|
+
});
|
|
10918
|
+
});
|
|
10919
|
+
await page.exposeFunction("__deepstorm_recordEvent", (type, data) => {
|
|
10920
|
+
events.push({
|
|
10921
|
+
ts: Date.now() - startTime,
|
|
10922
|
+
type,
|
|
10923
|
+
data
|
|
10924
|
+
});
|
|
10925
|
+
});
|
|
10926
|
+
await page.goto(targetUrl.href);
|
|
10927
|
+
await page.evaluate(`(function() {
|
|
10928
|
+
var send = window.__deepstorm_recordEvent;
|
|
10929
|
+
|
|
10930
|
+
// Click listener (capture phase)
|
|
10931
|
+
document.addEventListener('click', function(e) {
|
|
10932
|
+
var target = e.target;
|
|
10933
|
+
if (!target || target === document.body || target === document.documentElement) return;
|
|
10934
|
+
|
|
10935
|
+
var info = {
|
|
10936
|
+
tagName: target.tagName.toLowerCase(),
|
|
10937
|
+
id: target.id || undefined,
|
|
10938
|
+
className: (target.className || '').toString().slice(0, 100) || undefined,
|
|
10939
|
+
textContent: (target.textContent || '').trim().slice(0, 100) || undefined
|
|
10940
|
+
};
|
|
10941
|
+
|
|
10942
|
+
var role = target.getAttribute('role');
|
|
10943
|
+
if (role) info.role = role;
|
|
10944
|
+
var ariaLabel = target.getAttribute('aria-label');
|
|
10945
|
+
if (ariaLabel) info.ariaLabel = ariaLabel;
|
|
10946
|
+
var placeholder = target.getAttribute('placeholder');
|
|
10947
|
+
if (placeholder) info.placeholder = placeholder;
|
|
10948
|
+
var dataTestId = target.getAttribute('data-testid');
|
|
10949
|
+
if (dataTestId) info.dataTestId = dataTestId;
|
|
10950
|
+
|
|
10951
|
+
info.cssSelector = buildSimpleSelector(target);
|
|
10952
|
+
send('click', info);
|
|
10953
|
+
}, true);
|
|
10954
|
+
|
|
10955
|
+
// Input listener (change event for final value)
|
|
10956
|
+
document.addEventListener('change', function(e) {
|
|
10957
|
+
var target = e.target;
|
|
10958
|
+
if (!target) return;
|
|
10959
|
+
|
|
10960
|
+
if (target.tagName === 'SELECT') {
|
|
10961
|
+
send('select', {
|
|
10962
|
+
tagName: 'select',
|
|
10963
|
+
value: target.value,
|
|
10964
|
+
name: target.name || undefined,
|
|
10965
|
+
cssSelector: buildSimpleSelector(target)
|
|
10966
|
+
});
|
|
10967
|
+
return;
|
|
10968
|
+
}
|
|
10969
|
+
|
|
10970
|
+
if (target.type === 'password') {
|
|
10971
|
+
send('input', {
|
|
10972
|
+
tagName: target.tagName.toLowerCase(),
|
|
10973
|
+
type: 'password',
|
|
10974
|
+
value: '****',
|
|
10975
|
+
name: target.name || undefined,
|
|
10976
|
+
placeholder: target.placeholder || undefined,
|
|
10977
|
+
cssSelector: buildSimpleSelector(target)
|
|
10978
|
+
});
|
|
10979
|
+
return;
|
|
10980
|
+
}
|
|
10981
|
+
|
|
10982
|
+
send('input', {
|
|
10983
|
+
tagName: target.tagName.toLowerCase(),
|
|
10984
|
+
type: target.type || undefined,
|
|
10985
|
+
value: target.value,
|
|
10986
|
+
name: target.name || undefined,
|
|
10987
|
+
placeholder: target.placeholder || undefined,
|
|
10988
|
+
cssSelector: buildSimpleSelector(target)
|
|
10989
|
+
});
|
|
10990
|
+
}, true);
|
|
10991
|
+
|
|
10992
|
+
// Submit listener
|
|
10993
|
+
document.addEventListener('submit', function(e) {
|
|
10994
|
+
var form = e.target;
|
|
10995
|
+
if (!form) return;
|
|
10996
|
+
send('submit', {
|
|
10997
|
+
cssSelector: buildSimpleSelector(form),
|
|
10998
|
+
id: form.id || undefined,
|
|
10999
|
+
action: form.action || undefined
|
|
11000
|
+
});
|
|
11001
|
+
}, true);
|
|
11002
|
+
|
|
11003
|
+
// Helper: build simple CSS selector
|
|
11004
|
+
function buildSimpleSelector(el) {
|
|
11005
|
+
if (el.id) return '#' + CSS.escape(el.id);
|
|
11006
|
+
var testId = el.getAttribute('data-testid');
|
|
11007
|
+
if (testId) return '[data-testid="' + CSS.escape(testId) + '"]';
|
|
11008
|
+
var tag = el.tagName.toLowerCase();
|
|
11009
|
+
var cls = '';
|
|
11010
|
+
for (var i = 0; i < el.classList.length; i++) {
|
|
11011
|
+
cls += '.' + CSS.escape(el.classList[i]);
|
|
11012
|
+
}
|
|
11013
|
+
if (cls) return tag + cls;
|
|
11014
|
+
var parent = el.parentElement;
|
|
11015
|
+
if (parent) {
|
|
11016
|
+
var siblings = Array.from(parent.children).filter(function(s) {
|
|
11017
|
+
return s.tagName === el.tagName;
|
|
11018
|
+
});
|
|
11019
|
+
if (siblings.length > 1) {
|
|
11020
|
+
var idx = siblings.indexOf(el) + 1;
|
|
11021
|
+
return tag + ':nth-child(' + idx + ')';
|
|
11022
|
+
}
|
|
11023
|
+
}
|
|
11024
|
+
return tag;
|
|
11025
|
+
}
|
|
11026
|
+
})();`);
|
|
11027
|
+
console.log("\u{1F3A5} \u5F55\u5236\u4E2D... \u6309 Ctrl+D \u505C\u6B62");
|
|
11028
|
+
const stopPromise = new Promise((resolve4) => {
|
|
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
|
+
}
|
|
11036
|
+
process.stdin.resume();
|
|
11037
|
+
process.stdin.on("data", (chunk) => {
|
|
11038
|
+
if (chunk.length === 1 && chunk[0] === 4) {
|
|
11039
|
+
cleanup();
|
|
11040
|
+
resolve4();
|
|
11041
|
+
}
|
|
11042
|
+
});
|
|
11043
|
+
process.stdin.on("end", () => {
|
|
11044
|
+
cleanup();
|
|
11045
|
+
resolve4();
|
|
11046
|
+
});
|
|
11047
|
+
function cleanup() {
|
|
11048
|
+
if (rawModeSupported) {
|
|
11049
|
+
try {
|
|
11050
|
+
process.stdin.setRawMode?.(false);
|
|
11051
|
+
} catch {
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
11054
|
+
process.stdin.pause();
|
|
11055
|
+
}
|
|
11056
|
+
});
|
|
11057
|
+
const crashPromise = new Promise((_resolve, reject) => {
|
|
11058
|
+
browser.on("disconnected", () => {
|
|
11059
|
+
reject(new Error("\u6D4F\u89C8\u5668\u8FDE\u63A5\u65AD\u5F00"));
|
|
11060
|
+
});
|
|
11061
|
+
});
|
|
11062
|
+
try {
|
|
11063
|
+
await Promise.race([stopPromise, crashPromise]);
|
|
11064
|
+
} catch (err) {
|
|
11065
|
+
console.error("\n\u6D4F\u89C8\u5668\u8FDE\u63A5\u65AD\u5F00\uFF0C\u5F55\u5236\u5DF2\u7EC8\u6B62");
|
|
11066
|
+
throw err;
|
|
11067
|
+
} finally {
|
|
11068
|
+
try {
|
|
11069
|
+
process.stdin.setRawMode?.(false);
|
|
11070
|
+
} catch {
|
|
11071
|
+
}
|
|
11072
|
+
process.stdin.pause();
|
|
11073
|
+
}
|
|
11074
|
+
const duration = Date.now() - startTime;
|
|
11075
|
+
try {
|
|
11076
|
+
const screenshotBuffer = await page.screenshot({ type: "jpeg", quality: 70 });
|
|
11077
|
+
events.push({
|
|
11078
|
+
ts: Date.now() - startTime,
|
|
11079
|
+
type: "screenshot",
|
|
11080
|
+
data: {
|
|
11081
|
+
label: "final",
|
|
11082
|
+
data: screenshotBuffer.toString("base64")
|
|
11083
|
+
}
|
|
11084
|
+
});
|
|
11085
|
+
} catch {
|
|
11086
|
+
}
|
|
11087
|
+
await browser.close();
|
|
11088
|
+
const filteredEvents = dedupEvents(filterNoiseEvents(events));
|
|
11089
|
+
const recordingData = {
|
|
11090
|
+
meta: {
|
|
11091
|
+
url: targetUrl.href,
|
|
11092
|
+
recordedAt: new Date(startTime).toISOString(),
|
|
11093
|
+
duration,
|
|
11094
|
+
browser: `Playwright Chromium ${browser.version()}`
|
|
11095
|
+
},
|
|
11096
|
+
events: filteredEvents
|
|
11097
|
+
};
|
|
11098
|
+
const dir = recordingsDir();
|
|
11099
|
+
fs26.mkdirSync(dir, { recursive: true });
|
|
11100
|
+
const datePrefix = buildRecordingFileName().replace(".recording.json", "");
|
|
11101
|
+
const seq = getNextSeq(datePrefix);
|
|
11102
|
+
const fileName = buildRecordingFileName(seq);
|
|
11103
|
+
const filePath = path22.join(dir, fileName);
|
|
11104
|
+
fs26.writeFileSync(filePath, serializeRecording(recordingData), "utf-8");
|
|
11105
|
+
console.log(`
|
|
11106
|
+
\u2705 \u5F55\u5236\u5B8C\u6210`);
|
|
11107
|
+
console.log(` \u6301\u7EED\u65F6\u95F4: ${(duration / 1e3).toFixed(1)} \u79D2`);
|
|
11108
|
+
console.log(` \u4E8B\u4EF6\u603B\u6570: ${filteredEvents.length}`);
|
|
11109
|
+
console.log(` \u6587\u4EF6\u8DEF\u5F84: ${filePath}`);
|
|
11110
|
+
return filePath;
|
|
11111
|
+
}
|
|
11112
|
+
|
|
11113
|
+
// src/commands/record.ts
|
|
11114
|
+
function registerRecordCommand(program2) {
|
|
11115
|
+
const recordCmd = program2.command("record").description("\u6D4F\u89C8\u5668\u64CD\u4F5C\u5F55\u5236 \u2014 \u542F\u52A8 headed \u6D4F\u89C8\u5668\u5F55\u5236\u7528\u6237\u64CD\u4F5C\uFF0C\u8F93\u51FA .recording.json");
|
|
11116
|
+
recordCmd.command("start").description("\u5F00\u59CB\u5F55\u5236 \u2014 \u542F\u52A8 headed \u6D4F\u89C8\u5668\u5E76\u6253\u5F00\u6307\u5B9A URL").option("-u, --url <url>", "\u76EE\u6807 URL").action(async (options) => {
|
|
11117
|
+
if (!options.url) {
|
|
11118
|
+
console.error("\u8BF7\u4F7F\u7528 -u <url> \u6307\u5B9A\u76EE\u6807 URL");
|
|
11119
|
+
process.exit(1);
|
|
11120
|
+
}
|
|
11121
|
+
try {
|
|
11122
|
+
await recordBrowserSession(options.url);
|
|
11123
|
+
} catch (err) {
|
|
11124
|
+
console.error("\u5F55\u5236\u5931\u8D25:", err instanceof Error ? err.message : err);
|
|
11125
|
+
process.exit(1);
|
|
11126
|
+
}
|
|
11127
|
+
});
|
|
11128
|
+
recordCmd.command("stop").description("\u505C\u6B62\u5F55\u5236 \u2014 \u505C\u6B62\u5F53\u524D\u5F55\u5236\u5E76\u5199\u5165\u6587\u4EF6").action(() => {
|
|
11129
|
+
console.log("\u8BF7\u5728\u5F55\u5236\u7EC8\u7AEF\u6309 Ctrl+D \u505C\u6B62\u5F55\u5236");
|
|
11130
|
+
});
|
|
11131
|
+
}
|
|
11132
|
+
|
|
11133
|
+
// src/commands/doctor.ts
|
|
11134
|
+
var fs27 = __toESM(require("node:fs"));
|
|
11135
|
+
var path23 = __toESM(require("node:path"));
|
|
10513
11136
|
function getInstalledSkills(targetDir) {
|
|
10514
11137
|
const settingsPath = getDeepStormConfigPath(targetDir);
|
|
10515
11138
|
try {
|
|
10516
|
-
const settings = JSON.parse(
|
|
11139
|
+
const settings = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10517
11140
|
return settings.installedSkills || [];
|
|
10518
11141
|
} catch {
|
|
10519
11142
|
return [];
|
|
@@ -10530,7 +11153,7 @@ function runDoctor(targetDir) {
|
|
|
10530
11153
|
message: `v${version}\uFF08\u8FD0\u884C deepstorm update \u68C0\u67E5\u6700\u65B0\u7248\u672C\uFF09`
|
|
10531
11154
|
});
|
|
10532
11155
|
let hasDeepStorm = false;
|
|
10533
|
-
if (!
|
|
11156
|
+
if (!fs27.existsSync(settingsPath)) {
|
|
10534
11157
|
checks.push({
|
|
10535
11158
|
name: "\u914D\u7F6E\u6587\u4EF6",
|
|
10536
11159
|
status: "warn",
|
|
@@ -10538,7 +11161,7 @@ function runDoctor(targetDir) {
|
|
|
10538
11161
|
});
|
|
10539
11162
|
} else {
|
|
10540
11163
|
try {
|
|
10541
|
-
const config = JSON.parse(
|
|
11164
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10542
11165
|
if (config && Object.keys(config).length > 0) {
|
|
10543
11166
|
hasDeepStorm = true;
|
|
10544
11167
|
checks.push({
|
|
@@ -10561,20 +11184,18 @@ function runDoctor(targetDir) {
|
|
|
10561
11184
|
});
|
|
10562
11185
|
}
|
|
10563
11186
|
}
|
|
10564
|
-
const skillsDir =
|
|
10565
|
-
if (
|
|
10566
|
-
const skillDirs =
|
|
10567
|
-
(n) => fs25.statSync(path21.join(skillsDir, n)).isDirectory()
|
|
10568
|
-
);
|
|
11187
|
+
const skillsDir = path23.join(targetDir, ".claude", "skills");
|
|
11188
|
+
if (fs27.existsSync(skillsDir)) {
|
|
11189
|
+
const skillDirs = fs27.readdirSync(skillsDir).filter((n) => fs27.statSync(path23.join(skillsDir, n)).isDirectory());
|
|
10569
11190
|
let validCount = 0;
|
|
10570
11191
|
let invalidCount = 0;
|
|
10571
11192
|
for (const skillName of skillDirs) {
|
|
10572
|
-
const skillMd =
|
|
10573
|
-
if (!
|
|
11193
|
+
const skillMd = path23.join(skillsDir, skillName, "SKILL.md");
|
|
11194
|
+
if (!fs27.existsSync(skillMd)) {
|
|
10574
11195
|
invalidCount++;
|
|
10575
11196
|
continue;
|
|
10576
11197
|
}
|
|
10577
|
-
const content =
|
|
11198
|
+
const content = fs27.readFileSync(skillMd, "utf-8");
|
|
10578
11199
|
const frontmatter = parseFrontmatter(content);
|
|
10579
11200
|
if (frontmatter && frontmatter.name) {
|
|
10580
11201
|
validCount++;
|
|
@@ -10604,7 +11225,7 @@ function runDoctor(targetDir) {
|
|
|
10604
11225
|
const installedSkills = getInstalledSkills(targetDir);
|
|
10605
11226
|
const missingSkills = [];
|
|
10606
11227
|
for (const skillId of installedSkills) {
|
|
10607
|
-
if (!
|
|
11228
|
+
if (!fs27.existsSync(path23.join(skillsDir, skillId))) {
|
|
10608
11229
|
missingSkills.push(skillId);
|
|
10609
11230
|
}
|
|
10610
11231
|
}
|
|
@@ -10628,10 +11249,10 @@ function runDoctor(targetDir) {
|
|
|
10628
11249
|
message: ".claude/skills/ \u4E0D\u5B58\u5728"
|
|
10629
11250
|
});
|
|
10630
11251
|
}
|
|
10631
|
-
const mcpPath =
|
|
10632
|
-
if (
|
|
11252
|
+
const mcpPath = path23.join(targetDir, ".mcp.json");
|
|
11253
|
+
if (fs27.existsSync(mcpPath)) {
|
|
10633
11254
|
try {
|
|
10634
|
-
const mcp = JSON.parse(
|
|
11255
|
+
const mcp = JSON.parse(fs27.readFileSync(mcpPath, "utf-8"));
|
|
10635
11256
|
const hasServers = mcp.mcpServers && Object.keys(mcp.mcpServers).length > 0;
|
|
10636
11257
|
checks.push({
|
|
10637
11258
|
name: "MCP \u670D\u52A1\u5668",
|
|
@@ -10652,12 +11273,12 @@ function runDoctor(targetDir) {
|
|
|
10652
11273
|
message: ".mcp.json \u4E0D\u5B58\u5728"
|
|
10653
11274
|
});
|
|
10654
11275
|
}
|
|
10655
|
-
if (hasDeepStorm &&
|
|
11276
|
+
if (hasDeepStorm && fs27.existsSync(settingsPath)) {
|
|
10656
11277
|
try {
|
|
10657
|
-
const config = JSON.parse(
|
|
11278
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10658
11279
|
const installedMcp = config.installedMcpServers;
|
|
10659
11280
|
if (installedMcp && installedMcp.length > 0) {
|
|
10660
|
-
const mcpExists =
|
|
11281
|
+
const mcpExists = fs27.existsSync(mcpPath);
|
|
10661
11282
|
if (!mcpExists) {
|
|
10662
11283
|
checks.push({
|
|
10663
11284
|
name: "MCP \u4E00\u81F4\u6027",
|
|
@@ -10666,7 +11287,7 @@ function runDoctor(targetDir) {
|
|
|
10666
11287
|
});
|
|
10667
11288
|
} else {
|
|
10668
11289
|
try {
|
|
10669
|
-
const mcpConfig = JSON.parse(
|
|
11290
|
+
const mcpConfig = JSON.parse(fs27.readFileSync(mcpPath, "utf-8"));
|
|
10670
11291
|
const servers = mcpConfig.mcpServers || {};
|
|
10671
11292
|
const missing = [];
|
|
10672
11293
|
for (const toolName of installedMcp) {
|
|
@@ -10694,9 +11315,9 @@ function runDoctor(targetDir) {
|
|
|
10694
11315
|
} catch {
|
|
10695
11316
|
}
|
|
10696
11317
|
}
|
|
10697
|
-
if (hasDeepStorm &&
|
|
11318
|
+
if (hasDeepStorm && fs27.existsSync(settingsPath)) {
|
|
10698
11319
|
try {
|
|
10699
|
-
const config = JSON.parse(
|
|
11320
|
+
const config = JSON.parse(fs27.readFileSync(settingsPath, "utf-8"));
|
|
10700
11321
|
const validKeys = loadValidConfigKeys();
|
|
10701
11322
|
if (validKeys.size > 0 && config) {
|
|
10702
11323
|
const configKeys = [];
|
|
@@ -10749,18 +11370,18 @@ function printDoctorReport(report) {
|
|
|
10749
11370
|
}
|
|
10750
11371
|
|
|
10751
11372
|
// src/commands/uninstall.ts
|
|
10752
|
-
var
|
|
10753
|
-
var
|
|
11373
|
+
var fs28 = __toESM(require("node:fs"));
|
|
11374
|
+
var path24 = __toESM(require("node:path"));
|
|
10754
11375
|
var import_prompts4 = require("@clack/prompts");
|
|
10755
11376
|
async function uninstallDeepStorm(targetDir) {
|
|
10756
11377
|
const settingsPath = getDeepStormConfigPath(targetDir);
|
|
10757
|
-
if (!
|
|
11378
|
+
if (!fs28.existsSync(settingsPath)) {
|
|
10758
11379
|
console.log("DeepStorm \u5C1A\u672A\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D");
|
|
10759
11380
|
return;
|
|
10760
11381
|
}
|
|
10761
11382
|
let hasDeepStorm = false;
|
|
10762
11383
|
try {
|
|
10763
|
-
const settings = JSON.parse(
|
|
11384
|
+
const settings = JSON.parse(fs28.readFileSync(settingsPath, "utf-8"));
|
|
10764
11385
|
hasDeepStorm = !!settings && Object.keys(settings).length > 0;
|
|
10765
11386
|
} catch {
|
|
10766
11387
|
}
|
|
@@ -10770,14 +11391,14 @@ async function uninstallDeepStorm(targetDir) {
|
|
|
10770
11391
|
}
|
|
10771
11392
|
cleanInstalled(targetDir);
|
|
10772
11393
|
resetConfig(targetDir);
|
|
10773
|
-
const templatesDir =
|
|
10774
|
-
if (
|
|
11394
|
+
const templatesDir = path24.join(targetDir, ".deepstorm", "templates");
|
|
11395
|
+
if (fs28.existsSync(templatesDir)) {
|
|
10775
11396
|
const shouldDelete = await (0, import_prompts4.confirm)({
|
|
10776
11397
|
message: "\u662F\u5426\u5220\u9664 .deepstorm/templates/ \u76EE\u5F55\uFF1F",
|
|
10777
11398
|
initialValue: false
|
|
10778
11399
|
});
|
|
10779
11400
|
if (shouldDelete) {
|
|
10780
|
-
|
|
11401
|
+
fs28.rmSync(templatesDir, { recursive: true, force: true });
|
|
10781
11402
|
console.log("\u2714 .deepstorm/templates/ \u5DF2\u5220\u9664");
|
|
10782
11403
|
} else {
|
|
10783
11404
|
console.log("\u4FDD\u7559 .deepstorm/templates/");
|
|
@@ -10790,9 +11411,9 @@ async function uninstallDeepStorm(targetDir) {
|
|
|
10790
11411
|
var program = new import_commander.Command();
|
|
10791
11412
|
program.name("deepstorm").description("DeepStorm CLI \u2014 \u4E00\u952E\u914D\u7F6E\u9879\u76EE\u5F00\u53D1\u73AF\u5883").version(getCliVersion(), "-v, --version", "\u8F93\u51FA\u7248\u672C\u53F7");
|
|
10792
11413
|
function loadRegistry() {
|
|
10793
|
-
const registryPath =
|
|
11414
|
+
const registryPath = path25.join(__dirname, "registry.json");
|
|
10794
11415
|
try {
|
|
10795
|
-
const raw =
|
|
11416
|
+
const raw = fs29.readFileSync(registryPath, "utf-8");
|
|
10796
11417
|
return JSON.parse(raw);
|
|
10797
11418
|
} catch {
|
|
10798
11419
|
return { version: "1", tools: {}, wizards: {}, skills: {} };
|
|
@@ -10806,6 +11427,7 @@ registerConfigCommand(program, registry);
|
|
|
10806
11427
|
registerTemplateCommand(program, registry);
|
|
10807
11428
|
registerUpdateCommand(program);
|
|
10808
11429
|
registerPilotCommands(program);
|
|
11430
|
+
registerRecordCommand(program);
|
|
10809
11431
|
program.command("doctor").description("\u8BCA\u65AD\u9879\u76EE DeepStorm \u914D\u7F6E\u72B6\u6001").action(() => {
|
|
10810
11432
|
const report = runDoctor(process.cwd());
|
|
10811
11433
|
printDoctorReport(report);
|