@feng0531/dsh-code-review 0.70.0 → 0.71.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 +5 -1
- package/CORE-ALIGNMENT-TASKS.md +2 -1
- package/RELEASE-NOTES.md +9 -8
- package/SVN-SUPPORT-MATRIX.md +34 -3
- package/package.json +1 -1
- package/src/service.mjs +1 -1
- package/src/svn-eol-mapping.mjs +13 -0
- package/src/svn.mjs +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
本文件介绍对使用者有意义的变化。安装与参数见 [README](README.md),本次发布正文见 [发布说明](RELEASE-NOTES.md)。历史提交和安装包保留在 [GitHub Releases](https://github.com/f-e-n-g-0531/dsh-code-review/releases);本文不把开发日志当作功能介绍。
|
|
4
4
|
|
|
5
|
+
## 0.71.0 — SVN 工作副本换行映射元数据
|
|
6
|
+
|
|
7
|
+
有 svn:eol-style 的变更文件在预览和模型输入中披露双侧换行计数、样式和 LF 视图哈希,原文与原始字节证据保持不变。CRLF/LF 保持 LF 证据行号,单 CR 明确不是规范化 LF 行号的 identity 映射。混合换行不被静默改写,哈希相同不证明运行时等价。非法样式或 SVN 自身不可读取时明确失败。固定历史模式和上下文规范化不在本批范围,全面 SVN 目标尚未完成。
|
|
8
|
+
|
|
5
9
|
## 0.70.0 — SVN 工作副本标准关键字原文审查
|
|
6
10
|
|
|
7
|
-
标准 svn:keywords 文件支持行保持映射核验,BASE 收缩与未展开仓库正文比较,原正文/原hash不替换。预览披露映射元数据,模型仍使用原始展开源码、原行号和明确提示,不以关键字变化直接推定缺陷或行为等价。自定义、固定宽度与未闭合展开继续阻断;关键字上下文导航及换行规范化仍待实现。
|
|
11
|
+
标准 svn:keywords 文件支持行保持映射核验,BASE 收缩与未展开仓库正文比较,原正文/原hash不替换。预览披露映射元数据,模型仍使用原始展开源码、原行号和明确提示,不以关键字变化直接推定缺陷或行为等价。自定义、固定宽度与未闭合展开继续阻断;关键字上下文导航及换行规范化仍待实现。504 项串行回归、宿主、隔离安装和四矩阵 CI 通过;原产物/npm/Release 137,678 字节逐字节一致,双哈希、清单与冻结发布说明通过。
|
|
8
12
|
|
|
9
13
|
## 0.69.0 — SVN 固定历史限定调用方发现
|
|
10
14
|
|
package/CORE-ALIGNMENT-TASKS.md
CHANGED
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
## 当前验证结论
|
|
34
34
|
|
|
35
|
-
- 最近完整回归:
|
|
35
|
+
- 最近完整回归:504 项通过。
|
|
36
|
+
- v0.70.0 已发布标准 SVN 工作副本关键字原文审查,BASE收缩独立核验、原正文/hash/行号不替换,预览披露映射。504 项串行回归、宿主、隔离安装和四矩阵 CI 通过;原产物/npm/Release 137,678 字节逐字节一致,双哈希、清单与冻结发布说明通过。自定义/固定宽度关键字、换行规范化、未提交替换、跨URL分支等缺口仍未闭环。
|
|
36
37
|
- v0.69.0 已发布固定 SVN 历史限定调用方与autoContext组合,扫描两侧候选、仅命中侧正文捕获,同侧声明导航,统一采集/来源/探测预算;字面发现仍明确不完整。502 项串行回归、宿主、隔离安装和四矩阵 CI 通过;原产物/npm/Release 136,030 字节逐字节一致,双哈希、清单与冻结发布说明通过。全面 SVN 目标仍未完成。
|
|
37
38
|
- v0.68.0 已交付固定 SVN 历史三层 autoContext,逐侧正文/来源固定、父目录有界清单确认精确节点,不吞访问失败,不读工作树。496 项串行回归、宿主、隔离安装和四矩阵 CI 通过;原产物/npm/Release 134,056 字节逐字节一致,双哈希、清单与冻结发布说明通过。历史调用方和全面 SVN 其他缺口继续。
|
|
38
39
|
- v0.67.0 已交付 SVN 工作副本 BASE/工作侧 mergeinfo 的有界显式导航、预览与报告披露,不扩大来源读取或将导航视为审查证明。489 项串行回归、宿主、隔离安装和四矩阵 CI 通过;原产物/npm/Release 130,866 字节逐字节一致,双哈希、清单与冻结发布说明通过。全面 SVN 目标仍未完成。
|
package/RELEASE-NOTES.md
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
# v0.
|
|
1
|
+
# v0.71.0 发布说明
|
|
2
2
|
|
|
3
|
-
## SVN
|
|
3
|
+
## SVN 工作副本换行映射元数据
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
审查具有 `svn:eol-style` 的工作副本变更文件时,预览和模型输入新增双侧换行样式、CRLF/LF/CR 计数、混合换行标志、原文本哈希及 LF 视图哈希。
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
- 原始正文、原始字节哈希和证据行号不变,不用规范化正文替换审查来源。文本哈希不是编码前字节哈希。
|
|
8
|
+
- CRLF/LF 保持 LF 证据行号;单 CR 明确不能使用规范化 LF 视图行号。
|
|
9
|
+
- 不以换行差异或视图哈希相同直接推定缺陷、文本行为等价或 SVN 提交一定成功。
|
|
10
|
+
- 非法样式、超限及 SVN 自身不可读取时明确失败,不能伪造完整采集。
|
|
11
|
+
- 可与已支持的标准关键字映射组合;预览仍不发送模型,执行仍需确认。
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
本批只增加工作副本变更文件的映射元数据,不扩大上下文读取或网络访问,不新增工作副本写命令,不宣称固定历史/上下文规范化已支持。未提交替换、跨 URL 分支比较等剩余目标见 [支持矩阵](SVN-SUPPORT-MATRIX.md)。
|
|
13
14
|
|
|
14
15
|
使用见 [README](README.md)。
|
package/SVN-SUPPORT-MATRIX.md
CHANGED
|
@@ -21,16 +21,47 @@
|
|
|
21
21
|
| 普通新增/删除目录及后代 | v0.60.0 已发布:补齐默认 status 隐藏的删除后代,离线递归枚举与末尾清单复核;普通结构目录只在后代全选且可审查时开放,凭据/阻断子项导致目录覆盖不足。461 项串行回归、宿主、隔离安装与四矩阵 CI 通过;原产物/npm/Release 118,284 字节逐字节一致,双哈希/清单/冻结发布说明通过 | 第二批普通目录子批 |
|
|
22
22
|
| 替换、删除再新增、文件/目录类型变化 | 普通与复制替换分别用 SVN_REPLACEMENT/SVN_COPIED_REPLACEMENT 诊断;离线探测确认前者 BASE 无 pristine,后者可能返回复制来源,禁止伪造旧侧。已新增未接入采集的 candidate-only 完整 diff 重建组件及真实离线测试:匹配完整工作侧,拒绝片段、错侧、截断与超限。diff 仍不能独立证明旧节点/编码/旧属性,因此未提交工作副本真实双侧替换仍未支持,不能把辅助组件算作支持完成。v0.64.1 已发布已提交固定历史版本的同路径 deleted/added 合并,真实目标旧/新正文与属性通过测试;481 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 128,279 字节、双哈希/清单/发布说明通过。v0.65.0 已发布已提交固定历史文件/目录类型替换:分侧 kind/正文/属性、预览披露和目录后代覆盖;482 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 128,792 字节、双哈希/清单/发布说明通过。未提交替换仍拒绝 | 第二批:区分 BASE 旧节点与目标节点 |
|
|
23
23
|
| 缺失、文本/属性/树冲突、阻塞 | v0.60.1 已发布稳定状态诊断:SVN_MISSING_NODE/OBSTRUCTED_NODE/INCOMPLETE_NODE/TEXT_CONFLICT/PROPERTY_CONFLICT/TREE_CONFLICT 等,预览与报告透传 blockCode。463 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 119,462 字节、双哈希/清单/发布说明通过。诊断不算真实双侧支持,仍需后续实现 | 第三批:明确状态诊断;不能合成不存在的工作侧或声称审核通过 |
|
|
24
|
-
| svn:keywords、svn:eol-style |
|
|
24
|
+
| svn:keywords、svn:eol-style | v0.70.0 已发布标准关键字行保持映射,BASE收缩与cat --ignore-keywords核验、原正文及hash保留、预览披露与模型原行号证据通过;不以规范化正文代替证据或证明行为等价。自定义/固定宽度/未闭合展开仍阻断;504项串行全量回归、宿主/隔离安装、四矩阵CI通过;原包/npm/Release 137,678字节、双哈希/清单/发布说明核验通过。本地新增 EOL 元数据映射:保留原文/原hash与LF视图hash、CRLF/LF/CR计数,CRLF/LF行号identity,单CR明确不等同LF证据行号;预览与模型原文集成测试通过,已补充 UTF-16 字节/文本哈希区分、关键字组合、属性移除、非法样式明确失败与状态不变验证;专项3项、根目录预览/关键字/EOL组合7项、实际ASAR宿主及隔离安装通过,507项串行全量回归通过(0失败/跳过),v0.71.0 尚未发布。不以LF视图替换证据或证明行为等价 | 第三批:双侧可验证映射,保留原字节和定位 |
|
|
25
25
|
| svn:special/链接 | 当前阻断,不跟随链接取正文 | 第三批:如支持只审链接目标数据;不沿链接读取文件 |
|
|
26
26
|
| switched、externals、稀疏/混合 revision | 多数拒绝;调用方/依赖链要求祖先 normal | 第四批:明确仓库边界与独立来源,禁止隐式跨仓读取 |
|
|
27
|
-
| 固定 revision 单提交 | v0.62.0 已发布 svnRevision:r-1/r 固定对象、UUID/URL/peg/operative revision 逐侧绑定,正文不读工作树;远端显式 svnAllowNetwork。472 项串行回归、宿主、隔离安装、四矩阵 CI 及原包/npm/Release 125,486
|
|
28
|
-
| 固定 revision 区间 | v0.62.0 已发布 svnBaseRevision/svnTargetRevision,固定树端点 summary+逐侧 cat/proplist
|
|
27
|
+
| 固定 revision 单提交 | v0.62.0 已发布 svnRevision:r-1/r 固定对象、UUID/URL/peg/operative revision 逐侧绑定,正文不读工作树;远端显式 svnAllowNetwork。472 项串行回归、宿主、隔离安装、四矩阵 CI 及原包/npm/Release 125,486 字节、双哈希/清单/发布说明通过。历史上下文/规则/调用方已由下方 v0.63–0.69 行跟踪,不再沿用 v0.62 当时缺口 | 第五批:新增明确 SVN 参数与冻结身份 |
|
|
28
|
+
| 固定 revision 区间 | v0.62.0 已发布 svnBaseRevision/svnTargetRevision,固定树端点 summary+逐侧 cat/proplist,目录后代与属性纳入预算,不建临时工作树;同上述完整发布验证。历史上下文见下方 v0.63–0.69;分支间不同 URL 仍未支持 | 第五批:固定树端点与逐路径差异 |
|
|
29
29
|
| 分支复制、分支间比较、合并来源 | v0.66.0 已发布批准历史 mergeinfo 属性的来源路径/区间导航,保留非继承标记、有界不展开 revision、不读取分支源码;invalid/limited 明确且不裁剪。485 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 129,866 字节、双哈希/清单/发布说明通过;v0.67.0 已发布工作副本 BASE/工作侧属性的同一有界导航及预览/报告披露;489 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 130,866 字节、双哈希/清单/发布说明通过。有效继承 mergeinfo、跨 URL 比较、源码归属/合并提交覆盖仍未支持 | 第六批:URL/peg/operative revision 与 mergeinfo 导航披露 |
|
|
30
30
|
| 当前三层依赖与限定目录调用方 | v0.66.1 已发布根目录仅 mergeinfo 变化下的自动依赖/限定调用方修复:根目录不作源码候选,祖先双侧属性仅 mergeinfo 差异可通过且入指纹;其他属性/unsafe 状态仍拒绝。488 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 130,642 字节、双哈希/清单/发布说明通过。其他祖先/混合状态继续待验证 | 第四批补祖先/混合状态组合 |
|
|
31
31
|
| 历史两侧上下文与调用方 | v0.63.0 已发布显式 contextPaths 固定双侧来源及目标 rulePaths,UUID/URL/peg/operative revision/原字节与正文 hash 验证,禁止脏工作树与排除项回流。477 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 127,355 字节、双哈希/清单/发布说明通过。v0.64.0 已发布 oldContextPaths 旧侧独有正文、SVN 来源专用校验、预览披露与选中删除身份复用;479 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 127,879 字节、双哈希/清单/发布说明通过;本地开发了注入固定版本 lookup/read 能力的三层历史依赖导航核心,逐侧共享512探测/20候选/1MiB来源与上下文名额;排除项、旧侧限定和规则隔离测试通过。v0.68.0 已发布三层逐侧历史 autoContext,固定父目录有界清单 lookup,清单成功证明缺失、访问失败直接传播,真实旧/新版本链和脏工作树隔离通过。496 项串行回归、宿主、隔离安装、四矩阵 CI 与原包/npm/Release 134,056 字节、双哈希/清单/发布说明通过;本地新增逐侧固定 revision 调用方核心能力接口:共享256索引/128扫描/1MiB正文/512侧探测,命中侧才捕获正文,规则/变更排除与old-only限制保留,同侧命名调用声明导航测试通过;本地已接入固定 SVN 显式目录递归清单/同侧正文、统一30秒/512命令/元数据/正文预算,caller 与依赖共享精确探测及来源上限,真实集成专项13项通过;v0.69.0 已发布历史限定调用方和autoContext组合;502项串行全量回归、组合模型输入隔离、宿主/隔离安装、四矩阵 CI 通过。原包/npm/Release 136,030 字节、双哈希/清单/发布说明通过;字面发现仍不证明完整调用覆盖 | 第六批:逐侧固定版本,不能回退至工作副本 |
|
|
32
32
|
| 真正 r7314→r7315 样本 | 用户未提供隔离副本路径;本地类似复现不是该样本验收 | 获得路径后只读生成预览,不自动发送模型 |
|
|
33
33
|
|
|
34
|
+
## 实现与复现入口索引
|
|
35
|
+
|
|
36
|
+
以下入口便于逐项复核,测试存在不等于所有状态已支持;发布验收仍以对应批次实跑结果为准。
|
|
37
|
+
|
|
38
|
+
| 矩阵项 | 源码入口 | 复现测试入口 |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| 常规文件、子目录属性、新增/删除目录 | `src/svn.mjs` | `test/svn.test.mjs` |
|
|
41
|
+
| 根目录属性预览 | `src/file-relations.mjs`、`src/service.mjs` | `test/svn-root-preview.test.mjs` |
|
|
42
|
+
| 文件/目录复制、移动来源 | `src/svn.mjs` 的 structuralEntries 与 copySource | `test/svn.test.mjs` 离线复制/移动及复制目录案例 |
|
|
43
|
+
| 未提交替换辅助重建(未接入) | `src/svn-state.mjs`、`src/svn-replacement-text.mjs` | `test/svn-replacement-text.test.mjs`、`test/svn-state.test.mjs` |
|
|
44
|
+
| 已提交同路径与类型替换 | `src/svn-history.mjs` 的 mergeSvnHistoryRecord 与逐侧 kind | `test/svn-history-replacement.test.mjs` |
|
|
45
|
+
| 缺失/冲突/阻塞诊断 | `src/svn-state.mjs` | `test/svn-state.test.mjs`;真实缺失在 `test/svn.test.mjs` |
|
|
46
|
+
| 标准关键字与换行 | `src/svn-keyword-mapping.mjs`、`src/svn-eol-mapping.mjs` | `test/svn-keyword-mapping.test.mjs`、`test/svn-eol-mapping.test.mjs` |
|
|
47
|
+
| switched/外部根的拒绝 | `src/svn-caller-safety.mjs`、`src/svn-caller-node.mjs` | `test/svn-caller-special-roots.test.mjs`、`test/svn-caller-index.test.mjs` |
|
|
48
|
+
| 固定单 revision/区间及身份 | `src/svn-history.mjs` | `test/svn-history.test.mjs` |
|
|
49
|
+
| 显式 mergeinfo 来源导航 | `src/svn-mergeinfo.mjs` | `test/svn-mergeinfo.test.mjs` |
|
|
50
|
+
| 本地依赖/调用方及 mergeinfo 祖先 | `src/svn-dependency-chain.mjs`、`src/svn-caller-capture.mjs` | `test/svn-dependency-chain.test.mjs`、`test/svn-caller-capture.test.mjs`、`test/svn-mergeinfo-ancestor.test.mjs` |
|
|
51
|
+
| 历史两侧上下文/依赖/调用方 | `src/svn-history.mjs`、`src/svn-history-dependencies.mjs`、`src/svn-history-callers.mjs` | `test/svn-history.test.mjs`、`test/svn-history-dependencies.test.mjs`、`test/svn-history-callers-integration.test.mjs` |
|
|
52
|
+
| special、稀疏/混合状态、有效继承 mergeinfo、跨 URL | 上表限制仍有效 | 尚无完整支持验收,不能由其他案例推断完成 |
|
|
53
|
+
|
|
54
|
+
## EOL 子批验收索引(v0.71.0 待发布)
|
|
55
|
+
|
|
56
|
+
| 项目 | 实现/复现证据 | 当前结论 |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| CRLF/LF/CR 与混合计数、视图哈希 | `src/svn-eol-mapping.mjs`;`test/svn-eol-mapping.test.mjs` 前两项 | 专项通过;原文/原字节哈希不替换;单 CR 不保证 LF 行映射 |
|
|
59
|
+
| 编码身份 | 同上 UTF-16 BOM 案例 | 文本 hash 与 source bytes hash 明确区分,不能互换 |
|
|
60
|
+
| 预览/模型输入及只读 | `src/svn.mjs`、`src/service.mjs`;真实 SVN EOL 集成案例 | 预览不发送;受控模型读取原文;文件与解析后 status 不变 |
|
|
61
|
+
| 组合与失败 | 同一集成案例中标准关键字+CRLF、移除属性、强制非法样式 | 组合通过;非法样式被 SVN 在 status 阶段拒绝,采集明确失败 |
|
|
62
|
+
| 根目录优先修复持续回归 | `test/svn-root-preview.test.mjs` 默认/指定三文件预览 | 本批重新实跑通过,0模型发送,状态不变;原 v0.58.1 交付不重发 |
|
|
63
|
+
| 历史、上下文、特殊状态 | 不在本子批新增范围 | 仍按上表未完成项推进,不由元数据功能推断支持 |
|
|
64
|
+
|
|
34
65
|
## 每批发布门禁
|
|
35
66
|
|
|
36
67
|
1. 独立测试副本复现,确认 capture→关系推断→预览→执行的覆盖和拒绝路径。
|
package/package.json
CHANGED
package/src/service.mjs
CHANGED
|
@@ -49,7 +49,7 @@ export function createReviewService(llm, { capture = captureSnapshot, now = Date
|
|
|
49
49
|
while (previews.size >= maxPreviews) previews.delete(previews.keys().next().value);
|
|
50
50
|
const previewId = randomUUID();
|
|
51
51
|
previews.set(previewId, { ...current, target, options, rounds, snapshotId: snapshot.id, expires: now() + ttlMs });
|
|
52
|
-
return { ...(options.businessRequirement!==undefined?{businessRequirement:{text:options.businessRequirement,hash:hash(options.businessRequirement),bytes:Buffer.byteLength(options.businessRequirement)}}:{}), previewId, plan, snapshotId: snapshot.id, repositoryRoot: snapshot.root, vcs: snapshot.vcs, ...(snapshot.history ? { history: snapshot.history } : {}), ...(snapshot.mergeSources ? {mergeSources:snapshot.mergeSources} : {}), model: current.route, modelSendingEnabled: allowModelSending, files: snapshot.files.map(f => ({ path: f.path, eligibility: f.eligibility, reason: f.reason, ...(f.keywordMapping?{keywordMapping:f.keywordMapping,textNotice:f.textNotice}:{}), ...(f.rawStatus==='replaced'&&snapshot.history?.vcs==='svn'?{oldKind:f.oldKind,newKind:f.newKind,nodeNotice:f.nodeNotice}:{}), ...(f.blockCode ? {blockCode:f.blockCode} : {}), ...(f.copySource ? {copySource:f.copySource,copyNotice:f.copyNotice} : {}) })), contextPaths: snapshot.context.map(c => c.path), ...(options.oldContextPaths !== undefined ? {oldContextPaths:options.oldContextPaths,oldContextSources:snapshot.context.filter(c=>c.oldOnly).map(c=>({path:c.path,side:'context-old',revision:c.oldRevision,...(c.oldSvnSource?{svnSource:c.oldSvnSource}:{blobOid:c.oldBlobOid}),hash:c.oldHash}))} : {}), ...(snapshot.callerDiscovery ? {callerDiscovery:snapshot.callerDiscovery} : {}), ...(snapshot.autoContext ? { autoContext: snapshot.autoContext } : {}), rules: (snapshot.rules ?? []).map(({ path, hash }) => ({ path, hash })), notice: (snapshot.history?.vcs==='svn'&&options.autoContext===true?'SVN历史autoContext为精确依赖定位读取固定版本父目录有界清单,包含同目录非匹配名字元数据;仅匹配捕获正文发送模型,不扫描全仓,不用工作树替代历史版本。':'') + (options.oldContextPaths !== undefined ? 'oldContextPaths仅为baseline旧侧正文,无目标侧替代;选中变更复用原old身份,旧侧不能证明新侧行为。' : '') + (snapshot.callerDiscovery ? 'callerScopePaths已授权预览读取限定目录内tracked候选正文,包括不匹配文件;非匹配正文不发送模型,匹配捕获上下文会发送。仅字面引用导航,不是函数调用或完整调用覆盖。' : '') + (enableRiskPlanning ? '执行按plan阈值决定风险假设规划,小变更可跳过独立规划但仍主审并复核;计划不是证据,所有阶段共享原预算。' : '') + '执行会向上述模型提供方发送可审查文件两侧内容、预览列出的显式/自动上下文、所选项目规则全文及预览业务需求文本。模型可在该快照范围内多轮只读检索,不读取范围外文件;候选生成后会进行证据与反证复核,两阶段各最多3轮检索,共享每文件120秒和总模型调用100次预算;复核不能证明缺陷成立。plan.reviewRounds为独立审查工作量,非模型reasoning effort;后续轮不带首轮风险计划,所有轮共享原超时与预算。plan仅预检初始输入,ready不代表已审查;minimumCalls不含后续检索/复核/动态业务综合;多文件可先进行业务分组,分组失败保留原组并记录限制,动态综合数执行前未知,实际预算可能不足。请先向用户展示范围,获得确认后执行。' };
|
|
52
|
+
return { ...(options.businessRequirement!==undefined?{businessRequirement:{text:options.businessRequirement,hash:hash(options.businessRequirement),bytes:Buffer.byteLength(options.businessRequirement)}}:{}), previewId, plan, snapshotId: snapshot.id, repositoryRoot: snapshot.root, vcs: snapshot.vcs, ...(snapshot.history ? { history: snapshot.history } : {}), ...(snapshot.mergeSources ? {mergeSources:snapshot.mergeSources} : {}), model: current.route, modelSendingEnabled: allowModelSending, files: snapshot.files.map(f => ({ path: f.path, eligibility: f.eligibility, reason: f.reason, ...(f.eolMapping?{eolMapping:f.eolMapping,textNotice:f.textNotice}:{}), ...(f.keywordMapping?{keywordMapping:f.keywordMapping,textNotice:f.textNotice}:{}), ...(f.rawStatus==='replaced'&&snapshot.history?.vcs==='svn'?{oldKind:f.oldKind,newKind:f.newKind,nodeNotice:f.nodeNotice}:{}), ...(f.blockCode ? {blockCode:f.blockCode} : {}), ...(f.copySource ? {copySource:f.copySource,copyNotice:f.copyNotice} : {}) })), contextPaths: snapshot.context.map(c => c.path), ...(options.oldContextPaths !== undefined ? {oldContextPaths:options.oldContextPaths,oldContextSources:snapshot.context.filter(c=>c.oldOnly).map(c=>({path:c.path,side:'context-old',revision:c.oldRevision,...(c.oldSvnSource?{svnSource:c.oldSvnSource}:{blobOid:c.oldBlobOid}),hash:c.oldHash}))} : {}), ...(snapshot.callerDiscovery ? {callerDiscovery:snapshot.callerDiscovery} : {}), ...(snapshot.autoContext ? { autoContext: snapshot.autoContext } : {}), rules: (snapshot.rules ?? []).map(({ path, hash }) => ({ path, hash })), notice: (snapshot.history?.vcs==='svn'&&options.autoContext===true?'SVN历史autoContext为精确依赖定位读取固定版本父目录有界清单,包含同目录非匹配名字元数据;仅匹配捕获正文发送模型,不扫描全仓,不用工作树替代历史版本。':'') + (options.oldContextPaths !== undefined ? 'oldContextPaths仅为baseline旧侧正文,无目标侧替代;选中变更复用原old身份,旧侧不能证明新侧行为。' : '') + (snapshot.callerDiscovery ? 'callerScopePaths已授权预览读取限定目录内tracked候选正文,包括不匹配文件;非匹配正文不发送模型,匹配捕获上下文会发送。仅字面引用导航,不是函数调用或完整调用覆盖。' : '') + (enableRiskPlanning ? '执行按plan阈值决定风险假设规划,小变更可跳过独立规划但仍主审并复核;计划不是证据,所有阶段共享原预算。' : '') + '执行会向上述模型提供方发送可审查文件两侧内容、预览列出的显式/自动上下文、所选项目规则全文及预览业务需求文本。模型可在该快照范围内多轮只读检索,不读取范围外文件;候选生成后会进行证据与反证复核,两阶段各最多3轮检索,共享每文件120秒和总模型调用100次预算;复核不能证明缺陷成立。plan.reviewRounds为独立审查工作量,非模型reasoning effort;后续轮不带首轮风险计划,所有轮共享原超时与预算。plan仅预检初始输入,ready不代表已审查;minimumCalls不含后续检索/复核/动态业务综合;多文件可先进行业务分组,分组失败保留原组并记录限制,动态综合数执行前未知,实际预算可能不足。请先向用户展示范围,获得确认后执行。' };
|
|
53
53
|
} finally { busy = false; }
|
|
54
54
|
},
|
|
55
55
|
async execute(args, exec) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {hash} from './content.mjs';
|
|
2
|
+
|
|
3
|
+
// Keep raw text as evidence. LF view is metadata only, never a source replacement.
|
|
4
|
+
export function svnEolMapping(text,style=null){
|
|
5
|
+
if(typeof text!=='string'||Buffer.byteLength(text)>256*1024||!(style===null||['native','LF','CRLF','CR'].includes(style)))throw new Error('Unsupported SVN EOL mapping input or style');
|
|
6
|
+
let crlf=0,lf=0,cr=0;
|
|
7
|
+
for(let i=0;i<text.length;i++){
|
|
8
|
+
if(text[i]==='\r'){if(text[i+1]==='\n'){crlf++;i++;}else cr++;}
|
|
9
|
+
else if(text[i]==='\n')lf++;
|
|
10
|
+
}
|
|
11
|
+
const normalized=text.replace(/\r\n|\r/g,'\n');
|
|
12
|
+
return {rawTextHash:hash(text),lfViewHash:hash(normalized),style,counts:{crlf,lf,cr},mixed:[crlf,lf,cr].filter(Boolean).length>1,lineMapping:cr?'not-identity-for-LF-evidence':'identity',notice:'Hashes describe decoded text encoded as UTF-8, not original source bytes. LF-view hash only; raw text and raw evidence line numbering remain authoritative. Lone CR changes LF line boundaries; do not use normalized line numbers. Newline-only differences do not independently prove a defect or runtime equivalence.'};
|
|
13
|
+
}
|
package/src/svn.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { isSecretPath } from './secret-path.mjs';
|
|
|
2
2
|
import { svnStateIssue } from './svn-state.mjs';
|
|
3
3
|
import { snapshotMergeSources } from './svn-mergeinfo.mjs';
|
|
4
4
|
import { svnKeywordMapping } from './svn-keyword-mapping.mjs';
|
|
5
|
+
import { svnEolMapping } from './svn-eol-mapping.mjs';
|
|
5
6
|
import { realpath, lstat } from 'node:fs/promises';
|
|
6
7
|
import path from 'node:path';
|
|
7
8
|
import { isDeepStrictEqual } from 'node:util';
|
|
@@ -128,6 +129,10 @@ export async function captureSvn(cwd, options = {}) {
|
|
|
128
129
|
} else {
|
|
129
130
|
item.left = decode(hasBase ? await svn(root, ['cat', '-r', 'BASE', '--', target(name)], { ...options, maxBytes: maxFileBytes }) : Buffer.alloc(0));
|
|
130
131
|
item.right = status === 'deleted' ? decode(Buffer.alloc(0)) : await readLocal(root, name, options);
|
|
132
|
+
if(Object.hasOwn(leftProps,'svn:eol-style')||Object.hasOwn(rightProps,'svn:eol-style')){
|
|
133
|
+
item.eolMapping={old:svnEolMapping(item.left.text,leftProps['svn:eol-style']??null),new:svnEolMapping(item.right.text,rightProps['svn:eol-style']??null)};
|
|
134
|
+
item.textNotice+=' EOL mapping is hash-only metadata; raw text and LF evidence lines are authoritative. Lone CR has no identity mapping to normalized LF lines.';
|
|
135
|
+
}
|
|
131
136
|
if(keywordText){
|
|
132
137
|
const old=svnKeywordMapping(item.left.text,leftProps['svn:keywords']??''),current=svnKeywordMapping(item.right.text,rightProps['svn:keywords']??'');
|
|
133
138
|
if(hasBase){
|