progmune-runtime 3.7.19 → 3.7.21

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.
@@ -38,13 +38,10 @@ exports.extractIRJava = extractIRJava;
38
38
  /**
39
39
  * extract-ir-java.ts — Java 语言 IR 提取(纯 TS 词法,零工具链依赖)
40
40
  *
41
- * 与 C/Go 提取器同模式:逐 .java 文件扫描方法声明 → FunctionInfo 列表。
42
- * Java 语言支持(3.7.17 里程碑 1):注册表 LANGUAGE_EXTRACTORS 一项 +
43
- * evaluateTrust/engine 语言分派;Spring Security 路由覆盖模型见
44
- * src/frameworks/spring-detector.ts。
45
- *
46
- * 注意:提取为词法近似(方法签名正则)——注解驱动的协议金标建立后
47
- * 再评估是否需 AST(JavaParser 等不引入,保持零依赖)。
41
+ * 与 C/Go 提取器同模式:逐 .java 文件扫描方法声明 → FunctionInfo 列表,
42
+ * 附带:方法体调用边(calls)与方法前注释协议注解(protocol,
43
+ * // @protocol namespace=… pre_states=[…] post_states=[…],TS JSDoc
44
+ * 同口径)——供 SSG/序列验证(Java 协议行金标 v1,2026-09-02)。
48
45
  */
49
46
  const fs = __importStar(require("fs"));
50
47
  const path = __importStar(require("path"));
@@ -57,7 +54,48 @@ const JAVA_KEYWORDS = new Set([
57
54
  "if", "for", "while", "switch", "catch", "synchronized", "return",
58
55
  "new", "case", "do", "try", "else", "instanceof",
59
56
  ]);
