@nick848/sf-cli 1.0.1 → 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/CHANGELOG.md +44 -0
- package/README.md +4 -23
- package/dist/cli/index.js +459 -182
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +313 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +375 -109
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
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
|
|
4
|
+
var fs10 = require('fs');
|
|
5
5
|
var path4 = require('path');
|
|
6
6
|
var crypto = require('crypto');
|
|
7
7
|
var os = require('os');
|
|
@@ -12,7 +12,6 @@ var chalk9 = require('chalk');
|
|
|
12
12
|
var uuid = require('uuid');
|
|
13
13
|
var enquirer = require('enquirer');
|
|
14
14
|
var child_process = require('child_process');
|
|
15
|
-
var module$1 = require('module');
|
|
16
15
|
|
|
17
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
17
|
|
|
@@ -35,15 +34,13 @@ function _interopNamespace(e) {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
|
|
38
|
-
var
|
|
37
|
+
var fs10__namespace = /*#__PURE__*/_interopNamespace(fs10);
|
|
39
38
|
var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
|
|
40
39
|
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
41
40
|
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
42
41
|
var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
|
|
43
42
|
|
|
44
|
-
//
|
|
45
|
-
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
46
|
-
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
43
|
+
// src/services/config.ts
|
|
47
44
|
var DEFAULT_CONFIG = {
|
|
48
45
|
model: "GLM-5",
|
|
49
46
|
apiKey: "",
|
|
@@ -58,8 +55,8 @@ var KEY_FILE = ".key";
|
|
|
58
55
|
function getOrCreateEncryptionKey() {
|
|
59
56
|
const keyPath = path4__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
|
|
60
57
|
try {
|
|
61
|
-
if (
|
|
62
|
-
const keyBase64 =
|
|
58
|
+
if (fs10__namespace.existsSync(keyPath)) {
|
|
59
|
+
const keyBase64 = fs10__namespace.readFileSync(keyPath, "utf-8").trim();
|
|
63
60
|
return Buffer.from(keyBase64, "base64");
|
|
64
61
|
}
|
|
65
62
|
} catch {
|
|
@@ -67,10 +64,10 @@ function getOrCreateEncryptionKey() {
|
|
|
67
64
|
const key = crypto__namespace.randomBytes(32);
|
|
68
65
|
try {
|
|
69
66
|
const keyDir = path4__namespace.dirname(keyPath);
|
|
70
|
-
if (!
|
|
71
|
-
|
|
67
|
+
if (!fs10__namespace.existsSync(keyDir)) {
|
|
68
|
+
fs10__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
|
|
72
69
|
}
|
|
73
|
-
|
|
70
|
+
fs10__namespace.writeFileSync(keyPath, key.toString("base64"), {
|
|
74
71
|
mode: 384,
|
|
75
72
|
// 仅所有者可读写
|
|
76
73
|
encoding: "utf-8"
|
|
@@ -377,7 +374,7 @@ var BaseAdapter = class {
|
|
|
377
374
|
* 延迟工具函数
|
|
378
375
|
*/
|
|
379
376
|
delay(ms) {
|
|
380
|
-
return new Promise((
|
|
377
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
381
378
|
}
|
|
382
379
|
};
|
|
383
380
|
|
|
@@ -1822,17 +1819,17 @@ var FigmaMCPAdapter = class extends MCPAdapterBase {
|
|
|
1822
1819
|
* 解析设计规格
|
|
1823
1820
|
*/
|
|
1824
1821
|
parseDesignSpec(data, url, fileKey, nodeId) {
|
|
1825
|
-
const
|
|
1822
|
+
const document = data.document || data;
|
|
1826
1823
|
return {
|
|
1827
1824
|
id: nodeId || fileKey,
|
|
1828
|
-
name:
|
|
1825
|
+
name: document.name || "\u672A\u547D\u540D\u8BBE\u8BA1\u7A3F",
|
|
1829
1826
|
platform: "figma",
|
|
1830
1827
|
url,
|
|
1831
|
-
width:
|
|
1832
|
-
height:
|
|
1828
|
+
width: document.absoluteBoundingBox?.width || 0,
|
|
1829
|
+
height: document.absoluteBoundingBox?.height || 0,
|
|
1833
1830
|
scale: 1,
|
|
1834
|
-
layers: this.parseFigmaLayers(
|
|
1835
|
-
styles: this.extractStylesFromDocument(
|
|
1831
|
+
layers: this.parseFigmaLayers(document.children || []),
|
|
1832
|
+
styles: this.extractStylesFromDocument(document),
|
|
1836
1833
|
assets: this.parseAssets(data.assets || []),
|
|
1837
1834
|
extractedAt: /* @__PURE__ */ new Date()
|
|
1838
1835
|
};
|
|
@@ -1928,7 +1925,7 @@ var FigmaMCPAdapter = class extends MCPAdapterBase {
|
|
|
1928
1925
|
/**
|
|
1929
1926
|
* 从文档提取全局样式
|
|
1930
1927
|
*/
|
|
1931
|
-
extractStylesFromDocument(
|
|
1928
|
+
extractStylesFromDocument(document) {
|
|
1932
1929
|
const styles = {
|
|
1933
1930
|
colors: [],
|
|
1934
1931
|
typography: [],
|
|
@@ -1954,7 +1951,7 @@ var FigmaMCPAdapter = class extends MCPAdapterBase {
|
|
|
1954
1951
|
node.children.forEach(traverse);
|
|
1955
1952
|
}
|
|
1956
1953
|
};
|
|
1957
|
-
traverse(
|
|
1954
|
+
traverse(document);
|
|
1958
1955
|
styles.colors = this.deduplicateColors(styles.colors);
|
|
1959
1956
|
styles.typography = this.deduplicateTypography(styles.typography);
|
|
1960
1957
|
return styles;
|
|
@@ -2547,10 +2544,10 @@ var FRONTEND_DEV_AGENT = {
|
|
|
2547
2544
|
var CODE_REVIEWER_AGENT = {
|
|
2548
2545
|
id: "code-reviewer",
|
|
2549
2546
|
name: "\u4EE3\u7801\u5BA1\u6838",
|
|
2550
|
-
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",
|
|
2551
2548
|
icon: "\u{1F50D}",
|
|
2552
|
-
version: "1.
|
|
2553
|
-
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",
|
|
2554
2551
|
capabilities: [
|
|
2555
2552
|
{
|
|
2556
2553
|
id: "quality-review",
|
|
@@ -2571,13 +2568,24 @@ var CODE_REVIEWER_AGENT = {
|
|
|
2571
2568
|
id: "performance-review",
|
|
2572
2569
|
name: "\u6027\u80FD\u5BA1\u67E5",
|
|
2573
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"
|
|
2574
2581
|
}
|
|
2575
2582
|
],
|
|
2576
2583
|
tools: [
|
|
2577
2584
|
{ name: "read_file", description: "\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9", permission: "full" },
|
|
2578
2585
|
{ name: "glob", description: "\u641C\u7D22\u6587\u4EF6", permission: "full" },
|
|
2579
2586
|
{ name: "search_file_content", description: "\u641C\u7D22\u6587\u4EF6\u5185\u5BB9", permission: "full" },
|
|
2580
|
-
{ 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" }
|
|
2581
2589
|
],
|
|
2582
2590
|
triggers: [
|
|
2583
2591
|
{ type: "workflow", condition: { workflowStep: "apply" }, priority: 10 },
|
|
@@ -2588,6 +2596,7 @@ var CODE_REVIEWER_AGENT = {
|
|
|
2588
2596
|
protectedPaths: ["node_modules", ".git"]
|
|
2589
2597
|
},
|
|
2590
2598
|
behavior: {
|
|
2599
|
+
requireConfirmation: ["run_shell_command"],
|
|
2591
2600
|
autoCommit: false
|
|
2592
2601
|
}
|
|
2593
2602
|
},
|
|
@@ -2596,6 +2605,7 @@ var CODE_REVIEWER_AGENT = {
|
|
|
2596
2605
|
## \u4F60\u7684\u804C\u8D23
|
|
2597
2606
|
- \u5BA1\u67E5\u4EE3\u7801\u8D28\u91CF\u548C\u53EF\u7EF4\u62A4\u6027
|
|
2598
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
|
|
2599
2609
|
- \u63D0\u4F9B\u5177\u4F53\u7684\u6539\u8FDB\u5EFA\u8BAE
|
|
2600
2610
|
- \u786E\u4FDD\u9075\u5FAA\u6700\u4F73\u5B9E\u8DF5
|
|
2601
2611
|
|
|
@@ -2604,8 +2614,20 @@ var CODE_REVIEWER_AGENT = {
|
|
|
2604
2614
|
2. **\u5B89\u5168\u6027**: XSS\u3001\u6CE8\u5165\u3001\u654F\u611F\u6570\u636E\u5904\u7406
|
|
2605
2615
|
3. **\u6027\u80FD**: \u7B97\u6CD5\u6548\u7387\u3001\u5185\u5B58\u4F7F\u7528\u3001\u6E32\u67D3\u4F18\u5316
|
|
2606
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
|
|
2607
2624
|
|
|
2608
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
|
+
|
|
2609
2631
|
### \u5BA1\u67E5\u7ED3\u679C
|
|
2610
2632
|
- \u901A\u8FC7/\u9700\u4FEE\u6539/\u4E0D\u901A\u8FC7
|
|
2611
2633
|
|
|
@@ -2631,7 +2653,7 @@ var CODE_REVIEWER_AGENT = {
|
|
|
2631
2653
|
## \u4E0A\u4E0B\u6587
|
|
2632
2654
|
{{context}}
|
|
2633
2655
|
|
|
2634
|
-
\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`,
|
|
2635
2657
|
outputFormat: {
|
|
2636
2658
|
type: "markdown"
|
|
2637
2659
|
}
|
|
@@ -5621,8 +5643,8 @@ var CommandParser = class {
|
|
|
5621
5643
|
};
|
|
5622
5644
|
}
|
|
5623
5645
|
parseAtPath(input) {
|
|
5624
|
-
const
|
|
5625
|
-
if (!
|
|
5646
|
+
const path14 = input.slice(1).trim();
|
|
5647
|
+
if (!path14) {
|
|
5626
5648
|
return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
|
|
5627
5649
|
}
|
|
5628
5650
|
return {
|
|
@@ -5630,7 +5652,7 @@ var CommandParser = class {
|
|
|
5630
5652
|
command: {
|
|
5631
5653
|
type: "at" /* AT */,
|
|
5632
5654
|
raw: input,
|
|
5633
|
-
path:
|
|
5655
|
+
path: path14
|
|
5634
5656
|
}
|
|
5635
5657
|
};
|
|
5636
5658
|
}
|
|
@@ -6474,8 +6496,26 @@ function createSpinner(message) {
|
|
|
6474
6496
|
stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
|
|
6475
6497
|
};
|
|
6476
6498
|
}
|
|
6477
|
-
|
|
6478
|
-
|
|
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;
|
|
6479
6519
|
async function handleUpdate(args, ctx) {
|
|
6480
6520
|
const options = {
|
|
6481
6521
|
check: args.includes("--check") || args.includes("-c"),
|
|
@@ -6502,6 +6542,9 @@ async function checkForUpdates() {
|
|
|
6502
6542
|
const latestVersion = await getLatestVersion();
|
|
6503
6543
|
if (!latestVersion) {
|
|
6504
6544
|
lines.push(chalk9__default.default.yellow("\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
|
|
6545
|
+
lines.push(chalk9__default.default.gray("\u53EF\u80FD\u539F\u56E0:"));
|
|
6546
|
+
lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
|
|
6547
|
+
lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
|
|
6505
6548
|
return { output: lines.join("\n") };
|
|
6506
6549
|
}
|
|
6507
6550
|
lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
|
|
@@ -6520,43 +6563,70 @@ async function checkForUpdates() {
|
|
|
6520
6563
|
async function performUpdate(targetVersion) {
|
|
6521
6564
|
const lines = [];
|
|
6522
6565
|
lines.push(chalk9__default.default.cyan("\u6B63\u5728\u66F4\u65B0 sf-cli..."));
|
|
6566
|
+
lines.push(chalk9__default.default.gray(` \u5305\u540D: ${PACKAGE_NAME}`));
|
|
6567
|
+
lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
|
|
6523
6568
|
try {
|
|
6524
6569
|
const latestVersion = await getLatestVersion();
|
|
6570
|
+
if (!latestVersion && !targetVersion) {
|
|
6571
|
+
lines.push(chalk9__default.default.yellow("\n\u26A0 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
|
|
6572
|
+
lines.push(chalk9__default.default.gray("\n\u53EF\u80FD\u539F\u56E0:"));
|
|
6573
|
+
lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
|
|
6574
|
+
lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
|
|
6575
|
+
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
6576
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
6577
|
+
return { output: lines.join("\n") };
|
|
6578
|
+
}
|
|
6525
6579
|
if (latestVersion === CURRENT_VERSION && !targetVersion) {
|
|
6526
|
-
lines.push(chalk9__default.default.green("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
|
|
6580
|
+
lines.push(chalk9__default.default.green("\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
|
|
6527
6581
|
return { output: lines.join("\n") };
|
|
6528
6582
|
}
|
|
6529
6583
|
const packageSpec = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
|
|
6530
6584
|
lines.push(chalk9__default.default.gray(` \u5B89\u88C5: ${packageSpec}`));
|
|
6531
|
-
await new Promise((
|
|
6585
|
+
const installResult = await new Promise((resolve4) => {
|
|
6532
6586
|
const proc = child_process.spawn("npm", ["install", "-g", packageSpec], {
|
|
6533
6587
|
stdio: "pipe",
|
|
6534
6588
|
shell: true
|
|
6535
6589
|
});
|
|
6590
|
+
let output = "";
|
|
6591
|
+
proc.stdout?.on("data", (data) => {
|
|
6592
|
+
output += data.toString();
|
|
6593
|
+
});
|
|
6594
|
+
proc.stderr?.on("data", (data) => {
|
|
6595
|
+
output += data.toString();
|
|
6596
|
+
});
|
|
6536
6597
|
proc.on("close", (code) => {
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
}
|
|
6598
|
+
resolve4({
|
|
6599
|
+
success: code === 0,
|
|
6600
|
+
output
|
|
6601
|
+
});
|
|
6542
6602
|
});
|
|
6543
6603
|
proc.on("error", (err) => {
|
|
6544
|
-
|
|
6604
|
+
resolve4({
|
|
6605
|
+
success: false,
|
|
6606
|
+
output: err.message
|
|
6607
|
+
});
|
|
6545
6608
|
});
|
|
6546
6609
|
});
|
|
6547
|
-
|
|
6610
|
+
if (!installResult.success) {
|
|
6611
|
+
lines.push(chalk9__default.default.red("\n\u2717 \u66F4\u65B0\u5931\u8D25"));
|
|
6612
|
+
lines.push(chalk9__default.default.gray(installResult.output));
|
|
6613
|
+
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
6614
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
6615
|
+
return { output: lines.join("\n") };
|
|
6616
|
+
}
|
|
6617
|
+
lines.push(chalk9__default.default.green("\n\u2713 \u66F4\u65B0\u5B8C\u6210!"));
|
|
6548
6618
|
lines.push(chalk9__default.default.gray(` \u65B0\u7248\u672C: v${targetVersion || latestVersion}`));
|
|
6549
6619
|
lines.push(chalk9__default.default.gray("\n\u8BF7\u91CD\u542F CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"));
|
|
6550
6620
|
} catch (error) {
|
|
6551
6621
|
lines.push(chalk9__default.default.red("\u66F4\u65B0\u5931\u8D25: " + error.message));
|
|
6552
6622
|
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
6553
|
-
lines.push(chalk9__default.default.
|
|
6623
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
6554
6624
|
}
|
|
6555
6625
|
return { output: lines.join("\n") };
|
|
6556
6626
|
}
|
|
6557
6627
|
async function getLatestVersion() {
|
|
6558
6628
|
try {
|
|
6559
|
-
const result = await new Promise((
|
|
6629
|
+
const result = await new Promise((resolve4, reject) => {
|
|
6560
6630
|
const proc = child_process.spawn("npm", ["view", PACKAGE_NAME, "version"], {
|
|
6561
6631
|
stdio: "pipe",
|
|
6562
6632
|
shell: true
|
|
@@ -6566,13 +6636,17 @@ async function getLatestVersion() {
|
|
|
6566
6636
|
output += data.toString();
|
|
6567
6637
|
});
|
|
6568
6638
|
proc.on("close", (code) => {
|
|
6569
|
-
if (code === 0) {
|
|
6570
|
-
|
|
6639
|
+
if (code === 0 && output.trim()) {
|
|
6640
|
+
resolve4(output.trim());
|
|
6571
6641
|
} else {
|
|
6572
6642
|
reject(new Error("Failed to get version"));
|
|
6573
6643
|
}
|
|
6574
6644
|
});
|
|
6575
6645
|
proc.on("error", reject);
|
|
6646
|
+
setTimeout(() => {
|
|
6647
|
+
proc.kill();
|
|
6648
|
+
reject(new Error("Timeout"));
|
|
6649
|
+
}, 1e4);
|
|
6576
6650
|
});
|
|
6577
6651
|
return result || null;
|
|
6578
6652
|
} catch {
|
|
@@ -6895,6 +6969,78 @@ function extractTitle(requirement) {
|
|
|
6895
6969
|
return requirement.slice(0, 47) + "...";
|
|
6896
6970
|
}
|
|
6897
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
|
+
}
|
|
6898
7044
|
async function handleOpsx(command, args, ctx) {
|
|
6899
7045
|
const step = command.replace("opsx:", "");
|
|
6900
7046
|
const workflow = new WorkflowEngine();
|
|
@@ -6909,7 +7055,7 @@ async function handleOpsx(command, args, ctx) {
|
|
|
6909
7055
|
case "apply":
|
|
6910
7056
|
return handleApply(workflow);
|
|
6911
7057
|
case "archive":
|
|
6912
|
-
return handleArchive(workflow, args);
|
|
7058
|
+
return handleArchive(workflow, args, ctx);
|
|
6913
7059
|
case "propose":
|
|
6914
7060
|
return handlePropose(workflow, args);
|
|
6915
7061
|
case "status":
|
|
@@ -6924,12 +7070,50 @@ async function handleOpsx(command, args, ctx) {
|
|
|
6924
7070
|
return handleNext(workflow);
|
|
6925
7071
|
case "auto":
|
|
6926
7072
|
return handleAutoSchedule(args);
|
|
7073
|
+
case "test":
|
|
7074
|
+
return handleRegressionTest(ctx);
|
|
6927
7075
|
default:
|
|
6928
7076
|
return {
|
|
6929
7077
|
output: chalk9__default.default.red(`\u672A\u77E5\u7684OpenSpec\u547D\u4EE4: /${command}`)
|
|
6930
7078
|
};
|
|
6931
7079
|
}
|
|
6932
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
|
+
}
|
|
6933
7117
|
function handleAutoSchedule(args) {
|
|
6934
7118
|
const action = args[0]?.toLowerCase();
|
|
6935
7119
|
if (!action) {
|
|
@@ -7059,13 +7243,70 @@ async function handleArchive(workflow, args, ctx) {
|
|
|
7059
7243
|
${generateConfirmationPrompt(confirmation.point)}`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /opsx:confirm code-review \u786E\u8BA4\u540E\u5F52\u6863")
|
|
7060
7244
|
};
|
|
7061
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("");
|
|
7062
7263
|
const changeId = state.id;
|
|
7063
7264
|
const summary = args.join(" ") || "\u5B8C\u6210\u53D8\u66F4";
|
|
7064
7265
|
await workflow.archive(summary);
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
\u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55")
|
|
7068
|
-
};
|
|
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
|
+
}
|
|
7069
7310
|
}
|
|
7070
7311
|
async function handlePropose(workflow, args, ctx) {
|
|
7071
7312
|
const state = workflow.getState();
|
|
@@ -7254,9 +7495,27 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
|
|
|
7254
7495
|
throw e;
|
|
7255
7496
|
}
|
|
7256
7497
|
}
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7498
|
+
|
|
7499
|
+
// src/commands/runner.ts
|
|
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();
|
|
7260
7519
|
async function runSlashCommand(command, args, ctx) {
|
|
7261
7520
|
const normalizedCommand = normalizeCommand(command);
|
|
7262
7521
|
switch (normalizedCommand) {
|
|
@@ -7351,7 +7610,7 @@ async function executeShell(command, ctx) {
|
|
|
7351
7610
|
\u547D\u4EE4 "${command}" \u53EF\u80FD\u4F1A\u5220\u9664\u91CD\u8981\u6587\u4EF6`) + chalk9__default.default.gray("\n\u4F7F\u7528 yolo \u6A21\u5F0F\u5F3A\u5236\u6267\u884C")
|
|
7352
7611
|
};
|
|
7353
7612
|
}
|
|
7354
|
-
return new Promise((
|
|
7613
|
+
return new Promise((resolve4) => {
|
|
7355
7614
|
const shell = child_process.spawn(command, [], {
|
|
7356
7615
|
shell: true,
|
|
7357
7616
|
cwd: ctx.options.workingDirectory
|
|
@@ -7376,11 +7635,11 @@ async function executeShell(command, ctx) {
|
|
|
7376
7635
|
output += chalk9__default.default.red(`
|
|
7377
7636
|
\u9000\u51FA\u7801: ${code}`);
|
|
7378
7637
|
}
|
|
7379
|
-
|
|
7638
|
+
resolve4({ output: output || chalk9__default.default.gray("(\u65E0\u8F93\u51FA)") });
|
|
7380
7639
|
});
|
|
7381
7640
|
setTimeout(() => {
|
|
7382
7641
|
shell.kill();
|
|
7383
|
-
|
|
7642
|
+
resolve4({
|
|
7384
7643
|
output: chalk9__default.default.yellow("\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0C\u5DF2\u7EC8\u6B62")
|
|
7385
7644
|
});
|
|
7386
7645
|
}, 6e4);
|