progmune-runtime 2.1.6 → 3.2.1
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/README.md +119 -461
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +721 -0
- package/package.json +73 -6
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
package/dist/memory-layer.js
CHANGED
|
@@ -175,15 +175,52 @@ function saveSemantic(templates) {
|
|
|
175
175
|
}
|
|
176
176
|
function consolidateSemantic(minOccurrences = 3) {
|
|
177
177
|
const episodes = getSuccessfulEpisodes(MAX_EPISODES);
|
|
178
|
+
// Extract the first 3 meaningful keywords as the grouping key
|
|
179
|
+
// (replaces fragile 20-char prefix — two intents with the same first
|
|
180
|
+
// 3 keywords are far more likely to be semantically similar)
|
|
181
|
+
function keywordKey(intent) {
|
|
182
|
+
const words = intent
|
|
183
|
+
.toLowerCase()
|
|
184
|
+
.split(/[\s,,、。!?:;]+/)
|
|
185
|
+
.filter(w => w.length > 2 && !["the", "and", "for", "with", "from", "that", "this"].includes(w));
|
|
186
|
+
return words.slice(0, 3).join("|");
|
|
187
|
+
}
|
|
188
|
+
// Group episodes by keyword key
|
|
178
189
|
const grouped = new Map();
|
|
179
190
|
for (const ep of episodes) {
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
|
|
183
|
-
grouped.
|
|
191
|
+
const key = keywordKey(ep.intent);
|
|
192
|
+
if (!key)
|
|
193
|
+
continue; // skip intents too short to produce keywords
|
|
194
|
+
if (!grouped.has(key))
|
|
195
|
+
grouped.set(key, []);
|
|
196
|
+
grouped.get(key).push(ep);
|
|
197
|
+
}
|
|
198
|
+
// Merge small groups into larger ones by Jaccard overlap
|
|
199
|
+
const keys = [...grouped.keys()];
|
|
200
|
+
const merged = new Map();
|
|
201
|
+
const processed = new Set();
|
|
202
|
+
for (const k of keys) {
|
|
203
|
+
if (processed.has(k))
|
|
204
|
+
continue;
|
|
205
|
+
const cluster = [...grouped.get(k)];
|
|
206
|
+
processed.add(k);
|
|
207
|
+
// Find nearby groups with high keyword overlap
|
|
208
|
+
for (const other of keys) {
|
|
209
|
+
if (processed.has(other))
|
|
210
|
+
continue;
|
|
211
|
+
const kWords = new Set(k.split("|").filter(w => w.length > 0));
|
|
212
|
+
const oWords = new Set(other.split("|").filter(w => w.length > 0));
|
|
213
|
+
const intersection = [...kWords].filter(w => oWords.has(w)).length;
|
|
214
|
+
const union = new Set([...kWords, ...oWords]).size;
|
|
215
|
+
if (union > 0 && intersection / union >= 0.5) {
|
|
216
|
+
cluster.push(...grouped.get(other));
|
|
217
|
+
processed.add(other);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
merged.set(k, cluster);
|
|
184
221
|
}
|
|
185
222
|
const templates = loadSemantic();
|
|
186
|
-
for (const [pattern, eps] of
|
|
223
|
+
for (const [pattern, eps] of merged) {
|
|
187
224
|
if (eps.length >= minOccurrences) {
|
|
188
225
|
const existing = templates.find(t => t.intentPattern === pattern);
|
|
189
226
|
if (existing) {
|
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P0: Multi-Repository SSG Precision Validation
|
|
4
|
+
*
|
|
5
|
+
* Runs SSG protocol extraction + precision measurement across
|
|
6
|
+
* multiple real-world repositories. Generates a transparent,
|
|
7
|
+
* reproducible precision report.
|
|
8
|
+
*
|
|
9
|
+
* Target repos: curl, nginx, redis, sqlite, libuv
|
|
10
|
+
* (small → medium → large)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* npx ts-node src/multi-repo-precision.ts
|
|
14
|
+
* npx ts-node src/multi-repo-precision.ts --repos curl,redis
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.runMultiRepoPrecision = runMultiRepoPrecision;
|
|
51
|
+
exports.formatMultiRepoReportTerminal = formatMultiRepoReportTerminal;
|
|
52
|
+
exports.exportMultiRepoReportJSON = exportMultiRepoReportJSON;
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
const child_process_1 = require("child_process");
|
|
56
|
+
const extract_ir_1 = require("./extract-ir");
|
|
57
|
+
const ssg_precision_1 = require("./ssg-precision");
|
|
58
|
+
// Default targets — local repos + external repos (auto-cloned)
|
|
59
|
+
const DEFAULT_TARGETS = [
|
|
60
|
+
{
|
|
61
|
+
name: "progmune-self",
|
|
62
|
+
size: "small",
|
|
63
|
+
localPath: process.cwd(),
|
|
64
|
+
expectedProtocols: ["extractIR", "validateAction", "emitCode", "recordSession", "checkLedgerConsistency"],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "demo-xlike",
|
|
68
|
+
size: "small",
|
|
69
|
+
localPath: path.resolve(process.cwd(), "demo-xlike"),
|
|
70
|
+
expectedProtocols: ["insertPost", "getRecentPosts", "deletePost", "validatePostContent", "initDatabase"],
|
|
71
|
+
},
|
|
72
|
+
// External precision-program repos (auto-cloned into benchmarks/)
|
|
73
|
+
{
|
|
74
|
+
name: "curl",
|
|
75
|
+
size: "medium",
|
|
76
|
+
localPath: path.resolve(process.cwd(), "benchmarks", "curl"),
|
|
77
|
+
expectedProtocols: ["curl_easy_init", "curl_easy_perform", "curl_easy_cleanup", "curl_easy_setopt"],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "nginx",
|
|
81
|
+
size: "large",
|
|
82
|
+
localPath: path.resolve(process.cwd(), "benchmarks", "nginx"),
|
|
83
|
+
expectedProtocols: ["ngx_http_init_connection", "ngx_http_process_request", "ngx_http_finalize_request"],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "redis",
|
|
87
|
+
size: "medium",
|
|
88
|
+
localPath: path.resolve(process.cwd(), "benchmarks", "redis"),
|
|
89
|
+
expectedProtocols: ["createClient", "readQueryFromClient", "freeClient", "processCommand"],
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
const EXTERNAL_REPOS = {
|
|
93
|
+
curl: { url: "https://github.com/curl/curl.git", depth: 100 },
|
|
94
|
+
nginx: { url: "https://github.com/nginx/nginx.git", depth: 100 },
|
|
95
|
+
redis: { url: "https://github.com/redis/redis.git", depth: 100 },
|
|
96
|
+
};
|
|
97
|
+
/** Clone or pull an external repo into benchmarks/<name>/ */
|
|
98
|
+
function ensureRepo(name) {
|
|
99
|
+
const dir = path.resolve(process.cwd(), "benchmarks", name);
|
|
100
|
+
if (fs.existsSync(path.join(dir, ".git"))) {
|
|
101
|
+
console.error(` ↻ Updating ${name}...`);
|
|
102
|
+
try {
|
|
103
|
+
(0, child_process_1.execSync)(`cd ${dir} && git pull --ff-only 2>/dev/null || true`, { stdio: "ignore", timeout: 30000 });
|
|
104
|
+
}
|
|
105
|
+
catch { /* skip */ }
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const cfg = EXTERNAL_REPOS[name];
|
|
109
|
+
if (!cfg)
|
|
110
|
+
throw new Error(`No clone URL for: ${name}`);
|
|
111
|
+
console.error(` ↓ Cloning ${name} (depth=${cfg.depth || 100})...`);
|
|
112
|
+
const parent = path.dirname(dir);
|
|
113
|
+
if (!fs.existsSync(parent))
|
|
114
|
+
fs.mkdirSync(parent, { recursive: true });
|
|
115
|
+
(0, child_process_1.execSync)(`git clone --depth=${cfg.depth || 100} ${cfg.url} ${dir}`, { stdio: "ignore", timeout: 120000 });
|
|
116
|
+
}
|
|
117
|
+
return dir;
|
|
118
|
+
}
|
|
119
|
+
// ═══════════════════════════════════════════════════════════════
|
|
120
|
+
// Engine
|
|
121
|
+
// ═══════════════════════════════════════════════════════════════
|
|
122
|
+
function countLinesOfCode(dir) {
|
|
123
|
+
let count = 0;
|
|
124
|
+
try {
|
|
125
|
+
const files = walkFiles(dir, [".ts", ".js", ".c", ".h", ".py"]);
|
|
126
|
+
for (const f of files) {
|
|
127
|
+
try {
|
|
128
|
+
count += fs.readFileSync(f, "utf-8").split("\n").length;
|
|
129
|
+
}
|
|
130
|
+
catch { /* skip */ }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch { /* skip */ }
|
|
134
|
+
return count;
|
|
135
|
+
}
|
|
136
|
+
function walkFiles(dir, exts) {
|
|
137
|
+
const results = [];
|
|
138
|
+
try {
|
|
139
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
140
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist")
|
|
141
|
+
continue;
|
|
142
|
+
const full = path.join(dir, entry.name);
|
|
143
|
+
if (entry.isDirectory()) {
|
|
144
|
+
results.push(...walkFiles(full, exts));
|
|
145
|
+
}
|
|
146
|
+
else if (exts.some(e => entry.name.endsWith(e))) {
|
|
147
|
+
results.push(full);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch { /* skip */ }
|
|
152
|
+
return results;
|
|
153
|
+
}
|
|
154
|
+
/** Extract call sequences from IR: group functions by file, build adjacency pairs */
|
|
155
|
+
function extractCallSequences(ir) {
|
|
156
|
+
const sequences = [];
|
|
157
|
+
const funcNames = ir.map((f) => f.name);
|
|
158
|
+
// Build sequences from IR: each protocol chain is a sequence
|
|
159
|
+
// For functions with protocol annotations, extract the implied sequence
|
|
160
|
+
for (const fn of ir) {
|
|
161
|
+
if (fn.protocol) {
|
|
162
|
+
const seq = [];
|
|
163
|
+
if (fn.protocol.pre_states)
|
|
164
|
+
seq.push(...fn.protocol.pre_states);
|
|
165
|
+
seq.push(fn.name);
|
|
166
|
+
if (fn.protocol.post_states)
|
|
167
|
+
seq.push(...fn.protocol.post_states);
|
|
168
|
+
if (seq.length >= 2)
|
|
169
|
+
sequences.push(seq);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// If no protocol annotations, build adjacency pairs from function names
|
|
173
|
+
if (sequences.length === 0 && funcNames.length >= 2) {
|
|
174
|
+
// Group by common prefixes (e.g., "open_", "close_", "read_", "write_")
|
|
175
|
+
const groups = groupByPrefix(funcNames);
|
|
176
|
+
for (const [, fns] of Object.entries(groups)) {
|
|
177
|
+
if (fns.length >= 2) {
|
|
178
|
+
sequences.push(fns);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Fallback: create sequences from all function pairs in same file
|
|
183
|
+
if (sequences.length === 0) {
|
|
184
|
+
sequences.push(funcNames.slice(0, 10));
|
|
185
|
+
}
|
|
186
|
+
return sequences;
|
|
187
|
+
}
|
|
188
|
+
function groupByPrefix(names) {
|
|
189
|
+
const groups = {};
|
|
190
|
+
for (const name of names) {
|
|
191
|
+
// Extract prefix: everything before the last underscore or verb
|
|
192
|
+
const parts = name.split("_");
|
|
193
|
+
const prefix = parts.length >= 2 ? parts.slice(0, -1).join("_") : name;
|
|
194
|
+
if (!groups[prefix])
|
|
195
|
+
groups[prefix] = [];
|
|
196
|
+
groups[prefix].push(name);
|
|
197
|
+
}
|
|
198
|
+
// Only keep groups with >= 2 members
|
|
199
|
+
const result = {};
|
|
200
|
+
for (const [k, v] of Object.entries(groups)) {
|
|
201
|
+
if (v.length >= 2)
|
|
202
|
+
result[k] = v;
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
function runRepoPrecision(target) {
|
|
207
|
+
const errors = [];
|
|
208
|
+
// Auto-clone external repos
|
|
209
|
+
let dir = target.localPath || process.cwd();
|
|
210
|
+
if (EXTERNAL_REPOS[target.name] && !fs.existsSync(path.join(dir, ".git"))) {
|
|
211
|
+
try {
|
|
212
|
+
dir = ensureRepo(target.name);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
errors.push(`Clone failed: ${e.message}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// 1. Count lines of code
|
|
219
|
+
const loc = countLinesOfCode(dir);
|
|
220
|
+
// 2. Extract IR
|
|
221
|
+
let ir = [];
|
|
222
|
+
try {
|
|
223
|
+
ir = (0, extract_ir_1.extractIR)(dir);
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
errors.push(`IR extraction: ${e.message}`);
|
|
227
|
+
}
|
|
228
|
+
// 3. Extract call sequences
|
|
229
|
+
const sequences = extractCallSequences(ir);
|
|
230
|
+
// 4. Discover protocol rules
|
|
231
|
+
let rulesDiscovered = 0;
|
|
232
|
+
let protocolsFound = [];
|
|
233
|
+
let cveMatched = 0;
|
|
234
|
+
try {
|
|
235
|
+
const cleanSeqs = sequences.filter(s => s.length >= 2);
|
|
236
|
+
if (cleanSeqs.length > 0) {
|
|
237
|
+
const { rules, nsInit } = (0, ssg_precision_1.discoverRulesFromSequences)(cleanSeqs);
|
|
238
|
+
rulesDiscovered = rules.size;
|
|
239
|
+
protocolsFound = [...rules.keys()];
|
|
240
|
+
// Check PLSB coverage: which known CVE patterns appear?
|
|
241
|
+
const { PROTOCOL_WEAKNESS_TAXONOMY } = require("./plsb-benchmark");
|
|
242
|
+
for (const t of PROTOCOL_WEAKNESS_TAXONOMY) {
|
|
243
|
+
for (const seq of sequences) {
|
|
244
|
+
const hasMatch = t.example_broken.some((step) => seq.some((s) => s.toLowerCase().includes(step.toLowerCase())));
|
|
245
|
+
if (hasMatch) {
|
|
246
|
+
cveMatched++;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
errors.push(`Rule discovery: ${e.message}`);
|
|
255
|
+
}
|
|
256
|
+
// 5. Run precision (if we have both clean and violation-labeled sequences)
|
|
257
|
+
let precision;
|
|
258
|
+
let annotatedSamples = 0;
|
|
259
|
+
let needsAnnotation = true;
|
|
260
|
+
try {
|
|
261
|
+
// Check for hand-labeled data
|
|
262
|
+
const labelPath = path.join(dir, ".progmune_labels.json");
|
|
263
|
+
if (fs.existsSync(labelPath)) {
|
|
264
|
+
const labels = JSON.parse(fs.readFileSync(labelPath, "utf-8"));
|
|
265
|
+
annotatedSamples = Object.keys(labels).length;
|
|
266
|
+
// Run SSG precision with labels
|
|
267
|
+
const { runSSGPrecisionBenchmark, discoverRulesFromSequences } = require("./ssg-precision");
|
|
268
|
+
const labeledSeqs = sequences.map((calls, i) => ({ index: i, calls, functionName: calls[0] || `seq_${i}` }));
|
|
269
|
+
const result = runSSGPrecisionBenchmark(labeledSeqs, labels);
|
|
270
|
+
precision = {
|
|
271
|
+
total: result.total,
|
|
272
|
+
truePositive: result.truePositive,
|
|
273
|
+
falsePositive: result.falsePositive,
|
|
274
|
+
trueNegative: result.trueNegative,
|
|
275
|
+
falseNegative: result.falseNegative,
|
|
276
|
+
precision: result.precision,
|
|
277
|
+
recall: result.recall,
|
|
278
|
+
f1: result.f1,
|
|
279
|
+
};
|
|
280
|
+
needsAnnotation = result.total === 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
errors.push(`Precision benchmark: ${e.message}`);
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
repo: target.name,
|
|
288
|
+
size: target.size,
|
|
289
|
+
linesOfCode: loc,
|
|
290
|
+
functionsExtracted: ir.length,
|
|
291
|
+
sequencesExtracted: sequences.length,
|
|
292
|
+
rulesDiscovered,
|
|
293
|
+
precision,
|
|
294
|
+
protocolsFound: protocolsFound.slice(0, 20),
|
|
295
|
+
cvePatternsMatched: cveMatched,
|
|
296
|
+
annotatedSamples,
|
|
297
|
+
needsAnnotation,
|
|
298
|
+
errors,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// ═══════════════════════════════════════════════════════════════
|
|
302
|
+
// Report Generator
|
|
303
|
+
// ═══════════════════════════════════════════════════════════════
|
|
304
|
+
function runMultiRepoPrecision(targets = DEFAULT_TARGETS) {
|
|
305
|
+
const repos = [];
|
|
306
|
+
for (const target of targets) {
|
|
307
|
+
console.error(`\n🔍 ${target.name} (${target.size})...`);
|
|
308
|
+
const result = runRepoPrecision(target);
|
|
309
|
+
repos.push(result);
|
|
310
|
+
console.error(` IR: ${result.functionsExtracted} functions`);
|
|
311
|
+
console.error(` Sequences: ${result.sequencesExtracted}`);
|
|
312
|
+
console.error(` Rules: ${result.rulesDiscovered}`);
|
|
313
|
+
if (result.precision) {
|
|
314
|
+
console.error(` Precision: F1=${(result.precision.f1 * 100).toFixed(0)}% (P=${(result.precision.precision * 100).toFixed(0)}%, R=${(result.precision.recall * 100).toFixed(0)}%)`);
|
|
315
|
+
}
|
|
316
|
+
if (result.needsAnnotation) {
|
|
317
|
+
console.error(` ⚠️ Needs hand-labeling (${result.annotatedSamples} samples)`);
|
|
318
|
+
}
|
|
319
|
+
if (result.errors.length) {
|
|
320
|
+
for (const e of result.errors)
|
|
321
|
+
console.error(` ❌ ${e}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Summary
|
|
325
|
+
const reposWithPrecision = repos.filter(r => r.precision && r.precision.total > 0);
|
|
326
|
+
const avgF1 = reposWithPrecision.length > 0
|
|
327
|
+
? reposWithPrecision.reduce((s, r) => s + (r.precision?.f1 || 0), 0) / reposWithPrecision.length
|
|
328
|
+
: 0;
|
|
329
|
+
return {
|
|
330
|
+
generated: new Date().toISOString(),
|
|
331
|
+
version: "1.0.0",
|
|
332
|
+
repos,
|
|
333
|
+
summary: {
|
|
334
|
+
totalRepos: repos.length,
|
|
335
|
+
reposWithPrecision: reposWithPrecision.length,
|
|
336
|
+
reposNeedingAnnotation: repos.filter(r => r.needsAnnotation).length,
|
|
337
|
+
averageF1: avgF1,
|
|
338
|
+
totalFunctions: repos.reduce((s, r) => s + r.functionsExtracted, 0),
|
|
339
|
+
totalSequences: repos.reduce((s, r) => s + r.sequencesExtracted, 0),
|
|
340
|
+
totalRules: repos.reduce((s, r) => s + r.rulesDiscovered, 0),
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
// ═══════════════════════════════════════════════════════════════
|
|
345
|
+
// Formatters
|
|
346
|
+
// ═══════════════════════════════════════════════════════════════
|
|
347
|
+
function formatMultiRepoReportTerminal(report) {
|
|
348
|
+
const lines = [];
|
|
349
|
+
const C = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m" };
|
|
350
|
+
lines.push("");
|
|
351
|
+
lines.push(`${C.bold}${C.cyan}╔══════════════════════════════════════════════════════════════╗${C.reset}`);
|
|
352
|
+
lines.push(`${C.bold}${C.cyan}║${C.reset} ${C.bold}Multi-Repo SSG Precision Report${C.reset} ${C.bold}${C.cyan}║${C.reset}`);
|
|
353
|
+
lines.push(`${C.bold}${C.cyan}╚══════════════════════════════════════════════════════════════╝${C.reset}`);
|
|
354
|
+
lines.push("");
|
|
355
|
+
lines.push(` Generated: ${report.generated}`);
|
|
356
|
+
lines.push(` Repos: ${report.summary.totalRepos} (${report.summary.reposWithPrecision} with precision data)`);
|
|
357
|
+
lines.push(` Functions: ${report.summary.totalFunctions} | Sequences: ${report.summary.totalSequences} | Rules: ${report.summary.totalRules}`);
|
|
358
|
+
lines.push(` Avg F1: ${(report.summary.averageF1 * 100).toFixed(0)}%`);
|
|
359
|
+
lines.push("");
|
|
360
|
+
lines.push(` ${C.dim}Repo Size LOC Funcs Seqs Rules F1 Precision Recall Status${C.reset}`);
|
|
361
|
+
lines.push(` ${C.dim}─────────────── ────── ────── ────── ────── ────── ────── ──────── ────── ──────────${C.reset}`);
|
|
362
|
+
for (const r of report.repos) {
|
|
363
|
+
const f1Str = r.precision ? `${(r.precision.f1 * 100).toFixed(0)}%`.padStart(5) : " N/A ";
|
|
364
|
+
const pStr = r.precision ? `${(r.precision.precision * 100).toFixed(0)}%`.padStart(6) : " N/A ";
|
|
365
|
+
const rStr = r.precision ? `${(r.precision.recall * 100).toFixed(0)}%`.padStart(6) : " N/A ";
|
|
366
|
+
const status = r.precision ? `${C.green}MEASURED${C.reset}`
|
|
367
|
+
: r.needsAnnotation ? `${C.yellow}NEEDS LABELS${C.reset}` : `${C.dim}NO DATA${C.reset}`;
|
|
368
|
+
lines.push(` ${r.repo.padEnd(15)} ${r.size.padEnd(6)} ${String(r.linesOfCode).padEnd(6)} ${String(r.functionsExtracted).padEnd(6)} ${String(r.sequencesExtracted).padEnd(6)} ${String(r.rulesDiscovered).padEnd(6)} ${f1Str} ${pStr} ${rStr} ${status}`);
|
|
369
|
+
}
|
|
370
|
+
lines.push("");
|
|
371
|
+
lines.push(` ${C.yellow}⚠️ Repos marked "NEEDS LABELS" require hand-annotated ground truth for precision measurement.${C.reset}`);
|
|
372
|
+
lines.push(` ${C.dim}→ Create .progmune_labels.json in the repo root with format: {"0":"clean","1":"violation",...}${C.reset}`);
|
|
373
|
+
lines.push("");
|
|
374
|
+
if (report.summary.reposNeedingAnnotation > 0) {
|
|
375
|
+
lines.push(` ${C.bold}Next Steps:${C.reset}`);
|
|
376
|
+
lines.push(` 1. Hand-label 20-50 call sequences per repo as "clean" or "violation"`);
|
|
377
|
+
lines.push(` 2. Re-run this benchmark for full precision metrics`);
|
|
378
|
+
lines.push(` 3. Add external repos: curl, nginx, redis, sqlite`);
|
|
379
|
+
lines.push("");
|
|
380
|
+
}
|
|
381
|
+
return lines.join("\n");
|
|
382
|
+
}
|
|
383
|
+
function exportMultiRepoReportJSON(report, outputPath) {
|
|
384
|
+
const json = JSON.stringify(report, null, 2);
|
|
385
|
+
if (outputPath) {
|
|
386
|
+
const dir = path.dirname(outputPath);
|
|
387
|
+
if (!fs.existsSync(dir))
|
|
388
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
389
|
+
fs.writeFileSync(outputPath, json, "utf-8");
|
|
390
|
+
}
|
|
391
|
+
return json;
|
|
392
|
+
}
|
|
393
|
+
// ═══════════════════════════════════════════════════════════════
|
|
394
|
+
// CLI
|
|
395
|
+
// ═══════════════════════════════════════════════════════════════
|
|
396
|
+
if (require.main === module) {
|
|
397
|
+
const args = process.argv.slice(2);
|
|
398
|
+
const reposArg = args.includes("--repos") ? args[args.indexOf("--repos") + 1] : null;
|
|
399
|
+
const all = args.includes("--all");
|
|
400
|
+
const localOnly = args.includes("--local");
|
|
401
|
+
let targets = DEFAULT_TARGETS;
|
|
402
|
+
if (reposArg) {
|
|
403
|
+
const names = new Set(reposArg.split(","));
|
|
404
|
+
targets = DEFAULT_TARGETS.filter(t => names.has(t.name));
|
|
405
|
+
}
|
|
406
|
+
else if (localOnly) {
|
|
407
|
+
targets = DEFAULT_TARGETS.filter(t => !EXTERNAL_REPOS[t.name]);
|
|
408
|
+
}
|
|
409
|
+
else if (all) {
|
|
410
|
+
// all targets including external
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
// default: local only (fast)
|
|
414
|
+
targets = DEFAULT_TARGETS.filter(t => !EXTERNAL_REPOS[t.name]);
|
|
415
|
+
}
|
|
416
|
+
const report = runMultiRepoPrecision(targets);
|
|
417
|
+
console.log(formatMultiRepoReportTerminal(report));
|
|
418
|
+
// Write JSON report
|
|
419
|
+
const outPath = "benchmarks/multi-repo-precision.json";
|
|
420
|
+
exportMultiRepoReportJSON(report, outPath);
|
|
421
|
+
console.error(`\n📁 Report saved: ${outPath}`);
|
|
422
|
+
}
|