60
- const MODIFIERS = "(?:public|protected|private|static|final|synchronized|abstract|default|native|strictfp|transient|volatile|\\s)+";
57
+ /** 从方法前注释(// @protocol … / // @progmune())解析协议注解,
58
+ * 与 TS JSDoc @protocol 同口径:namespace/pre_states/post_states/invalidate */
59
+ function parseJavaProtocol(commentText) {
60
+ const nsMatch = commentText.match(/namespace\s*=\s*["']?(\w+)/);
61
+ const preMatch = commentText.match(/pre(?:_states)?\s*=\s*\[([^\]]*)\]/);
62
+ const postMatch = commentText.match(/post(?:_states)?\s*=\s*\[([^\]]*)\]/);
63
+ if (!preMatch || !postMatch)
64
+ return undefined;
65
+ const split = (g) => g.split(",").map((x) => x.trim().replace(/["']/g, "")).filter(Boolean);
66
+ const invMatch = commentText.match(/invalidate\s*=\s*\[([^\]]*)\]/);
67
+ return {
68
+ pre_states: split(preMatch[1]),
69
+ post_states: split(postMatch[1]),
70
+ invalidate: invMatch ? split(invMatch[1]) : undefined,
71
+ namespace: nsMatch ? nsMatch[1] : undefined,
72
+ };
73
+ }
74
+ /** 方法头部向上收集注释(只允许空行/注释/@注解行;遇代码即停,防串方法) */
75
+ function collectPrecedingComment(code, matchIndex) {
76
+ const headerLine = code.slice(0, matchIndex).split("\n").length; // 1-based
77
+ const srcLines = code.split("\n");
78
+ const pieces = [];
79
+ let li = headerLine - 2;
80
+ while (li >= 0) {
81
+ const t = srcLines[li].trim();
82
+ if (t === "") {
83
+ li--;
84
+ continue;
85
+ }
86
+ if (/^\/\//.test(t) || /^\/\*/.test(t) || /^\*/.test(t)) {
87
+ pieces.unshift(srcLines[li]);
88
+ li--;
89
+ continue;
90
+ }
91
+ if (/^@[A-Za-z]/.test(t)) {
92
+ li--;
93
+ continue;
94
+ } // @Override 等注解行
95
+ break;
96
+ }
97
+ return pieces.join("\n");
98
+ }
61
99
  /** 单文件提取 */
62
100
  function extractJavaFile(filePath) {
63
101
  const out = [];
@@ -75,12 +113,24 @@ function extractJavaFile(filePath) {
75
113
  const name = m[1];
76
114
  if (JAVA_KEYWORDS.has(name))
77
115
  continue;
78
- // 前置字符过滤:排除 '.'/'='/'( ' 前导(调用/赋值/子表达式误匹配);
79
- // '@' 允许——@Override protected void … 是注解修饰的合法方法
116
+ // 重叠守卫:匹配起点若早于参数 '(' 所在行(如从上一行注释/注解开吃
117
+ // 吞掉真头)→ 从 '(' 行首重扫,避免方法被错配候选吞掉
118
+ const parenPos = code.indexOf("(", m.index + m[0].indexOf(name));
119
+ const parenLineStart = code.lastIndexOf("\n", parenPos - 1) + 1;
120
+ if (m.index < parenLineStart) {
121
+ re.lastIndex = parenLineStart;
122
+ continue;
123
+ }
124
+ // 起点规则:'.' 前导 = 方法调用(如 adminService.act( 的 act);
125
+ // 注解行起点(@RequestMapping…)非方法声明;容忍注释内起点——
126
+ // 其名字/参数/体边界本就正确(正则 type-part 可吞注释空白)
80
127
  const pre = code.slice(Math.max(0, m.index - 1), m.index);
81
- if (/[.=(]/.test(pre))
128
+ if (pre === ".")
129
+ continue;
130
+ const lineStart = code.lastIndexOf("\n", m.index - 1) + 1;
131
+ const curLine = code.slice(lineStart, code.indexOf("\n", lineStart) === -1 ? code.length : code.indexOf("\n", lineStart)).trim();
132
+ if (curLine.startsWith("@") && !curLine.startsWith("@protocol") && !curLine.startsWith("@progmune"))
82
133
  continue;
83
- // 可见性(近似):行内是否有 public/protected(或文件在接口里默认 public)
84
134
  const head = code.slice(m.index, m.index + 40);
85
135
  const visM = head.match(/\b(public|protected|private)\b/);
86
136
  const exported = visM ? visM[1] !== "private" : /^interface\s/.test(code.slice(0, m.index).split("\n").pop() || "") ? true : undefined;
@@ -91,7 +141,6 @@ function extractJavaFile(filePath) {
91
141
  const t = raw.trim();
92
142
  if (!t)
93
143
  continue;
94
- // 最后一个词为参数名,其余为类型(含泛型/数组)
95
144
  const parts = t.split(/\s+/);
96
145
  const pname = parts.pop() || "";
97
146
  const ptype = parts.join(" ") || "?";
@@ -100,10 +149,20 @@ function extractJavaFile(filePath) {
100
149
  }
101
150
  }
102
151
  }
103
- // 返回类型:方法名前的一段(简化取最近一个类型令牌)
104
152
  const returnType = "unknown";
153
+ // protocol:方法前注释里的 @protocol/@progmune
154
+ // 行号基准 = 参数 '(' 所在行(正则匹配起点可能早于方法行——用
155
+ // '(' 位置定真实 header 行,避免注释归属串位)
156
+ let protocol;
157
+ {
158
+ const parenIdx = code.indexOf("(", m.index);
159
+ const joined = parenIdx === -1 ? "" : collectPrecedingComment(code, parenIdx);
160
+ const lastAt = Math.max(joined.lastIndexOf("@protocol"), joined.lastIndexOf("@progmune"));
161
+ if (lastAt !== -1) {
162
+ protocol = parseJavaProtocol(joined.slice(lastAt, Math.min(joined.length, lastAt + 300)));
163
+ }
164
+ }
105
165
  // calls:方法体(自头正则消费的 '{' 起平衡到 '}')内的方法调用
106
- // (词法近似:标识符 + '(',过滤关键字;obj.method → 取末段)
107
166
  const calls = [];
108
167
  const bodyStart = m.index + m[0].length; // 正则已含 '{'
109
168
  let depth = 1;
@@ -117,16 +176,15 @@ function extractJavaFile(filePath) {
117
176
  bodyEnd++;
118
177
  }
119
178
  const body = code.slice(bodyStart, Math.min(bodyEnd, bodyStart + 8000));
120
- const callRe = /(?:^|[^\w$])([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\(/g;
179
+ // 零宽后视:前导 '(' 等不被上一匹配吞掉(if (verifyToken() 中能收到 verifyToken)
180
+ const callRe = /(?<=^|[^\w$])([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\(/g;
121
181
  let cm;
122
182
  while ((cm = callRe.exec(body)) !== null) {
123
- const full = cm[1];
124
- const seg = full.split(".").pop() || "";
183
+ const seg = cm[1].split(".").pop() || "";
125
184
  if (JAVA_KEYWORDS.has(seg))
126
185
  continue;
127
186
  if (/^(if|for|while|switch|catch|new|return|case|do)$/.test(seg))
128
187
  continue;
129
- // 排除声明后立即调用形态(如 new Foo( 里 Foo)——new 已过滤
130
188
  if (calls.length < 400 && !calls.includes(seg))
131
189
  calls.push(seg);
132
190
  }
@@ -137,6 +195,7 @@ function extractJavaFile(filePath) {
137
195
  file: filePath,
138
196
  exported,
139
197
  calls,
198
+ protocol,
140
199
  });
141
200
  }
142
201
  return out;
package/dist/sdk.js CHANGED
@@ -20,7 +20,7 @@ const risk_model_1 = require("./risk-model");
20
20
  const protocol_knowledge_1 = require("./protocol-knowledge");
21
21
  const evidence_repository_1 = require("./evidence-repository");
22
22
  /** Runtime version — stable public identifier. Internal layers evolve underneath. */
23
- exports.RUNTIME_VERSION = "3.7.19";
23
+ exports.RUNTIME_VERSION = "3.7.21";
24
24
  function verify(filePath) {
25
25
  const cert = (0, certify_1.certify)(filePath);
26
26
  const kb = (0, protocol_knowledge_1.buildKnowledgeBase)();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "progmune-runtime",
3
- "version": "3.7.19",
3
+ "version": "3.7.21",
4
4
  "description": "Progmune — AI Trust Decision Engine. Verify AI-generated code before it reaches production. Outputs APPROVED / NEEDS_REVIEW / BLOCKED with evidence.",
5
5
  "files": [
6
6
  "dist/",