progmune-runtime 3.3.1 → 3.3.2
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/mcp-server.mjs +8 -4
- package/dist/planner.js +37 -5
- package/package.json +1 -1
package/dist/mcp-server.mjs
CHANGED
|
@@ -13,9 +13,13 @@ import { fileURLToPath } from "url";
|
|
|
13
13
|
import { createLogger } from "./logger.js";
|
|
14
14
|
// ── ESM-compatible __dirname (the compiled output is an .mjs module) ──
|
|
15
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
// ── Load .env ──
|
|
17
|
-
const envPath
|
|
18
|
-
|
|
16
|
+
// ── Load .env(包目录 + 项目目录,后者优先) ──
|
|
17
|
+
for (const envPath of [
|
|
18
|
+
path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".env"),
|
|
19
|
+
path.resolve(__dirname, "..", ".env"),
|
|
20
|
+
]) {
|
|
21
|
+
if (!fs.existsSync(envPath))
|
|
22
|
+
continue;
|
|
19
23
|
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
20
24
|
for (const line of envContent.split("\n")) {
|
|
21
25
|
const trimmed = line.trim();
|
|
@@ -335,7 +339,7 @@ async function main() {
|
|
|
335
339
|
|
|
336
340
|
Progmune needs an LLM API key to generate code. Configure via:
|
|
337
341
|
|
|
338
|
-
【.env file】Add to ${
|
|
342
|
+
【.env file】Add to ${path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".env")}:
|
|
339
343
|
LLM_API_KEY=your-key
|
|
340
344
|
LLM_BASE_URL=https://api.deepseek.com/v1
|
|
341
345
|
LLM_MODEL=deepseek-chat
|
package/dist/planner.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.validateProtocolWithTransitions = validateProtocolWithTransitions;
|
|
36
37
|
exports.plan = plan;
|
|
37
38
|
const llm_1 = require("./llm");
|
|
38
39
|
const runtime_types_1 = require("./runtime-types");
|
|
@@ -393,22 +394,41 @@ function validateProtocolWithTransitions(actions, protocols, namespaceInitialSta
|
|
|
393
394
|
// End-of-sequence check: held resources must be released (resource leak).
|
|
394
395
|
// A state S is resource-holding when some rule REQUIRES S and INVALIDATES S
|
|
395
396
|
// (acquire/release semantics — e.g. FILE_OPEN set by open_file, released by
|
|
396
|
-
// close_file).
|
|
397
|
-
//
|
|
397
|
+
// close_file). Only RESOURCE-LIFECYCLE namespaces apply: session/auth flows
|
|
398
|
+
// legitimately END with an active session (SESSION_ACTIVE is not a leak).
|
|
399
|
+
const RESOURCE_NS = /^(file|db|database|connection|conn|socket|stream|resource|io)/i;
|
|
398
400
|
const heldStates = [];
|
|
399
401
|
for (const p of protocols) {
|
|
400
402
|
const ann = p.protocol;
|
|
401
403
|
if (!ann)
|
|
402
404
|
continue;
|
|
405
|
+
const ns = ann.namespace || "";
|
|
406
|
+
if (!RESOURCE_NS.test(ns))
|
|
407
|
+
continue;
|
|
403
408
|
const inv = ann.invalidate || [];
|
|
404
409
|
const pre = ann.pre_states || [];
|
|
405
410
|
for (const s of inv) {
|
|
406
411
|
if (pre.includes(s))
|
|
407
|
-
heldStates.push({ state: s, releaseFn: p.function, namespace:
|
|
412
|
+
heldStates.push({ state: s, releaseFn: p.function, namespace: ns });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// 只检查"本序列中获取"的持有状态——继承自命名空间初始状态的
|
|
416
|
+
// (如 db 初始即 DB_CONNECTED)不算泄漏。
|
|
417
|
+
const acquiredStates = new Set();
|
|
418
|
+
for (const t of transitions) {
|
|
419
|
+
for (const ns of Object.keys(t.statesAfter || {})) {
|
|
420
|
+
const after = t.statesAfter[ns] || [];
|
|
421
|
+
const before = t.statesBefore?.[ns] || [];
|
|
422
|
+
for (const s of after) {
|
|
423
|
+
if (!before.includes(s))
|
|
424
|
+
acquiredStates.add(`${ns}::${s}`);
|
|
425
|
+
}
|
|
408
426
|
}
|
|
409
427
|
}
|
|
410
428
|
for (const hs of heldStates) {
|
|
411
429
|
const cur = ctx.currentState[hs.namespace] || [];
|
|
430
|
+
if (!acquiredStates.has(`${hs.namespace}::${hs.state}`))
|
|
431
|
+
continue;
|
|
412
432
|
if (cur.includes(hs.state)) {
|
|
413
433
|
const trace = transitions.map(t => ({
|
|
414
434
|
function: t.function,
|
|
@@ -444,7 +464,11 @@ function validateProtocolWithTransitions(actions, protocols, namespaceInitialSta
|
|
|
444
464
|
return { valid: true, transitions, ledgerConsistent: consistency.consistent, ruleHash };
|
|
445
465
|
}
|
|
446
466
|
/** SSG 确定性修复:当协议违规有已知修复路径时,自动插入缺失函数 */
|
|
447
|
-
function attemptSSGRepair(actions, rejection, ir, protocols, namespaceInitialStates) {
|
|
467
|
+
function attemptSSGRepair(actions, rejection, ir, protocols, namespaceInitialStates, depth = 0) {
|
|
468
|
+
if (depth > 5) {
|
|
469
|
+
console.error(`[修复] 递归深度超限 (${depth}),放弃确定性修复`);
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
448
472
|
if (!rejection.fixPath || rejection.fixPath.length === 0)
|
|
449
473
|
return null;
|
|
450
474
|
// 名称归一化:内置规则可能是下划线风格(generate_jwt),项目 IR 是
|
|
@@ -496,7 +520,8 @@ function attemptSSGRepair(actions, rejection, ir, protocols, namespaceInitialSta
|
|
|
496
520
|
}
|
|
497
521
|
// 单步修复不够,尝试递归修复
|
|
498
522
|
if (recheck.rejection && recheck.rejection.fixPath && recheck.rejection.fixPath.length > 0) {
|
|
499
|
-
|
|
523
|
+
console.error(`[修复] 重验仍失败 (blocked=${recheck.rejection.blocked}, fixPath=${recheck.rejection.fixPath.join(" → ")}),递归深度 ${depth + 1}`);
|
|
524
|
+
const nested = attemptSSGRepair(repaired, recheck.rejection, ir, protocols, namespaceInitialStates, depth + 1);
|
|
500
525
|
if (nested)
|
|
501
526
|
return nested;
|
|
502
527
|
}
|
|
@@ -1079,6 +1104,13 @@ ${planner_prompts_1.RETRY_HINT}
|
|
|
1079
1104
|
const protoResult = validateProtocolWithTransitions(filtered, protocols, namespaceInitialStates);
|
|
1080
1105
|
if (!protoResult.valid && protoResult.rejection) {
|
|
1081
1106
|
const rej = protoResult.rejection;
|
|
1107
|
+
// P3:fixPath / missingFunctions 归一化到 IR 真实函数名——
|
|
1108
|
+
// 内置规则是下划线风格(generate_jwt),项目 IR 是 camelCase
|
|
1109
|
+
// (generateJwt)。提示与记录使用项目里真实存在的名字。
|
|
1110
|
+
const normIRName = (n) => ir.find((f) => f.name === n)
|
|
1111
|
+
|| ir.find((f) => f.name.replace(/[_-]/g, "").toLowerCase() === n.replace(/[_-]/g, "").toLowerCase());
|
|
1112
|
+
rej.fixPath = (rej.fixPath || []).map(n => normIRName(n)?.name || n);
|
|
1113
|
+
rej.missingFunctions = (rej.missingFunctions || []).map(n => normIRName(n)?.name || n);
|
|
1082
1114
|
const explain = (0, ssg_validator_1.explainRejection)(rej);
|
|
1083
1115
|
console.error(explain);
|
|
1084
1116
|
const violation = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "progmune-runtime",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
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/",
|