@deepstorm/cli 0.2.1 → 0.2.3

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.
@@ -125,11 +125,11 @@ function buildRegistry(cliDir) {
125
125
  console.log(` \u26A0 ${pkg}/${skillName}: frontmatter \u89E3\u6790\u5931\u8D25\uFF0C\u8DF3\u8FC7`);
126
126
  continue;
127
127
  }
128
- if (!fm.deepstormm) {
129
- console.log(` - ${pkg}/${skillName}: \u65E0 deepstormm \u5B57\u6BB5\uFF0C\u8DF3\u8FC7\u6CE8\u518C`);
128
+ if (!fm.deepstorm) {
129
+ console.log(` - ${pkg}/${skillName}: \u65E0 deepstorm \u5B57\u6BB5\uFF0C\u8DF3\u8FC7\u6CE8\u518C`);
130
130
  continue;
131
131
  }
132
- const df = fm.deepstormm;
132
+ const df = fm.deepstorm;
133
133
  const entry = {
134
134
  tool: df.tool,
135
135
  configKey: df.configKey,
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(path22) {
1191
- return /^\.|this\b/.test(path22.original);
1190
+ scopedId: function scopedId(path23) {
1191
+ return /^\.|this\b/.test(path23.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(path22) {
1196
- return path22.parts.length === 1 && !AST.helpers.scopedId(path22) && !path22.depth;
1195
+ simpleId: function simpleId(path23) {
1196
+ return path23.parts.length === 1 && !AST.helpers.scopedId(path23) && !path23.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(path22, params, hash, open, strip, locInfo) {
2266
+ function prepareMustache(path23, 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: path22,
2271
+ path: path23,
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), path22 = decorator.path;
2589
+ var params = this.setupFullMustacheParams(decorator, program2, void 0), path23 = decorator.path;
2590
2590
  this.useDecorators = true;
2591
- this.opcode("registerDecorator", params.length, path22.original);
2591
+ this.opcode("registerDecorator", params.length, path23.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 path22 = sexpr.path, name = path22.parts[0], isBlock = program2 != null || inverse != null;
2656
- this.opcode("getContext", path22.depth);
2655
+ var path23 = sexpr.path, name = path23.parts[0], isBlock = program2 != null || inverse != null;
2656
+ this.opcode("getContext", path23.depth);
2657
2657
  this.opcode("pushProgram", program2);
2658
2658
  this.opcode("pushProgram", inverse);
2659
- path22.strict = true;
2660
- this.accept(path22);
2659
+ path23.strict = true;
2660
+ this.accept(path23);
2661
2661
  this.opcode("invokeAmbiguous", name, isBlock);
2662
2662
  },
2663
2663
  simpleSexpr: function simpleSexpr(sexpr) {
2664
- var path22 = sexpr.path;
2665
- path22.strict = true;
2666
- this.accept(path22);
2664
+ var path23 = sexpr.path;
2665
+ path23.strict = true;
2666
+ this.accept(path23);
2667
2667
  this.opcode("resolvePossibleLambda");
2668
2668
  },
2669
2669
  helperSexpr: function helperSexpr(sexpr, program2, inverse) {
2670
- var params = this.setupFullMustacheParams(sexpr, program2, inverse), path22 = sexpr.path, name = path22.parts[0];
2670
+ var params = this.setupFullMustacheParams(sexpr, program2, inverse), path23 = sexpr.path, name = path23.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
- path22.strict = true;
2677
- path22.falsy = true;
2678
- this.accept(path22);
2679
- this.opcode("invokeHelper", params.length, path22.original, _ast2["default"].helpers.simpleId(path22));
2676
+ path23.strict = true;
2677
+ path23.falsy = true;
2678
+ this.accept(path23);
2679
+ this.opcode("invokeHelper", params.length, path23.original, _ast2["default"].helpers.simpleId(path23));
2680
2680
  }
2681
2681
  },
2682
- PathExpression: function PathExpression(path22) {
2683
- this.addDepth(path22.depth);
2684
- this.opcode("getContext", path22.depth);
2685
- var name = path22.parts[0], scoped = _ast2["default"].helpers.scopedId(path22), blockParamId = !path22.depth && !scoped && this.blockParamIndex(name);
2682
+ PathExpression: function PathExpression(path23) {
2683
+ this.addDepth(path23.depth);
2684
+ this.opcode("getContext", path23.depth);
2685
+ var name = path23.parts[0], scoped = _ast2["default"].helpers.scopedId(path23), blockParamId = !path23.depth && !scoped && this.blockParamIndex(name);
2686
2686
  if (blockParamId) {
2687
- this.opcode("lookupBlockParam", blockParamId, path22.parts);
2687
+ this.opcode("lookupBlockParam", blockParamId, path23.parts);
2688
2688
  } else if (!name) {
2689
2689
  this.opcode("pushContext");
2690
- } else if (path22.data) {
2690
+ } else if (path23.data) {
2691
2691
  this.options.data = true;
2692
- this.opcode("lookupData", path22.depth, path22.parts, path22.strict);
2692
+ this.opcode("lookupData", path23.depth, path23.parts, path23.strict);
2693
2693
  } else {
2694
- this.opcode("lookupOnContext", path22.parts, path22.falsy, path22.strict, scoped);
2694
+ this.opcode("lookupOnContext", path23.parts, path23.falsy, path23.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 path22 = aPath;
3044
+ var path23 = aPath;
3045
3045
  var url = urlParse(aPath);
3046
3046
  if (url) {
3047
3047
  if (!url.path) {
3048
3048
  return aPath;
3049
3049
  }
3050
- path22 = url.path;
3050
+ path23 = url.path;
3051
3051
  }
3052
- var isAbsolute = exports2.isAbsolute(path22);
3053
- var parts = path22.split(/\/+/);
3052
+ var isAbsolute = exports2.isAbsolute(path23);
3053
+ var parts = path23.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
- path22 = parts.join("/");
3071
- if (path22 === "") {
3072
- path22 = isAbsolute ? "/" : ".";
3070
+ path23 = parts.join("/");
3071
+ if (path23 === "") {
3072
+ path23 = isAbsolute ? "/" : ".";
3073
3073
  }
3074
3074
  if (url) {
3075
- url.path = path22;
3075
+ url.path = path23;
3076
3076
  return urlGenerate(url);
3077
3077
  }
3078
- return path22;
3078
+ return path23;
3079
3079
  }
3080
3080
  exports2.normalize = normalize;
3081
- function join20(aRoot, aPath) {
3081
+ function join21(aRoot, aPath) {
3082
3082
  if (aRoot === "") {
3083
3083
  aRoot = ".";
3084
3084
  }
@@ -3110,11 +3110,11 @@ var require_util = __commonJS({
3110
3110
  }
3111
3111
  return joined;
3112
3112
  }
3113
- exports2.join = join20;
3113
+ exports2.join = join21;
3114
3114
  exports2.isAbsolute = function(aPath) {
3115
3115
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
3116
3116
  };
3117
- function relative(aRoot, aPath) {
3117
+ function relative2(aRoot, aPath) {
3118
3118
  if (aRoot === "") {
3119
3119
  aRoot = ".";
3120
3120
  }
@@ -3133,7 +3133,7 @@ var require_util = __commonJS({
3133
3133
  }
3134
3134
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
3135
3135
  }
3136
- exports2.relative = relative;
3136
+ exports2.relative = relative2;
3137
3137
  var supportsNullProto = (function() {
3138
3138
  var obj = /* @__PURE__ */ Object.create(null);
3139
3139
  return !("__proto__" in obj);
@@ -3283,7 +3283,7 @@ var require_util = __commonJS({
3283
3283
  parsed.path = parsed.path.substring(0, index + 1);
3284
3284
  }
3285
3285
  }
3286
- sourceURL = join20(urlGenerate(parsed), sourceURL);
3286
+ sourceURL = join21(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 path22 = id.parts.join("/");
5862
- return (id.data ? "@" : "") + "PATH:" + path22;
5861
+ var path23 = id.parts.join("/");
5862
+ return (id.data ? "@" : "") + "PATH:" + path23;
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 fs24 = require("fs");
5902
- var templateString = fs24.readFileSync(filename, "utf8");
5901
+ var fs25 = require("fs");
5902
+ var templateString = fs25.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 fs23 = __toESM(require("node:fs"));
5915
- var path21 = __toESM(require("node:path"));
5914
+ var fs24 = __toESM(require("node:fs"));
5915
+ var path22 = __toESM(require("node:path"));
5916
5916
 
5917
5917
  // src/commands/setup.ts
5918
5918
  var path6 = __toESM(require("node:path"));
@@ -6609,7 +6609,7 @@ function buildMcpCapabilities(mcpCapabilities, installedMcpServers, mcpTools) {
6609
6609
  return JSON.stringify(result);
6610
6610
  }
6611
6611
  function deriveVariableName(frontmatter) {
6612
- const deepstorm = frontmatter.deepstormm;
6612
+ const deepstorm = frontmatter.deepstorm;
6613
6613
  const tool = deepstorm?.tool;
6614
6614
  if (tool && /^[a-z_]+$/.test(tool)) {
6615
6615
  return `${tool}_capabilities`;
@@ -8116,6 +8116,11 @@ function registerTemplateCommand(program2, registry2) {
8116
8116
  });
8117
8117
  }
8118
8118
 
8119
+ // src/commands/update.ts
8120
+ var fs21 = __toESM(require("node:fs"));
8121
+ var path19 = __toESM(require("node:path"));
8122
+ var import_node_child_process = require("node:child_process");
8123
+
8119
8124
  // src/utils/version.ts
8120
8125
  var fs19 = __toESM(require("node:fs"));
8121
8126
  var path17 = __toESM(require("node:path"));
@@ -8140,20 +8145,281 @@ function getCliVersion() {
8140
8145
  // src/commands/template-upgrade.ts
8141
8146
  var fs20 = __toESM(require("node:fs"));
8142
8147
  var path18 = __toESM(require("node:path"));
8143
- function upgradeTemplates(cliDir2, targetDir, skillIds) {
8144
- const templatesDir = path18.join(targetDir, ".deepstorm", "templates");
8148
+ var crypto = __toESM(require("node:crypto"));
8149
+ var CHECKSUM_FILE = "deepstorm-checksums.json";
8150
+ function computeFileChecksum(filePath) {
8151
+ try {
8152
+ if (!fs20.existsSync(filePath)) return null;
8153
+ const content = fs20.readFileSync(filePath);
8154
+ return crypto.createHash("sha256").update(content).digest("hex");
8155
+ } catch {
8156
+ return null;
8157
+ }
8158
+ }
8159
+ function computeDirChecksums(dirPath, relativeTo = dirPath) {
8160
+ const result = {};
8161
+ if (!fs20.existsSync(dirPath)) return result;
8162
+ function walk(current) {
8163
+ for (const entry of fs20.readdirSync(current, { withFileTypes: true })) {
8164
+ const fullPath = path18.join(current, entry.name);
8165
+ if (entry.name === ".DS_Store") continue;
8166
+ if (entry.isDirectory()) {
8167
+ walk(fullPath);
8168
+ } else if (entry.isFile()) {
8169
+ const relPath = path18.relative(relativeTo, fullPath);
8170
+ const checksum = computeFileChecksum(fullPath);
8171
+ if (checksum) result[relPath] = checksum;
8172
+ }
8173
+ }
8174
+ }
8175
+ walk(dirPath);
8176
+ return result;
8177
+ }
8178
+ function loadChecksums(targetDir) {
8179
+ const filePath = path18.join(targetDir, ".claude", CHECKSUM_FILE);
8180
+ try {
8181
+ return JSON.parse(fs20.readFileSync(filePath, "utf-8"));
8182
+ } catch {
8183
+ return {};
8184
+ }
8185
+ }
8186
+ function saveChecksums(targetDir, checksums) {
8187
+ const dir = path18.join(targetDir, ".claude");
8188
+ ensureDir(dir);
8189
+ fs20.writeFileSync(
8190
+ path18.join(dir, CHECKSUM_FILE),
8191
+ JSON.stringify(checksums, null, 2) + "\n",
8192
+ "utf-8"
8193
+ );
8194
+ }
8195
+ function backupFile(filePath) {
8196
+ try {
8197
+ if (!fs20.existsSync(filePath)) return null;
8198
+ const dir = path18.dirname(filePath);
8199
+ const ext = path18.extname(filePath);
8200
+ const base = path18.basename(filePath, ext);
8201
+ const timestamp = Date.now();
8202
+ const bakName = `${base}.${timestamp}.bak`;
8203
+ const bakPath = path18.join(dir, bakName);
8204
+ fs20.cpSync(filePath, bakPath, { force: true });
8205
+ return bakName;
8206
+ } catch {
8207
+ return null;
8208
+ }
8209
+ }
8210
+ function checkAndBackup(fileKey, filePath, stored, backedUp) {
8211
+ const lastChecksum = stored[fileKey];
8212
+ if (!lastChecksum) return;
8213
+ const current = computeFileChecksum(filePath);
8214
+ if (current === null) return;
8215
+ if (current === lastChecksum) return;
8216
+ const bakName = backupFile(filePath);
8217
+ if (bakName) {
8218
+ backedUp.push(`${fileKey} \u2192 ${bakName}`);
8219
+ }
8220
+ }
8221
+ function backupModifiedAssets(targetDir, skillIds, toolNames, registry2) {
8222
+ const stored = loadChecksums(targetDir);
8223
+ const backedUp = [];
8145
8224
  for (const skillId of skillIds) {
8146
- const userTemplate = path18.join(templatesDir, skillId);
8147
- if (fs20.existsSync(userTemplate)) {
8148
- console.log(`${skillId}\uFF1A\u68C0\u6D4B\u5230\u7528\u6237\u4FEE\u6539\uFF0C\u8DF3\u8FC7\u3002\u5982\u9700\u540C\u6B65\u8BF7\u8FD0\u884C deepstorm template apply ${skillId}`);
8225
+ const skillDir = path18.join(targetDir, ".claude", "skills", skillId);
8226
+ if (!fs20.existsSync(skillDir)) continue;
8227
+ const checksums = computeDirChecksums(skillDir);
8228
+ for (const [relPath] of Object.entries(checksums)) {
8229
+ const key = `skills/${skillId}/${relPath}`;
8230
+ checkAndBackup(key, path18.join(skillDir, relPath), stored, backedUp);
8231
+ }
8232
+ }
8233
+ const reader = new RegistryReader(registry2);
8234
+ for (const tool of toolNames) {
8235
+ const agents = reader.getToolAgents(tool);
8236
+ for (const agentFile of agents) {
8237
+ const filePath = path18.join(targetDir, ".claude", "agents", agentFile.replace(/\.tmpl$/, ""));
8238
+ const key = `agents/${agentFile.replace(/\.tmpl$/, "")}`;
8239
+ checkAndBackup(key, filePath, stored, backedUp);
8240
+ }
8241
+ }
8242
+ for (const tool of toolNames) {
8243
+ const hooks = reader.getToolHooks(tool);
8244
+ for (const hookFile of hooks) {
8245
+ const filePath = path18.join(targetDir, ".claude", "hooks", hookFile);
8246
+ const key = `hooks/${hookFile}`;
8247
+ checkAndBackup(key, filePath, stored, backedUp);
8248
+ }
8249
+ }
8250
+ return backedUp;
8251
+ }
8252
+ function storeNewChecksums(targetDir, skillIds, toolNames, registry2) {
8253
+ const newChecksums = {};
8254
+ const reader = new RegistryReader(registry2);
8255
+ for (const skillId of skillIds) {
8256
+ const skillDir = path18.join(targetDir, ".claude", "skills", skillId);
8257
+ const checksums = computeDirChecksums(skillDir);
8258
+ for (const [relPath, checksum] of Object.entries(checksums)) {
8259
+ newChecksums[`skills/${skillId}/${relPath}`] = checksum;
8260
+ }
8261
+ }
8262
+ for (const tool of toolNames) {
8263
+ const agents = reader.getToolAgents(tool);
8264
+ for (const agentFile of agents) {
8265
+ const installedName = agentFile.replace(/\.tmpl$/, "");
8266
+ const filePath = path18.join(targetDir, ".claude", "agents", installedName);
8267
+ const chk = computeFileChecksum(filePath);
8268
+ if (chk) newChecksums[`agents/${installedName}`] = chk;
8269
+ }
8270
+ }
8271
+ for (const tool of toolNames) {
8272
+ const hooks = reader.getToolHooks(tool);
8273
+ for (const hookFile of hooks) {
8274
+ const filePath = path18.join(targetDir, ".claude", "hooks", hookFile);
8275
+ const chk = computeFileChecksum(filePath);
8276
+ if (chk) newChecksums[`hooks/${hookFile}`] = chk;
8277
+ }
8278
+ }
8279
+ saveChecksums(targetDir, newChecksums);
8280
+ }
8281
+ function skillIdsToTools(skillIds, registry2) {
8282
+ const toolSet = /* @__PURE__ */ new Set();
8283
+ for (const skillId of skillIds) {
8284
+ const skill = registry2.skills[skillId];
8285
+ if (skill?.tool) {
8286
+ toolSet.add(skill.tool);
8287
+ }
8288
+ }
8289
+ return [...toolSet];
8290
+ }
8291
+ function readSettingsConfig(targetDir) {
8292
+ const settingsPath = path18.join(targetDir, ".claude", "settings.json");
8293
+ try {
8294
+ const raw = fs20.readFileSync(settingsPath, "utf-8");
8295
+ const settings = JSON.parse(raw);
8296
+ const deepstorm = settings.deepstorm || {};
8297
+ const metaKeys = /* @__PURE__ */ new Set([
8298
+ "installedSkills",
8299
+ "installedMcpServers",
8300
+ "installedAt",
8301
+ "mcpCapabilities"
8302
+ ]);
8303
+ const config = {};
8304
+ flattenNestedConfig(deepstorm, "", config, metaKeys);
8305
+ const installedMcpTools = deepstorm.installedMcpServers ?? [];
8306
+ return { config, installedMcpTools };
8307
+ } catch {
8308
+ return { config: {}, installedMcpTools: [] };
8309
+ }
8310
+ }
8311
+ function flattenNestedConfig(obj, prefix, result, skipKeys) {
8312
+ for (const [key, value] of Object.entries(obj)) {
8313
+ if (skipKeys.has(key)) continue;
8314
+ const fullKey = prefix ? `${prefix}.${key}` : key;
8315
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
8316
+ flattenNestedConfig(value, fullKey, result, skipKeys);
8317
+ } else if (typeof value === "string") {
8318
+ result[fullKey] = value;
8319
+ }
8320
+ }
8321
+ }
8322
+ function loadRegistryFromCliDir(cliDir2) {
8323
+ const registryPath = path18.join(cliDir2, "registry.json");
8324
+ try {
8325
+ const raw = fs20.readFileSync(registryPath, "utf-8");
8326
+ return JSON.parse(raw);
8327
+ } catch {
8328
+ return null;
8329
+ }
8330
+ }
8331
+ function mergeToolHooksJson(toolNames, cliDir2, targetDir) {
8332
+ const hooksSrcDir = path18.join(cliDir2, "hooks");
8333
+ const targetHooksDir = path18.join(targetDir, ".claude", "hooks");
8334
+ const destHooksJson = path18.join(targetHooksDir, "hooks.json");
8335
+ for (const tool of toolNames) {
8336
+ const toolHooksJsonPath = path18.join(hooksSrcDir, `${tool}-hooks.json`);
8337
+ if (fs20.existsSync(toolHooksJsonPath)) {
8338
+ ensureDir(targetHooksDir);
8339
+ const incoming = JSON.parse(fs20.readFileSync(toolHooksJsonPath, "utf-8"));
8340
+ mergeHooks(destHooksJson, incoming);
8341
+ }
8342
+ }
8343
+ }
8344
+ function syncToolAssets(cliDir2, targetDir, installedSkillIds) {
8345
+ const registry2 = loadRegistryFromCliDir(cliDir2);
8346
+ if (!registry2) {
8347
+ console.log("\u26A0 \u65E0\u6CD5\u52A0\u8F7D registry.json\uFF0C\u8DF3\u8FC7\u8D44\u4EA7\u540C\u6B65");
8348
+ return { syncedSkills: [], syncedAgents: [], syncedHooks: [], backedUpFiles: [] };
8349
+ }
8350
+ const reader = new RegistryReader(registry2);
8351
+ const toolNames = skillIdsToTools(installedSkillIds, registry2);
8352
+ if (toolNames.length === 0) {
8353
+ console.log("\u26A0 \u65E0\u6CD5\u4ECE\u5DF2\u5B89\u88C5 skill \u89E3\u6790\u5DE5\u5177\u540D\u79F0\uFF0C\u8DF3\u8FC7\u8D44\u4EA7\u540C\u6B65");
8354
+ return { syncedSkills: [], syncedAgents: [], syncedHooks: [], backedUpFiles: [] };
8355
+ }
8356
+ const { config, installedMcpTools } = readSettingsConfig(targetDir);
8357
+ const templateVariables = buildTemplateVariables(registry2, config, installedMcpTools);
8358
+ const backedUpFiles = backupModifiedAssets(targetDir, installedSkillIds, toolNames, registry2);
8359
+ if (backedUpFiles.length > 0) {
8360
+ console.log("\n\u26A0 \u68C0\u6D4B\u5230\u7528\u6237\u4FEE\u6539\u7684\u6587\u4EF6\uFF1A");
8361
+ for (const info of backedUpFiles) {
8362
+ console.log(` \u5DF2\u5907\u4EFD ${info}`);
8363
+ }
8364
+ console.log("");
8365
+ }
8366
+ const actualSkillIds = [];
8367
+ const syncedAgents = [];
8368
+ const syncedHooks = [];
8369
+ let hasWarning = false;
8370
+ for (const tool of toolNames) {
8371
+ try {
8372
+ reader.getToolEntry(tool);
8373
+ } catch {
8149
8374
  continue;
8150
8375
  }
8151
- const src = path18.join(cliDir2, "skills", skillId);
8152
- const dest = path18.join(targetDir, ".claude", "skills", skillId);
8153
- if (fs20.existsSync(src)) {
8154
- ensureDir(path18.dirname(dest));
8155
- copyDir(src, dest);
8156
- console.log(`\u2714 ${skillId} \u5DF2\u66F4\u65B0`);
8376
+ const beforeAgents = reader.getToolAgents(tool);
8377
+ const beforeHooks = reader.getToolHooks(tool);
8378
+ try {
8379
+ const ids = renderToolAssets(
8380
+ tool,
8381
+ reader,
8382
+ cliDir2,
8383
+ targetDir,
8384
+ templateVariables,
8385
+ config,
8386
+ registry2,
8387
+ installedMcpTools,
8388
+ ".claude"
8389
+ );
8390
+ actualSkillIds.push(...ids);
8391
+ syncedAgents.push(...beforeAgents);
8392
+ syncedHooks.push(...beforeHooks);
8393
+ } catch (err) {
8394
+ hasWarning = true;
8395
+ console.log(` \u26A0 ${tool} \u540C\u6B65\u51FA\u9519: ${err instanceof Error ? err.message : String(err)}`);
8396
+ }
8397
+ }
8398
+ const syncedSkills = actualSkillIds.length > 0 ? actualSkillIds : [...installedSkillIds];
8399
+ mergeToolHooksJson(toolNames, cliDir2, targetDir);
8400
+ storeNewChecksums(targetDir, installedSkillIds, toolNames, registry2);
8401
+ if (hasWarning) {
8402
+ console.log("\n\u26A0 \u90E8\u5206\u5DE5\u5177\u540C\u6B65\u51FA\u9519\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5");
8403
+ }
8404
+ const uniqueAgents = [...new Set(syncedAgents)];
8405
+ const uniqueHooks = [...new Set(syncedHooks)];
8406
+ return {
8407
+ syncedSkills,
8408
+ syncedAgents: uniqueAgents,
8409
+ syncedHooks: uniqueHooks,
8410
+ backedUpFiles
8411
+ };
8412
+ }
8413
+ function upgradeTemplates(cliDir2, targetDir, skillIds) {
8414
+ const report = syncToolAssets(cliDir2, targetDir, skillIds);
8415
+ if (report.syncedSkills.length > 0) {
8416
+ const count = report.syncedSkills.length;
8417
+ const agentCount = report.syncedAgents.length;
8418
+ const hookCount = report.syncedHooks.length;
8419
+ console.log(`
8420
+ \u2714 \u540C\u6B65\u5B8C\u6210\uFF1A${count} \u4E2A skill${agentCount > 0 ? `\u3001${agentCount} \u4E2A agent` : ""}${hookCount > 0 ? `\u3001${hookCount} \u4E2A hook` : ""}`);
8421
+ if (report.backedUpFiles.length > 0) {
8422
+ console.log(` \u5DF2\u5907\u4EFD ${report.backedUpFiles.length} \u4E2A\u4FEE\u6539\u8FC7\u7684\u6587\u4EF6`);
8157
8423
  }
8158
8424
  }
8159
8425
  }
@@ -8211,75 +8477,49 @@ async function updateCLI(fetchFn) {
8211
8477
  console.log(`\u2714 \u5F53\u524D\u7248\u672C: v${result.current}`);
8212
8478
  console.log(`\u2714 \u6700\u65B0\u7248\u672C: v${result.latest}`);
8213
8479
  if (result.hasUpdate) {
8214
- console.log("");
8215
- console.log("\u2192 \u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0\uFF1A");
8216
- console.log(" npm install -g @deepstorm/cli@latest");
8480
+ console.log("\u2192 \u6B63\u5728\u81EA\u52A8\u66F4\u65B0...");
8481
+ try {
8482
+ (0, import_node_child_process.execSync)("npm install -g @deepstorm/cli@latest", { stdio: "inherit" });
8483
+ console.log(`
8484
+ \u2714 \u5DF2\u66F4\u65B0\u81F3 v${result.latest}`);
8485
+ } catch {
8486
+ console.log("\n\u26A0 \u81EA\u52A8\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\uFF1A");
8487
+ console.log(" npm install -g @deepstorm/cli@latest");
8488
+ }
8217
8489
  } else {
8218
8490
  console.log("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C");
8219
8491
  }
8220
8492
  }
8221
- function updateSkills(cliDir2, targetDir, skillIds) {
8222
- upgradeTemplates(cliDir2, targetDir, skillIds);
8493
+ function getInstalledSkillIds(targetDir) {
8494
+ const settingsPath = path19.join(targetDir, ".claude", "settings.json");
8495
+ try {
8496
+ const raw = fs21.readFileSync(settingsPath, "utf-8");
8497
+ const settings = JSON.parse(raw);
8498
+ return settings.deepstorm?.installedSkills ?? [];
8499
+ } catch {
8500
+ return [];
8501
+ }
8223
8502
  }
8224
- function registerUpdateCommand(program2, registry2) {
8503
+ function registerUpdateCommand(program2) {
8225
8504
  const cliDir2 = __dirname;
8226
- const updateCmd = program2.command("update").description("\u68C0\u67E5\u66F4\u65B0\u5E76\u540C\u6B65 skill \u6A21\u677F");
8227
- updateCmd.option("--check", "\u4EC5\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C").option("--cli", "\u66F4\u65B0 CLI \u81EA\u8EAB").option("--skills", "\u540C\u6B65 skill \u6A21\u677F\u5230\u672C\u5730").action(async (options) => {
8228
- const { check, cli, skills } = options;
8229
- if (!check && !cli && !skills) {
8230
- const result = await checkNpmVersion();
8231
- printVersionInfo(result);
8232
- if (result.latest) {
8233
- console.log("");
8234
- upgradeTemplates(cliDir2, process.cwd(), Object.keys(registry2.skills));
8235
- } else {
8236
- console.log("");
8237
- console.log("\u8DF3\u8FC7 skill \u540C\u6B65\uFF08\u7248\u672C\u68C0\u67E5\u5931\u8D25\u65F6\u4FDD\u7559\u73B0\u6709\u6A21\u677F\uFF09");
8238
- }
8239
- return;
8240
- }
8241
- if (check) {
8242
- const result = await checkNpmVersion();
8243
- printVersionInfo(result);
8244
- if (result.error) process.exit(1);
8245
- return;
8246
- }
8247
- if (cli) {
8248
- await updateCLI();
8249
- return;
8250
- }
8251
- if (skills) {
8252
- const skillIds = Object.keys(registry2.skills);
8253
- if (skillIds.length === 0) {
8254
- console.log("registry \u4E2D\u65E0\u5DF2\u6CE8\u518C skill");
8255
- return;
8256
- }
8257
- updateSkills(cliDir2, process.cwd(), skillIds);
8258
- return;
8505
+ program2.command("update").description("\u68C0\u67E5 CLI \u66F4\u65B0\u5E76\u540C\u6B65\u5DF2\u5B89\u88C5 skill \u7684\u5B98\u65B9\u6700\u65B0\u6A21\u677F").action(async () => {
8506
+ await updateCLI();
8507
+ console.log("");
8508
+ const installedIds = getInstalledSkillIds(process.cwd());
8509
+ if (installedIds.length === 0) {
8510
+ console.log("\u672A\u68C0\u6D4B\u5230\u5DF2\u5B89\u88C5\u7684 skill\uFF0C\u8DF3\u8FC7\u540C\u6B65");
8511
+ } else {
8512
+ upgradeTemplates(cliDir2, process.cwd(), installedIds);
8259
8513
  }
8260
8514
  });
8261
8515
  }
8262
- function printVersionInfo(result) {
8263
- if (result.error) {
8264
- console.log(`\u26A0 \u65E0\u6CD5\u68C0\u67E5\u66F4\u65B0\uFF1A${result.error}`);
8265
- return;
8266
- }
8267
- console.log(`\u2714 \u5F53\u524D\u7248\u672C: v${result.current}`);
8268
- console.log(`\u2714 \u6700\u65B0\u7248\u672C: v${result.latest}`);
8269
- if (result.hasUpdate) {
8270
- console.log("");
8271
- console.log('\u2192 \u6709\u65B0\u7248\u672C\u53EF\u7528\uFF01\u8FD0\u884C "deepstorm update --cli" \u66F4\u65B0');
8272
- } else {
8273
- console.log("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C");
8274
- }
8275
- }
8276
8516
 
8277
8517
  // src/commands/doctor.ts
8278
- var fs21 = __toESM(require("node:fs"));
8279
- var path19 = __toESM(require("node:path"));
8518
+ var fs22 = __toESM(require("node:fs"));
8519
+ var path20 = __toESM(require("node:path"));
8280
8520
  function getInstalledSkills(settingsPath) {
8281
8521
  try {
8282
- const settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
8522
+ const settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
8283
8523
  return settings.deepstorm?.installedSkills || [];
8284
8524
  } catch {
8285
8525
  return [];
@@ -8288,7 +8528,7 @@ function getInstalledSkills(settingsPath) {
8288
8528
  function runDoctor(targetDir) {
8289
8529
  const checks = [];
8290
8530
  const version = getCliVersion();
8291
- const settingsPath = path19.join(targetDir, ".claude", "settings.json");
8531
+ const settingsPath = path20.join(targetDir, ".claude", "settings.json");
8292
8532
  readDeepStormConfig(settingsPath);
8293
8533
  checks.push({
8294
8534
  name: "CLI \u7248\u672C",
@@ -8296,7 +8536,7 @@ function runDoctor(targetDir) {
8296
8536
  message: `v${version}\uFF08\u8FD0\u884C deepstorm update --check \u68C0\u67E5\u6700\u65B0\u7248\u672C\uFF09`
8297
8537
  });
8298
8538
  let hasDeepStorm = false;
8299
- if (!fs21.existsSync(settingsPath)) {
8539
+ if (!fs22.existsSync(settingsPath)) {
8300
8540
  checks.push({
8301
8541
  name: "\u914D\u7F6E\u6587\u4EF6",
8302
8542
  status: "warn",
@@ -8304,7 +8544,7 @@ function runDoctor(targetDir) {
8304
8544
  });
8305
8545
  } else {
8306
8546
  try {
8307
- const settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
8547
+ const settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
8308
8548
  if (settings.deepstorm) {
8309
8549
  hasDeepStorm = true;
8310
8550
  checks.push({
@@ -8327,20 +8567,20 @@ function runDoctor(targetDir) {
8327
8567
  });
8328
8568
  }
8329
8569
  }
8330
- const skillsDir = path19.join(targetDir, ".claude", "skills");
8331
- if (fs21.existsSync(skillsDir)) {
8332
- const skillDirs = fs21.readdirSync(skillsDir).filter(
8333
- (n) => fs21.statSync(path19.join(skillsDir, n)).isDirectory()
8570
+ const skillsDir = path20.join(targetDir, ".claude", "skills");
8571
+ if (fs22.existsSync(skillsDir)) {
8572
+ const skillDirs = fs22.readdirSync(skillsDir).filter(
8573
+ (n) => fs22.statSync(path20.join(skillsDir, n)).isDirectory()
8334
8574
  );
8335
8575
  let validCount = 0;
8336
8576
  let invalidCount = 0;
8337
8577
  for (const skillName of skillDirs) {
8338
- const skillMd = path19.join(skillsDir, skillName, "SKILL.md");
8339
- if (!fs21.existsSync(skillMd)) {
8578
+ const skillMd = path20.join(skillsDir, skillName, "SKILL.md");
8579
+ if (!fs22.existsSync(skillMd)) {
8340
8580
  invalidCount++;
8341
8581
  continue;
8342
8582
  }
8343
- const content = fs21.readFileSync(skillMd, "utf-8");
8583
+ const content = fs22.readFileSync(skillMd, "utf-8");
8344
8584
  const frontmatter = parseFrontmatter(content);
8345
8585
  if (frontmatter && frontmatter.name) {
8346
8586
  validCount++;
@@ -8370,7 +8610,7 @@ function runDoctor(targetDir) {
8370
8610
  const installedSkills = getInstalledSkills(settingsPath);
8371
8611
  const missingSkills = [];
8372
8612
  for (const skillId of installedSkills) {
8373
- if (!fs21.existsSync(path19.join(skillsDir, skillId))) {
8613
+ if (!fs22.existsSync(path20.join(skillsDir, skillId))) {
8374
8614
  missingSkills.push(skillId);
8375
8615
  }
8376
8616
  }
@@ -8394,10 +8634,10 @@ function runDoctor(targetDir) {
8394
8634
  message: ".claude/skills/ \u4E0D\u5B58\u5728"
8395
8635
  });
8396
8636
  }
8397
- const mcpPath = path19.join(targetDir, ".mcp.json");
8398
- if (fs21.existsSync(mcpPath)) {
8637
+ const mcpPath = path20.join(targetDir, ".mcp.json");
8638
+ if (fs22.existsSync(mcpPath)) {
8399
8639
  try {
8400
- const mcp = JSON.parse(fs21.readFileSync(mcpPath, "utf-8"));
8640
+ const mcp = JSON.parse(fs22.readFileSync(mcpPath, "utf-8"));
8401
8641
  const hasServers = mcp.mcpServers && Object.keys(mcp.mcpServers).length > 0;
8402
8642
  checks.push({
8403
8643
  name: "MCP \u670D\u52A1\u5668",
@@ -8418,12 +8658,12 @@ function runDoctor(targetDir) {
8418
8658
  message: ".mcp.json \u4E0D\u5B58\u5728"
8419
8659
  });
8420
8660
  }
8421
- if (hasDeepStorm && fs21.existsSync(settingsPath)) {
8661
+ if (hasDeepStorm && fs22.existsSync(settingsPath)) {
8422
8662
  try {
8423
- const settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
8663
+ const settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
8424
8664
  const installedMcp = settings.deepstorm?.installedMcpServers;
8425
8665
  if (installedMcp && installedMcp.length > 0) {
8426
- const mcpExists = fs21.existsSync(mcpPath);
8666
+ const mcpExists = fs22.existsSync(mcpPath);
8427
8667
  if (!mcpExists) {
8428
8668
  checks.push({
8429
8669
  name: "MCP \u4E00\u81F4\u6027",
@@ -8432,7 +8672,7 @@ function runDoctor(targetDir) {
8432
8672
  });
8433
8673
  } else {
8434
8674
  try {
8435
- const mcpConfig = JSON.parse(fs21.readFileSync(mcpPath, "utf-8"));
8675
+ const mcpConfig = JSON.parse(fs22.readFileSync(mcpPath, "utf-8"));
8436
8676
  const servers = mcpConfig.mcpServers || {};
8437
8677
  const missing = [];
8438
8678
  for (const toolName of installedMcp) {
@@ -8460,9 +8700,9 @@ function runDoctor(targetDir) {
8460
8700
  } catch {
8461
8701
  }
8462
8702
  }
8463
- if (hasDeepStorm && fs21.existsSync(settingsPath)) {
8703
+ if (hasDeepStorm && fs22.existsSync(settingsPath)) {
8464
8704
  try {
8465
- const settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
8705
+ const settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
8466
8706
  const config = settings.deepstorm;
8467
8707
  const validKeys = loadValidConfigKeys();
8468
8708
  if (validKeys.size > 0 && config) {
@@ -8516,18 +8756,18 @@ function printDoctorReport(report) {
8516
8756
  }
8517
8757
 
8518
8758
  // src/commands/uninstall.ts
8519
- var fs22 = __toESM(require("node:fs"));
8520
- var path20 = __toESM(require("node:path"));
8759
+ var fs23 = __toESM(require("node:fs"));
8760
+ var path21 = __toESM(require("node:path"));
8521
8761
  var import_prompts4 = require("@clack/prompts");
8522
8762
  async function uninstallDeepStorm(targetDir) {
8523
- const settingsPath = path20.join(targetDir, ".claude", "settings.json");
8524
- if (!fs22.existsSync(settingsPath)) {
8763
+ const settingsPath = path21.join(targetDir, ".claude", "settings.json");
8764
+ if (!fs23.existsSync(settingsPath)) {
8525
8765
  console.log("DeepStorm \u5C1A\u672A\u914D\u7F6E\uFF0C\u65E0\u9700\u5378\u8F7D");
8526
8766
  return;
8527
8767
  }
8528
8768
  let hasDeepStorm = false;
8529
8769
  try {
8530
- const settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
8770
+ const settings = JSON.parse(fs23.readFileSync(settingsPath, "utf-8"));
8531
8771
  hasDeepStorm = !!settings.deepstorm;
8532
8772
  } catch {
8533
8773
  }
@@ -8537,14 +8777,14 @@ async function uninstallDeepStorm(targetDir) {
8537
8777
  }
8538
8778
  cleanInstalled(targetDir);
8539
8779
  resetConfig(targetDir);
8540
- const templatesDir = path20.join(targetDir, ".deepstorm", "templates");
8541
- if (fs22.existsSync(templatesDir)) {
8780
+ const templatesDir = path21.join(targetDir, ".deepstorm", "templates");
8781
+ if (fs23.existsSync(templatesDir)) {
8542
8782
  const shouldDelete = await (0, import_prompts4.confirm)({
8543
8783
  message: "\u662F\u5426\u5220\u9664 .deepstorm/templates/ \u76EE\u5F55\uFF1F",
8544
8784
  initialValue: false
8545
8785
  });
8546
8786
  if (shouldDelete) {
8547
- fs22.rmSync(templatesDir, { recursive: true, force: true });
8787
+ fs23.rmSync(templatesDir, { recursive: true, force: true });
8548
8788
  console.log("\u2714 .deepstorm/templates/ \u5DF2\u5220\u9664");
8549
8789
  } else {
8550
8790
  console.log("\u4FDD\u7559 .deepstorm/templates/");
@@ -8555,11 +8795,11 @@ async function uninstallDeepStorm(targetDir) {
8555
8795
 
8556
8796
  // src/index.ts
8557
8797
  var program = new import_commander.Command();
8558
- program.name("deepstorm").description("DeepStorm CLI \u2014 \u4E00\u952E\u914D\u7F6E\u9879\u76EE\u5F00\u53D1\u73AF\u5883").version(getCliVersion());
8798
+ 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");
8559
8799
  function loadRegistry() {
8560
- const registryPath = path21.join(__dirname, "registry.json");
8800
+ const registryPath = path22.join(__dirname, "registry.json");
8561
8801
  try {
8562
- const raw = fs23.readFileSync(registryPath, "utf-8");
8802
+ const raw = fs24.readFileSync(registryPath, "utf-8");
8563
8803
  return JSON.parse(raw);
8564
8804
  } catch {
8565
8805
  return { version: "1", tools: {}, wizards: {}, skills: {} };
@@ -8570,7 +8810,7 @@ registerSetupCommand(program, registry);
8570
8810
  registerPluginBuildCommand(program, registry);
8571
8811
  registerConfigCommand(program, registry);
8572
8812
  registerTemplateCommand(program, registry);
8573
- registerUpdateCommand(program, registry);
8813
+ registerUpdateCommand(program);
8574
8814
  program.command("doctor").description("\u8BCA\u65AD\u9879\u76EE DeepStorm \u914D\u7F6E\u72B6\u6001").action(() => {
8575
8815
  const report = runDoctor(process.cwd());
8576
8816
  printDoctorReport(report);
@@ -807,7 +807,100 @@
807
807
  "questions": []
808
808
  }
809
809
  },
810
- "skills": {},
810
+ "skills": {
811
+ "tide-discuss": {
812
+ "tool": "tide",
813
+ "name": "tide-discuss",
814
+ "description": "BMAD 多角色需求讨论 → PRD 自动生成 → 知识库推送 → 任务拆分 → Issue 创建。当用户讨论产品需求、新功能、改进建议时自动激活,引导用户通过结构化的 BMAD 工作流(分析师→产品经理→架构师→UX设计师→产品负责人)收敛需求并输出 PRD 文档。",
815
+ "hasTemplate": true
816
+ },
817
+ "reef-commit": {
818
+ "tool": "reef",
819
+ "name": "reef-commit",
820
+ "description": "根据当前变更和 OpenSpec 上下文,生成规范的提交信息并创建新提交。用户说「提交代码」「commit」「git push」「提交」「推送」等触发"
821
+ },
822
+ "reef-gen-backend": {
823
+ "tool": "reef",
824
+ "configKey": "reef.backend.language",
825
+ "name": "reef-gen-backend",
826
+ "description": "后端代码编写流程({{reef.backend.language.label}})。编写或生成后端代码时自动加载,编码规范详情引用 reef:reef-style-backend。",
827
+ "hasTemplate": true
828
+ },
829
+ "reef-gen-frontend": {
830
+ "tool": "reef",
831
+ "configKey": "reef.frontend.framework",
832
+ "name": "reef-gen-frontend",
833
+ "description": "前端代码编写流程({{reef.frontend.framework.label}})。编写或生成前端代码时自动加载,编码规范详情引用 reef:reef-style-frontend。",
834
+ "hasTemplate": true
835
+ },
836
+ "reef-harden": {
837
+ "tool": "reef",
838
+ "name": "reef-harden",
839
+ "description": "对 AI 生成的 spec、proposal、design、tasks 等 SDD 文档进行系统性加固。使用四道筛 + 反向 grill + Known Limitations 沉淀。当 AI 刚写完或用户想审查 spec/proposal/design/tasks 文档时触发,尤其当用户说\"加固spec\"、\"按四道筛过\"、\"补不做什么\"、\"补known limitation\" 或需要改进 SDD 文档质量时。"
840
+ },
841
+ "reef-pr": {
842
+ "tool": "reef",
843
+ "name": "reef-pr",
844
+ "description": "将当前分支的变更创建为 GitHub PR。读取 commits 和 OpenSpec 上下文,生成 PR 描述并提交。用户说「创建 PR」「发起 PR」「pull request」「提 PR」「提交 PR」时触发。"
845
+ },
846
+ "reef-review": {
847
+ "tool": "reef",
848
+ "name": "reef-review",
849
+ "description": "对当前分支变更执行前后端代码审查。自动检测变更范围,派发 Sub‑Agent 执行审查并生成结构化报告。",
850
+ "hasTemplate": true
851
+ },
852
+ "reef-scope": {
853
+ "tool": "reef",
854
+ "name": "reef-scope",
855
+ "description": "分支范围检查与拆分 — 在提交代码时验证分支是否涉及多个业务领域,以及自动拆分"
856
+ },
857
+ "reef-start": {
858
+ "tool": "reef",
859
+ "name": "reef-start",
860
+ "description": "从 Issue 跟踪系统或从零需求讨论启动开发生命周期。用户提供 Issue 编号时获取 Issue 详情和相关上下文(PRD 设计稿);无 Issue 时直接走 OpenSpec 自由讨论流程。通过 SDD 工作流生成高质量 spec 文档并进入 TDD 实现阶段。",
861
+ "hasTemplate": true
862
+ },
863
+ "reef-style-backend": {
864
+ "tool": "reef",
865
+ "configKey": "reef.backend.language",
866
+ "name": "reef-style-backend",
867
+ "description": "后端编码规范({{reef.backend.language.label}})。包含实体层次、DTO、Service/Controller/Repository 模式、MapStruct、多租户安全等完整规范。创建/修改后端代码时必须按本技能输出。",
868
+ "hasTemplate": true
869
+ },
870
+ "reef-style-frontend": {
871
+ "tool": "reef",
872
+ "configKey": "reef.frontend.framework",
873
+ "name": "reef-style-frontend",
874
+ "description": "前端编码规范({{reef.frontend.framework.label}})。创建/修改前端代码时必须按本技能输出。",
875
+ "hasTemplate": true
876
+ },
877
+ "reef-testcase": {
878
+ "tool": "reef",
879
+ "name": "reef-testcase",
880
+ "description": "基于 Jira Issue 生成结构化测试用例清单。从 Jira 功能描述和 PRD 上下文中提取测试场景,覆盖正常流程、边界条件、异常场景、验收标准四维。输出格式兼容 superpowers,可辅助生成更完备的单元测试。"
881
+ },
882
+ "sweep-init": {
883
+ "tool": "sweep",
884
+ "name": "sweep-init",
885
+ "description": "初始化 E2E 测试项目骨架。创建目录结构、根据 setup 配置生成对应测试框架配置、读取 MCP 配置、设置多环境变量,标志项目可被 flow-create 和 flow-run 使用。"
886
+ },
887
+ "sweep-plan": {
888
+ "tool": "sweep",
889
+ "name": "sweep-plan",
890
+ "description": "交互式生成 .flow.md 测试意图文档。从 Issue 或 PRD 提取验收标准,通过结构化对话覆盖功能流程、边界条件、异常场景,输出 Markdown 格式的测试流程。",
891
+ "hasTemplate": true
892
+ },
893
+ "sweep-run": {
894
+ "tool": "sweep",
895
+ "name": "sweep-run",
896
+ "description": "执行 .flow.md 测试意图文档。根据项目配置的 E2E 框架(如 Playwright),默认使用混合执行模式(Hybrid Execution):先通过预编译的 .flow.spec.ts 原生 Playwright 执行获得 ~20x 加速,失败后由 AI 驱动诊断和自动修复。支持交互式模块选择、直接参数指定、多环境切换、批量执行、多 Agent 并行。"
897
+ },
898
+ "atoll-ops": {
899
+ "tool": "atoll",
900
+ "name": "atoll-ops",
901
+ "description": "运维辅助 — 部署策略、监控查询、故障排查"
902
+ }
903
+ },
811
904
  "mcpTools": {
812
905
  "github": {
813
906
  "domain": "code-hosting",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstorm/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "DeepStorm CLI — 一键配置项目开发环境",
5
5
  "license": "MIT",
6
6
  "author": "billkang",