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.
- package/dist/extract-ir-java.js +78 -19
- package/dist/sdk.js +1 -1
- package/package.json +1 -1
package/dist/extract-ir-java.js
CHANGED
|
@@ -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
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
-
|
|
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
|
-
// '
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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/",
|