progmune-runtime 2.1.6 → 3.2.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/README.md +108 -468
- 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 +710 -0
- package/package.json +74 -7
- 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
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Progmune V3.2 — Behavior Mining Engine
|
|
4
|
+
* =======================================
|
|
5
|
+
* 从代码的实际行为(不是方法名)中恢复业务逻辑。
|
|
6
|
+
*
|
|
7
|
+
* 三个核心改进(vs V3.1):
|
|
8
|
+
* 1. CFG-based workflow — 分析函数体内的真实调用序列,不依赖命名
|
|
9
|
+
* 2. Business-layer projection — 将调用图投影到 Controller/Service/Repo 层
|
|
10
|
+
* 3. Decomposed confidence — Frequency × Topology × Consistency
|
|
11
|
+
*
|
|
12
|
+
* 输入: TypeScript 项目路径
|
|
13
|
+
* 输出: BehaviorGraph — 一张包含实体、状态机、业务工作流、约束的治理图谱
|
|
14
|
+
*/
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
+
}) : function(o, v) {
|
|
29
|
+
o["default"] = v;
|
|
30
|
+
});
|
|
31
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
+
var ownKeys = function(o) {
|
|
33
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
+
var ar = [];
|
|
35
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
return ownKeys(o);
|
|
39
|
+
};
|
|
40
|
+
return function (mod) {
|
|
41
|
+
if (mod && mod.__esModule) return mod;
|
|
42
|
+
var result = {};
|
|
43
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
+
__setModuleDefault(result, mod);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
})();
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.buildBehaviorGraph = buildBehaviorGraph;
|
|
50
|
+
const ts_morph_1 = require("ts-morph");
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
// ══════════════════════════════════════════════
|
|
54
|
+
// L1: BUSINESS LAYER CLASSIFICATION
|
|
55
|
+
// ══════════════════════════════════════════════
|
|
56
|
+
/**
|
|
57
|
+
* Classify a function into its business layer based on:
|
|
58
|
+
* - File path (server/ vs client/)
|
|
59
|
+
* - File name (router, controller, service, db, repository)
|
|
60
|
+
* - Function name (handle*, process*, get*, create*)
|
|
61
|
+
*/
|
|
62
|
+
function classifyLayer(funcName, filePath, className) {
|
|
63
|
+
const fileLower = filePath.toLowerCase();
|
|
64
|
+
const nameLower = funcName.toLowerCase();
|
|
65
|
+
const classLower = (className || "").toLowerCase();
|
|
66
|
+
// Strong signals from file naming
|
|
67
|
+
if (fileLower.includes("router") || fileLower.includes("routes")) {
|
|
68
|
+
return { layer: "controller", confidence: 0.9 };
|
|
69
|
+
}
|
|
70
|
+
if (fileLower.includes("controller")) {
|
|
71
|
+
return { layer: "controller", confidence: 0.95 };
|
|
72
|
+
}
|
|
73
|
+
if (fileLower.includes("service") || classLower.includes("service")) {
|
|
74
|
+
return { layer: "service", confidence: 0.9 };
|
|
75
|
+
}
|
|
76
|
+
if (fileLower.includes("repository") || fileLower.includes("db") || fileLower.includes("dao")) {
|
|
77
|
+
return { layer: "repository", confidence: 0.9 };
|
|
78
|
+
}
|
|
79
|
+
if (fileLower.includes("sdk") || fileLower.includes("api") || fileLower.includes("client")) {
|
|
80
|
+
return { layer: "external", confidence: 0.7 };
|
|
81
|
+
}
|
|
82
|
+
// Medium signals from function naming
|
|
83
|
+
if (nameLower.startsWith("handle") || nameLower.includes("route")) {
|
|
84
|
+
return { layer: "controller", confidence: 0.6 };
|
|
85
|
+
}
|
|
86
|
+
if (nameLower.includes("process") || nameLower.includes("verify") || nameLower.includes("validate")) {
|
|
87
|
+
return { layer: "service", confidence: 0.5 };
|
|
88
|
+
}
|
|
89
|
+
if (nameLower.includes("insert") || nameLower.includes("update") || nameLower.includes("delete") || nameLower.includes("query") || nameLower.includes("select")) {
|
|
90
|
+
return { layer: "repository", confidence: 0.6 };
|
|
91
|
+
}
|
|
92
|
+
// Default
|
|
93
|
+
return { layer: "unknown", confidence: 0.3 };
|
|
94
|
+
}
|
|
95
|
+
// ══════════════════════════════════════════════
|
|
96
|
+
// L2: CFG-BASED CALL SEQUENCE EXTRACTION
|
|
97
|
+
// ══════════════════════════════════════════════
|
|
98
|
+
/**
|
|
99
|
+
* Extract the ordered call sequence from a function body.
|
|
100
|
+
* This is CFG-based — we read the AST in execution order,
|
|
101
|
+
* not by method name convention.
|
|
102
|
+
*/
|
|
103
|
+
function extractCallSequence(funcNode) {
|
|
104
|
+
const calls = [];
|
|
105
|
+
const body = funcNode.getBody();
|
|
106
|
+
if (!body)
|
|
107
|
+
return calls;
|
|
108
|
+
// Walk the body in statement order (which maps to execution order)
|
|
109
|
+
body.forEachDescendant((node) => {
|
|
110
|
+
if (ts_morph_1.Node.isCallExpression(node)) {
|
|
111
|
+
const expr = node.getExpression();
|
|
112
|
+
const calleeName = expr.getText();
|
|
113
|
+
// Filter out literals, property access on primitives
|
|
114
|
+
if (!calleeName.startsWith("'") && !calleeName.startsWith('"') && calleeName.length > 1) {
|
|
115
|
+
calls.push(calleeName);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return calls;
|
|
120
|
+
}
|
|
121
|
+
// ══════════════════════════════════════════════
|
|
122
|
+
// L3: BEHAVIOR GRAPH CONSTRUCTION
|
|
123
|
+
// ══════════════════════════════════════════════
|
|
124
|
+
/**
|
|
125
|
+
* Build the full Behavior Graph from a project.
|
|
126
|
+
* L1: Classify functions → L2: Extract call sequences → L3: Build edges → L4: Discover workflows
|
|
127
|
+
*/
|
|
128
|
+
function buildBehaviorGraph(projectPath) {
|
|
129
|
+
const project = new ts_morph_1.Project({
|
|
130
|
+
tsConfigFilePath: path.join(projectPath, "tsconfig.json"),
|
|
131
|
+
skipAddingFilesFromTsConfig: false,
|
|
132
|
+
});
|
|
133
|
+
const functions = [];
|
|
134
|
+
const sequenceMap = new Map();
|
|
135
|
+
const edgeMap = new Map();
|
|
136
|
+
console.log("🔬 Progmune Behavior Mining Engine — V3.2");
|
|
137
|
+
console.log(" Project:", projectPath);
|
|
138
|
+
// ── Step 1: Classify all functions + Extract call sequences ──
|
|
139
|
+
console.log("\nL1+L2 · Function Classification + CFG Extraction...");
|
|
140
|
+
let funcCount = 0;
|
|
141
|
+
let seqCount = 0;
|
|
142
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
143
|
+
const filePath = sourceFile.getFilePath().replace(projectPath + "/", "");
|
|
144
|
+
if (filePath.includes("node_modules") || filePath.includes(".test."))
|
|
145
|
+
continue;
|
|
146
|
+
// Named functions
|
|
147
|
+
for (const funcDecl of sourceFile.getFunctions()) {
|
|
148
|
+
const name = funcDecl.getName() || "(anonymous)";
|
|
149
|
+
if (name === "(anonymous)")
|
|
150
|
+
continue;
|
|
151
|
+
const classification = classifyLayer(name, filePath);
|
|
152
|
+
const calls = extractCallSequence(funcDecl);
|
|
153
|
+
functions.push({
|
|
154
|
+
name,
|
|
155
|
+
file: filePath,
|
|
156
|
+
layer: classification.layer,
|
|
157
|
+
calls,
|
|
158
|
+
callCount: calls.length,
|
|
159
|
+
layerConfidence: classification.confidence,
|
|
160
|
+
});
|
|
161
|
+
funcCount++;
|
|
162
|
+
// Record call sequence if it has 2+ business-relevant calls
|
|
163
|
+
const businessCalls = calls.filter(c => !isUtilityCall(c));
|
|
164
|
+
if (businessCalls.length >= 2) {
|
|
165
|
+
const key = `${name}::${businessCalls.join("→")}`;
|
|
166
|
+
if (sequenceMap.has(key)) {
|
|
167
|
+
sequenceMap.get(key).frequency++;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
sequenceMap.set(key, {
|
|
171
|
+
caller: name,
|
|
172
|
+
callerLayer: classification.layer,
|
|
173
|
+
callees: businessCalls,
|
|
174
|
+
file: filePath,
|
|
175
|
+
frequency: 1,
|
|
176
|
+
});
|
|
177
|
+
seqCount++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Class methods
|
|
182
|
+
for (const classDecl of sourceFile.getClasses()) {
|
|
183
|
+
const className = classDecl.getName() || "";
|
|
184
|
+
for (const method of classDecl.getMethods()) {
|
|
185
|
+
const name = method.getName();
|
|
186
|
+
const fullName = `${className}.${name}`;
|
|
187
|
+
const classification = classifyLayer(name, filePath, className);
|
|
188
|
+
const calls = extractCallSequence(method);
|
|
189
|
+
functions.push({
|
|
190
|
+
name: fullName,
|
|
191
|
+
file: filePath,
|
|
192
|
+
layer: classification.layer,
|
|
193
|
+
calls,
|
|
194
|
+
callCount: calls.length,
|
|
195
|
+
layerConfidence: classification.confidence,
|
|
196
|
+
});
|
|
197
|
+
funcCount++;
|
|
198
|
+
const businessCalls = calls.filter(c => !isUtilityCall(c));
|
|
199
|
+
if (businessCalls.length >= 2) {
|
|
200
|
+
const key = `${fullName}::${businessCalls.join("→")}`;
|
|
201
|
+
if (sequenceMap.has(key)) {
|
|
202
|
+
sequenceMap.get(key).frequency++;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
sequenceMap.set(key, {
|
|
206
|
+
caller: fullName,
|
|
207
|
+
callerLayer: classification.layer,
|
|
208
|
+
callees: businessCalls,
|
|
209
|
+
file: filePath,
|
|
210
|
+
frequency: 1,
|
|
211
|
+
});
|
|
212
|
+
seqCount++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// ── Step 1b: Build project function name registry ──
|
|
219
|
+
const projectFuncNames = new Set(functions.map(f => f.name));
|
|
220
|
+
// Also index by short name (method name without class prefix)
|
|
221
|
+
const shortToFull = new Map();
|
|
222
|
+
for (const f of functions) {
|
|
223
|
+
const parts = f.name.split(".");
|
|
224
|
+
if (parts.length > 1) {
|
|
225
|
+
const short = parts[parts.length - 1];
|
|
226
|
+
if (!shortToFull.has(short))
|
|
227
|
+
shortToFull.set(short, []);
|
|
228
|
+
shortToFull.get(short).push(f.name);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ── Step 2: Build edges from cross-function calls ──
|
|
232
|
+
// An edge exists when one project-defined function calls another project-defined function.
|
|
233
|
+
// This is the "business projection" — we only care about business→business relationships.
|
|
234
|
+
console.log("\nL3 · Building Business Edges (function→function)...");
|
|
235
|
+
for (const func of functions) {
|
|
236
|
+
if (func.layer === "external" || func.layer === "unknown")
|
|
237
|
+
continue;
|
|
238
|
+
for (const calleeName of func.calls) {
|
|
239
|
+
// Skip utility calls
|
|
240
|
+
if (isUtilityCall(calleeName))
|
|
241
|
+
continue;
|
|
242
|
+
// Check if callee is a project-defined function
|
|
243
|
+
let resolvedName = calleeName;
|
|
244
|
+
let resolvedLayer = "unknown";
|
|
245
|
+
if (projectFuncNames.has(calleeName)) {
|
|
246
|
+
resolvedLayer = functions.find(f => f.name === calleeName)?.layer || "unknown";
|
|
247
|
+
}
|
|
248
|
+
else if (shortToFull.has(calleeName)) {
|
|
249
|
+
// This is a method call — match by method name
|
|
250
|
+
const fullNames = shortToFull.get(calleeName);
|
|
251
|
+
resolvedName = fullNames[0];
|
|
252
|
+
resolvedLayer = functions.find(f => f.name === resolvedName)?.layer || "unknown";
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
continue; // Not a project-defined function — skip
|
|
256
|
+
}
|
|
257
|
+
const edgeKey = `${func.name}→${resolvedName}`;
|
|
258
|
+
if (edgeMap.has(edgeKey)) {
|
|
259
|
+
const existing = edgeMap.get(edgeKey);
|
|
260
|
+
existing.frequency++;
|
|
261
|
+
if (!existing.files.includes(func.file)) {
|
|
262
|
+
existing.files.push(func.file);
|
|
263
|
+
}
|
|
264
|
+
existing.consistencyScore = Math.min(1.0, (existing.files.length + existing.frequency) / 6);
|
|
265
|
+
const freqNorm = Math.min(1.0, existing.frequency / 3);
|
|
266
|
+
existing.confidence = Math.round((freqNorm * 0.4 + existing.topologyScore * 0.35 + existing.consistencyScore * 0.25) * 100);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
edgeMap.set(edgeKey, {
|
|
270
|
+
from: func.name,
|
|
271
|
+
to: resolvedName,
|
|
272
|
+
fromLayer: func.layer,
|
|
273
|
+
toLayer: resolvedLayer,
|
|
274
|
+
frequency: 1,
|
|
275
|
+
topologyScore: 1.0,
|
|
276
|
+
consistencyScore: 0.2,
|
|
277
|
+
confidence: 35,
|
|
278
|
+
files: [func.file],
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const edges = Array.from(edgeMap.values())
|
|
284
|
+
.filter(e => e.confidence >= 30)
|
|
285
|
+
.sort((a, b) => b.confidence - a.confidence);
|
|
286
|
+
// Remove the old pairwise edge building code
|
|
287
|
+
// (edges are now built from function→function calls only)
|
|
288
|
+
const highConfEdges = edges.filter(e => e.confidence >= 60).length;
|
|
289
|
+
console.log(` ${edges.length} business edges (${highConfEdges} high confidence ≥60%)`);
|
|
290
|
+
// ── Step 3: Discover Business Workflows ──
|
|
291
|
+
console.log("\nL4 · Workflow Discovery...");
|
|
292
|
+
const workflows = [];
|
|
293
|
+
// Group edges by their fromLayer → toLayer chain
|
|
294
|
+
// A workflow is: Controller → Service → Repository → External (or any chain of high-conf edges)
|
|
295
|
+
const highConfEdgeSet = new Set(edges.filter(e => e.confidence >= 40));
|
|
296
|
+
// Find chains of 2+ connected high-confidence edges
|
|
297
|
+
const visited = new Set();
|
|
298
|
+
for (const edge of highConfEdgeSet) {
|
|
299
|
+
if (visited.has(`${edge.from}→${edge.to}`))
|
|
300
|
+
continue;
|
|
301
|
+
const chain = [edge];
|
|
302
|
+
visited.add(`${edge.from}→${edge.to}`);
|
|
303
|
+
// Extend forward
|
|
304
|
+
let current = edge.to;
|
|
305
|
+
let extended = true;
|
|
306
|
+
while (extended) {
|
|
307
|
+
extended = false;
|
|
308
|
+
for (const next of highConfEdgeSet) {
|
|
309
|
+
if (next.from === current && !visited.has(`${next.from}→${next.to}`)) {
|
|
310
|
+
chain.push(next);
|
|
311
|
+
visited.add(`${next.from}→${next.to}`);
|
|
312
|
+
current = next.to;
|
|
313
|
+
extended = true;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (chain.length >= 2) {
|
|
319
|
+
// Build workflow name from the business domain
|
|
320
|
+
const layers = chain.map(e => e.fromLayer);
|
|
321
|
+
const uniqueLayers = [...new Set(layers)];
|
|
322
|
+
// Determine business domain
|
|
323
|
+
const domainKeywords = ["payment", "order", "user", "auth", "product", "upload", "supplier", "notification"];
|
|
324
|
+
const allNames = chain.flatMap(e => [e.from, e.to]).join(" ").toLowerCase();
|
|
325
|
+
const domain = domainKeywords.find(kw => allNames.includes(kw)) || "business";
|
|
326
|
+
const avgConf = Math.round(chain.reduce((s, e) => s + e.confidence, 0) / chain.length);
|
|
327
|
+
const steps = [chain[0].from, ...chain.map(e => e.to)];
|
|
328
|
+
const stepLayers = [chain[0].fromLayer, ...chain.map(e => e.toLayer)];
|
|
329
|
+
workflows.push({
|
|
330
|
+
name: `${domain.charAt(0).toUpperCase() + domain.slice(1)} Workflow`,
|
|
331
|
+
steps,
|
|
332
|
+
layers: stepLayers,
|
|
333
|
+
edges: chain,
|
|
334
|
+
totalFrequency: chain.reduce((s, e) => s + e.frequency, 0),
|
|
335
|
+
confidence: avgConf,
|
|
336
|
+
description: `${steps.length} steps · ${uniqueLayers.join(" → ")} · avg confidence ${avgConf}%`,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
console.log(` ${workflows.length} workflows discovered`);
|
|
341
|
+
// ── Print summary ──
|
|
342
|
+
for (const wf of workflows) {
|
|
343
|
+
console.log(`\n 📋 ${wf.name} [${wf.confidence}%]`);
|
|
344
|
+
console.log(` ${wf.steps.join(" → ")}`);
|
|
345
|
+
console.log(` ${wf.description}`);
|
|
346
|
+
for (const e of wf.edges) {
|
|
347
|
+
console.log(` ${e.from} → ${e.to} (freq=${e.frequency}, topo=${e.topologyScore}, cons=${e.consistencyScore.toFixed(1)})`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Top edges
|
|
351
|
+
console.log("\n Top Behavior Edges:");
|
|
352
|
+
for (const e of edges.slice(0, 5)) {
|
|
353
|
+
console.log(` ${e.from.padEnd(30)} → ${e.to.padEnd(30)} [${e.fromLayer}→${e.toLayer}] conf=${e.confidence}% (×${e.frequency})`);
|
|
354
|
+
}
|
|
355
|
+
const report = {
|
|
356
|
+
projectPath,
|
|
357
|
+
timestamp: new Date().toISOString(),
|
|
358
|
+
functions,
|
|
359
|
+
sequences: [], // Deprecated — edges now come from business projection
|
|
360
|
+
edges,
|
|
361
|
+
workflows,
|
|
362
|
+
summary: {
|
|
363
|
+
functionsFound: funcCount,
|
|
364
|
+
sequencesFound: edges.length, // Edge count serves as the meaningful metric
|
|
365
|
+
edgesFound: edges.length,
|
|
366
|
+
workflowsFound: workflows.length,
|
|
367
|
+
highConfidenceEdges: highConfEdges,
|
|
368
|
+
highConfidenceWorkflows: workflows.filter(w => w.confidence >= 60).length,
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
return report;
|
|
372
|
+
}
|
|
373
|
+
// ══════════════════════════════════════════════
|
|
374
|
+
// UTILITY
|
|
375
|
+
// ══════════════════════════════════════════════
|
|
376
|
+
/**
|
|
377
|
+
* Filter out calls that are clearly not business logic.
|
|
378
|
+
*/
|
|
379
|
+
function isUtilityCall(name) {
|
|
380
|
+
const utilityPatterns = [
|
|
381
|
+
// Standard utilities
|
|
382
|
+
"console.", "z.", "JSON.", "Math.", "Object.", "Array.",
|
|
383
|
+
"parseInt", "parseFloat", "String", "Number", "Boolean",
|
|
384
|
+
"log", "error", "warn", "debug",
|
|
385
|
+
"map", "filter", "reduce", "forEach", "find",
|
|
386
|
+
"toString", "valueOf", "hasOwnProperty",
|
|
387
|
+
"require", "import",
|
|
388
|
+
// React hooks
|
|
389
|
+
"useState", "useEffect", "useCallback", "useMemo", "useRef",
|
|
390
|
+
"useLocation", "useParams", "useAuth",
|
|
391
|
+
"navigate", "localStorage.", "sessionStorage.",
|
|
392
|
+
"setTimeout", "setInterval", "clearTimeout",
|
|
393
|
+
// Drizzle query builder (infrastructure, not business)
|
|
394
|
+
"db.select", "db.update", "db.insert", "db.delete",
|
|
395
|
+
"db.transaction", "getDb",
|
|
396
|
+
"tx.select", "tx.update", "tx.insert", "tx.delete",
|
|
397
|
+
".select()", ".from(", ".where(", ".limit(", ".orderBy",
|
|
398
|
+
"eq(", "and(", "or(", "desc(", "asc(",
|
|
399
|
+
"conditions.push", "whereConditions.push",
|
|
400
|
+
// General utilities
|
|
401
|
+
"console.error", "console.log", "console.warn",
|
|
402
|
+
"new Date(", "Date.now", "crypto.randomBytes",
|
|
403
|
+
"res.status", "res.json", "res.send",
|
|
404
|
+
"app.post", "app.get", "app.use",
|
|
405
|
+
// String/number formatting
|
|
406
|
+
".toString()", ".toLowerCase()", ".toUpperCase()",
|
|
407
|
+
".split(", ".replace(", ".join(",
|
|
408
|
+
"JSON.stringify", "JSON.parse",
|
|
409
|
+
"params.get", "url.searchParams",
|
|
410
|
+
"formData.append", "xhr.",
|
|
411
|
+
"Array.isArray", ".push(", ".pop(",
|
|
412
|
+
"parseInt(", "parseFloat(", "isNaN(",
|
|
413
|
+
"trpc.", ".useQuery", ".useMutation",
|
|
414
|
+
".refetch", ".invalidate",
|
|
415
|
+
];
|
|
416
|
+
for (const p of utilityPatterns) {
|
|
417
|
+
if (name.includes(p))
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
// ══════════════════════════════════════════════
|
|
423
|
+
// CLI
|
|
424
|
+
// ══════════════════════════════════════════════
|
|
425
|
+
if (require.main === module) {
|
|
426
|
+
const targetProject = process.argv[2];
|
|
427
|
+
if (!targetProject) {
|
|
428
|
+
console.error("Usage: npx ts-node src/behavior-miner.ts <project-path>");
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
431
|
+
const graph = buildBehaviorGraph(targetProject);
|
|
432
|
+
// Write output
|
|
433
|
+
const outputPath = path.join(targetProject, ".progmune_behavior_graph.json");
|
|
434
|
+
fs.writeFileSync(outputPath, JSON.stringify(graph, null, 2));
|
|
435
|
+
console.log(`\n✅ Behavior Graph saved to: ${outputPath}`);
|
|
436
|
+
console.log("\n═══ Behavior Mining Summary ═══");
|
|
437
|
+
console.log(` Functions: ${graph.summary.functionsFound}`);
|
|
438
|
+
console.log(` Sequences: ${graph.summary.sequencesFound}`);
|
|
439
|
+
console.log(` Edges: ${graph.summary.edgesFound} (${graph.summary.highConfidenceEdges} high confidence)`);
|
|
440
|
+
console.log(` Workflows: ${graph.summary.workflowsFound} (${graph.summary.highConfidenceWorkflows} high confidence)`);
|
|
441
|
+
console.log();
|
|
442
|
+
}
|