@spaceflow/review 0.47.0 → 0.49.0
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 +46 -0
- package/dist/index.js +38 -13
- package/package.json +3 -3
- package/src/index.ts +1 -1
- package/src/review.service.ts +45 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.48.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.47.0...@spaceflow/review@0.48.0) (2026-02-27)
|
|
4
|
+
|
|
5
|
+
### 新特性
|
|
6
|
+
|
|
7
|
+
* **mcp:** 添加 MCP 资源支持,包括扩展资源和内置配置/扩展列表资源 ([ab19889](https://github.com/Lydanne/spaceflow/commit/ab198890a13c998c17987734da3875834f747a70))
|
|
8
|
+
|
|
9
|
+
### 其他修改
|
|
10
|
+
|
|
11
|
+
* **cli:** released version 0.38.0 [no ci] ([b8c1a54](https://github.com/Lydanne/spaceflow/commit/b8c1a546876b1ad74d5da755c9ecafea9a99798d))
|
|
12
|
+
* **core:** released version 0.16.0 [no ci] ([4486a32](https://github.com/Lydanne/spaceflow/commit/4486a320fccea858e400b79c5b4f18ed4a6f58ea))
|
|
13
|
+
* **publish:** released version 0.40.0 [no ci] ([8fe14c7](https://github.com/Lydanne/spaceflow/commit/8fe14c7faffa2784b91710d3f129911534bf64d2))
|
|
14
|
+
* **review-summary:** released version 0.17.0 [no ci] ([e00f17d](https://github.com/Lydanne/spaceflow/commit/e00f17dc2ade751ff4de7b45b4d9671b25271f7c))
|
|
15
|
+
* **scripts:** released version 0.17.0 [no ci] ([8946ea6](https://github.com/Lydanne/spaceflow/commit/8946ea68e1ea372ae9d1c20cef098e1ef59bdf25))
|
|
16
|
+
* **shell:** released version 0.17.0 [no ci] ([fb4e833](https://github.com/Lydanne/spaceflow/commit/fb4e833b1a469bf2446b25656a3b439584a4639a))
|
|
17
|
+
|
|
18
|
+
## [0.47.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.46.0...@spaceflow/review@0.47.0) (2026-02-27)
|
|
19
|
+
|
|
20
|
+
### 新特性
|
|
21
|
+
|
|
22
|
+
* **shared:** 新增 findProjectRoot 函数用于查找项目根目录 ([7135262](https://github.com/Lydanne/spaceflow/commit/71352621f13e17a192821363e655607cfc097307))
|
|
23
|
+
|
|
24
|
+
### 修复BUG
|
|
25
|
+
|
|
26
|
+
* **cli:** 为扩展动态导入添加错误处理,防止单个扩展加载失败导致整体崩溃 ([09230dd](https://github.com/Lydanne/spaceflow/commit/09230ddf88568286b1f65c389976cb9a1a2fc880))
|
|
27
|
+
* **cli:** 修复 connectProjectMcpClient 函数中工作目录解析问题 ([94a927c](https://github.com/Lydanne/spaceflow/commit/94a927c8850b0b754459e0d8833be70721bc38d1))
|
|
28
|
+
|
|
29
|
+
### 代码重构
|
|
30
|
+
|
|
31
|
+
* **cli:** 分离工作目录和项目根目录概念,修复 .spaceflow 目录定位逻辑 ([5b7daab](https://github.com/Lydanne/spaceflow/commit/5b7daab2a3965fbd298ff85ad210d45028ff9d3d))
|
|
32
|
+
* **cli:** 重构工作目录和 .spaceflow 目录获取逻辑 ([a9708da](https://github.com/Lydanne/spaceflow/commit/a9708da6ea5b4315f802a0709125e24fe42bb10f))
|
|
33
|
+
* **core:** 优化 ExtensionLoader 访问器,简化 MCP 服务上下文获取 ([c1ac91f](https://github.com/Lydanne/spaceflow/commit/c1ac91f1990b565dbbc449e8349561e65fae368f))
|
|
34
|
+
* **core:** 简化 MCP 架构,移除 McpServerDefinition 层级 ([0d963a8](https://github.com/Lydanne/spaceflow/commit/0d963a874d03df50a140c57707b5363407e6b37d))
|
|
35
|
+
* **core:** 统一工作目录管理,优化 MCP 服务上下文 ([efe7244](https://github.com/Lydanne/spaceflow/commit/efe72444ff6207077a503200c629373a97e47a2c))
|
|
36
|
+
* **review:** 简化 MCP 工具的输入参数,统一从上下文获取工作目录 ([104893b](https://github.com/Lydanne/spaceflow/commit/104893b689bf32444850b06a2f4566292a1f8eba))
|
|
37
|
+
|
|
38
|
+
### 其他修改
|
|
39
|
+
|
|
40
|
+
* **.spaceflow:** 初始化 Spaceflow 扩展的包结构和依赖 ([5ac8d70](https://github.com/Lydanne/spaceflow/commit/5ac8d7008edcb96168a15ffc04973d154ca9f955))
|
|
41
|
+
* **cli:** released version 0.37.0 [no ci] ([a260a9a](https://github.com/Lydanne/spaceflow/commit/a260a9a13f1f7d8457ea036e40f5562548b4513e))
|
|
42
|
+
* **core:** released version 0.15.0 [no ci] ([e44cd0a](https://github.com/Lydanne/spaceflow/commit/e44cd0af8caadf1f2b89179d1ea44ecc0d018966))
|
|
43
|
+
* **publish:** released version 0.39.0 [no ci] ([f4db046](https://github.com/Lydanne/spaceflow/commit/f4db04635eab83ad44f8f3b935aa66ecfd02feff))
|
|
44
|
+
* **review-summary:** released version 0.16.0 [no ci] ([912b5f5](https://github.com/Lydanne/spaceflow/commit/912b5f5cf907935e7ef9e39ad32b742c46843b7e))
|
|
45
|
+
* **scripts:** released version 0.16.0 [no ci] ([77be50e](https://github.com/Lydanne/spaceflow/commit/77be50ea413e7b5c969c111429fd8cc425263cd1))
|
|
46
|
+
* **shared:** released version 0.6.0 [no ci] ([fcfdf75](https://github.com/Lydanne/spaceflow/commit/fcfdf75efa2146b5ed91e5c7f273a4f938c032b8))
|
|
47
|
+
* **shell:** released version 0.16.0 [no ci] ([538e157](https://github.com/Lydanne/spaceflow/commit/538e15783ed4482a25faf251a1513eae0dfb33ad))
|
|
48
|
+
|
|
3
49
|
## [0.46.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.45.0...@spaceflow/review@0.46.0) (2026-02-27)
|
|
4
50
|
|
|
5
51
|
### 新特性
|
package/dist/index.js
CHANGED
|
@@ -2427,8 +2427,14 @@ ${fileChanges || "无"}`;
|
|
|
2427
2427
|
await this.syncResolvedComments(owner, repo, prNumber, result);
|
|
2428
2428
|
// 获取评论的 reactions,同步 valid 状态(👎 标记为无效)
|
|
2429
2429
|
await this.syncReactionsToIssues(owner, repo, prNumber, result, verbose);
|
|
2430
|
-
// 查找已有的 AI 评论(Issue Comment
|
|
2431
|
-
|
|
2430
|
+
// 查找已有的 AI 评论(Issue Comment),可能存在多个重复评论
|
|
2431
|
+
if (shouldLog(verbose, 2)) {
|
|
2432
|
+
console.log(`[postOrUpdateReviewComment] owner=${owner}, repo=${repo}, prNumber=${prNumber}`);
|
|
2433
|
+
}
|
|
2434
|
+
const existingComments = await this.findExistingAiComments(owner, repo, prNumber, verbose);
|
|
2435
|
+
if (shouldLog(verbose, 2)) {
|
|
2436
|
+
console.log(`[postOrUpdateReviewComment] found ${existingComments.length} existing AI comments`);
|
|
2437
|
+
}
|
|
2432
2438
|
// 调试:检查 issues 是否有 author
|
|
2433
2439
|
if (shouldLog(verbose, 3)) {
|
|
2434
2440
|
for (const issue of result.issues.slice(0, 3)){
|
|
@@ -2445,9 +2451,19 @@ ${fileChanges || "无"}`;
|
|
|
2445
2451
|
const commitId = pr.head?.sha;
|
|
2446
2452
|
// 1. 发布或更新主评论(使用 Issue Comment API,支持删除和更新)
|
|
2447
2453
|
try {
|
|
2448
|
-
if (
|
|
2449
|
-
|
|
2454
|
+
if (existingComments.length > 0) {
|
|
2455
|
+
// 更新第一个 AI 评论
|
|
2456
|
+
await this.gitProvider.updateIssueComment(owner, repo, existingComments[0].id, reviewBody);
|
|
2450
2457
|
console.log(`✅ 已更新 AI Review 评论`);
|
|
2458
|
+
// 删除多余的重复 AI 评论
|
|
2459
|
+
for (const duplicate of existingComments.slice(1)){
|
|
2460
|
+
try {
|
|
2461
|
+
await this.gitProvider.deleteIssueComment(owner, repo, duplicate.id);
|
|
2462
|
+
console.log(`🗑️ 已删除重复的 AI Review 评论 (id: ${duplicate.id})`);
|
|
2463
|
+
} catch {
|
|
2464
|
+
console.warn(`⚠️ 删除重复评论失败 (id: ${duplicate.id})`);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2451
2467
|
} else {
|
|
2452
2468
|
await this.gitProvider.createIssueComment(owner, repo, prNumber, {
|
|
2453
2469
|
body: reviewBody
|
|
@@ -2529,16 +2545,25 @@ ${fileChanges || "无"}`;
|
|
|
2529
2545
|
}
|
|
2530
2546
|
}
|
|
2531
2547
|
/**
|
|
2532
|
-
*
|
|
2533
|
-
|
|
2548
|
+
* 查找已有的所有 AI 评论(Issue Comment)
|
|
2549
|
+
* 返回所有包含 REVIEW_COMMENT_MARKER 的评论,用于更新第一个并清理重复项
|
|
2550
|
+
*/ async findExistingAiComments(owner, repo, prNumber, verbose) {
|
|
2534
2551
|
try {
|
|
2535
2552
|
const comments = await this.gitProvider.listIssueComments(owner, repo, prNumber);
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2553
|
+
if (shouldLog(verbose, 2)) {
|
|
2554
|
+
console.log(`[findExistingAiComments] listIssueComments returned ${Array.isArray(comments) ? comments.length : typeof comments} comments`);
|
|
2555
|
+
if (Array.isArray(comments)) {
|
|
2556
|
+
for (const c of comments.slice(0, 5)){
|
|
2557
|
+
console.log(`[findExistingAiComments] comment id=${c.id}, body starts with: ${c.body?.slice(0, 80) ?? "(no body)"}`);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
return comments.filter((c)=>c.body?.includes(REVIEW_COMMENT_MARKER) && c.id).map((c)=>({
|
|
2562
|
+
id: c.id
|
|
2563
|
+
}));
|
|
2564
|
+
} catch (error) {
|
|
2565
|
+
console.warn("[findExistingAiComments] error:", error);
|
|
2566
|
+
return [];
|
|
2542
2567
|
}
|
|
2543
2568
|
}
|
|
2544
2569
|
/**
|
|
@@ -5212,7 +5237,7 @@ const extension = defineExtension({
|
|
|
5212
5237
|
deletionAnalysisMode: options?.deletionAnalysisMode,
|
|
5213
5238
|
deletionOnly: !!options?.deletionOnly,
|
|
5214
5239
|
outputFormat: options?.outputFormat,
|
|
5215
|
-
generateDescription:
|
|
5240
|
+
generateDescription: options?.generateDescription ? true : undefined,
|
|
5216
5241
|
showAll: !!options?.showAll,
|
|
5217
5242
|
flush: isFlush,
|
|
5218
5243
|
eventAction: options?.eventAction
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spaceflow/review",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"description": "Spaceflow 代码审查插件,使用 LLM 对 PR 代码进行自动审查",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Lydanne",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"@vitest/coverage-v8": "^4.0.18",
|
|
26
26
|
"unplugin-swc": "^1.5.9",
|
|
27
27
|
"vitest": "^4.0.18",
|
|
28
|
-
"@spaceflow/cli": "0.
|
|
28
|
+
"@spaceflow/cli": "0.38.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@spaceflow/core": "0.
|
|
31
|
+
"@spaceflow/core": "0.17.0"
|
|
32
32
|
},
|
|
33
33
|
"spaceflow": {
|
|
34
34
|
"type": "flow",
|
package/src/index.ts
CHANGED
|
@@ -98,7 +98,7 @@ export const extension = defineExtension({
|
|
|
98
98
|
deletionAnalysisMode: options?.deletionAnalysisMode as LLMMode,
|
|
99
99
|
deletionOnly: !!options?.deletionOnly,
|
|
100
100
|
outputFormat: options?.outputFormat as ReportFormat,
|
|
101
|
-
generateDescription:
|
|
101
|
+
generateDescription: options?.generateDescription ? true : undefined,
|
|
102
102
|
showAll: !!options?.showAll,
|
|
103
103
|
flush: isFlush,
|
|
104
104
|
eventAction: options?.eventAction as string,
|
package/src/review.service.ts
CHANGED
|
@@ -1880,8 +1880,16 @@ ${fileChanges || "无"}`;
|
|
|
1880
1880
|
// 获取评论的 reactions,同步 valid 状态(👎 标记为无效)
|
|
1881
1881
|
await this.syncReactionsToIssues(owner, repo, prNumber, result, verbose);
|
|
1882
1882
|
|
|
1883
|
-
// 查找已有的 AI 评论(Issue Comment
|
|
1884
|
-
|
|
1883
|
+
// 查找已有的 AI 评论(Issue Comment),可能存在多个重复评论
|
|
1884
|
+
if (shouldLog(verbose, 2)) {
|
|
1885
|
+
console.log(`[postOrUpdateReviewComment] owner=${owner}, repo=${repo}, prNumber=${prNumber}`);
|
|
1886
|
+
}
|
|
1887
|
+
const existingComments = await this.findExistingAiComments(owner, repo, prNumber, verbose);
|
|
1888
|
+
if (shouldLog(verbose, 2)) {
|
|
1889
|
+
console.log(
|
|
1890
|
+
`[postOrUpdateReviewComment] found ${existingComments.length} existing AI comments`,
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1885
1893
|
|
|
1886
1894
|
// 调试:检查 issues 是否有 author
|
|
1887
1895
|
if (shouldLog(verbose, 3)) {
|
|
@@ -1904,9 +1912,19 @@ ${fileChanges || "无"}`;
|
|
|
1904
1912
|
|
|
1905
1913
|
// 1. 发布或更新主评论(使用 Issue Comment API,支持删除和更新)
|
|
1906
1914
|
try {
|
|
1907
|
-
if (
|
|
1908
|
-
|
|
1915
|
+
if (existingComments.length > 0) {
|
|
1916
|
+
// 更新第一个 AI 评论
|
|
1917
|
+
await this.gitProvider.updateIssueComment(owner, repo, existingComments[0].id, reviewBody);
|
|
1909
1918
|
console.log(`✅ 已更新 AI Review 评论`);
|
|
1919
|
+
// 删除多余的重复 AI 评论
|
|
1920
|
+
for (const duplicate of existingComments.slice(1)) {
|
|
1921
|
+
try {
|
|
1922
|
+
await this.gitProvider.deleteIssueComment(owner, repo, duplicate.id);
|
|
1923
|
+
console.log(`🗑️ 已删除重复的 AI Review 评论 (id: ${duplicate.id})`);
|
|
1924
|
+
} catch {
|
|
1925
|
+
console.warn(`⚠️ 删除重复评论失败 (id: ${duplicate.id})`);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1910
1928
|
} else {
|
|
1911
1929
|
await this.gitProvider.createIssueComment(owner, repo, prNumber, { body: reviewBody });
|
|
1912
1930
|
console.log(`✅ 已发布 AI Review 评论`);
|
|
@@ -1994,19 +2012,35 @@ ${fileChanges || "无"}`;
|
|
|
1994
2012
|
}
|
|
1995
2013
|
|
|
1996
2014
|
/**
|
|
1997
|
-
*
|
|
2015
|
+
* 查找已有的所有 AI 评论(Issue Comment)
|
|
2016
|
+
* 返回所有包含 REVIEW_COMMENT_MARKER 的评论,用于更新第一个并清理重复项
|
|
1998
2017
|
*/
|
|
1999
|
-
protected async
|
|
2018
|
+
protected async findExistingAiComments(
|
|
2000
2019
|
owner: string,
|
|
2001
2020
|
repo: string,
|
|
2002
2021
|
prNumber: number,
|
|
2003
|
-
|
|
2022
|
+
verbose?: VerboseLevel,
|
|
2023
|
+
): Promise<{ id: number }[]> {
|
|
2004
2024
|
try {
|
|
2005
2025
|
const comments = await this.gitProvider.listIssueComments(owner, repo, prNumber);
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2026
|
+
if (shouldLog(verbose, 2)) {
|
|
2027
|
+
console.log(
|
|
2028
|
+
`[findExistingAiComments] listIssueComments returned ${Array.isArray(comments) ? comments.length : typeof comments} comments`,
|
|
2029
|
+
);
|
|
2030
|
+
if (Array.isArray(comments)) {
|
|
2031
|
+
for (const c of comments.slice(0, 5)) {
|
|
2032
|
+
console.log(
|
|
2033
|
+
`[findExistingAiComments] comment id=${c.id}, body starts with: ${c.body?.slice(0, 80) ?? "(no body)"}`,
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
return comments
|
|
2039
|
+
.filter((c) => c.body?.includes(REVIEW_COMMENT_MARKER) && c.id)
|
|
2040
|
+
.map((c) => ({ id: c.id! }));
|
|
2041
|
+
} catch (error) {
|
|
2042
|
+
console.warn("[findExistingAiComments] error:", error);
|
|
2043
|
+
return [];
|
|
2010
2044
|
}
|
|
2011
2045
|
}
|
|
2012
2046
|
|