@feng0531/dsh-code-review 0.33.1 → 0.33.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 CHANGED
@@ -1,9 +1,19 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.33.3
4
+
5
+ - 超预算主审切为精确窗口时,上下文正文留在原批准快照按需read;初始输入仅带版本侧catalog,避免上下文重复导致所有窗口持续超限。不扩大读取范围,不裁剪证据;报告明确未声明全部上下文核查。
6
+ - 当前/历史旧侧隔离、无scope仍阻断、预览执行预算一致、超时等适配器清理且窗口pending验收通过;320离线及真实宿主离线smoke通过。候选待远端门禁,不宣称用户碰撞审查已恢复或超时根因已定位。
7
+
8
+ ## 0.33.2
9
+
10
+ - 接受唯一完整JSON的单一json/无语言Markdown围栏,不提取任意说明中的JSON、不修正文法/字段、不重试;后续原schema及证据校验不变。
11
+ - 不完整JSON返回MODEL_INVALID_JSON及字节/封装类型诊断,不泄露响应正文。317离线测试通过。实际碰撞审查原始响应未知,不能宣称复现其三处根因;超时与大文件范围缺口仍待定位。
12
+
3
13
  ## 0.33.1
4
14
 
5
15
  - 修正named import alias同一调用行再次出现别名(重赋值/逃逸/嵌套调用)仍产生绑定提示的误关联;保留字面导航而不证明真实绑定。
6
- - 314离线测试通过。该patch候选待pack/隔离安装、固定标签四矩阵及原工件发布核验;B3整体未完成。
16
+ - 314离线测试、pack/隔离安装、固定标签四矩阵及原工件发布核验通过:npm/Release88082字节双hash一致;B3整体未完成。
7
17
 
8
18
  ## 0.33.0
9
19
 
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## 当前状态
6
6
 
7
- 当前正式版本为 0.33.0(轮103固定标签四矩阵及npm/Release原工件字节双hash门禁通过)
7
+ 当前正式版本为 0.33.1(固定标签四矩阵及npm/Release原工件字节双hash门禁通过);0.33.2为JSON封装兼容候选,尚未正式验收。
8
8
 
9
9
  Git历史预览新增oldContextPaths:最多20个显式仓库相对文件,与contextPaths/自动上下文共享20槽、256KiB每blob及4MiB快照。仅从baseline普通Git blob捕获,不checkout/fetch/读取工作树;根提交无baseline拒绝,working/SVN明确拒绝。旧侧条目携带oldRevision/oldBlobOid/oldHash,仅进入context-old;oldOnly表示仅批准旧侧,不证明target路径不存在。所选变更复用原changed-old,不重复上下文;excluded/blocked变更、链接/submodule、凭据路径不能重新进入。预览显示身份元数据、不显示正文,确认执行才按宿主正常权限发送。主审/综合/复核按侧提示,计入原输入预算,旧证据不能冒充新侧回归证明。
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feng0531/dsh-code-review",
3
- "version": "0.33.1",
3
+ "version": "0.33.3",
4
4
  "private": false,
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
package/src/dsh-model.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { modelJson } from './model-json.mjs';
1
2
  /** One-shot host LLM call. No agent loop and no executable tools. */
2
3
  export function createDshModel(llm, route, { maxTokens = 4096, maxOutputBytes = 128 * 1024 } = {}) {
3
4
  if (!llm || typeof llm.stream !== 'function' || !route?.provider || !route?.model) throw new Error('DSH provider and model are required');
@@ -21,6 +22,6 @@ export function createDshModel(llm, route, { maxTokens = 4096, maxOutputBytes =
21
22
  }
22
23
  }
23
24
  if (!finished) throw new Error('Model stream ended without finish');
24
- return output;
25
+ return modelJson(output);
25
26
  };
26
27
  }
@@ -0,0 +1,12 @@
1
+ // Accept one complete JSON value, optionally inside one exact Markdown fence.
2
+ export function modelJson(text) {
3
+ const bytes=Buffer.byteLength(text);
4
+ const trimmed=text.trim();
5
+ const fence=/^```(?:json)?\r?\n([\s\S]*)\r?\n```$/.exec(trimmed);
6
+ const body=fence?fence[1]:trimmed;
7
+ try { JSON.parse(body); } catch {
8
+ const error=new Error('Model response is not complete JSON (bytes='+bytes+', envelope='+(fence?'json-fence':'plain')+'); no repair or retry performed');
9
+ error.code='MODEL_INVALID_JSON';throw error;
10
+ }
11
+ return body;
12
+ }
@@ -46,7 +46,9 @@ export function preparePrimaryInput(input, file, { instructions, scope, grouping
46
46
  const windows = changeWindows(file, changes);
47
47
  if (windows) {
48
48
  const compactFile = { ...file, left: { ...file.left, text: undefined }, right: { ...file.right, text: undefined } };
49
- const compact = JSON.stringify({ ...base, file: compactFile, windows, sourceMode: 'change-windows', windowNotice: '仅提供全部精确hunk窗口,start/count为原始源码行号,不得重编号。完整源码未随初始输入发送,可在catalog批准范围内检索;缺少上下文时说明限制。' });
49
+ const contextCatalog = scope.catalog().filter(source => ['context', 'context-old'].includes(source.side));
50
+ if (contextCatalog.length) metadata.contextMode = 'approved-retrieval';
51
+ const compact = JSON.stringify({ ...base, context: [], contextCatalog, contextMode: 'approved-retrieval', contextNotice: '上下文全文仍在同一批准快照,仅目录进入窗口初始输入;必须按sourceId和版本侧read原文,不把目录视为证据或完整覆盖。', file: compactFile, windows, sourceMode: 'change-windows', windowNotice: '仅提供全部精确hunk窗口,start/count为原始源码行号,不得重编号。完整源码未随初始输入发送,可在catalog批准范围内检索;缺少上下文时说明限制。' });
50
52
  if (!measure(compact).fits) {
51
53
  const envelope = JSON.parse(compact);
52
54
  const plan = planWindowBatches(windows, subset => JSON.stringify({ ...envelope, windows: subset, windowNotice: '本批仅审查windows包含的编辑,其他hunk另批;行号为原始行号,跨片段上下文不足说明限制。' }), measure);
package/src/review.mjs CHANGED
@@ -117,6 +117,7 @@ export async function reviewSnapshot(snapshot, model, options = {}) {
117
117
  const prepared = preparePrimaryInput(input, file, { instructions: REVIEW_INSTRUCTIONS, scope, grouping: report.grouping, maxInputBytes });
118
118
  const { changes, payload } = prepared;
119
119
  Object.assign(state, prepared.metadata);
120
+ if (state.contextMode === 'approved-retrieval') report.limitations.push({ fileId: file.id, text: '窗口初始输入仅带上下文身份目录,全文须按需读取;不声明所有上下文已核查。' });
120
121
  if (prepared.synthesis) state.synthesisStatus = prepared.synthesis.budget.fits ? 'pending' : 'blocked';
121
122
  if (prepared.synthesis && !prepared.synthesis.budget.fits) report.limitations.push({ fileId: file.id, text: '跨窗口综合输入超限,未发送;单窗口完成不表示交互影响已检查' });
122
123
  if (state.sourceMode === 'change-windows') state.windowCoverage = { completed: [], pending: [...state.windowIds] };