@feng0531/dsh-code-review 0.14.0 → 0.15.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.15.0
4
+
5
+ - C#显式批准上下文补窄范围静态类型/零参方法位置线索,原行号进入主输入及输入预算,无新增读取/权限。
6
+ - 不支持目标仍保留为歧义竞争者,拒绝重载、同名遮蔽及畸形/类型外/嵌套声明;current context不冒充old历史。
7
+ - 219项全量与宿主只读审批离线冒烟通过;仅语法提示,不是通用语义绑定或C++适配,不宣称真实模型质量。
8
+
3
9
  ## 0.14.0
4
10
 
5
11
  - 同一批准仓库关联组追加有界跨文件综合,2–4文件,目录精确编辑与本阶段原文read覆盖,不静默截断规则/context。
package/README.md CHANGED
@@ -4,12 +4,16 @@
4
4
 
5
5
  ## 当前状态
6
6
 
7
- 当前代码版本为 0.14.0,包含有界覆盖预检、显式项目规则及候选证据与反证复核;发布状态以 npm 和 GitHub Release 为准。已通过真实临时 Git/SVN 仓库测试,以及隔离进程中的真实 DSH ToolRuntime 注册验证。当前开发会话的实际预览已返回0.6.0的plan/rules字段,空变更预览与默认关闭外发已验证;已进行经宿主审批的六次小规模真实试跑,累计12次模型调用;四组合成正负例与历史修复对照符合预期,历史引入方向检出候选但引用复核未完成(partial)。不是独立盲测或整体质量证明。详情见 [试跑结果](evaluation/PILOT-RESULTS.md)。
7
+ 当前代码版本为 0.15.0,包含有界覆盖预检、显式项目规则及候选证据与反证复核;发布状态以 npm 和 GitHub Release 为准。已通过真实临时 Git/SVN 仓库测试,以及隔离进程中的真实 DSH ToolRuntime 注册验证。当前开发会话的实际预览已返回0.6.0的plan/rules字段,空变更预览与默认关闭外发已验证;已进行经宿主审批的六次小规模真实试跑,累计12次模型调用;四组合成正负例与历史修复对照符合预期,历史引入方向检出候选但引用复核未完成(partial)。不是独立盲测或整体质量证明。详情见 [试跑结果](evaluation/PILOT-RESULTS.md)。
8
8
 
9
9
  ## 工作区下多个子仓库(0.11.0)
10
10
 
11
11
  当会话目录不是仓库而其子目录含Git/SVN仓库时,预览可指定 `repositoryPath`,例如会话位于工作区根时传 `{ "repositoryPath": "c3animation" }`。该参数必须是工作区相对路径(正斜杠),指向明确仓库根;不能使用绝对路径、上级路径或链接目录。文件、上下文、规则路径仍相对此次选定仓库。多个子仓库分别预览和审批执行,不混用快照;execute只接收previewId,不能另改目标。省略参数保持原行为。使用此参数需宿主安装0.11.0或更新版本;仓库发布不会自动更新当前宿主。
12
12
 
13
+ ## C#显式上下文位置线索(0.15.0)
14
+
15
+ 仅注释已批准.cs context,不增加读取或覆盖。支持file-scoped同namespace、静态class、public static零参void/int/bool/string方法与独立Type.Method()语法;保留调用/类型/方法原始行号。目标括号须平衡、方法直属类型;重载、同名竞争者(包括不支持语法)、局部遮蔽、using/partial/继承或动态等不推定绑定。有字符串/注释/预处理等不支持文本保守不生成线索,不影响普通源码审查。当前context明确不是old历史内容。不执行编译器、工程或用户源码,不冒充C++适配、语义绑定或可达性证明,线索不足仍须模型说明证据限制。
16
+
13
17
  ## 批准快照内跨文件综合(0.14.0)
14
18
 
