@nick848/sf-cli 1.0.2 → 1.0.4
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/CHANGELOG.md +59 -0
- package/README.md +4 -23
- package/dist/cli/index.js +767 -116
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +746 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +745 -112
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fs4 = require('fs/promises');
|
|
4
|
-
var
|
|
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
|
|
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 (
|
|
59
|
-
const keyBase64 =
|
|
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 (!
|
|
68
|
-
|
|
67
|
+
if (!fs10__namespace.existsSync(keyDir)) {
|
|
68
|
+
fs10__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
|
|
69
69
|
}
|
|
70
|
-
|
|
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.
|
|
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
|
}
|
|
@@ -3604,12 +3629,20 @@ function getScheduleRuleDescription(step) {
|
|
|
3604
3629
|
var DEFAULT_CONFIRMATION_POINTS = [
|
|
3605
3630
|
{
|
|
3606
3631
|
type: "spec-review",
|
|
3607
|
-
name: "\u89C4\
|
|
3608
|
-
description: "\u89C4\
|
|
3632
|
+
name: "\u89C4\u683C\u786E\u8BA4",
|
|
3633
|
+
description: "\u89C4\u683C\u62C6\u5206\u5DF2\u5B8C\u6210\uFF0C\u8BF7\u786E\u8BA4\u89C4\u683C\u6587\u4EF6\u540E\u7EE7\u7EED",
|
|
3609
3634
|
triggerStep: "explore",
|
|
3610
3635
|
targetStep: "new",
|
|
3611
3636
|
required: true
|
|
3612
3637
|
},
|
|
3638
|
+
{
|
|
3639
|
+
type: "spec-review",
|
|
3640
|
+
name: "\u89C4\u683C\u786E\u8BA4",
|
|
3641
|
+
description: "\u89C4\u683C\u62C6\u5206\u5DF2\u5B8C\u6210\uFF0C\u8BF7\u786E\u8BA4\u89C4\u683C\u6587\u4EF6\u540E\u7EE7\u7EED",
|
|
3642
|
+
triggerStep: "propose",
|
|
3643
|
+
targetStep: "apply",
|
|
3644
|
+
required: true
|
|
3645
|
+
},
|
|
3613
3646
|
{
|
|
3614
3647
|
type: "architecture",
|
|
3615
3648
|
name: "\u67B6\u6784\u8C03\u6574\u786E\u8BA4",
|
|
@@ -3645,19 +3678,15 @@ var ConfirmationManager = class {
|
|
|
3645
3678
|
confirmationPoints;
|
|
3646
3679
|
confirmations = /* @__PURE__ */ new Map();
|
|
3647
3680
|
constructor(customPoints) {
|
|
3648
|
-
|
|
3649
|
-
this.confirmationPoints = new Map(points.map((p) => [p.type, p]));
|
|
3681
|
+
this.confirmationPoints = customPoints || DEFAULT_CONFIRMATION_POINTS;
|
|
3650
3682
|
}
|
|
3651
3683
|
/**
|
|
3652
3684
|
* 获取指定阶段的确认点
|
|
3653
3685
|
*/
|
|
3654
3686
|
getConfirmationPointForTransition(from, to) {
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
}
|
|
3659
|
-
}
|
|
3660
|
-
return void 0;
|
|
3687
|
+
return this.confirmationPoints.find(
|
|
3688
|
+
(point) => point.triggerStep === from && point.targetStep === to
|
|
3689
|
+
);
|
|
3661
3690
|
}
|
|
3662
3691
|
/**
|
|
3663
3692
|
* 检查是否需要确认
|
|
@@ -3670,7 +3699,7 @@ var ConfirmationManager = class {
|
|
|
3670
3699
|
* 获取确认点详情
|
|
3671
3700
|
*/
|
|
3672
3701
|
getConfirmationPoint(type) {
|
|
3673
|
-
return this.confirmationPoints.
|
|
3702
|
+
return this.confirmationPoints.find((point) => point.type === type);
|
|
3674
3703
|
}
|
|
3675
3704
|
/**
|
|
3676
3705
|
* 记录确认
|
|
@@ -3714,14 +3743,14 @@ var ConfirmationManager = class {
|
|
|
3714
3743
|
* 获取所有确认点
|
|
3715
3744
|
*/
|
|
3716
3745
|
getAllConfirmationPoints() {
|
|
3717
|
-
return
|
|
3746
|
+
return [...this.confirmationPoints];
|
|
3718
3747
|
}
|
|
3719
3748
|
/**
|
|
3720
3749
|
* 获取指定阶段需要清除的确认点
|
|
3721
3750
|
*/
|
|
3722
3751
|
getConfirmationsToClear(targetStep) {
|
|
3723
3752
|
const types = [];
|
|
3724
|
-
for (const point of this.confirmationPoints
|
|
3753
|
+
for (const point of this.confirmationPoints) {
|
|
3725
3754
|
const stepOrder = ["explore", "new", "continue", "propose", "apply", "archive"];
|
|
3726
3755
|
const targetIndex = stepOrder.indexOf(targetStep);
|
|
3727
3756
|
const triggerIndex = stepOrder.indexOf(point.triggerStep);
|
|
@@ -3844,6 +3873,26 @@ var WorkflowEngine = class {
|
|
|
3844
3873
|
devStandards: this.devStandards
|
|
3845
3874
|
};
|
|
3846
3875
|
}
|
|
3876
|
+
/**
|
|
3877
|
+
* 获取规格文件路径
|
|
3878
|
+
*/
|
|
3879
|
+
getSpecFilePath() {
|
|
3880
|
+
if (!this.state) return null;
|
|
3881
|
+
return path4__namespace.join(this.openspecPath, "changes", `${this.state.id}-spec.md`);
|
|
3882
|
+
}
|
|
3883
|
+
/**
|
|
3884
|
+
* 检查规格文件是否存在
|
|
3885
|
+
*/
|
|
3886
|
+
async hasSpecFile() {
|
|
3887
|
+
const specPath = this.getSpecFilePath();
|
|
3888
|
+
if (!specPath) return false;
|
|
3889
|
+
try {
|
|
3890
|
+
await fs4__namespace.access(specPath);
|
|
3891
|
+
return true;
|
|
3892
|
+
} catch {
|
|
3893
|
+
return false;
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3847
3896
|
/**
|
|
3848
3897
|
* 启动新工作流
|
|
3849
3898
|
*/
|
|
@@ -5618,8 +5667,8 @@ var CommandParser = class {
|
|
|
5618
5667
|
};
|
|
5619
5668
|
}
|
|
5620
5669
|
parseAtPath(input) {
|
|
5621
|
-
const
|
|
5622
|
-
if (!
|
|
5670
|
+
const path14 = input.slice(1).trim();
|
|
5671
|
+
if (!path14) {
|
|
5623
5672
|
return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
|
|
5624
5673
|
}
|
|
5625
5674
|
return {
|
|
@@ -5627,7 +5676,7 @@ var CommandParser = class {
|
|
|
5627
5676
|
command: {
|
|
5628
5677
|
type: "at" /* AT */,
|
|
5629
5678
|
raw: input,
|
|
5630
|
-
path:
|
|
5679
|
+
path: path14
|
|
5631
5680
|
}
|
|
5632
5681
|
};
|
|
5633
5682
|
}
|
|
@@ -6471,10 +6520,26 @@ function createSpinner(message) {
|
|
|
6471
6520
|
stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
|
|
6472
6521
|
};
|
|
6473
6522
|
}
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6523
|
+
function getPackageInfo() {
|
|
6524
|
+
const possiblePaths = [
|
|
6525
|
+
path4__namespace.resolve(__dirname, "..", "..", "package.json"),
|
|
6526
|
+
path4__namespace.resolve(__dirname, "..", "..", "..", "package.json")
|
|
6527
|
+
];
|
|
6528
|
+
for (const pkgPath of possiblePaths) {
|
|
6529
|
+
try {
|
|
6530
|
+
if (fs10__namespace.existsSync(pkgPath)) {
|
|
6531
|
+
const content = fs10__namespace.readFileSync(pkgPath, "utf-8");
|
|
6532
|
+
return JSON.parse(content);
|
|
6533
|
+
}
|
|
6534
|
+
} catch {
|
|
6535
|
+
continue;
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6538
|
+
return { version: "1.0.0", name: "@nick848/sf-cli" };
|
|
6539
|
+
}
|
|
6540
|
+
var packageInfo = getPackageInfo();
|
|
6541
|
+
var CURRENT_VERSION = packageInfo.version;
|
|
6542
|
+
var PACKAGE_NAME = packageInfo.name;
|
|
6478
6543
|
async function handleUpdate(args, ctx) {
|
|
6479
6544
|
const options = {
|
|
6480
6545
|
check: args.includes("--check") || args.includes("-c"),
|
|
@@ -6691,16 +6756,23 @@ async function handleNew(args, ctx) {
|
|
|
6691
6756
|
if (workflowEngine) {
|
|
6692
6757
|
const existingState = workflowEngine.getState();
|
|
6693
6758
|
if (existingState && existingState.status === "running") {
|
|
6759
|
+
if (existingState.currentStep === "explore" || existingState.currentStep === "propose") {
|
|
6760
|
+
const specPath = path4__namespace.join(workingDir, "openspec", "changes", `${existingState.id}-spec.md`);
|
|
6761
|
+
if (fs10__namespace.existsSync(specPath)) {
|
|
6762
|
+
return {
|
|
6763
|
+
output: chalk9__default.default.yellow("\u5F53\u524D\u5DE5\u4F5C\u6D41\u6B63\u5728\u7B49\u5F85\u89C4\u683C\u786E\u8BA4") + chalk9__default.default.gray(`
|
|
6764
|
+
|
|
6765
|
+
\u5DE5\u4F5C\u6D41: ${existingState.title}`) + chalk9__default.default.gray(`
|
|
6766
|
+
\u53D8\u66F4ID: ${existingState.id}`) + chalk9__default.default.cyan("\n\n\u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210:") + chalk9__default.default.white(`
|
|
6767
|
+
${specPath}`) + chalk9__default.default.yellow("\n\n\u8BF7\u786E\u8BA4\u89C4\u683C\u540E\u7EE7\u7EED:") + chalk9__default.default.gray("\n /opsx:confirm spec-review - \u786E\u8BA4\u89C4\u683C") + chalk9__default.default.gray("\n /opsx:status - \u67E5\u770B\u8BE6\u60C5")
|
|
6768
|
+
};
|
|
6769
|
+
}
|
|
6770
|
+
}
|
|
6694
6771
|
return {
|
|
6695
6772
|
output: chalk9__default.default.yellow("\u5F53\u524D\u5DF2\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41") + chalk9__default.default.gray(`
|
|
6696
6773
|
|
|
6697
6774
|
\u5DE5\u4F5C\u6D41: ${existingState.title}`) + chalk9__default.default.gray(`
|
|
6698
|
-
\u5F53\u524D\u9636\u6BB5: ${existingState.currentStep}`) + chalk9__default.default.gray(
|
|
6699
|
-
|
|
6700
|
-
\u9009\u9879:`) + chalk9__default.default.gray(`
|
|
6701
|
-
1. \u7EE7\u7EED\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:${existingState.currentStep}`) + chalk9__default.default.gray(`
|
|
6702
|
-
2. \u53D6\u6D88\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:cancel`) + chalk9__default.default.gray(`
|
|
6703
|
-
3. \u67E5\u770B\u5DE5\u4F5C\u6D41\u72B6\u6001: /opsx:status`)
|
|
6775
|
+
\u5F53\u524D\u9636\u6BB5: ${existingState.currentStep}`) + chalk9__default.default.gray("\n\n\u9009\u9879:") + chalk9__default.default.gray("\n 1. \u7EE7\u7EED\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:status") + chalk9__default.default.gray("\n 2. \u53D6\u6D88\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:cancel")
|
|
6704
6776
|
};
|
|
6705
6777
|
}
|
|
6706
6778
|
}
|
|
@@ -6715,6 +6787,7 @@ async function handleNew(args, ctx) {
|
|
|
6715
6787
|
async function newFeature(options, workingDir, workflowEngine) {
|
|
6716
6788
|
const cwd = workingDir || process.cwd();
|
|
6717
6789
|
const { requirement, forceComplexity } = options;
|
|
6790
|
+
const lines = [];
|
|
6718
6791
|
try {
|
|
6719
6792
|
const stats = await fs4__namespace.stat(cwd);
|
|
6720
6793
|
if (!stats.isDirectory()) {
|
|
@@ -6722,51 +6795,283 @@ async function newFeature(options, workingDir, workflowEngine) {
|
|
|
6722
6795
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
6723
6796
|
};
|
|
6724
6797
|
}
|
|
6725
|
-
} catch
|
|
6798
|
+
} catch {
|
|
6726
6799
|
return {
|
|
6727
6800
|
output: chalk9__default.default.red(`\u9519\u8BEF: \u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6743\u9650\u8BBF\u95EE ${cwd}`)
|
|
6728
6801
|
};
|
|
6729
6802
|
}
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6803
|
+
lines.push(chalk9__default.default.cyan("\u{1F50D} \u5206\u6790\u9879\u76EE..."));
|
|
6804
|
+
const context = await readProjectContext(cwd);
|
|
6805
|
+
lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${context.name}`));
|
|
6806
|
+
lines.push(chalk9__default.default.gray(` \u7C7B\u578B: ${context.type}`));
|
|
6807
|
+
lines.push(chalk9__default.default.gray(` \u6846\u67B6: ${context.framework || "\u672A\u8BC6\u522B"}`));
|
|
6808
|
+
lines.push("");
|
|
6809
|
+
lines.push(chalk9__default.default.cyan("\u{1F4CA} \u5206\u6790\u9700\u6C42\u590D\u6742\u5EA6..."));
|
|
6810
|
+
const analysis = forceComplexity ? createForcedAnalysis(forceComplexity) : analyzeComplexity(requirement, context);
|
|
6811
|
+
lines.push(chalk9__default.default.gray(` \u590D\u6742\u5EA6: ${analysis.score}/10`));
|
|
6812
|
+
lines.push(chalk9__default.default.gray(` \u6D41\u7A0B\u7C7B\u578B: ${analysis.recommendation === "complex" ? "\u590D\u6742\u6D41\u7A0B" : "\u7B80\u5355\u6D41\u7A0B"}`));
|
|
6813
|
+
for (const factor of analysis.factors) {
|
|
6814
|
+
lines.push(chalk9__default.default.gray(` - ${factor}`));
|
|
6815
|
+
}
|
|
6816
|
+
lines.push("");
|
|
6817
|
+
lines.push(chalk9__default.default.cyan("\u{1F4CB} \u521D\u59CB\u5316\u5DE5\u4F5C\u6D41..."));
|
|
6818
|
+
const workflow = workflowEngine || new WorkflowEngine();
|
|
6819
|
+
if (!workflowEngine) {
|
|
6820
|
+
await workflow.initialize(cwd);
|
|
6821
|
+
}
|
|
6822
|
+
const state = await workflow.start(requirement, analysis.score, {
|
|
6823
|
+
title: extractTitle(requirement)
|
|
6824
|
+
});
|
|
6825
|
+
lines.push(chalk9__default.default.gray(` \u53D8\u66F4ID: ${state.id}`));
|
|
6826
|
+
lines.push(chalk9__default.default.gray(` \u5DE5\u4F5C\u6D41: ${state.type}`));
|
|
6827
|
+
lines.push("");
|
|
6828
|
+
lines.push(chalk9__default.default.cyan("\u{1F4DD} \u751F\u6210\u89C4\u683C\u62C6\u5206..."));
|
|
6829
|
+
const spec = await generateSpec(requirement, context, analysis, state.id);
|
|
6830
|
+
const specPath = await saveSpecFile(cwd, spec);
|
|
6831
|
+
lines.push(chalk9__default.default.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
6832
|
+
lines.push(chalk9__default.default.gray(` \u8DEF\u5F84: ${specPath}`));
|
|
6833
|
+
lines.push("");
|
|
6834
|
+
lines.push(chalk9__default.default.cyan.bold("\u{1F4CB} \u89C4\u683C\u6982\u89C8:"));
|
|
6835
|
+
lines.push(chalk9__default.default.white(`
|
|
6836
|
+
${spec.summary}`));
|
|
6837
|
+
if (spec.items.length > 0) {
|
|
6838
|
+
lines.push("");
|
|
6839
|
+
lines.push(chalk9__default.default.cyan(" \u4EFB\u52A1\u62C6\u5206:"));
|
|
6840
|
+
for (const item of spec.items) {
|
|
6841
|
+
const priorityIcon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
6842
|
+
lines.push(chalk9__default.default.gray(` ${priorityIcon} [${item.id}] ${item.title}`));
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
if (spec.risks.length > 0) {
|
|
6846
|
+
lines.push("");
|
|
6847
|
+
lines.push(chalk9__default.default.yellow(" \u26A0\uFE0F \u98CE\u9669\u63D0\u793A:"));
|
|
6848
|
+
for (const risk of spec.risks) {
|
|
6849
|
+
lines.push(chalk9__default.default.gray(` - ${risk}`));
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
lines.push("");
|
|
6853
|
+
lines.push(chalk9__default.default.yellow.bold("\u23F3 \u7B49\u5F85\u89C4\u683C\u786E\u8BA4"));
|
|
6854
|
+
lines.push(chalk9__default.default.gray("\n\u8BF7\u68C0\u67E5\u751F\u6210\u7684\u89C4\u683C\u6587\u4EF6\uFF0C\u786E\u8BA4\u540E\u7EE7\u7EED:"));
|
|
6855
|
+
lines.push(chalk9__default.default.white("\n /opsx:confirm spec-review - \u786E\u8BA4\u89C4\u683C\uFF0C\u8FDB\u5165\u4E0B\u4E00\u9636\u6BB5"));
|
|
6856
|
+
lines.push(chalk9__default.default.white(" /opsx:rollback explore - \u89C4\u683C\u4E0D\u7B26\uFF0C\u91CD\u65B0\u62C6\u5206"));
|
|
6857
|
+
lines.push(chalk9__default.default.white(" /opsx:status - \u67E5\u770B\u5DE5\u4F5C\u6D41\u72B6\u6001"));
|
|
6858
|
+
return { output: lines.join("\n") };
|
|
6859
|
+
}
|
|
6860
|
+
async function generateSpec(requirement, context, analysis, changeId) {
|
|
6861
|
+
const spec = {
|
|
6862
|
+
changeId,
|
|
6863
|
+
requirement,
|
|
6864
|
+
summary: "",
|
|
6865
|
+
items: [],
|
|
6866
|
+
architectureNotes: [],
|
|
6867
|
+
risks: [],
|
|
6868
|
+
suggestions: []
|
|
6869
|
+
};
|
|
6870
|
+
spec.summary = generateSummary(requirement);
|
|
6871
|
+
if (analysis.recommendation === "complex") {
|
|
6872
|
+
spec.items = generateComplexTasks(requirement, context, analysis);
|
|
6873
|
+
spec.architectureNotes = generateArchitectureNotes(requirement, context);
|
|
6874
|
+
} else {
|
|
6875
|
+
spec.items = generateSimpleTasks(requirement);
|
|
6876
|
+
}
|
|
6877
|
+
spec.risks = generateRisks(requirement, context, analysis);
|
|
6878
|
+
spec.suggestions = generateSuggestions(requirement, context, analysis);
|
|
6879
|
+
return spec;
|
|
6880
|
+
}
|
|
6881
|
+
function generateSummary(requirement) {
|
|
6882
|
+
const firstSentence = requirement.split(/[。!?\n]/)[0];
|
|
6883
|
+
return firstSentence.length > 100 ? firstSentence.slice(0, 97) + "..." : firstSentence;
|
|
6884
|
+
}
|
|
6885
|
+
function generateComplexTasks(requirement, context, analysis) {
|
|
6886
|
+
const items = [];
|
|
6887
|
+
let itemId = 1;
|
|
6888
|
+
const featurePatterns = [
|
|
6889
|
+
{ pattern: /用户|登录|注册|认证|权限/, title: "\u7528\u6237\u8BA4\u8BC1\u6A21\u5757", priority: "high" },
|
|
6890
|
+
{ pattern: /数据|存储|缓存|数据库/, title: "\u6570\u636E\u5C42\u5B9E\u73B0", priority: "high" },
|
|
6891
|
+
{ pattern: /接口|API|请求|响应/, title: "API \u63A5\u53E3\u5F00\u53D1", priority: "high" },
|
|
6892
|
+
{ pattern: /界面|页面|组件|UI/, title: "\u754C\u9762\u5F00\u53D1", priority: "medium" },
|
|
6893
|
+
{ pattern: /测试|单测|覆盖/, title: "\u6D4B\u8BD5\u7528\u4F8B\u7F16\u5199", priority: "medium" },
|
|
6894
|
+
{ pattern: /文档|说明/, title: "\u6587\u6863\u7F16\u5199", priority: "low" },
|
|
6895
|
+
{ pattern: /配置|设置/, title: "\u914D\u7F6E\u7BA1\u7406", priority: "low" },
|
|
6896
|
+
{ pattern: /优化|性能/, title: "\u6027\u80FD\u4F18\u5316", priority: "medium" },
|
|
6897
|
+
{ pattern: /安全|加密/, title: "\u5B89\u5168\u5B9E\u73B0", priority: "high" },
|
|
6898
|
+
{ pattern: /日志|监控/, title: "\u65E5\u5FD7\u76D1\u63A7", priority: "low" }
|
|
6899
|
+
];
|
|
6900
|
+
for (const { pattern, title, priority } of featurePatterns) {
|
|
6901
|
+
if (pattern.test(requirement)) {
|
|
6902
|
+
items.push({
|
|
6903
|
+
id: `T${itemId.toString().padStart(3, "0")}`,
|
|
6904
|
+
title,
|
|
6905
|
+
description: `${title}\u76F8\u5173\u7684\u529F\u80FD\u5B9E\u73B0`,
|
|
6906
|
+
priority,
|
|
6907
|
+
dependencies: itemId > 1 ? [`T${(itemId - 1).toString().padStart(3, "0")}`] : [],
|
|
6908
|
+
estimatedComplexity: priority === "high" ? 3 : priority === "medium" ? 2 : 1
|
|
6909
|
+
});
|
|
6910
|
+
itemId++;
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
if (items.length === 0) {
|
|
6914
|
+
items.push({
|
|
6915
|
+
id: "T001",
|
|
6916
|
+
title: "\u9700\u6C42\u5206\u6790\u4E0E\u8BBE\u8BA1",
|
|
6917
|
+
description: "\u5206\u6790\u9700\u6C42\u7EC6\u8282\uFF0C\u8BBE\u8BA1\u5B9E\u73B0\u65B9\u6848",
|
|
6918
|
+
priority: "high",
|
|
6919
|
+
dependencies: [],
|
|
6920
|
+
estimatedComplexity: 2
|
|
6739
6921
|
});
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
"",
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6922
|
+
items.push({
|
|
6923
|
+
id: "T002",
|
|
6924
|
+
title: "\u6838\u5FC3\u529F\u80FD\u5B9E\u73B0",
|
|
6925
|
+
description: requirement,
|
|
6926
|
+
priority: "high",
|
|
6927
|
+
dependencies: ["T001"],
|
|
6928
|
+
estimatedComplexity: analysis.score
|
|
6929
|
+
});
|
|
6930
|
+
items.push({
|
|
6931
|
+
id: "T003",
|
|
6932
|
+
title: "\u6D4B\u8BD5\u4E0E\u9A8C\u8BC1",
|
|
6933
|
+
description: "\u7F16\u5199\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u9A8C\u8BC1\u529F\u80FD\u6B63\u786E\u6027",
|
|
6934
|
+
priority: "medium",
|
|
6935
|
+
dependencies: ["T002"],
|
|
6936
|
+
estimatedComplexity: 2
|
|
6937
|
+
});
|
|
6938
|
+
}
|
|
6939
|
+
return items;
|
|
6940
|
+
}
|
|
6941
|
+
function generateSimpleTasks(requirement, context) {
|
|
6942
|
+
return [
|
|
6943
|
+
{
|
|
6944
|
+
id: "T001",
|
|
6945
|
+
title: "\u5B9E\u73B0\u53D8\u66F4",
|
|
6946
|
+
description: requirement,
|
|
6947
|
+
priority: "high",
|
|
6948
|
+
dependencies: [],
|
|
6949
|
+
estimatedComplexity: 3
|
|
6950
|
+
},
|
|
6951
|
+
{
|
|
6952
|
+
id: "T002",
|
|
6953
|
+
title: "\u6D4B\u8BD5\u9A8C\u8BC1",
|
|
6954
|
+
description: "\u9A8C\u8BC1\u53D8\u66F4\u6B63\u786E\u6027",
|
|
6955
|
+
priority: "medium",
|
|
6956
|
+
dependencies: ["T001"],
|
|
6957
|
+
estimatedComplexity: 1
|
|
6765
6958
|
}
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6959
|
+
];
|
|
6960
|
+
}
|
|
6961
|
+
function generateArchitectureNotes(requirement, context) {
|
|
6962
|
+
const notes = [];
|
|
6963
|
+
if (context.framework) {
|
|
6964
|
+
notes.push(`\u9879\u76EE\u4F7F\u7528 ${context.framework} \u6846\u67B6\uFF0C\u9700\u9075\u5FAA\u5176\u6700\u4F73\u5B9E\u8DF5`);
|
|
6965
|
+
}
|
|
6966
|
+
if (requirement.includes("\u6A21\u5757") || requirement.includes("\u7EC4\u4EF6")) {
|
|
6967
|
+
notes.push("\u5EFA\u8BAE\u91C7\u7528\u6A21\u5757\u5316\u8BBE\u8BA1\uFF0C\u4FDD\u6301\u7EC4\u4EF6\u804C\u8D23\u5355\u4E00");
|
|
6968
|
+
}
|
|
6969
|
+
if (requirement.includes("API") || requirement.includes("\u63A5\u53E3")) {
|
|
6970
|
+
notes.push("API \u8BBE\u8BA1\u9700\u8003\u8651\u7248\u672C\u63A7\u5236\u548C\u5411\u540E\u517C\u5BB9");
|
|
6971
|
+
}
|
|
6972
|
+
if (context.structure.srcStructure) {
|
|
6973
|
+
notes.push(`\u73B0\u6709\u6E90\u7801\u7ED3\u6784: ${context.structure.srcStructure}`);
|
|
6974
|
+
}
|
|
6975
|
+
return notes;
|
|
6976
|
+
}
|
|
6977
|
+
function generateRisks(requirement, context, analysis) {
|
|
6978
|
+
const risks = [];
|
|
6979
|
+
if (!context.framework) {
|
|
6980
|
+
risks.push("\u9879\u76EE\u6846\u67B6\u672A\u8BC6\u522B\uFF0C\u53EF\u80FD\u5F71\u54CD\u4EE3\u7801\u98CE\u683C\u4E00\u81F4\u6027");
|
|
6981
|
+
}
|
|
6982
|
+
if (analysis.score >= 7) {
|
|
6983
|
+
risks.push("\u9700\u6C42\u590D\u6742\u5EA6\u8F83\u9AD8\uFF0C\u5EFA\u8BAE\u5206\u9636\u6BB5\u5B9E\u73B0");
|
|
6769
6984
|
}
|
|
6985
|
+
if (requirement.includes("\u8FC1\u79FB") || requirement.includes("\u91CD\u6784")) {
|
|
6986
|
+
risks.push("\u6D89\u53CA\u73B0\u6709\u4EE3\u7801\u4FEE\u6539\uFF0C\u9700\u6CE8\u610F\u56DE\u5F52\u6D4B\u8BD5");
|
|
6987
|
+
}
|
|
6988
|
+
if (requirement.includes("\u6743\u9650") || requirement.includes("\u5B89\u5168")) {
|
|
6989
|
+
risks.push("\u6D89\u53CA\u5B89\u5168\u654F\u611F\u529F\u80FD\uFF0C\u9700\u8981\u989D\u5916\u5BA1\u67E5");
|
|
6990
|
+
}
|
|
6991
|
+
return risks;
|
|
6992
|
+
}
|
|
6993
|
+
function generateSuggestions(requirement, context, analysis) {
|
|
6994
|
+
const suggestions = [];
|
|
6995
|
+
if (context.norms.devStandards) {
|
|
6996
|
+
suggestions.push("\u9879\u76EE\u5DF2\u6709\u5F00\u53D1\u89C4\u8303\uFF0C\u8BF7\u9075\u5FAA\u73B0\u6709\u89C4\u8303");
|
|
6997
|
+
}
|
|
6998
|
+
if (analysis.recommendation === "complex") {
|
|
6999
|
+
suggestions.push("\u590D\u6742\u9700\u6C42\u5EFA\u8BAE\u5148\u8FDB\u884C\u6280\u672F\u8BC4\u5BA1");
|
|
7000
|
+
suggestions.push("\u5EFA\u8BAE\u8C03\u7528 $architect \u83B7\u53D6\u67B6\u6784\u5EFA\u8BAE");
|
|
7001
|
+
}
|
|
7002
|
+
if (context.techStack.length > 0) {
|
|
7003
|
+
suggestions.push(`\u6280\u672F\u6808: ${context.techStack.join(", ")}`);
|
|
7004
|
+
}
|
|
7005
|
+
return suggestions;
|
|
7006
|
+
}
|
|
7007
|
+
async function saveSpecFile(cwd, spec) {
|
|
7008
|
+
const changesDir = path4__namespace.join(cwd, "openspec", "changes");
|
|
7009
|
+
await fs4__namespace.mkdir(changesDir, { recursive: true });
|
|
7010
|
+
const specPath = path4__namespace.join(changesDir, `${spec.changeId}-spec.md`);
|
|
7011
|
+
const content = formatSpecFile(spec);
|
|
7012
|
+
await fs4__namespace.writeFile(specPath, content, "utf-8");
|
|
7013
|
+
return specPath;
|
|
7014
|
+
}
|
|
7015
|
+
function formatSpecFile(spec) {
|
|
7016
|
+
const lines = [];
|
|
7017
|
+
lines.push(`# Spec: ${spec.summary}`);
|
|
7018
|
+
lines.push("");
|
|
7019
|
+
lines.push(`> \u53D8\u66F4ID: ${spec.changeId}`);
|
|
7020
|
+
lines.push(`> \u751F\u6210\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
7021
|
+
lines.push("");
|
|
7022
|
+
lines.push("---");
|
|
7023
|
+
lines.push("");
|
|
7024
|
+
lines.push("## \u9700\u6C42\u6982\u8FF0");
|
|
7025
|
+
lines.push("");
|
|
7026
|
+
lines.push(spec.requirement);
|
|
7027
|
+
lines.push("");
|
|
7028
|
+
lines.push("## \u4EFB\u52A1\u62C6\u5206");
|
|
7029
|
+
lines.push("");
|
|
7030
|
+
for (const item of spec.items) {
|
|
7031
|
+
const priorityLabel = item.priority === "high" ? "\u{1F534} \u9AD8" : item.priority === "medium" ? "\u{1F7E1} \u4E2D" : "\u{1F7E2} \u4F4E";
|
|
7032
|
+
lines.push(`### ${item.id}: ${item.title}`);
|
|
7033
|
+
lines.push("");
|
|
7034
|
+
lines.push(`- **\u4F18\u5148\u7EA7**: ${priorityLabel}`);
|
|
7035
|
+
lines.push(`- **\u63CF\u8FF0**: ${item.description}`);
|
|
7036
|
+
lines.push(`- **\u9884\u4F30\u590D\u6742\u5EA6**: ${item.estimatedComplexity}/5`);
|
|
7037
|
+
if (item.dependencies.length > 0) {
|
|
7038
|
+
lines.push(`- **\u4F9D\u8D56**: ${item.dependencies.join(", ")}`);
|
|
7039
|
+
}
|
|
7040
|
+
lines.push("");
|
|
7041
|
+
}
|
|
7042
|
+
if (spec.architectureNotes.length > 0) {
|
|
7043
|
+
lines.push("## \u67B6\u6784\u8BF4\u660E");
|
|
7044
|
+
lines.push("");
|
|
7045
|
+
for (const note of spec.architectureNotes) {
|
|
7046
|
+
lines.push(`- ${note}`);
|
|
7047
|
+
}
|
|
7048
|
+
lines.push("");
|
|
7049
|
+
}
|
|
7050
|
+
if (spec.risks.length > 0) {
|
|
7051
|
+
lines.push("## \u26A0\uFE0F \u98CE\u9669\u8BC4\u4F30");
|
|
7052
|
+
lines.push("");
|
|
7053
|
+
for (const risk of spec.risks) {
|
|
7054
|
+
lines.push(`- ${risk}`);
|
|
7055
|
+
}
|
|
7056
|
+
lines.push("");
|
|
7057
|
+
}
|
|
7058
|
+
if (spec.suggestions.length > 0) {
|
|
7059
|
+
lines.push("## \u{1F4A1} \u5EFA\u8BAE");
|
|
7060
|
+
lines.push("");
|
|
7061
|
+
for (const suggestion of spec.suggestions) {
|
|
7062
|
+
lines.push(`- ${suggestion}`);
|
|
7063
|
+
}
|
|
7064
|
+
lines.push("");
|
|
7065
|
+
}
|
|
7066
|
+
lines.push("---");
|
|
7067
|
+
lines.push("");
|
|
7068
|
+
lines.push("## \u786E\u8BA4\u72B6\u6001");
|
|
7069
|
+
lines.push("");
|
|
7070
|
+
lines.push("- [ ] \u89C4\u683C\u5DF2\u5BA1\u9605");
|
|
7071
|
+
lines.push("- [ ] \u4EFB\u52A1\u62C6\u5206\u5DF2\u786E\u8BA4");
|
|
7072
|
+
lines.push("");
|
|
7073
|
+
lines.push("**\u786E\u8BA4\u540E\u6267\u884C**: `/opsx:confirm spec-review`");
|
|
7074
|
+
return lines.join("\n");
|
|
6770
7075
|
}
|
|
6771
7076
|
function parseArgs(args) {
|
|
6772
7077
|
let forceComplexity;
|
|
@@ -6791,42 +7096,52 @@ async function readProjectContext(cwd) {
|
|
|
6791
7096
|
type: "unknown",
|
|
6792
7097
|
framework: null,
|
|
6793
7098
|
techStack: [],
|
|
6794
|
-
description: ""
|
|
7099
|
+
description: "",
|
|
7100
|
+
structure: {
|
|
7101
|
+
directories: [],
|
|
7102
|
+
keyFiles: [],
|
|
7103
|
+
srcStructure: ""
|
|
7104
|
+
},
|
|
7105
|
+
norms: {
|
|
7106
|
+
devStandards: "",
|
|
7107
|
+
patterns: "",
|
|
7108
|
+
weights: ""
|
|
7109
|
+
}
|
|
7110
|
+
};
|
|
7111
|
+
const [agentsContext, configContext, normsContext, structureContext] = await Promise.all([
|
|
7112
|
+
readAgentsMd(cwd),
|
|
7113
|
+
readConfigYaml(cwd),
|
|
7114
|
+
readNorms(cwd),
|
|
7115
|
+
analyzeStructure(cwd)
|
|
7116
|
+
]);
|
|
7117
|
+
return {
|
|
7118
|
+
...defaultContext,
|
|
7119
|
+
...agentsContext,
|
|
7120
|
+
...configContext,
|
|
7121
|
+
norms: normsContext,
|
|
7122
|
+
structure: structureContext
|
|
6795
7123
|
};
|
|
7124
|
+
}
|
|
7125
|
+
async function readAgentsMd(cwd) {
|
|
6796
7126
|
const agentsPath = path4__namespace.join(cwd, "AGENTS.md");
|
|
6797
7127
|
try {
|
|
6798
7128
|
const stats = await fs4__namespace.stat(agentsPath);
|
|
6799
7129
|
if (stats.size > MAX_FILE_SIZE2) {
|
|
6800
7130
|
console.warn(`\u8B66\u544A: AGENTS.md \u6587\u4EF6\u8FC7\u5927 (${stats.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
6801
|
-
return
|
|
7131
|
+
return {};
|
|
6802
7132
|
}
|
|
6803
7133
|
const content = await fs4__namespace.readFile(agentsPath, "utf-8");
|
|
6804
|
-
return parseAgentsMd(content
|
|
7134
|
+
return parseAgentsMd(content);
|
|
6805
7135
|
} catch (e) {
|
|
6806
7136
|
const err = e;
|
|
6807
7137
|
if (err.code !== "ENOENT") {
|
|
6808
7138
|
console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 AGENTS.md - ${err.message}`);
|
|
6809
7139
|
}
|
|
7140
|
+
return {};
|
|
6810
7141
|
}
|
|
6811
|
-
const configPath = path4__namespace.join(cwd, "openspec", "config.yaml");
|
|
6812
|
-
try {
|
|
6813
|
-
const stats = await fs4__namespace.stat(configPath);
|
|
6814
|
-
if (stats.size > MAX_FILE_SIZE2) {
|
|
6815
|
-
console.warn(`\u8B66\u544A: config.yaml \u6587\u4EF6\u8FC7\u5927\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
6816
|
-
return defaultContext;
|
|
6817
|
-
}
|
|
6818
|
-
const content = await fs4__namespace.readFile(configPath, "utf-8");
|
|
6819
|
-
return parseConfigYaml(content, defaultContext);
|
|
6820
|
-
} catch (e) {
|
|
6821
|
-
const err = e;
|
|
6822
|
-
if (err.code !== "ENOENT") {
|
|
6823
|
-
console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 config.yaml - ${err.message}`);
|
|
6824
|
-
}
|
|
6825
|
-
}
|
|
6826
|
-
return defaultContext;
|
|
6827
7142
|
}
|
|
6828
|
-
function parseAgentsMd(content
|
|
6829
|
-
const context = {
|
|
7143
|
+
function parseAgentsMd(content) {
|
|
7144
|
+
const context = {};
|
|
6830
7145
|
const nameMatch = content.match(/\|\s*项目名称\s*\|\s*([^\s|]+)/);
|
|
6831
7146
|
if (nameMatch) {
|
|
6832
7147
|
context.name = nameMatch[1];
|
|
@@ -6843,10 +7158,32 @@ function parseAgentsMd(content, defaults) {
|
|
|
6843
7158
|
if (descMatch) {
|
|
6844
7159
|
context.description = descMatch[1].trim();
|
|
6845
7160
|
}
|
|
7161
|
+
const techStackMatch = content.match(/技术栈[::]\s*([^\n]+)/);
|
|
7162
|
+
if (techStackMatch) {
|
|
7163
|
+
context.techStack = techStackMatch[1].split(/[,,、]/).map((s) => s.trim()).filter(Boolean);
|
|
7164
|
+
}
|
|
6846
7165
|
return context;
|
|
6847
7166
|
}
|
|
6848
|
-
function
|
|
6849
|
-
const
|
|
7167
|
+
async function readConfigYaml(cwd) {
|
|
7168
|
+
const configPath = path4__namespace.join(cwd, "openspec", "config.yaml");
|
|
7169
|
+
try {
|
|
7170
|
+
const stats = await fs4__namespace.stat(configPath);
|
|
7171
|
+
if (stats.size > MAX_FILE_SIZE2) {
|
|
7172
|
+
console.warn("\u8B66\u544A: config.yaml \u6587\u4EF6\u8FC7\u5927\uFF0C\u8DF3\u8FC7\u8BFB\u53D6");
|
|
7173
|
+
return {};
|
|
7174
|
+
}
|
|
7175
|
+
const content = await fs4__namespace.readFile(configPath, "utf-8");
|
|
7176
|
+
return parseConfigYaml(content);
|
|
7177
|
+
} catch (e) {
|
|
7178
|
+
const err = e;
|
|
7179
|
+
if (err.code !== "ENOENT") {
|
|
7180
|
+
console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 config.yaml - ${err.message}`);
|
|
7181
|
+
}
|
|
7182
|
+
return {};
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
function parseConfigYaml(content) {
|
|
7186
|
+
const context = {};
|
|
6850
7187
|
const nameMatch = content.match(/name:\s*(.+)/);
|
|
6851
7188
|
if (nameMatch) {
|
|
6852
7189
|
context.name = nameMatch[1].trim();
|
|
@@ -6861,6 +7198,67 @@ function parseConfigYaml(content, defaults) {
|
|
|
6861
7198
|
}
|
|
6862
7199
|
return context;
|
|
6863
7200
|
}
|
|
7201
|
+
async function readNorms(cwd) {
|
|
7202
|
+
const normsDir = path4__namespace.join(cwd, ".sf-cli", "norms");
|
|
7203
|
+
const norms = {
|
|
7204
|
+
devStandards: "",
|
|
7205
|
+
patterns: "",
|
|
7206
|
+
weights: ""
|
|
7207
|
+
};
|
|
7208
|
+
try {
|
|
7209
|
+
const devStandardsPath = path4__namespace.join(normsDir, "devstanded.md");
|
|
7210
|
+
norms.devStandards = await fs4__namespace.readFile(devStandardsPath, "utf-8").catch(() => "");
|
|
7211
|
+
} catch {
|
|
7212
|
+
}
|
|
7213
|
+
try {
|
|
7214
|
+
const patternsPath = path4__namespace.join(normsDir, "patterns.json");
|
|
7215
|
+
norms.patterns = await fs4__namespace.readFile(patternsPath, "utf-8").catch(() => "");
|
|
7216
|
+
} catch {
|
|
7217
|
+
}
|
|
7218
|
+
try {
|
|
7219
|
+
const weightsPath = path4__namespace.join(normsDir, "weights.json");
|
|
7220
|
+
norms.weights = await fs4__namespace.readFile(weightsPath, "utf-8").catch(() => "");
|
|
7221
|
+
} catch {
|
|
7222
|
+
}
|
|
7223
|
+
return norms;
|
|
7224
|
+
}
|
|
7225
|
+
async function analyzeStructure(cwd) {
|
|
7226
|
+
const structure = {
|
|
7227
|
+
directories: [],
|
|
7228
|
+
keyFiles: [],
|
|
7229
|
+
srcStructure: ""
|
|
7230
|
+
};
|
|
7231
|
+
try {
|
|
7232
|
+
const entries = await fs4__namespace.readdir(cwd, { withFileTypes: true });
|
|
7233
|
+
for (const entry of entries) {
|
|
7234
|
+
if (entry.isDirectory() && !["node_modules", "dist", ".git", "build"].includes(entry.name)) {
|
|
7235
|
+
structure.directories.push(entry.name);
|
|
7236
|
+
}
|
|
7237
|
+
}
|
|
7238
|
+
const keyFiles = [
|
|
7239
|
+
"package.json",
|
|
7240
|
+
"tsconfig.json",
|
|
7241
|
+
"AGENTS.md",
|
|
7242
|
+
"README.md"
|
|
7243
|
+
];
|
|
7244
|
+
for (const file of keyFiles) {
|
|
7245
|
+
const filePath = path4__namespace.join(cwd, file);
|
|
7246
|
+
try {
|
|
7247
|
+
await fs4__namespace.access(filePath);
|
|
7248
|
+
structure.keyFiles.push(file);
|
|
7249
|
+
} catch {
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
const srcDir = path4__namespace.join(cwd, "src");
|
|
7253
|
+
try {
|
|
7254
|
+
const srcEntries = await fs4__namespace.readdir(srcDir, { withFileTypes: true });
|
|
7255
|
+
structure.srcStructure = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name).join("/");
|
|
7256
|
+
} catch {
|
|
7257
|
+
}
|
|
7258
|
+
} catch (e) {
|
|
7259
|
+
}
|
|
7260
|
+
return { structure };
|
|
7261
|
+
}
|
|
6864
7262
|
function analyzeComplexity(requirement, context) {
|
|
6865
7263
|
let score = 3;
|
|
6866
7264
|
const factors = [];
|
|
@@ -6928,6 +7326,78 @@ function extractTitle(requirement) {
|
|
|
6928
7326
|
return requirement.slice(0, 47) + "...";
|
|
6929
7327
|
}
|
|
6930
7328
|
var autoScheduleEnabled = true;
|
|
7329
|
+
var DEFAULT_REGRESSION_CONFIG = {
|
|
7330
|
+
enabled: true,
|
|
7331
|
+
command: "npm test -- --run",
|
|
7332
|
+
timeout: 12e4,
|
|
7333
|
+
// 2分钟
|
|
7334
|
+
coverageThreshold: 80
|
|
7335
|
+
};
|
|
7336
|
+
async function runRegressionTest(workingDirectory, config = DEFAULT_REGRESSION_CONFIG) {
|
|
7337
|
+
const startTime = Date.now();
|
|
7338
|
+
const result = {
|
|
7339
|
+
success: false,
|
|
7340
|
+
passed: 0,
|
|
7341
|
+
failed: 0,
|
|
7342
|
+
total: 0,
|
|
7343
|
+
duration: 0,
|
|
7344
|
+
output: "",
|
|
7345
|
+
errors: []
|
|
7346
|
+
};
|
|
7347
|
+
return new Promise((resolve4) => {
|
|
7348
|
+
const proc = child_process.spawn(config.command, [], {
|
|
7349
|
+
cwd: workingDirectory,
|
|
7350
|
+
shell: true,
|
|
7351
|
+
stdio: "pipe"
|
|
7352
|
+
});
|
|
7353
|
+
let stdout = "";
|
|
7354
|
+
let stderr = "";
|
|
7355
|
+
proc.stdout?.on("data", (data) => {
|
|
7356
|
+
stdout += data.toString();
|
|
7357
|
+
});
|
|
7358
|
+
proc.stderr?.on("data", (data) => {
|
|
7359
|
+
stderr += data.toString();
|
|
7360
|
+
});
|
|
7361
|
+
const timeout = setTimeout(() => {
|
|
7362
|
+
proc.kill();
|
|
7363
|
+
result.errors.push("\u6D4B\u8BD5\u8D85\u65F6");
|
|
7364
|
+
result.output = stdout + stderr;
|
|
7365
|
+
result.duration = Date.now() - startTime;
|
|
7366
|
+
resolve4(result);
|
|
7367
|
+
}, config.timeout);
|
|
7368
|
+
proc.on("close", (code) => {
|
|
7369
|
+
clearTimeout(timeout);
|
|
7370
|
+
result.output = stdout + stderr;
|
|
7371
|
+
result.duration = Date.now() - startTime;
|
|
7372
|
+
const passMatch = stdout.match(/(\d+)\s+(?:passed|tests?\s+passed)/i);
|
|
7373
|
+
const failMatch = stdout.match(/(\d+)\s+(?:failed|tests?\s+failed)/i);
|
|
7374
|
+
const totalMatch = stdout.match(/Tests?:\s*(\d+)/i);
|
|
7375
|
+
if (passMatch) {
|
|
7376
|
+
result.passed = parseInt(passMatch[1], 10);
|
|
7377
|
+
}
|
|
7378
|
+
if (failMatch) {
|
|
7379
|
+
result.failed = parseInt(failMatch[1], 10);
|
|
7380
|
+
}
|
|
7381
|
+
if (totalMatch) {
|
|
7382
|
+
result.total = parseInt(totalMatch[1], 10);
|
|
7383
|
+
} else {
|
|
7384
|
+
result.total = result.passed + result.failed;
|
|
7385
|
+
}
|
|
7386
|
+
const coverageMatch = stdout.match(/All files[^\d]*(\d+(?:\.\d+)?)/);
|
|
7387
|
+
if (coverageMatch) {
|
|
7388
|
+
result.coverage = parseFloat(coverageMatch[1]);
|
|
7389
|
+
}
|
|
7390
|
+
result.success = code === 0 && result.failed === 0;
|
|
7391
|
+
resolve4(result);
|
|
7392
|
+
});
|
|
7393
|
+
proc.on("error", (err) => {
|
|
7394
|
+
clearTimeout(timeout);
|
|
7395
|
+
result.errors.push(err.message);
|
|
7396
|
+
result.duration = Date.now() - startTime;
|
|
7397
|
+
resolve4(result);
|
|
7398
|
+
});
|
|
7399
|
+
});
|
|
7400
|
+
}
|
|
6931
7401
|
async function handleOpsx(command, args, ctx) {
|
|
6932
7402
|
const step = command.replace("opsx:", "");
|
|
6933
7403
|
const workflow = new WorkflowEngine();
|
|
@@ -6942,7 +7412,7 @@ async function handleOpsx(command, args, ctx) {
|
|
|
6942
7412
|
case "apply":
|
|
6943
7413
|
return handleApply(workflow);
|
|
6944
7414
|
case "archive":
|
|
6945
|
-
return handleArchive(workflow, args);
|
|
7415
|
+
return handleArchive(workflow, args, ctx);
|
|
6946
7416
|
case "propose":
|
|
6947
7417
|
return handlePropose(workflow, args);
|
|
6948
7418
|
case "status":
|
|
@@ -6952,17 +7422,55 @@ async function handleOpsx(command, args, ctx) {
|
|
|
6952
7422
|
case "rollback":
|
|
6953
7423
|
return handleRollback(workflow, args);
|
|
6954
7424
|
case "confirm":
|
|
6955
|
-
return handleConfirm(workflow, args);
|
|
7425
|
+
return handleConfirm(workflow, args, ctx);
|
|
6956
7426
|
case "next":
|
|
6957
7427
|
return handleNext(workflow);
|
|
6958
7428
|
case "auto":
|
|
6959
7429
|
return handleAutoSchedule(args);
|
|
7430
|
+
case "test":
|
|
7431
|
+
return handleRegressionTest(ctx);
|
|
6960
7432
|
default:
|
|
6961
7433
|
return {
|
|
6962
7434
|
output: chalk9__default.default.red(`\u672A\u77E5\u7684OpenSpec\u547D\u4EE4: /${command}`)
|
|
6963
7435
|
};
|
|
6964
7436
|
}
|
|
6965
7437
|
}
|
|
7438
|
+
async function handleRegressionTest(ctx) {
|
|
7439
|
+
const lines = [];
|
|
7440
|
+
lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u56DE\u5F52\u6D4B\u8BD5..."));
|
|
7441
|
+
lines.push(chalk9__default.default.gray(` \u5DE5\u4F5C\u76EE\u5F55: ${ctx.options.workingDirectory}`));
|
|
7442
|
+
lines.push("");
|
|
7443
|
+
const result = await runRegressionTest(ctx.options.workingDirectory);
|
|
7444
|
+
lines.push(chalk9__default.default.gray("\u2500".repeat(50)));
|
|
7445
|
+
if (result.success) {
|
|
7446
|
+
lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
|
|
7447
|
+
} else {
|
|
7448
|
+
lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
|
|
7449
|
+
}
|
|
7450
|
+
lines.push("");
|
|
7451
|
+
lines.push(chalk9__default.default.cyan("\u6D4B\u8BD5\u7ED3\u679C:"));
|
|
7452
|
+
lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${result.passed}`));
|
|
7453
|
+
lines.push(chalk9__default.default.gray(` \u5931\u8D25: ${result.failed}`));
|
|
7454
|
+
lines.push(chalk9__default.default.gray(` \u603B\u8BA1: ${result.total}`));
|
|
7455
|
+
lines.push(chalk9__default.default.gray(` \u8017\u65F6: ${(result.duration / 1e3).toFixed(2)}s`));
|
|
7456
|
+
if (result.coverage !== void 0) {
|
|
7457
|
+
const coverageColor = result.coverage >= 80 ? chalk9__default.default.green : result.coverage >= 60 ? chalk9__default.default.yellow : chalk9__default.default.red;
|
|
7458
|
+
lines.push(coverageColor(` \u8986\u76D6\u7387: ${result.coverage}%`));
|
|
7459
|
+
}
|
|
7460
|
+
if (result.errors.length > 0) {
|
|
7461
|
+
lines.push("");
|
|
7462
|
+
lines.push(chalk9__default.default.red("\u9519\u8BEF\u4FE1\u606F:"));
|
|
7463
|
+
for (const error of result.errors) {
|
|
7464
|
+
lines.push(chalk9__default.default.gray(` - ${error}`));
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
if (result.failed > 0) {
|
|
7468
|
+
lines.push("");
|
|
7469
|
+
lines.push(chalk9__default.default.yellow("\u26A0 \u5B58\u5728\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u8BF7\u68C0\u67E5\u5E76\u4FEE\u590D"));
|
|
7470
|
+
lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
|
|
7471
|
+
}
|
|
7472
|
+
return { output: lines.join("\n") };
|
|
7473
|
+
}
|
|
6966
7474
|
function handleAutoSchedule(args) {
|
|
6967
7475
|
const action = args[0]?.toLowerCase();
|
|
6968
7476
|
if (!action) {
|
|
@@ -7092,13 +7600,70 @@ async function handleArchive(workflow, args, ctx) {
|
|
|
7092
7600
|
${generateConfirmationPrompt(confirmation.point)}`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /opsx:confirm code-review \u786E\u8BA4\u540E\u5F52\u6863")
|
|
7093
7601
|
};
|
|
7094
7602
|
}
|
|
7603
|
+
const lines = [];
|
|
7604
|
+
lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u5F52\u6863\u524D\u56DE\u5F52\u6D4B\u8BD5..."));
|
|
7605
|
+
lines.push("");
|
|
7606
|
+
const testResult = await runRegressionTest(ctx.options.workingDirectory);
|
|
7607
|
+
if (!testResult.success) {
|
|
7608
|
+
lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
|
|
7609
|
+
lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u5931\u8D25: ${testResult.failed} | \u603B\u8BA1: ${testResult.total}`));
|
|
7610
|
+
lines.push("");
|
|
7611
|
+
lines.push(chalk9__default.default.yellow("\u26A0 \u5F52\u6863\u88AB\u963B\u6B62"));
|
|
7612
|
+
lines.push(chalk9__default.default.gray("\n\u8BF7\u4FEE\u590D\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\u540E\u91CD\u8BD5"));
|
|
7613
|
+
lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
|
|
7614
|
+
lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:test \u53EF\u5355\u72EC\u8FD0\u884C\u56DE\u5F52\u6D4B\u8BD5"));
|
|
7615
|
+
return { output: lines.join("\n") };
|
|
7616
|
+
}
|
|
7617
|
+
lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
|
|
7618
|
+
lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u8017\u65F6: ${(testResult.duration / 1e3).toFixed(2)}s`));
|
|
7619
|
+
lines.push("");
|
|
7095
7620
|
const changeId = state.id;
|
|
7096
7621
|
const summary = args.join(" ") || "\u5B8C\u6210\u53D8\u66F4";
|
|
7097
7622
|
await workflow.archive(summary);
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
\u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55")
|
|
7101
|
-
};
|
|
7623
|
+
await updateChangelog(ctx.options.workingDirectory, summary, changeId);
|
|
7624
|
+
lines.push(chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5F52\u6863") + chalk9__default.default.gray(`
|
|
7625
|
+
\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"));
|
|
7626
|
+
return { output: lines.join("\n") };
|
|
7627
|
+
}
|
|
7628
|
+
async function updateChangelog(workingDirectory, summary, changeId) {
|
|
7629
|
+
try {
|
|
7630
|
+
const changelogPath = path4__namespace.join(workingDirectory, "CHANGELOG.md");
|
|
7631
|
+
const pkgPath = path4__namespace.join(workingDirectory, "package.json");
|
|
7632
|
+
let version = "1.0.0";
|
|
7633
|
+
try {
|
|
7634
|
+
const pkgContent = fs10__namespace.readFileSync(pkgPath, "utf-8");
|
|
7635
|
+
const pkg = JSON.parse(pkgContent);
|
|
7636
|
+
version = pkg.version || "1.0.0";
|
|
7637
|
+
} catch {
|
|
7638
|
+
}
|
|
7639
|
+
const today = /* @__PURE__ */ new Date();
|
|
7640
|
+
const dateStr = today.toISOString().split("T")[0];
|
|
7641
|
+
const entry = `
|
|
7642
|
+
## v${version} (${dateStr})
|
|
7643
|
+
|
|
7644
|
+
**\u53D8\u66F4\u5185\u5BB9**
|
|
7645
|
+
|
|
7646
|
+
- ${summary} (${changeId})
|
|
7647
|
+
`;
|
|
7648
|
+
if (fs10__namespace.existsSync(changelogPath)) {
|
|
7649
|
+
const content = fs10__namespace.readFileSync(changelogPath, "utf-8");
|
|
7650
|
+
const versionPattern = /^## v\d+\.\d+\.\d+/m;
|
|
7651
|
+
const match = content.match(versionPattern);
|
|
7652
|
+
if (match && match.index !== void 0) {
|
|
7653
|
+
const newContent = content.slice(0, match.index) + entry + content.slice(match.index);
|
|
7654
|
+
fs10__namespace.writeFileSync(changelogPath, newContent, "utf-8");
|
|
7655
|
+
} else {
|
|
7656
|
+
fs10__namespace.appendFileSync(changelogPath, entry, "utf-8");
|
|
7657
|
+
}
|
|
7658
|
+
} else {
|
|
7659
|
+
const header = `# Changelog
|
|
7660
|
+
|
|
7661
|
+
All notable changes to this project will be documented in this file.
|
|
7662
|
+
`;
|
|
7663
|
+
fs10__namespace.writeFileSync(changelogPath, header + entry, "utf-8");
|
|
7664
|
+
}
|
|
7665
|
+
} catch (error) {
|
|
7666
|
+
}
|
|
7102
7667
|
}
|
|
7103
7668
|
async function handlePropose(workflow, args, ctx) {
|
|
7104
7669
|
const state = workflow.getState();
|
|
@@ -7225,6 +7790,16 @@ async function handleConfirm(workflow, args, ctx) {
|
|
|
7225
7790
|
const type = args[0];
|
|
7226
7791
|
if (!type) {
|
|
7227
7792
|
const pendingPoint = workflow.getCurrentConfirmationPoint();
|
|
7793
|
+
const specPath = await checkPendingSpec(ctx.options.workingDirectory, state.id);
|
|
7794
|
+
if (specPath) {
|
|
7795
|
+
return {
|
|
7796
|
+
output: chalk9__default.default.cyan("\u{1F4CB} \u89C4\u683C\u6587\u4EF6\u5F85\u786E\u8BA4") + chalk9__default.default.gray(`
|
|
7797
|
+
|
|
7798
|
+
\u89C4\u683C\u6587\u4EF6: ${specPath}`) + chalk9__default.default.gray(`
|
|
7799
|
+
|
|
7800
|
+
\u8BF7\u68C0\u67E5\u89C4\u683C\u6587\u4EF6\u540E\u786E\u8BA4:`) + chalk9__default.default.white("\n /opsx:confirm spec-review - \u786E\u8BA4\u89C4\u683C") + chalk9__default.default.white("\n /opsx:rollback explore - \u91CD\u65B0\u62C6\u5206")
|
|
7801
|
+
};
|
|
7802
|
+
}
|
|
7228
7803
|
if (pendingPoint) {
|
|
7229
7804
|
return {
|
|
7230
7805
|
output: chalk9__default.default.cyan("\u5F85\u786E\u8BA4\u7684\u68C0\u67E5\u70B9:") + chalk9__default.default.white(`
|
|
@@ -7246,12 +7821,54 @@ ${generateConfirmationPrompt(pendingPoint)}`) + chalk9__default.default.gray(`
|
|
|
7246
7821
|
}
|
|
7247
7822
|
const comment = args.slice(1).join(" ");
|
|
7248
7823
|
workflow.confirm(type, comment);
|
|
7249
|
-
|
|
7250
|
-
|
|
7824
|
+
const lines = [];
|
|
7825
|
+
lines.push(chalk9__default.default.green("\u2713 \u5DF2\u786E\u8BA4"));
|
|
7826
|
+
lines.push(chalk9__default.default.white(`
|
|
7827
|
+
${point.name}`));
|
|
7828
|
+
if (comment) {
|
|
7829
|
+
lines.push(chalk9__default.default.gray(`
|
|
7830
|
+
\u5907\u6CE8: ${comment}`));
|
|
7831
|
+
}
|
|
7832
|
+
if (type === "spec-review") {
|
|
7833
|
+
const allowed = workflow.getAllowedTransitions();
|
|
7834
|
+
if (allowed.length > 0) {
|
|
7835
|
+
const nextStep = allowed[0];
|
|
7836
|
+
try {
|
|
7837
|
+
const transition = await workflow.transition(nextStep);
|
|
7838
|
+
lines.push("");
|
|
7839
|
+
lines.push(chalk9__default.default.cyan(`\u2713 \u5DF2\u81EA\u52A8\u8FDB\u5165 ${nextStep} \u9636\u6BB5`));
|
|
7840
|
+
lines.push(chalk9__default.default.gray(`\u8F6C\u6362: ${transition.from} \u2192 ${transition.to}`));
|
|
7841
|
+
if (nextStep === "new") {
|
|
7842
|
+
lines.push(chalk9__default.default.yellow("\n\u4E0B\u4E00\u6B65: \u8BBE\u8BA1\u65B9\u6848"));
|
|
7843
|
+
lines.push(chalk9__default.default.gray(" \u53EF\u8C03\u7528 $architect \u6216 $frontend-dev \u8FDB\u884C\u8BBE\u8BA1"));
|
|
7844
|
+
} else if (nextStep === "apply") {
|
|
7845
|
+
lines.push(chalk9__default.default.yellow("\n\u4E0B\u4E00\u6B65: \u6267\u884C\u53D8\u66F4"));
|
|
7846
|
+
lines.push(chalk9__default.default.gray(" \u53EF\u8C03\u7528 $frontend-dev \u6267\u884C\u4EE3\u7801\u4FEE\u6539"));
|
|
7847
|
+
}
|
|
7848
|
+
return { output: lines.join("\n") };
|
|
7849
|
+
} catch (e) {
|
|
7850
|
+
if (e instanceof ConfirmationRequiredError) {
|
|
7851
|
+
lines.push(chalk9__default.default.yellow("\n\u26A0 \u8FD8\u9700\u8981\u786E\u8BA4:") + chalk9__default.default.white(`
|
|
7852
|
+
${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
|
|
7251
7853
|
|
|
7252
|
-
${point.
|
|
7253
|
-
|
|
7254
|
-
|
|
7854
|
+
\u4F7F\u7528 /opsx:confirm ${e.point.type}`));
|
|
7855
|
+
return { output: lines.join("\n") };
|
|
7856
|
+
}
|
|
7857
|
+
throw e;
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
7860
|
+
}
|
|
7861
|
+
lines.push(chalk9__default.default.yellow("\n\u4F7F\u7528 /opsx:next \u7EE7\u7EED\u4E0B\u4E00\u9636\u6BB5"));
|
|
7862
|
+
return { output: lines.join("\n") };
|
|
7863
|
+
}
|
|
7864
|
+
async function checkPendingSpec(workingDirectory, changeId) {
|
|
7865
|
+
const specPath = path4__namespace.join(workingDirectory, "openspec", "changes", `${changeId}-spec.md`);
|
|
7866
|
+
try {
|
|
7867
|
+
await fs10__namespace.promises.access(specPath);
|
|
7868
|
+
return specPath;
|
|
7869
|
+
} catch {
|
|
7870
|
+
return null;
|
|
7871
|
+
}
|
|
7255
7872
|
}
|
|
7256
7873
|
async function handleNext(workflow, args, ctx) {
|
|
7257
7874
|
const state = workflow.getState();
|
|
@@ -7289,9 +7906,25 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
|
|
|
7289
7906
|
}
|
|
7290
7907
|
|
|
7291
7908
|
// src/commands/runner.ts
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7909
|
+
function getVersion() {
|
|
7910
|
+
const possiblePaths = [
|
|
7911
|
+
path4__namespace.resolve(__dirname, "..", "..", "package.json"),
|
|
7912
|
+
path4__namespace.resolve(__dirname, "..", "..", "..", "package.json")
|
|
7913
|
+
];
|
|
7914
|
+
for (const pkgPath of possiblePaths) {
|
|
7915
|
+
try {
|
|
7916
|
+
if (fs10__namespace.existsSync(pkgPath)) {
|
|
7917
|
+
const content = fs10__namespace.readFileSync(pkgPath, "utf-8");
|
|
7918
|
+
const pkg = JSON.parse(content);
|
|
7919
|
+
return pkg.version;
|
|
7920
|
+
}
|
|
7921
|
+
} catch {
|
|
7922
|
+
continue;
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
return "1.0.0";
|
|
7926
|
+
}
|
|
7927
|
+
var VERSION2 = getVersion();
|
|
7295
7928
|
async function runSlashCommand(command, args, ctx) {
|
|
7296
7929
|
const normalizedCommand = normalizeCommand(command);
|
|
7297
7930
|
switch (normalizedCommand) {
|