progmune-runtime 2.0.4 → 2.1.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/.mcp.json +11 -0
- package/.progmune_allowlist +50 -0
- package/.test_report/test_report.md +87 -0
- package/Dockerfile +2 -10
- package/FAQ.md +167 -0
- package/demo-project/auth.ts +55 -0
- package/demo-project/tsconfig.json +8 -0
- package/dist/ab-stats.js +11 -0
- package/dist/acl-breakdown.js +13 -0
- package/dist/all-sessions.js +11 -0
- package/dist/antibody-stats.js +11 -0
- package/dist/audit.js +218 -0
- package/dist/benchmark-count.js +7 -0
- package/dist/benchmark-full.js +17 -0
- package/dist/benchmark-pass-rate.js +54 -0
- package/dist/benchmark-report.js +67 -0
- package/dist/benchmark-save.js +62 -0
- package/dist/benchmark-status.js +15 -0
- package/dist/branch-ledger.js +365 -0
- package/dist/branch-tree-count.js +14 -0
- package/dist/check.js +506 -0
- package/dist/common-fixpath.js +12 -0
- package/dist/constraint-types.js +12 -0
- package/dist/deterministic-replay.js +277 -0
- package/dist/emitter.js +112 -12
- package/dist/exec-metrics.js +11 -0
- package/dist/execute.js +242 -0
- package/dist/extract-ir.js +550 -5
- package/dist/failure-collector.js +143 -0
- package/dist/failure-corpus.js +481 -35
- package/dist/failure-report.js +11 -0
- package/dist/failures.js +11 -0
- package/dist/fast-path-hits.js +13 -0
- package/dist/feedback.js +6 -3
- package/dist/file-lock.js +82 -0
- package/dist/find-session.js +10 -0
- package/dist/fingerprint-list.js +15 -0
- package/dist/gen-history-log.js +13 -0
- package/dist/generate.js +2 -1
- package/dist/generate_500.js +4 -2
- package/dist/genome.js +11 -0
- package/dist/heatmap-data.js +11 -0
- package/dist/heatmap.js +11 -0
- package/dist/immune-reporter.js +33 -22
- package/dist/learned.js +11 -0
- package/dist/ledger-registry.js +241 -0
- package/dist/llm.js +43 -2
- package/dist/load-benchmarks.js +47 -0
- package/dist/main.js +2 -1
- package/dist/mcp-server.mjs +445 -43
- package/dist/memory-layer.js +51 -13
- package/dist/metrics.js +11 -0
- package/dist/obs-web.js +561 -0
- package/dist/p0_ssg_demo.js +255 -40
- package/dist/planner.js +905 -80
- package/dist/protocol-registry.js +105 -0
- package/dist/recent-session.js +12 -0
- package/dist/repair-proposal.js +353 -0
- package/dist/runtime-invariants.js +161 -0
- package/dist/runtime-types.js +117 -0
- package/dist/search-planner.js +38 -9
- package/dist/semantic-snapshot.js +155 -0
- package/dist/semantic-trace.js +1497 -0
- package/dist/semantic-validator.js +3 -2
- package/dist/semantic_guard_test.js +2 -1
- package/dist/sessions.js +11 -0
- package/dist/ssg-validator.js +658 -20
- package/dist/svl-distribution.js +11 -0
- package/dist/terminal-status.js +11 -0
- package/dist/test_failure_corpus.js +3 -1
- package/dist/token-savings.js +11 -0
- package/dist/total-repairs.js +12 -0
- package/dist/unresolved-count.js +12 -0
- package/dist/valid-fingerprints.js +13 -0
- package/dist/validator.js +116 -60
- package/dist/verify-fps.js +11 -0
- package/dist/verify-ledgers.js +11 -0
- package/docs/whitepaper-style.css +77 -0
- package/docs/whitepaper-v2.1.md +609 -0
- package/docs/whitepaper-v2.2.md +1064 -0
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +1 -1
- package/package.json +13 -4
- package/protocols.json +131 -11
- package/public/dashboard.html +119 -0
- package/readme.md +829 -0
- package/server/hub.js +84 -12
- package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
- package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
- package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
- package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
- package/test/replay-golden.ts +84 -0
- package/test_benchmark.js +165 -0
- package/test_comprehensive.mjs +638 -0
- package/test_concurrency.js +129 -0
- package/test_ir_robustness.js +85 -0
- package/test_semantic_contracts.js +269 -0
- package/test_ssg_stress.js +156 -0
- package/test_svl3.js +58 -0
- package/tsconfig.json +1 -1
- package/.env.example +0 -3
- package/.progmune_memory/episodic.json +0 -186
- package/.progmune_memory/fingerprints.json +0 -7
- package/.progmune_memory/opt_in.json +0 -4
- package/README.md +0 -118
- package/immune_hub_data/2026-05-14.json +0 -50
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.withLock = withLock;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* 基于目录原子性的轻量级文件锁
|
|
41
|
+
* mkdir 在系统层面是原子操作,用锁目录的存在与否表示锁定状态
|
|
42
|
+
*/
|
|
43
|
+
const LOCK_DIR = path.resolve(__dirname, "../.locks");
|
|
44
|
+
function ensureLockDir() {
|
|
45
|
+
if (!fs.existsSync(LOCK_DIR))
|
|
46
|
+
fs.mkdirSync(LOCK_DIR, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
function lockPath(name) {
|
|
49
|
+
return path.join(LOCK_DIR, name.replace(/[^a-zA-Z0-9_\-\.]/g, "_"));
|
|
50
|
+
}
|
|
51
|
+
function withLock(name, fn) {
|
|
52
|
+
ensureLockDir();
|
|
53
|
+
const lock = lockPath(name);
|
|
54
|
+
const maxRetries = 100;
|
|
55
|
+
const retryDelay = 5; // ms
|
|
56
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
57
|
+
try {
|
|
58
|
+
fs.mkdirSync(lock);
|
|
59
|
+
// 获取锁成功
|
|
60
|
+
try {
|
|
61
|
+
return fn();
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
try {
|
|
65
|
+
fs.rmdirSync(lock);
|
|
66
|
+
}
|
|
67
|
+
catch { }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err.code !== 'EEXIST')
|
|
72
|
+
throw err;
|
|
73
|
+
// 锁被占用,等待重试
|
|
74
|
+
if (attempt < maxRetries - 1) {
|
|
75
|
+
// busy-wait,但每次最多 5ms × 100 = 500ms
|
|
76
|
+
const start = Date.now();
|
|
77
|
+
while (Date.now() - start < retryDelay) { }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`无法获取锁: ${name} (超过最大重试次数 ${maxRetries})`);
|
|
82
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345171834_s7714 timestamp=2026-06-01T20:19:33.214Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 382 functions, 17 protocol rules
|
|
6
|
+
const semantic_snapshot_1 = require("./semantic-snapshot");
|
|
7
|
+
function main(sessionId) {
|
|
8
|
+
const snapshot = (0, semantic_snapshot_1.findSnapshotBySession)(sessionId);
|
|
9
|
+
return snapshot;
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343673382_7ucqe timestamp=2026-06-01T19:54:34.915Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 391 functions, 17 protocol rules
|
|
6
|
+
const ledger_registry_1 = require("./ledger-registry");
|
|
7
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
8
|
+
const ssg_validator_1 = require("./ssg-validator");
|
|
9
|
+
function main() {
|
|
10
|
+
const summary = (0, ledger_registry_1.verifyAllFingerprints)("defaultStr");
|
|
11
|
+
const sessions = (0, failure_corpus_1.getAllSessions)();
|
|
12
|
+
const states = (0, ssg_validator_1.listAllStates)(sessions);
|
|
13
|
+
return sessions;
|
|
14
|
+
}
|
|
15
|
+
main();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343705506_4rpek timestamp=2026-06-01T19:55:07.332Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 392 functions, 17 protocol rules
|
|
6
|
+
const execute_1 = require("./execute");
|
|
7
|
+
const memory_layer_1 = require("./memory-layer");
|
|
8
|
+
function main() {
|
|
9
|
+
const metrics = (0, execute_1.getExecutionMetrics)();
|
|
10
|
+
const episodes = (0, memory_layer_1.getRecentEpisodes)(0);
|
|
11
|
+
return episodes;
|
|
12
|
+
}
|
|
13
|
+
main();
|
package/dist/generate.js
CHANGED
|
@@ -62,7 +62,8 @@ async function main() {
|
|
|
62
62
|
let actions = [];
|
|
63
63
|
try {
|
|
64
64
|
if (planner === "llm") {
|
|
65
|
-
|
|
65
|
+
const result = await (0, planner_1.plan)(intent);
|
|
66
|
+
actions = result.actions;
|
|
66
67
|
}
|
|
67
68
|
else {
|
|
68
69
|
actions = await (0, search_planner_1.searchPlan)(intent, 2, 4);
|
package/dist/generate_500.js
CHANGED
|
@@ -60,8 +60,10 @@ async function main() {
|
|
|
60
60
|
const start = Date.now();
|
|
61
61
|
let actions = [];
|
|
62
62
|
try {
|
|
63
|
-
if (planner === "llm")
|
|
64
|
-
|
|
63
|
+
if (planner === "llm") {
|
|
64
|
+
const result = await (0, planner_1.plan)(intent);
|
|
65
|
+
actions = result.actions;
|
|
66
|
+
}
|
|
65
67
|
else
|
|
66
68
|
actions = await (0, search_planner_1.searchPlan)(intent, 2, 4);
|
|
67
69
|
}
|
package/dist/genome.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345697005_lpif0 timestamp=2026-06-01T20:28:18.667Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 386 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const genome = (0, failure_corpus_1.getFailureGenome)();
|
|
9
|
+
return genome;
|
|
10
|
+
}
|
|
11
|
+
main();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780343480174_btx1s timestamp=2026-06-01T19:51:21.674Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 387 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const heatmap = (0, failure_corpus_1.getSemanticHeatmap)();
|
|
9
|
+
return heatmap;
|
|
10
|
+
}
|
|
11
|
+
main();
|
package/dist/heatmap.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345774681_xbrxl timestamp=2026-06-01T20:29:36.190Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 389 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const heatmap = (0, failure_corpus_1.getSemanticHeatmap)();
|
|
9
|
+
return heatmap;
|
|
10
|
+
}
|
|
11
|
+
main();
|
package/dist/immune-reporter.js
CHANGED
|
@@ -42,26 +42,44 @@ const https = __importStar(require("https"));
|
|
|
42
42
|
const http = __importStar(require("http"));
|
|
43
43
|
const crypto = __importStar(require("crypto"));
|
|
44
44
|
const REPORT_ENDPOINT = process.env.PROGMUNE_HUB || "http://localhost:3000/report";
|
|
45
|
-
const
|
|
45
|
+
const CURSOR_FILE = path.resolve(__dirname, "../.progmune_memory/report_cursor.json");
|
|
46
46
|
function getInstanceId() {
|
|
47
47
|
const host = require("os").hostname();
|
|
48
48
|
const cwd = process.cwd();
|
|
49
49
|
return crypto.createHash("sha256").update(host + cwd).digest("hex").substring(0, 16);
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function getReportCursor() {
|
|
52
|
+
try {
|
|
53
|
+
if (fs.existsSync(CURSOR_FILE))
|
|
54
|
+
return JSON.parse(fs.readFileSync(CURSOR_FILE, "utf-8"));
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
return { lastTimestamp: null, reportedCount: 0 };
|
|
58
|
+
}
|
|
59
|
+
function saveReportCursor(timestamp, count) {
|
|
60
|
+
const dir = path.dirname(CURSOR_FILE);
|
|
61
|
+
if (!fs.existsSync(dir))
|
|
62
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
fs.writeFileSync(CURSOR_FILE, JSON.stringify({ lastTimestamp: timestamp, reportedCount: count, updatedAt: new Date().toISOString() }, null, 2));
|
|
64
|
+
}
|
|
65
|
+
function extractFingerprints(cursor) {
|
|
52
66
|
const corpusDir = path.resolve(__dirname, "../failure_corpus");
|
|
53
67
|
if (!fs.existsSync(corpusDir))
|
|
54
68
|
return [];
|
|
55
69
|
const fingerprints = [];
|
|
56
70
|
const instanceId = getInstanceId();
|
|
57
|
-
for (const dateDir of fs.readdirSync(corpusDir)) {
|
|
71
|
+
for (const dateDir of fs.readdirSync(corpusDir).sort()) {
|
|
58
72
|
const datePath = path.join(corpusDir, dateDir);
|
|
59
73
|
if (!fs.statSync(datePath).isDirectory())
|
|
60
74
|
continue;
|
|
61
|
-
for (const file of fs.readdirSync(datePath)) {
|
|
75
|
+
for (const file of fs.readdirSync(datePath).sort()) {
|
|
62
76
|
if (!file.endsWith(".json"))
|
|
63
77
|
continue;
|
|
64
|
-
const
|
|
78
|
+
const filePath = path.join(datePath, file);
|
|
79
|
+
const record = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
80
|
+
// 如果游标存在且该记录时间戳 <= 游标,跳过
|
|
81
|
+
if (cursor && cursor.lastTimestamp && record.timestamp <= cursor.lastTimestamp)
|
|
82
|
+
continue;
|
|
65
83
|
const funcSeq = (record.actionSequence || [])
|
|
66
84
|
.filter((a) => a.kind === "call")
|
|
67
85
|
.map((a) => a.function);
|
|
@@ -80,19 +98,15 @@ function extractFingerprints() {
|
|
|
80
98
|
return fingerprints;
|
|
81
99
|
}
|
|
82
100
|
async function reportFingerprints() {
|
|
83
|
-
const
|
|
101
|
+
const cursor = getReportCursor();
|
|
102
|
+
const fingerprints = extractFingerprints(cursor);
|
|
84
103
|
if (fingerprints.length === 0) {
|
|
85
104
|
return { success: true, message: "无新指纹需要上报" };
|
|
86
105
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
const newFingerprints = fingerprints.filter(f => !reported.includes(f.functionSequence.join(",")));
|
|
92
|
-
if (newFingerprints.length === 0) {
|
|
93
|
-
return { success: true, message: "所有指纹已上报,无新增" };
|
|
94
|
-
}
|
|
95
|
-
const payload = JSON.stringify({ fingerprints: newFingerprints });
|
|
106
|
+
// 按时间戳排序,取最新的作为游标
|
|
107
|
+
fingerprints.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
108
|
+
const maxTimestamp = fingerprints[fingerprints.length - 1].timestamp;
|
|
109
|
+
const payload = JSON.stringify({ fingerprints });
|
|
96
110
|
return new Promise((resolve) => {
|
|
97
111
|
const url = new URL(REPORT_ENDPOINT);
|
|
98
112
|
const transport = url.protocol === "https:" ? https : http;
|
|
@@ -104,12 +118,9 @@ async function reportFingerprints() {
|
|
|
104
118
|
res.on("data", (chunk) => data += chunk);
|
|
105
119
|
res.on("end", () => {
|
|
106
120
|
if (res.statusCode === 200) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
111
|
-
fs.writeFileSync(FINGERPRINT_FILE, JSON.stringify(updated, null, 2));
|
|
112
|
-
resolve({ success: true, message: `成功上报 ${newFingerprints.length} 条新指纹` });
|
|
121
|
+
const total = (cursor.reportedCount || 0) + fingerprints.length;
|
|
122
|
+
saveReportCursor(maxTimestamp, total);
|
|
123
|
+
resolve({ success: true, message: `成功上报 ${fingerprints.length} 条新指纹(累计 ${total} 条)` });
|
|
113
124
|
}
|
|
114
125
|
else {
|
|
115
126
|
resolve({ success: false, message: `上报失败: ${res.statusCode} ${data}` });
|
|
@@ -122,5 +133,5 @@ async function reportFingerprints() {
|
|
|
122
133
|
});
|
|
123
134
|
}
|
|
124
135
|
function previewFingerprints() {
|
|
125
|
-
return extractFingerprints();
|
|
136
|
+
return extractFingerprints({ lastTimestamp: null });
|
|
126
137
|
}
|
package/dist/learned.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
// @progmune-generated session=sess_1780345941461_pofm6 timestamp=2026-06-01T20:32:23.160Z ruleHash=9dec68bc2995e92a
|
|
5
|
+
// Generated with IR constraint: 391 functions, 17 protocol rules
|
|
6
|
+
const failure_corpus_1 = require("./failure-corpus");
|
|
7
|
+
function main() {
|
|
8
|
+
const patterns = (0, failure_corpus_1.getLearnedPatterns)();
|
|
9
|
+
return patterns;
|
|
10
|
+
}
|
|
11
|
+
main();
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 4: Ledger Fingerprint Registry (P0)
|
|
4
|
+
*
|
|
5
|
+
* Execution Certificate = session + ledgerHash + ruleHash + timestamp.
|
|
6
|
+
* Answers: "Has this session been tampered with? Have the rules changed?"
|
|
7
|
+
*
|
|
8
|
+
* Does NOT do: previousHash chains, blockchain-style verification, multi-node sync.
|
|
9
|
+
* Those are for Phase 5+ when distributed execution is needed.
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.registerFingerprint = registerFingerprint;
|
|
46
|
+
exports.getFingerprint = getFingerprint;
|
|
47
|
+
exports.getFingerprintRegistry = getFingerprintRegistry;
|
|
48
|
+
exports.verifyFingerprint = verifyFingerprint;
|
|
49
|
+
exports.verifyAllFingerprints = verifyAllFingerprints;
|
|
50
|
+
exports.registerAllMissingFingerprints = registerAllMissingFingerprints;
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const ssg_validator_1 = require("./ssg-validator");
|
|
54
|
+
// ── Storage ──
|
|
55
|
+
function fingerprintsDir() {
|
|
56
|
+
const projectDir = process.env.PROGMUNE_PROJECT_DIR || process.cwd();
|
|
57
|
+
return path.resolve(projectDir, ".progmune_corpus/fingerprints");
|
|
58
|
+
}
|
|
59
|
+
function fingerprintPath(sessionId) {
|
|
60
|
+
return path.join(fingerprintsDir(), `${sessionId}.json`);
|
|
61
|
+
}
|
|
62
|
+
// ── Core API ──
|
|
63
|
+
/** Register a ledger fingerprint (execution certificate).
|
|
64
|
+
* Called after a session is recorded — creates an immutable proof of the ledger state. */
|
|
65
|
+
function registerFingerprint(sessionId, transitions, ruleHash) {
|
|
66
|
+
const dir = fingerprintsDir();
|
|
67
|
+
if (!fs.existsSync(dir)) {
|
|
68
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
const fingerprint = {
|
|
71
|
+
sessionId,
|
|
72
|
+
ledgerHash: (0, ssg_validator_1.hashLedger)(transitions),
|
|
73
|
+
ruleHash,
|
|
74
|
+
transitionCount: transitions.length,
|
|
75
|
+
timestamp: Date.now(),
|
|
76
|
+
};
|
|
77
|
+
fs.writeFileSync(fingerprintPath(sessionId), JSON.stringify(fingerprint, null, 2), "utf-8");
|
|
78
|
+
return fingerprint;
|
|
79
|
+
}
|
|
80
|
+
/** Get a single stored fingerprint by sessionId. Returns null if not registered. */
|
|
81
|
+
function getFingerprint(sessionId) {
|
|
82
|
+
const fpPath = fingerprintPath(sessionId);
|
|
83
|
+
if (!fs.existsSync(fpPath))
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(fs.readFileSync(fpPath, "utf-8"));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** List all registered fingerprints, sorted by timestamp (oldest first). */
|
|
93
|
+
function getFingerprintRegistry() {
|
|
94
|
+
const dir = fingerprintsDir();
|
|
95
|
+
if (!fs.existsSync(dir))
|
|
96
|
+
return [];
|
|
97
|
+
const fingerprints = [];
|
|
98
|
+
for (const file of fs.readdirSync(dir)) {
|
|
99
|
+
if (!file.endsWith(".json"))
|
|
100
|
+
continue;
|
|
101
|
+
try {
|
|
102
|
+
const fp = JSON.parse(fs.readFileSync(path.join(dir, file), "utf-8"));
|
|
103
|
+
if (fp.sessionId && fp.ledgerHash) {
|
|
104
|
+
fingerprints.push(fp);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Skip corrupted fingerprint files
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return fingerprints.sort((a, b) => a.timestamp - b.timestamp);
|
|
112
|
+
}
|
|
113
|
+
/** Verify a single session's fingerprint.
|
|
114
|
+
* Requires the session's transitions to re-hash and compare. */
|
|
115
|
+
function verifyFingerprint(sessionId, transitions, currentRuleHash) {
|
|
116
|
+
const stored = getFingerprint(sessionId);
|
|
117
|
+
if (!stored) {
|
|
118
|
+
return {
|
|
119
|
+
sessionId,
|
|
120
|
+
valid: false,
|
|
121
|
+
stored: { sessionId, ledgerHash: "", ruleHash: "", transitionCount: 0, timestamp: 0 },
|
|
122
|
+
tampered: true,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const result = {
|
|
126
|
+
sessionId,
|
|
127
|
+
valid: true,
|
|
128
|
+
stored,
|
|
129
|
+
tampered: false,
|
|
130
|
+
};
|
|
131
|
+
if (transitions && transitions.length > 0) {
|
|
132
|
+
result.currentHash = (0, ssg_validator_1.hashLedger)(transitions);
|
|
133
|
+
if (result.currentHash !== stored.ledgerHash) {
|
|
134
|
+
result.valid = false;
|
|
135
|
+
result.tampered = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (currentRuleHash && currentRuleHash !== stored.ruleHash) {
|
|
139
|
+
result.currentRuleHash = currentRuleHash;
|
|
140
|
+
// Rule hash mismatch doesn't mean tampering — rules may have legitimately changed
|
|
141
|
+
result.valid = false;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
/** Verify all registered fingerprints.
|
|
146
|
+
* Loads each session to re-hash and compare against the stored fingerprint. */
|
|
147
|
+
function verifyAllFingerprints(currentRuleHash) {
|
|
148
|
+
const fingerprints = getFingerprintRegistry();
|
|
149
|
+
const results = [];
|
|
150
|
+
let valid = 0;
|
|
151
|
+
let tampered = 0;
|
|
152
|
+
let notFound = 0;
|
|
153
|
+
const sessionsDir = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".progmune_corpus/sessions");
|
|
154
|
+
for (const fp of fingerprints) {
|
|
155
|
+
// Try to load the session file
|
|
156
|
+
const sessionFile = path.join(sessionsDir, `${fp.sessionId}.json`);
|
|
157
|
+
if (!fs.existsSync(sessionFile)) {
|
|
158
|
+
notFound++;
|
|
159
|
+
results.push({
|
|
160
|
+
sessionId: fp.sessionId,
|
|
161
|
+
valid: false,
|
|
162
|
+
stored: fp,
|
|
163
|
+
tampered: false,
|
|
164
|
+
});
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const session = JSON.parse(fs.readFileSync(sessionFile, "utf-8"));
|
|
169
|
+
let allTransitions = [];
|
|
170
|
+
for (const attempt of (session.attempts || [])) {
|
|
171
|
+
allTransitions = allTransitions.concat(attempt.transitions || []);
|
|
172
|
+
}
|
|
173
|
+
const result = verifyFingerprint(fp.sessionId, allTransitions, currentRuleHash);
|
|
174
|
+
results.push(result);
|
|
175
|
+
if (result.valid) {
|
|
176
|
+
valid++;
|
|
177
|
+
}
|
|
178
|
+
else if (result.tampered) {
|
|
179
|
+
tampered++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
notFound++;
|
|
184
|
+
results.push({
|
|
185
|
+
sessionId: fp.sessionId,
|
|
186
|
+
valid: false,
|
|
187
|
+
stored: fp,
|
|
188
|
+
tampered: false,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
total: fingerprints.length,
|
|
194
|
+
verified: results,
|
|
195
|
+
valid,
|
|
196
|
+
tampered,
|
|
197
|
+
notFound,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/** Register fingerprints for all sessions that don't yet have one.
|
|
201
|
+
* Called during `npm run check` to ensure all sessions are fingerprinted. */
|
|
202
|
+
function registerAllMissingFingerprints() {
|
|
203
|
+
const sessionsDir = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".progmune_corpus/sessions");
|
|
204
|
+
if (!fs.existsSync(sessionsDir))
|
|
205
|
+
return 0;
|
|
206
|
+
let registered = 0;
|
|
207
|
+
for (const file of fs.readdirSync(sessionsDir)) {
|
|
208
|
+
if (!file.endsWith(".json"))
|
|
209
|
+
continue;
|
|
210
|
+
try {
|
|
211
|
+
const session = JSON.parse(fs.readFileSync(path.join(sessionsDir, file), "utf-8"));
|
|
212
|
+
const sessionId = session.sessionId;
|
|
213
|
+
if (!sessionId)
|
|
214
|
+
continue;
|
|
215
|
+
// Skip if already fingerprinted
|
|
216
|
+
const existing = getFingerprint(sessionId);
|
|
217
|
+
if (existing && existing.ledgerHash)
|
|
218
|
+
continue;
|
|
219
|
+
let allTransitions = [];
|
|
220
|
+
let ruleHash = "";
|
|
221
|
+
for (const attempt of (session.attempts || [])) {
|
|
222
|
+
allTransitions = allTransitions.concat(attempt.transitions || []);
|
|
223
|
+
if (!ruleHash && (attempt.ruleHash || session.ruleHash)) {
|
|
224
|
+
ruleHash = attempt.ruleHash || session.ruleHash;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (allTransitions.length === 0)
|
|
228
|
+
continue;
|
|
229
|
+
// Fall back to hashRules from existing info if no ruleHash found
|
|
230
|
+
if (!ruleHash) {
|
|
231
|
+
ruleHash = session.ruleHash || "unknown";
|
|
232
|
+
}
|
|
233
|
+
registerFingerprint(sessionId, allTransitions, ruleHash);
|
|
234
|
+
registered++;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Skip unreadable session files
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return registered;
|
|
241
|
+
}
|
package/dist/llm.js
CHANGED
|
@@ -5,14 +5,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.callCount = void 0;
|
|
7
7
|
exports.resetCallCount = resetCallCount;
|
|
8
|
+
exports.estimateTokens = estimateTokens;
|
|
8
9
|
exports.generate = generate;
|
|
10
|
+
exports.chat = chat;
|
|
11
|
+
try {
|
|
12
|
+
require("dotenv/config");
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
9
15
|
const openai_1 = __importDefault(require("openai"));
|
|
16
|
+
const provider = process.env.LLM_PROVIDER || "deepseek";
|
|
17
|
+
const configs = {
|
|
18
|
+
deepseek: {
|
|
19
|
+
baseURL: "https://api.deepseek.com/v1",
|
|
20
|
+
model: "deepseek-chat",
|
|
21
|
+
},
|
|
22
|
+
openai: {
|
|
23
|
+
baseURL: "https://api.openai.com/v1",
|
|
24
|
+
model: "gpt-4",
|
|
25
|
+
},
|
|
26
|
+
ollama: {
|
|
27
|
+
baseURL: "http://localhost:11434/v1",
|
|
28
|
+
model: "llama3",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const selected = configs[provider] || configs.deepseek;
|
|
10
32
|
const apiKey = process.env.LLM_API_KEY || "sk-xxxx";
|
|
11
|
-
const baseURL = process.env.LLM_BASE_URL ||
|
|
12
|
-
const model = process.env.LLM_MODEL ||
|
|
33
|
+
const baseURL = process.env.LLM_BASE_URL || selected.baseURL;
|
|
34
|
+
const model = process.env.LLM_MODEL || selected.model;
|
|
13
35
|
const client = new openai_1.default({ apiKey, baseURL });
|
|
14
36
|
exports.callCount = 0;
|
|
15
37
|
function resetCallCount() { exports.callCount = 0; }
|
|
38
|
+
/** 粗略 token 估算:CJK 字符 ~1.5 token/字,其余 ~0.4 token/字符 */
|
|
39
|
+
function estimateTokens(text) {
|
|
40
|
+
const cjk = (text.match(/[一-鿿㐀-䶿]/g) || []).length;
|
|
41
|
+
const other = text.length - cjk;
|
|
42
|
+
return Math.ceil(cjk * 1.5 + other * 0.4);
|
|
43
|
+
}
|
|
16
44
|
async function generate(prompt) {
|
|
17
45
|
exports.callCount++;
|
|
18
46
|
const resp = await client.chat.completions.create({
|
|
@@ -22,3 +50,16 @@ async function generate(prompt) {
|
|
|
22
50
|
});
|
|
23
51
|
return resp.choices[0]?.message?.content || "";
|
|
24
52
|
}
|
|
53
|
+
/** 带 system prompt 的调用:静态规则放 system,动态内容放 user,语义分离便于未来对接各平台缓存策略 */
|
|
54
|
+
async function chat(systemPrompt, userPrompt) {
|
|
55
|
+
exports.callCount++;
|
|
56
|
+
const resp = await client.chat.completions.create({
|
|
57
|
+
model,
|
|
58
|
+
messages: [
|
|
59
|
+
{ role: "system", content: systemPrompt },
|
|
60
|
+
{ role: "user", content: userPrompt },
|
|
61
|
+
],
|
|
62
|
+
temperature: 0.0,
|
|
63
|
+
});
|
|
64
|
+
return resp.choices[0]?.message?.content || "";
|
|
65
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadBenchmarks = loadBenchmarks;
|
|
37
|
+
/** Load benchmark tasks from bench/tasks.json
|
|
38
|
+
* @protocol pre_states=[] post_states=["BENCHMARKS_LOADED"]
|
|
39
|
+
*/
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
function loadBenchmarks() {
|
|
43
|
+
const tasksPath = path.resolve(process.cwd(), "bench/tasks.json");
|
|
44
|
+
if (!fs.existsSync(tasksPath))
|
|
45
|
+
return [];
|
|
46
|
+
return JSON.parse(fs.readFileSync(tasksPath, "utf-8"));
|
|
47
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -75,7 +75,8 @@ async function main() {
|
|
|
75
75
|
// 2. 获取正常动作序列
|
|
76
76
|
const intent = "实现登录接口,验证密码后返回 JWT,并记录日志";
|
|
77
77
|
console.log("\n🧠 正常规划...");
|
|
78
|
-
const
|
|
78
|
+
const result = await (0, planner_1.plan)(intent);
|
|
79
|
+
const normalActions = result.actions;
|
|
79
80
|
console.log("🎯 正常动作:");
|
|
80
81
|
console.log(JSON.stringify(normalActions, null, 2));
|
|
81
82
|
// 3. 正常流程
|