15
19
  关联组最多4个批准主文件、至少2个文本变化时追加跨文件综合。目录保留完整精确编辑原位置,不作为源码证据;每条发现须引用至少2文件的 `interaction.editRefs:[{fileId,editId}]`,主attribution与主引用一致,原锚重叠主编辑,每个引用编辑至少一非空侧须本综合生成read完整覆盖。共享批准reader/全局调用额度,嵌入组最后主文件原超时,不重置生命周期;预检包含额外初始调用,检索复核另计。interactions独立记录pending/completed/blocked,跨组和未完成明确限制。不合并多文件候选,不自动扩文件/仓库。源码/规则/context仍不可信。真实模型样本未跑,安全反例空输出模拟不代表模型查准率;拒绝审批表示未审查不是通过。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feng0531/dsh-code-review",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "private": false,
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
@@ -0,0 +1,46 @@
1
+ // Approved text only, no compiler/module lookup. Intentionally narrow syntax hints.
2
+ const safe = text => typeof text === 'string' && Buffer.byteLength(text) <= 256 * 1024 && !/["'\x60#]|\/\/|\/\*/.test(text);
3
+ const namespaceOf = text => { const matches = [...text.matchAll(/^\s*namespace\s+([A-Za-z_][A-Za-z0-9_.]*)\s*;\s*$/gm)]; return matches.length === 1 ? matches[0][1] : null; };
4
+ export function inferCsharpContext(input, primary) {
5
+ if (!primary.path.endsWith('.cs')) return [];
6
+ const contexts = (input.context ?? []).filter(c => c.path.endsWith('.cs') && !input.files.some(f => f.path === c.path));
7
+ const result = [];
8
+ for (const side of ['old', 'new']) {
9
+ const source = (side === 'old' ? primary.left : primary.right)?.text;
10
+ if (!safe(source) || /\busing\b|\bdynamic\b/.test(source)) continue;
11
+ const ns = namespaceOf(source); if (!ns) continue;
12
+ const lines = source.split(String.fromCharCode(10));
13
+ for (let i = 0; i < lines.length; i++) {
14
+ const call = /^\s*(?:await\s+)?([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)\s*\(\s*\)\s*;\s*$/.exec(lines[i]);
15
+ if (!call) continue;
16
+ const [, type, method] = call;
17
+ const token = new RegExp('\\b' + type + '\\b');
18
+ // Other occurrences may introduce a variable/type that shadows the qualifier.
19
+ if (lines.some((line,j) => j !== i && token.test(line))) continue;
20
+ // Unsupported declarations still compete; filtering them out must not create uniqueness.
21
+ const competitors = contexts.filter(c => typeof c.text !== 'string' || token.test(c.text));
22
+ if (competitors.length !== 1 || input.files.some(f => f !== primary && f.path.endsWith('.cs') && f.path.split('/').at(-1) === type + '.cs')) continue;
23
+ const candidates = competitors.filter(c => safe(c.text) && namespaceOf(c.text) === ns && !/\busing\b|\bpartial\b|\bvirtual\b|\boverride\b|\binterface\b/.test(c.text));
24
+ const declarations = [];
25
+ for (const context of candidates) {
26
+ const targetLines = context.text.split(String.fromCharCode(10));
27
+ const classes = targetLines.map((line,j) => ({ line, number:j+1 })).filter(item => /^\s*(?:public|internal)\s+static\s+class\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{?\s*$/.exec(item.line)?.[1] === type);
28
+ // Only one type per file; no nesting, inheritance, generics or partial resolution.
29
+ if (classes.length !== 1 || (context.text.match(/\bclass\b|\bstruct\b|\brecord\b/g) ?? []).length !== 1) continue;
30
+ const occurrences = targetLines.filter(line => new RegExp('\\b' + method + '\\s*\\(').test(line));
31
+ const methods = targetLines.map((line,j) => ({ line, number:j+1 })).filter(item => new RegExp('^\\s*public\\s+static\\s+(?:void|int|bool|string)\\s+' + method + '\\s*\\(\\s*\\)\\s*(?:\\{|$)').test(item.line));
32
+ let depth = 0, typeDepth, methodDepth, malformed = false;
33
+ for (let j = 0; j < targetLines.length; j++) {
34
+ if (j + 1 === classes[0].number) typeDepth = depth;
35
+ if (j + 1 === methods[0]?.number) methodDepth = depth;
36
+ for (const character of targetLines[j]) { if (character === '{') depth++; if (character === '}') depth--; if (depth < 0) malformed = true; }
37
+ }
38
+ if (malformed || depth !== 0 || typeDepth !== 0 || methodDepth !== 1 || methods[0]?.number <= classes[0].number) continue;
39
+ if (occurrences.length === 1 && methods.length === 1) declarations.push({ contextPath:context.path, typeLine:classes[0].number, declarationLine:methods[0].number });
40
+ }
41
+ if (declarations.length === 1) result.push({ primaryPath:primary.path, side, contextVersion:'approved-current-not-historical', callLine:i+1, namespace:ns, type, method, ...declarations[0], confidence:'conservative-syntax-only' });
42
+ if (result.length >= 20) return result;
43
+ }
44
+ }
45
+ return result;
46
+ }
@@ -1,3 +1,4 @@
1
+ import { inferCsharpContext } from './csharp-context.mjs';
1
2
  import { inferImportRelations } from './import-relations.mjs';
2
3
  import { inferContextRelations } from './context-relations.mjs';
3
4
  import { prepareWindowSynthesis } from './window-synthesis.mjs';
@@ -15,6 +16,8 @@ export function preparePrimaryInput(input, file, { instructions, scope, grouping
15
16
  base.contextRelations = contextRelations;
16
17
  base.contextRelationNotice = '导入与调用位置仅为语法线索;可能被同名局部变量遮蔽,不证明绑定、可达性或因果。';
17
18
  }
19
+ const csharpHints = inferCsharpContext(input, file);
20
+ if (csharpHints.length) { base.csharpContextHints = csharpHints; base.csharpContextNotice = '仅批准当前context的C#静态类型/方法语法位置;不证明语义绑定或执行可达,也不是旧侧历史上下文。歧义不推定,线索不增加审查覆盖。'; }
18
21
  let payload = JSON.stringify(base);
19
22
  const measure = value => initialInputBudget({ instructions, input: value }, scope, maxInputBytes);
20
23
  const metadata = {};