feat: 规则导入 Converter 架构 + Excel/AI 转换 + 多项优化
- 提取 RuleConverter 接口及 5 个实现(Yaml/Md/Txt/ExcelConverter), 由 ImportService 按扩展名路由,简化 setupView.ts addRule() 为单行调用 - Excel 导入:读取 xlsx → Markdown 表格 → AI 识别列头 → 生成 YAML - 添加规则支持 yaml/yml/md/txt/xlsx/xls 多种格式 - 导出报告改为 QuickPick 双选(复制到剪贴板 / 下载 Markdown 文件) - 修复测试连接成功后第三步圆圈不变绿的 bug - 侧边栏标题改为「净码特工 · 代码审查 · 设置」 - 规则名称输入框增加提示文字 - 新增测试:adapter、config、merger、pipeline + fixtures/manual - 依赖:新增 xlsx
This commit is contained in:
@@ -89,3 +89,11 @@
|
||||
| 2026-07-20 20:52 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 | 按审查面板优化 spec 重写 src/panel/webview.ts:对齐 review-panel-preview.html 原型(SVG 图标 header、severity 侧栏+圆点双指示器、来源 Badge、展开/折叠详情、错误框、严重级别分色 Tab 计数徽章、section-header)。移除 emoji 严重性图标和 diff 展示。 | 视觉伴侣(环境不支持)→ 终端 brainstorm;方案选择(用户选 A);讨论移除 diff。 | src/panel/webview.ts | deepseek-v4-flash |
|
||||
| 2026-07-20 21:30 | ① 用户提出 → ⑤ 编码实现 → ⑥ 审查验证 | Bug fix: 静态分析展开详情「原文:」重复显示消息内容。合并后 suggestion 与 message 相同时不渲染详情;linter/custom 项禁止展开(仅 AI 项保留展开)。 | 三轮迭代:①删原文→②加 check dup→③加 expandable 参数 | src/panel/webview.ts | deepseek-v4-flash |
|
||||
| 2026-07-20 21:42 | ① 用户提出 → ⑤ 编码实现 | 设置画面改用 `--vscode-*` CSS 变量,跟随 VS Code 主题 | 先用 `--vscode-editor-background` 但用户反馈没生效 → 改用 `--vscode-sideBar-background` 并加 `html` 规则 + fallback;replaceAll 导致双层嵌套 → 手动修复 | src/views/setupView.ts | deepseek-v4-flash |
|
||||
| 2026-07-21 20:51 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 | 导出报告按钮改为 QuickPick 双选(复制到剪贴板 / 下载 Markdown 文件) | 无 | src/activation/commands.ts | deepseek-v4-flash |
|
||||
| 2026-07-21 21:15 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 | 侧边栏设置视图 HTML 标题栏改为「净码特工 · 代码审查 · 设置」 | 方案先包含 package.json → 审批阶段用户取消面板标题改、仅保留 HTML 标题栏改动 | src/views/setupView.ts | deepseek-v4-flash |
|
||||
| 2026-07-21 21:21 | ① 用户提出 → ⑤ 编码实现 → ⑥ 审查验证 | Bug fix: 测试连接成功后第三步圆圈不变绿 — testResult 消息处理器缺少 step 指示器更新,仅 initConfig 处理器更新;提取 updateSteps() 共享函数并从 testResult 中调用 | 无 | src/views/setupView.js | deepseek-v4-flash |
|
||||
| 2026-07-21 21:32 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 添加规则支持更多文件类型:文件过滤器从仅 md 扩展为 yaml/yml/md/txt;.yaml/.yml 直接复制跳过 AI 转换;.txt 与 .md 走 AI 转换 | 无 | src/views/setupView.ts | deepseek-v4-flash |
|
||||
| 2026-07-21 21:35 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 规则名称输入框下方增加提示文字:「建议使用英文名称,无需输入 .yaml 后缀(如 security-rules)」 | 无 | src/views/setupView.ts | deepseek-v4-flash |
|
||||
| 2026-07-21 21:47 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 规则导入 Converter 架构:提取 RuleConverter 接口、YamlConverter/MdConverter/TxtConverter、ImportService,简化 setupView.ts addRule() | 无 | src/rules/converters/converter.ts src/rules/converters/yaml-converter.ts src/rules/converters/md-converter.ts src/rules/converters/txt-converter.ts src/rules/import-service.ts src/views/setupView.ts docs/superpowers/specs/2026-07-21-converter-architecture-design.md | deepseek-v4-flash |
|
||||
| 2026-07-21 21:50 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 新增 Excel 导入支持:ExcelConverter + 更新文件选择过滤器 + 注册到 ImportService | 无 | src/rules/converters/excel-converter.ts src/views/setupView.ts package.json | deepseek-v4-flash |
|
||||
| 2026-07-21 22:04 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | Excel 导入改为全 AI 转换:移除固定列名校验,转为 Markdown 表格 → AI 识别 → YAML | 无 | src/rules/converters/excel-converter.ts docs/superpowers/specs/2026-07-21-excel-ai-converter-design.md | deepseek-v4-flash |
|
||||
|
||||
Generated
+107
-25
@@ -9,7 +9,9 @@
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"eslint": "^9.39.3",
|
||||
"stylelint": "^17.14.0"
|
||||
"stylelint": "^17.14.0",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^10.0.10",
|
||||
@@ -19,8 +21,7 @@
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"@vscode/vsce": "^3.9.2",
|
||||
"esbuild": "^0.28.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.1"
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.120.0"
|
||||
@@ -1621,7 +1622,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz",
|
||||
"integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
@@ -1650,7 +1650,6 @@
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
@@ -1660,7 +1659,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz",
|
||||
"integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.60.1",
|
||||
@@ -1685,7 +1683,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz",
|
||||
"integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.60.1",
|
||||
@@ -1707,7 +1704,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz",
|
||||
"integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.60.1",
|
||||
@@ -1725,7 +1721,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz",
|
||||
"integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1742,7 +1737,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz",
|
||||
"integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.60.1",
|
||||
@@ -1767,7 +1761,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz",
|
||||
"integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1781,7 +1774,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz",
|
||||
"integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.60.1",
|
||||
@@ -1809,7 +1801,6 @@
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
@@ -1819,7 +1810,6 @@
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
@@ -1832,7 +1822,6 @@
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
|
||||
"integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^5.0.5"
|
||||
@@ -1848,7 +1837,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz",
|
||||
"integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
@@ -1872,7 +1860,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz",
|
||||
"integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.60.1",
|
||||
@@ -1890,7 +1877,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
|
||||
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
@@ -2252,6 +2238,15 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adler-32": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
|
||||
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
@@ -2665,6 +2660,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cfb": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
|
||||
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"crc-32": "~1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -2887,6 +2895,15 @@
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
|
||||
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -2980,6 +2997,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/crc-32": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
|
||||
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"crc32": "bin/crc32.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -3869,6 +3898,15 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/frac": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
|
||||
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
@@ -6432,7 +6470,6 @@
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz",
|
||||
"integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
@@ -6690,6 +6727,18 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/ssf": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
|
||||
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"frac": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/stdin-discarder": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
|
||||
@@ -7256,7 +7305,6 @@
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
@@ -7273,7 +7321,6 @@
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
@@ -7291,7 +7338,6 @@
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -7326,7 +7372,6 @@
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
|
||||
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
@@ -7407,7 +7452,6 @@
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -7421,7 +7465,6 @@
|
||||
"version": "8.60.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz",
|
||||
"integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.60.1",
|
||||
@@ -7594,6 +7637,24 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/wmf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
|
||||
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
|
||||
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
@@ -7741,6 +7802,27 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
|
||||
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"cfb": "~1.2.1",
|
||||
"codepage": "~1.15.0",
|
||||
"crc-32": "~1.2.1",
|
||||
"ssf": "~0.11.2",
|
||||
"wmf": "~1.0.1",
|
||||
"word": "~0.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"xlsx": "bin/xlsx.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
|
||||
|
||||
+2
-1
@@ -244,7 +244,8 @@
|
||||
"dependencies": {
|
||||
"eslint": "^9.39.3",
|
||||
"stylelint": "^17.14.0",
|
||||
"typescript-eslint": "^8.56.1"
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^10.0.10",
|
||||
|
||||
@@ -112,8 +112,28 @@ export function registerCommands(
|
||||
return;
|
||||
}
|
||||
const markdown = reportToMarkdown(currentReport);
|
||||
const doc = await vscode.workspace.openTextDocument({ content: markdown, language: 'markdown' });
|
||||
await vscode.window.showTextDocument(doc);
|
||||
const pick = await vscode.window.showQuickPick([
|
||||
{ label: '📋 复制到剪贴板', description: '将报告内容以 Markdown 格式复制到剪贴板' },
|
||||
{ label: '📄 下载 Markdown 文件', description: '将报告保存为 .md 文件' },
|
||||
], { placeHolder: '选择导出方式' });
|
||||
if (!pick) { return; }
|
||||
if (pick.label.startsWith('📋')) {
|
||||
await vscode.env.clipboard.writeText(markdown);
|
||||
vscode.window.showInformationMessage('报告已复制到剪贴板');
|
||||
} else {
|
||||
const fileName = currentReport.filePath.split(/[/\\]/).pop()?.replace(/\.[^.]+$/, '') ?? 'review-report';
|
||||
const defaultUri = vscode.workspace.workspaceFolders?.[0]
|
||||
? vscode.Uri.joinPath(vscode.workspace.workspaceFolders[0].uri, `${fileName}-review.md`)
|
||||
: undefined;
|
||||
const uri = await vscode.window.showSaveDialog({
|
||||
defaultUri,
|
||||
filters: { 'Markdown': ['md'] },
|
||||
title: '保存审查报告',
|
||||
});
|
||||
if (!uri) { return; }
|
||||
await vscode.workspace.fs.writeFile(uri, Buffer.from(markdown, 'utf-8'));
|
||||
vscode.window.showInformationMessage(`报告已保存到 ${uri.fsPath}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
+22
-14
@@ -20,6 +20,23 @@
|
||||
vscode.postMessage({ type: 'deleteFile', fileName: fileName });
|
||||
}
|
||||
|
||||
var _step1Done = false;
|
||||
var _step2Done = false;
|
||||
|
||||
function updateSteps(step3Done) {
|
||||
var steps = [_step1Done, _step2Done, step3Done];
|
||||
for (var i = 0; i < steps.length; i++) {
|
||||
var el = document.querySelector('.gs-step[data-step="' + (i + 1) + '"]');
|
||||
if (!el) { continue; }
|
||||
el.classList.remove('gs-step-done', 'gs-step-skip');
|
||||
if (steps[i]) {
|
||||
el.classList.add('gs-step-done');
|
||||
} else if (step3Done) {
|
||||
el.classList.add('gs-step-skip');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
var d = document.createElement('div');
|
||||
d.textContent = text;
|
||||
@@ -123,20 +140,9 @@
|
||||
ruleList.innerHTML = '<div style="font-size:12px;color:#484f58;padding:8px 0;text-align:center;">暂无规则文件</div>';
|
||||
}
|
||||
|
||||
var step1Done = c.provider && c.model && c.apiKeyConfigured && c.baseUrlConfigured;
|
||||
var step2Done = msg.ruleFiles && msg.ruleFiles.length > 0;
|
||||
var step3Done = msg.connectionTested && msg.connectionSuccess;
|
||||
var steps = [step1Done, step2Done, step3Done];
|
||||
for (var i = 0; i < steps.length; i++) {
|
||||
var el = document.querySelector('.gs-step[data-step="' + (i + 1) + '"]');
|
||||
if (!el) { continue; }
|
||||
el.classList.remove('gs-step-done', 'gs-step-skip');
|
||||
if (steps[i]) {
|
||||
el.classList.add('gs-step-done');
|
||||
} else if (step3Done) {
|
||||
el.classList.add('gs-step-skip');
|
||||
}
|
||||
}
|
||||
_step1Done = c.provider && c.model && c.apiKeyConfigured && c.baseUrlConfigured;
|
||||
_step2Done = msg.ruleFiles && msg.ruleFiles.length > 0;
|
||||
updateSteps(msg.connectionTested && msg.connectionSuccess);
|
||||
}
|
||||
|
||||
if (msg.type === 'testResult') {
|
||||
@@ -152,6 +158,8 @@
|
||||
} else {
|
||||
btnTest.innerHTML = '✗ 重试';
|
||||
}
|
||||
|
||||
updateSteps(msg.success);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+21
-65
@@ -5,6 +5,11 @@ import { getAIProvider, getAIModel, getAIOutputLanguage, getAIConfig } from '../
|
||||
import { getApiKey, setApiKey } from '../config/secret';
|
||||
import { createProvider, getAllProviderMeta, getProviderModels } from '../ai/factory';
|
||||
import { listRuleFiles } from '../rules/yaml-parser';
|
||||
import { ImportService } from '../rules/import-service';
|
||||
import { YamlConverter } from '../rules/converters/yaml-converter';
|
||||
import { MdConverter } from '../rules/converters/md-converter';
|
||||
import { TxtConverter } from '../rules/converters/txt-converter';
|
||||
import { ExcelConverter } from '../rules/converters/excel-converter';
|
||||
|
||||
const languageLabels: Record<string, string> = {
|
||||
'zh-CN': '中文(简体)',
|
||||
@@ -16,8 +21,14 @@ export class SetupViewProvider implements vscode.WebviewViewProvider {
|
||||
private _view?: vscode.WebviewView;
|
||||
public connectionTested = false;
|
||||
public connectionSuccess = false;
|
||||
private importService = new ImportService();
|
||||
|
||||
constructor(private context: vscode.ExtensionContext) {}
|
||||
constructor(private context: vscode.ExtensionContext) {
|
||||
this.importService.registerConverter(new YamlConverter());
|
||||
this.importService.registerConverter(new MdConverter());
|
||||
this.importService.registerConverter(new TxtConverter());
|
||||
this.importService.registerConverter(new ExcelConverter());
|
||||
}
|
||||
|
||||
resolveWebviewView(
|
||||
webviewView: vscode.WebviewView,
|
||||
@@ -168,30 +179,19 @@ export class SetupViewProvider implements vscode.WebviewViewProvider {
|
||||
}
|
||||
|
||||
private async addRule(name: string): Promise<void> {
|
||||
if (!name.trim()) {return;}
|
||||
if (!name.trim()) { return; }
|
||||
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (!workspaceRoot) {return;}
|
||||
if (!workspaceRoot) { return; }
|
||||
|
||||
const result = await vscode.window.showOpenDialog({
|
||||
canSelectMany: false,
|
||||
openLabel: '选择 Markdown 规则文件',
|
||||
filters: { 'Markdown': ['md'] },
|
||||
openLabel: '选择规则文件',
|
||||
filters: { '规则文件': ['yaml', 'yml', 'md', 'txt', 'xlsx', 'xls'] },
|
||||
});
|
||||
if (!result || result.length === 0) {return;}
|
||||
if (!result || result.length === 0) { return; }
|
||||
|
||||
const mdPath = result[0].fsPath;
|
||||
const mdContent = fs.readFileSync(mdPath, 'utf-8');
|
||||
if (!mdContent.trim()) {
|
||||
vscode.window.showErrorMessage('所选文件为空');
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey = await getApiKey(this.context);
|
||||
if (!apiKey) {
|
||||
vscode.window.showErrorMessage('请先在设置面板中配置 API Key');
|
||||
return;
|
||||
}
|
||||
const srcPath = result[0].fsPath;
|
||||
|
||||
const rulesDir = path.join(workspaceRoot, '.code-review', 'rules');
|
||||
if (!fs.existsSync(rulesDir)) {
|
||||
@@ -206,52 +206,7 @@ export class SetupViewProvider implements vscode.WebviewViewProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = getAIConfig();
|
||||
const provider = createProvider(config.provider, apiKey, config.baseUrl);
|
||||
|
||||
const systemPrompt = `你是一个代码审查规则转换器。将用户提供的自然语言规则描述,转换为结构化的 YAML 格式,用于代码审查工具。
|
||||
|
||||
每条规则需要包含以下字段:
|
||||
- id: 规则唯一标识(kebab-case 英文)
|
||||
- severity: 严重级别(error / warning / info)
|
||||
- description: 规则简短描述(中文)
|
||||
- message: 违反时的提示消息(中文)
|
||||
- languages: 适用语言数组(可选,如 [javascript, typescript])
|
||||
|
||||
输出格式示例:
|
||||
- id: no-console-log
|
||||
severity: warning
|
||||
description: 禁止使用 console.log
|
||||
message: 请使用 logger 工具替代 console.log
|
||||
languages: [javascript, typescript]
|
||||
|
||||
仅输出 YAML,不要额外说明。`;
|
||||
|
||||
let yamlOutput: string;
|
||||
try {
|
||||
yamlOutput = await provider.chat(systemPrompt, mdContent, {
|
||||
model: config.model,
|
||||
temperature: 0.1,
|
||||
maxTokens: 4096,
|
||||
timeoutMs: 30000,
|
||||
});
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
vscode.window.showErrorMessage(`AI 生成规则失败: ${msg}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const cleaned = yamlOutput
|
||||
.replace(/```(yaml|yml)?\s*/gi, '')
|
||||
.replace(/```\s*$/gm, '')
|
||||
.trim();
|
||||
|
||||
if (!cleaned) {
|
||||
vscode.window.showErrorMessage('AI 返回内容为空');
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(yamlPath, cleaned, 'utf-8');
|
||||
await this.importService.convert(srcPath, yamlPath, this.context);
|
||||
}
|
||||
|
||||
private async resetConfig(): Promise<void> {
|
||||
@@ -485,7 +440,7 @@ input::placeholder { color: var(--vscode-input-placeholderForeground, var(--vsco
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
</svg>
|
||||
代码审查 · 设置
|
||||
净码特工 · 代码审查 · 设置
|
||||
</div>
|
||||
|
||||
<!-- 1. 快速开始 -->
|
||||
@@ -613,6 +568,7 @@ input::placeholder { color: var(--vscode-input-placeholderForeground, var(--vsco
|
||||
<input type="text" id="newRuleInput" placeholder="输入规则名称...">
|
||||
<button class="btn btn-sm" style="background:#7c3aed;color:#fff;border-color:#7c3aed;" onclick="addRule()">+ 添加</button>
|
||||
</div>
|
||||
<div class="field-hint">建议使用英文名称,无需输入 .yaml 后缀(如 security-rules)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user