@nick848/sf-cli 1.0.2 → 1.0.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.
package/dist/index.d.mts CHANGED
@@ -1772,7 +1772,7 @@ declare function createAgentExecutor(modelService: ModelService, normsManager: N
1772
1772
  declare const FRONTEND_DEV_AGENT: AgentDefinition;
1773
1773
  /**
1774
1774
  * 代码审核 Agent
1775
- * 负责代码质量检查、安全审查、最佳实践建议
1775
+ * 负责代码质量检查、安全审查、最佳实践建议、回归测试
1776
1776
  */
1777
1777
  declare const CODE_REVIEWER_AGENT: AgentDefinition;
1778
1778
  /**
package/dist/index.d.ts CHANGED
@@ -1772,7 +1772,7 @@ declare function createAgentExecutor(modelService: ModelService, normsManager: N
1772
1772
  declare const FRONTEND_DEV_AGENT: AgentDefinition;
1773
1773
  /**
1774
1774
  * 代码审核 Agent
1775
- * 负责代码质量检查、安全审查、最佳实践建议
1775
+ * 负责代码质量检查、安全审查、最佳实践建议、回归测试
1776
1776
  */
1777
1777
  declare const CODE_REVIEWER_AGENT: AgentDefinition;
1778
1778
  /**
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var fs4 = require('fs/promises');
4
- var fsSync = require('fs');
4
+ var fs10 = require('fs');
5
5
  var path4 = require('path');
6
6
  var crypto = require('crypto');
7
7
  var os = require('os');
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
34
34
  }
35
35
 
36
36
  var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
37
- var fsSync__namespace = /*#__PURE__*/_interopNamespace(fsSync);
37
+ var fs10__namespace = /*#__PURE__*/_interopNamespace(fs10);
38
38
  var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
39
39
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
40
40
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
@@ -55,8 +55,8 @@ var KEY_FILE = ".key";
55
55
  function getOrCreateEncryptionKey() {
56
56
  const keyPath = path4__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
57
57
  try {
58
- if (fsSync__namespace.existsSync(keyPath)) {
59
- const keyBase64 = fsSync__namespace.readFileSync(keyPath, "utf-8").trim();
58
+ if (fs10__namespace.existsSync(keyPath)) {
59
+ const keyBase64 = fs10__namespace.readFileSync(keyPath, "utf-8").trim();
60
60
  return Buffer.from(keyBase64, "base64");
61
61
  }
62
62
  } catch {
@@ -64,10 +64,10 @@ function getOrCreateEncryptionKey() {
64
64
  const key = crypto__namespace.randomBytes(32);
65
65
  try {
66
66
  const keyDir = path4__namespace.dirname(keyPath);
67
- if (!fsSync__namespace.existsSync(keyDir)) {
68
- fsSync__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
67
+ if (!fs10__namespace.existsSync(keyDir)) {
68
+ fs10__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
69
69
  }
70
- fsSync__namespace.writeFileSync(keyPath, key.toString("base64"), {
70
+ fs10__namespace.writeFileSync(keyPath, key.toString("base64"), {
71
71
  mode: 384,
72
72
  // 仅所有者可读写
73
73
  encoding: "utf-8"
@@ -2544,10 +2544,10 @@ var FRONTEND_DEV_AGENT = {
2544
2544
  var CODE_REVIEWER_AGENT = {
2545
2545
  id: "code-reviewer",
2546
2546
  name: "\u4EE3\u7801\u5BA1\u6838",
2547
- description: "\u5BA1\u6838\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u89C4\u8303\u6027\uFF0C\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE",
2547
+ description: "\u5BA1\u6838\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u89C4\u8303\u6027\uFF0C\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE",
2548
2548
  icon: "\u{1F50D}",
2549
- version: "1.0.0",
2550
- role: "\u4F60\u662F\u4E00\u540D\u8D44\u6DF1\u4EE3\u7801\u5BA1\u6838\u4E13\u5BB6\uFF0C\u4E13\u6CE8\u4E8E\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u6700\u4F73\u5B9E\u8DF5\u3002\u4F60\u8D1F\u8D23\u5BA1\u67E5\u4EE3\u7801\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE\u3002",
2549
+ version: "1.1.0",
2550
+ role: "\u4F60\u662F\u4E00\u540D\u8D44\u6DF1\u4EE3\u7801\u5BA1\u6838\u4E13\u5BB6\uFF0C\u4E13\u6CE8\u4E8E\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u6700\u4F73\u5B9E\u8DF5\u3002\u4F60\u8D1F\u8D23\u5BA1\u67E5\u4EE3\u7801\u3001\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE\u3002",
2551
2551
  capabilities: [
2552
2552
  {
2553
2553
  id: "quality-review",
@@ -2568,13 +2568,24 @@ var CODE_REVIEWER_AGENT = {
2568
2568
  id: "performance-review",
2569
2569
  name: "\u6027\u80FD\u5BA1\u67E5",
2570
2570
  description: "\u68C0\u67E5\u6027\u80FD\u95EE\u9898\u548C\u4F18\u5316\u5EFA\u8BAE"
2571
+ },
2572
+ {
2573
+ id: "regression-test",
2574
+ name: "\u56DE\u5F52\u6D4B\u8BD5",
2575
+ description: "\u6267\u884C\u6D4B\u8BD5\u5957\u4EF6\uFF0C\u786E\u4FDD\u4FEE\u6539\u4E0D\u7834\u574F\u5DF2\u6709\u529F\u80FD"
2576
+ },
2577
+ {
2578
+ id: "coverage-analysis",
2579
+ name: "\u8986\u76D6\u7387\u5206\u6790",
2580
+ description: "\u5206\u6790\u6D4B\u8BD5\u8986\u76D6\u7387\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE"
2571
2581
  }
2572
2582
  ],
2573
2583
  tools: [
2574
2584
  { name: "read_file", description: "\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9", permission: "full" },
2575
2585
  { name: "glob", description: "\u641C\u7D22\u6587\u4EF6", permission: "full" },
2576
2586
  { name: "search_file_content", description: "\u641C\u7D22\u6587\u4EF6\u5185\u5BB9", permission: "full" },
2577
- { name: "list_directory", description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9", permission: "full" }
2587
+ { name: "list_directory", description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9", permission: "full" },
2588
+ { name: "run_shell_command", description: "\u6267\u884C\u6D4B\u8BD5\u547D\u4EE4", permission: "confirm" }
2578
2589
  ],
2579
2590
  triggers: [
2580
2591
  { type: "workflow", condition: { workflowStep: "apply" }, priority: 10 },
@@ -2585,6 +2596,7 @@ var CODE_REVIEWER_AGENT = {
2585
2596
  protectedPaths: ["node_modules", ".git"]
2586
2597
  },
2587
2598
  behavior: {
2599
+ requireConfirmation: ["run_shell_command"],
2588
2600
  autoCommit: false
2589
2601
  }
2590
2602
  },
@@ -2593,6 +2605,7 @@ var CODE_REVIEWER_AGENT = {
2593
2605
  ## \u4F60\u7684\u804C\u8D23
2594
2606
  - \u5BA1\u67E5\u4EE3\u7801\u8D28\u91CF\u548C\u53EF\u7EF4\u62A4\u6027
2595
2607
  - \u68C0\u67E5\u5B89\u5168\u6F0F\u6D1E\u548C\u98CE\u9669
2608
+ - \u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u786E\u4FDD\u4FEE\u6539\u4E0D\u7834\u574F\u5DF2\u6709\u529F\u80FD
2596
2609
  - \u63D0\u4F9B\u5177\u4F53\u7684\u6539\u8FDB\u5EFA\u8BAE
2597
2610
  - \u786E\u4FDD\u9075\u5FAA\u6700\u4F73\u5B9E\u8DF5
2598
2611
 
@@ -2601,8 +2614,20 @@ var CODE_REVIEWER_AGENT = {
2601
2614
  2. **\u5B89\u5168\u6027**: XSS\u3001\u6CE8\u5165\u3001\u654F\u611F\u6570\u636E\u5904\u7406
2602
2615
  3. **\u6027\u80FD**: \u7B97\u6CD5\u6548\u7387\u3001\u5185\u5B58\u4F7F\u7528\u3001\u6E32\u67D3\u4F18\u5316
2603
2616
  4. **\u89C4\u8303\u6027**: \u547D\u540D\u3001\u683C\u5F0F\u3001\u6CE8\u91CA
2617
+ 5. **\u6D4B\u8BD5\u8986\u76D6**: \u56DE\u5F52\u6D4B\u8BD5\u7ED3\u679C\u3001\u8986\u76D6\u7387\u5206\u6790
2618
+
2619
+ ## \u56DE\u5F52\u6D4B\u8BD5\u6D41\u7A0B
2620
+ 1. \u6267\u884C \`npm test -- --run\` \u8FD0\u884C\u6D4B\u8BD5\u5957\u4EF6
2621
+ 2. \u5206\u6790\u6D4B\u8BD5\u7ED3\u679C\uFF0C\u8BC6\u522B\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B
2622
+ 3. \u5982\u679C\u6D4B\u8BD5\u5931\u8D25\uFF0C\u963B\u6B62\u5F52\u6863\u5E76\u63D0\u793A\u4FEE\u590D
2623
+ 4. \u63D0\u4F9B\u8986\u76D6\u7387\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE
2604
2624
 
2605
2625
  ## \u8F93\u51FA\u683C\u5F0F
2626
+ ### \u56DE\u5F52\u6D4B\u8BD5\u7ED3\u679C
2627
+ - \u6D4B\u8BD5\u901A\u8FC7/\u5931\u8D25\u72B6\u6001
2628
+ - \u901A\u8FC7/\u5931\u8D25\u6570\u91CF
2629
+ - \u8986\u76D6\u7387\u767E\u5206\u6BD4
2630
+
2606
2631
  ### \u5BA1\u67E5\u7ED3\u679C
2607
2632
  - \u901A\u8FC7/\u9700\u4FEE\u6539/\u4E0D\u901A\u8FC7
2608
2633
 
@@ -2628,7 +2653,7 @@ var CODE_REVIEWER_AGENT = {
2628
2653
  ## \u4E0A\u4E0B\u6587
2629
2654
  {{context}}
2630
2655
 
2631
- \u8BF7\u5BF9\u4EE5\u4E0A\u6587\u4EF6\u8FDB\u884C\u5168\u9762\u5BA1\u67E5\uFF0C\u63D0\u4F9B\u8BE6\u7EC6\u7684\u5BA1\u67E5\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE\u3002`,
2656
+ \u8BF7\u5BF9\u4EE5\u4E0A\u6587\u4EF6\u8FDB\u884C\u5168\u9762\u5BA1\u67E5\uFF0C\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u5E76\u63D0\u4F9B\u8BE6\u7EC6\u7684\u5BA1\u67E5\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE\u3002`,
2632
2657
  outputFormat: {
2633
2658
  type: "markdown"
2634
2659
  }
@@ -5618,8 +5643,8 @@ var CommandParser = class {
5618
5643
  };
5619
5644
  }
5620
5645
  parseAtPath(input) {
5621
- const path13 = input.slice(1).trim();
5622
- if (!path13) {
5646
+ const path14 = input.slice(1).trim();
5647
+ if (!path14) {
5623
5648
  return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
5624
5649
  }
5625
5650
  return {
@@ -5627,7 +5652,7 @@ var CommandParser = class {
5627
5652
  command: {
5628
5653
  type: "at" /* AT */,
5629
5654
  raw: input,
5630
- path: path13
5655
+ path: path14
5631
5656
  }
5632
5657
  };
5633
5658
  }
@@ -6471,10 +6496,26 @@ function createSpinner(message) {
6471
6496
  stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
6472
6497
  };
6473
6498
  }
6474
- var packageJsonPath = path4__namespace.resolve(__dirname, "../../package.json");
6475
- var packageJson = JSON.parse(fsSync__namespace.readFileSync(packageJsonPath, "utf-8"));
6476
- var CURRENT_VERSION = packageJson.version;
6477
- var PACKAGE_NAME = packageJson.name;
6499
+ function getPackageInfo() {
6500
+ const possiblePaths = [
6501
+ path4__namespace.resolve(__dirname, "..", "..", "package.json"),
6502
+ path4__namespace.resolve(__dirname, "..", "..", "..", "package.json")
6503
+ ];
6504
+ for (const pkgPath of possiblePaths) {
6505
+ try {
6506
+ if (fs10__namespace.existsSync(pkgPath)) {
6507
+ const content = fs10__namespace.readFileSync(pkgPath, "utf-8");
6508
+ return JSON.parse(content);
6509
+ }
6510
+ } catch {
6511
+ continue;
6512
+ }
6513
+ }
6514
+ return { version: "1.0.0", name: "@nick848/sf-cli" };
6515
+ }
6516
+ var packageInfo = getPackageInfo();
6517
+ var CURRENT_VERSION = packageInfo.version;
6518
+ var PACKAGE_NAME = packageInfo.name;
6478
6519
  async function handleUpdate(args, ctx) {
6479
6520
  const options = {
6480
6521
  check: args.includes("--check") || args.includes("-c"),
@@ -6928,6 +6969,78 @@ function extractTitle(requirement) {
6928
6969
  return requirement.slice(0, 47) + "...";
6929
6970
  }
6930
6971
  var autoScheduleEnabled = true;
6972
+ var DEFAULT_REGRESSION_CONFIG = {
6973
+ enabled: true,
6974
+ command: "npm test -- --run",
6975
+ timeout: 12e4,
6976
+ // 2分钟
6977
+ coverageThreshold: 80
6978
+ };
6979
+ async function runRegressionTest(workingDirectory, config = DEFAULT_REGRESSION_CONFIG) {
6980
+ const startTime = Date.now();
6981
+ const result = {
6982
+ success: false,
6983
+ passed: 0,
6984
+ failed: 0,
6985
+ total: 0,
6986
+ duration: 0,
6987
+ output: "",
6988
+ errors: []
6989
+ };
6990
+ return new Promise((resolve4) => {
6991
+ const proc = child_process.spawn(config.command, [], {
6992
+ cwd: workingDirectory,
6993
+ shell: true,
6994
+ stdio: "pipe"
6995
+ });
6996
+ let stdout = "";
6997
+ let stderr = "";
6998
+ proc.stdout?.on("data", (data) => {
6999
+ stdout += data.toString();
7000
+ });
7001
+ proc.stderr?.on("data", (data) => {
7002
+ stderr += data.toString();
7003
+ });
7004
+ const timeout = setTimeout(() => {
7005
+ proc.kill();
7006
+ result.errors.push("\u6D4B\u8BD5\u8D85\u65F6");
7007
+ result.output = stdout + stderr;
7008
+ result.duration = Date.now() - startTime;
7009
+ resolve4(result);
7010
+ }, config.timeout);
7011
+ proc.on("close", (code) => {
7012
+ clearTimeout(timeout);
7013
+ result.output = stdout + stderr;
7014
+ result.duration = Date.now() - startTime;
7015
+ const passMatch = stdout.match(/(\d+)\s+(?:passed|tests?\s+passed)/i);
7016
+ const failMatch = stdout.match(/(\d+)\s+(?:failed|tests?\s+failed)/i);
7017
+ const totalMatch = stdout.match(/Tests?:\s*(\d+)/i);
7018
+ if (passMatch) {
7019
+ result.passed = parseInt(passMatch[1], 10);
7020
+ }
7021
+ if (failMatch) {
7022
+ result.failed = parseInt(failMatch[1], 10);
7023
+ }
7024
+ if (totalMatch) {
7025
+ result.total = parseInt(totalMatch[1], 10);
7026
+ } else {
7027
+ result.total = result.passed + result.failed;
7028
+ }
7029
+ const coverageMatch = stdout.match(/All files[^\d]*(\d+(?:\.\d+)?)/);
7030
+ if (coverageMatch) {
7031
+ result.coverage = parseFloat(coverageMatch[1]);
7032
+ }
7033
+ result.success = code === 0 && result.failed === 0;
7034
+ resolve4(result);
7035
+ });
7036
+ proc.on("error", (err) => {
7037
+ clearTimeout(timeout);
7038
+ result.errors.push(err.message);
7039
+ result.duration = Date.now() - startTime;
7040
+ resolve4(result);
7041
+ });
7042
+ });
7043
+ }
6931
7044
  async function handleOpsx(command, args, ctx) {
6932
7045
  const step = command.replace("opsx:", "");
6933
7046
  const workflow = new WorkflowEngine();
@@ -6942,7 +7055,7 @@ async function handleOpsx(command, args, ctx) {
6942
7055
  case "apply":
6943
7056
  return handleApply(workflow);
6944
7057
  case "archive":
6945
- return handleArchive(workflow, args);
7058
+ return handleArchive(workflow, args, ctx);
6946
7059
  case "propose":
6947
7060
  return handlePropose(workflow, args);
6948
7061
  case "status":
@@ -6957,12 +7070,50 @@ async function handleOpsx(command, args, ctx) {
6957
7070
  return handleNext(workflow);
6958
7071
  case "auto":
6959
7072
  return handleAutoSchedule(args);
7073
+ case "test":
7074
+ return handleRegressionTest(ctx);
6960
7075
  default:
6961
7076
  return {
6962
7077
  output: chalk9__default.default.red(`\u672A\u77E5\u7684OpenSpec\u547D\u4EE4: /${command}`)
6963
7078
  };
6964
7079
  }
6965
7080
  }
7081
+ async function handleRegressionTest(ctx) {
7082
+ const lines = [];
7083
+ lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u56DE\u5F52\u6D4B\u8BD5..."));
7084
+ lines.push(chalk9__default.default.gray(` \u5DE5\u4F5C\u76EE\u5F55: ${ctx.options.workingDirectory}`));
7085
+ lines.push("");
7086
+ const result = await runRegressionTest(ctx.options.workingDirectory);
7087
+ lines.push(chalk9__default.default.gray("\u2500".repeat(50)));
7088
+ if (result.success) {
7089
+ lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
7090
+ } else {
7091
+ lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
7092
+ }
7093
+ lines.push("");
7094
+ lines.push(chalk9__default.default.cyan("\u6D4B\u8BD5\u7ED3\u679C:"));
7095
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${result.passed}`));
7096
+ lines.push(chalk9__default.default.gray(` \u5931\u8D25: ${result.failed}`));
7097
+ lines.push(chalk9__default.default.gray(` \u603B\u8BA1: ${result.total}`));
7098
+ lines.push(chalk9__default.default.gray(` \u8017\u65F6: ${(result.duration / 1e3).toFixed(2)}s`));
7099
+ if (result.coverage !== void 0) {
7100
+ const coverageColor = result.coverage >= 80 ? chalk9__default.default.green : result.coverage >= 60 ? chalk9__default.default.yellow : chalk9__default.default.red;
7101
+ lines.push(coverageColor(` \u8986\u76D6\u7387: ${result.coverage}%`));
7102
+ }
7103
+ if (result.errors.length > 0) {
7104
+ lines.push("");
7105
+ lines.push(chalk9__default.default.red("\u9519\u8BEF\u4FE1\u606F:"));
7106
+ for (const error of result.errors) {
7107
+ lines.push(chalk9__default.default.gray(` - ${error}`));
7108
+ }
7109
+ }
7110
+ if (result.failed > 0) {
7111
+ lines.push("");
7112
+ lines.push(chalk9__default.default.yellow("\u26A0 \u5B58\u5728\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u8BF7\u68C0\u67E5\u5E76\u4FEE\u590D"));
7113
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
7114
+ }
7115
+ return { output: lines.join("\n") };
7116
+ }
6966
7117
  function handleAutoSchedule(args) {
6967
7118
  const action = args[0]?.toLowerCase();
6968
7119
  if (!action) {
@@ -7092,13 +7243,70 @@ async function handleArchive(workflow, args, ctx) {
7092
7243
  ${generateConfirmationPrompt(confirmation.point)}`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /opsx:confirm code-review \u786E\u8BA4\u540E\u5F52\u6863")
7093
7244
  };
7094
7245
  }
7246
+ const lines = [];
7247
+ lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u5F52\u6863\u524D\u56DE\u5F52\u6D4B\u8BD5..."));
7248
+ lines.push("");
7249
+ const testResult = await runRegressionTest(ctx.options.workingDirectory);
7250
+ if (!testResult.success) {
7251
+ lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
7252
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u5931\u8D25: ${testResult.failed} | \u603B\u8BA1: ${testResult.total}`));
7253
+ lines.push("");
7254
+ lines.push(chalk9__default.default.yellow("\u26A0 \u5F52\u6863\u88AB\u963B\u6B62"));
7255
+ lines.push(chalk9__default.default.gray("\n\u8BF7\u4FEE\u590D\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\u540E\u91CD\u8BD5"));
7256
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
7257
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:test \u53EF\u5355\u72EC\u8FD0\u884C\u56DE\u5F52\u6D4B\u8BD5"));
7258
+ return { output: lines.join("\n") };
7259
+ }
7260
+ lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
7261
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u8017\u65F6: ${(testResult.duration / 1e3).toFixed(2)}s`));
7262
+ lines.push("");
7095
7263
  const changeId = state.id;
7096
7264
  const summary = args.join(" ") || "\u5B8C\u6210\u53D8\u66F4";
7097
7265
  await workflow.archive(summary);
7098
- return {
7099
- output: chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5F52\u6863") + chalk9__default.default.gray(`
7100
- \u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55")
7101
- };
7266
+ await updateChangelog(ctx.options.workingDirectory, summary, changeId);
7267
+ lines.push(chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5F52\u6863") + chalk9__default.default.gray(`
7268
+ \u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55") + chalk9__default.default.gray("\nCHANGELOG.md \u5DF2\u66F4\u65B0"));
7269
+ return { output: lines.join("\n") };
7270
+ }
7271
+ async function updateChangelog(workingDirectory, summary, changeId) {
7272
+ try {
7273
+ const changelogPath = path4__namespace.join(workingDirectory, "CHANGELOG.md");
7274
+ const pkgPath = path4__namespace.join(workingDirectory, "package.json");
7275
+ let version = "1.0.0";
7276
+ try {
7277
+ const pkgContent = fs10__namespace.readFileSync(pkgPath, "utf-8");
7278
+ const pkg = JSON.parse(pkgContent);
7279
+ version = pkg.version || "1.0.0";
7280
+ } catch {
7281
+ }
7282
+ const today = /* @__PURE__ */ new Date();
7283
+ const dateStr = today.toISOString().split("T")[0];
7284
+ const entry = `
7285
+ ## v${version} (${dateStr})
7286
+
7287
+ **\u53D8\u66F4\u5185\u5BB9**
7288
+
7289
+ - ${summary} (${changeId})
7290
+ `;
7291
+ if (fs10__namespace.existsSync(changelogPath)) {
7292
+ const content = fs10__namespace.readFileSync(changelogPath, "utf-8");
7293
+ const versionPattern = /^## v\d+\.\d+\.\d+/m;
7294
+ const match = content.match(versionPattern);
7295
+ if (match && match.index !== void 0) {
7296
+ const newContent = content.slice(0, match.index) + entry + content.slice(match.index);
7297
+ fs10__namespace.writeFileSync(changelogPath, newContent, "utf-8");
7298
+ } else {
7299
+ fs10__namespace.appendFileSync(changelogPath, entry, "utf-8");
7300
+ }
7301
+ } else {
7302
+ const header = `# Changelog
7303
+
7304
+ All notable changes to this project will be documented in this file.
7305
+ `;
7306
+ fs10__namespace.writeFileSync(changelogPath, header + entry, "utf-8");
7307
+ }
7308
+ } catch (error) {
7309
+ }
7102
7310
  }
7103
7311
  async function handlePropose(workflow, args, ctx) {
7104
7312
  const state = workflow.getState();
@@ -7289,9 +7497,25 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
7289
7497
  }
7290
7498
 
7291
7499
  // src/commands/runner.ts
7292
- var packageJsonPath2 = path4__namespace.resolve(__dirname, "../../package.json");
7293
- var packageJson2 = JSON.parse(fsSync__namespace.readFileSync(packageJsonPath2, "utf-8"));
7294
- var VERSION2 = packageJson2.version;
7500
+ function getVersion() {
7501
+ const possiblePaths = [
7502
+ path4__namespace.resolve(__dirname, "..", "..", "package.json"),
7503
+ path4__namespace.resolve(__dirname, "..", "..", "..", "package.json")
7504
+ ];
7505
+ for (const pkgPath of possiblePaths) {
7506
+ try {
7507
+ if (fs10__namespace.existsSync(pkgPath)) {
7508
+ const content = fs10__namespace.readFileSync(pkgPath, "utf-8");
7509
+ const pkg = JSON.parse(content);
7510
+ return pkg.version;
7511
+ }
7512
+ } catch {
7513
+ continue;
7514
+ }
7515
+ }
7516
+ return "1.0.0";
7517
+ }
7518
+ var VERSION2 = getVersion();
7295
7519
  async function runSlashCommand(command, args, ctx) {
7296
7520
  const normalizedCommand = normalizeCommand(command);
7297
7521
  switch (normalizedCommand) {