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,505 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Progmune V3.1 — Policy Mining Engine
|
|
4
|
+
* =====================================
|
|
5
|
+
* 从代码自动发现业务规则,不再人工手写。
|
|
6
|
+
*
|
|
7
|
+
* 四层架构:
|
|
8
|
+
* L1: Entity Discovery — 从 AST 发现领域对象、状态枚举
|
|
9
|
+
* L2: Flow Mining — 从调用图恢复业务流程
|
|
10
|
+
* L3: Constraint Mining — 从代码模式发现隐含约束
|
|
11
|
+
* L4: Policy Generation — 自动生成 protocol rules
|
|
12
|
+
*
|
|
13
|
+
* 输入: 一个 TypeScript 项目的路径
|
|
14
|
+
* 输出: 自动生成的 Policy(状态机 + 协议规则)
|
|
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.discoverEntities = discoverEntities;
|
|
51
|
+
exports.buildCallGraph = buildCallGraph;
|
|
52
|
+
exports.discoverWorkflows = discoverWorkflows;
|
|
53
|
+
exports.generatePolicy = generatePolicy;
|
|
54
|
+
exports.mineProject = mineProject;
|
|
55
|
+
const ts_morph_1 = require("ts-morph");
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
// ══════════════════════════════════════════════
|
|
59
|
+
// L1: ENTITY DISCOVERY
|
|
60
|
+
// ══════════════════════════════════════════════
|
|
61
|
+
/**
|
|
62
|
+
* Scan the project for domain entities, state enums, and their transitions.
|
|
63
|
+
* Uses heuristics based on TypeScript naming conventions and type structures.
|
|
64
|
+
*/
|
|
65
|
+
function discoverEntities(projectPath) {
|
|
66
|
+
const project = new ts_morph_1.Project({
|
|
67
|
+
tsConfigFilePath: path.join(projectPath, "tsconfig.json"),
|
|
68
|
+
skipAddingFilesFromTsConfig: false,
|
|
69
|
+
});
|
|
70
|
+
const entities = [];
|
|
71
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
72
|
+
// Skip test files and node_modules
|
|
73
|
+
if (sourceFile.getFilePath().includes("node_modules"))
|
|
74
|
+
continue;
|
|
75
|
+
if (sourceFile.getFilePath().includes(".test."))
|
|
76
|
+
continue;
|
|
77
|
+
// ── Find Enums (likely state machines) ──
|
|
78
|
+
for (const enumDecl of sourceFile.getEnums()) {
|
|
79
|
+
const members = enumDecl.getMembers().map(m => m.getName());
|
|
80
|
+
const name = enumDecl.getName();
|
|
81
|
+
// Heuristic: enums with "Status" or "State" in name are state machines
|
|
82
|
+
if (name.includes("Status") || name.includes("State") || name.includes("Stage") || name.includes("Step")) {
|
|
83
|
+
const entity = entities.find(e => e.name === name) || {
|
|
84
|
+
name,
|
|
85
|
+
kind: "enum",
|
|
86
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
87
|
+
states: [],
|
|
88
|
+
transitions: [],
|
|
89
|
+
};
|
|
90
|
+
// Extract states from enum members
|
|
91
|
+
entity.states = members;
|
|
92
|
+
// Infer transitions from enum ordering (if enum values are sequential)
|
|
93
|
+
for (let i = 0; i < members.length - 1; i++) {
|
|
94
|
+
entity.transitions = entity.transitions || [];
|
|
95
|
+
const existingTransition = entity.transitions.find(t => t.from === members[i] && t.to === members[i + 1]);
|
|
96
|
+
if (!existingTransition) {
|
|
97
|
+
entity.transitions.push({
|
|
98
|
+
from: members[i],
|
|
99
|
+
to: members[i + 1],
|
|
100
|
+
function: `transition_${members[i]}_to_${members[i + 1]}`.toLowerCase(),
|
|
101
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
102
|
+
lineNumber: enumDecl.getStartLineNumber(),
|
|
103
|
+
confidence: 0.5, // Enum ordering is a weak signal — needs flow mining to confirm
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!entities.find(e => e.name === name)) {
|
|
108
|
+
entities.push(entity);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// ── Find Interfaces/Types (likely domain entities) ──
|
|
113
|
+
for (const interfaceDecl of sourceFile.getInterfaces()) {
|
|
114
|
+
const name = interfaceDecl.getName();
|
|
115
|
+
// Heuristic: interfaces with status/state/id fields are domain entities
|
|
116
|
+
const properties = interfaceDecl.getProperties();
|
|
117
|
+
const hasId = properties.some(p => p.getName() === "id");
|
|
118
|
+
const hasStatus = properties.some(p => p.getName().includes("status") || p.getName().includes("state"));
|
|
119
|
+
if (hasId && hasStatus) {
|
|
120
|
+
const entity = {
|
|
121
|
+
name,
|
|
122
|
+
kind: "entity",
|
|
123
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
124
|
+
states: [],
|
|
125
|
+
transitions: [],
|
|
126
|
+
};
|
|
127
|
+
// Try to find the corresponding status enum
|
|
128
|
+
const statusProp = properties.find(p => p.getName().includes("status") || p.getName().includes("state"));
|
|
129
|
+
if (statusProp) {
|
|
130
|
+
const typeName = statusProp.getType().getText();
|
|
131
|
+
const matchingEnum = entities.find(e => e.kind === "enum" && typeName.includes(e.name));
|
|
132
|
+
if (matchingEnum && matchingEnum.states) {
|
|
133
|
+
entity.states = matchingEnum.states;
|
|
134
|
+
entity.transitions = matchingEnum.transitions;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!entities.find(e => e.name === name)) {
|
|
138
|
+
entities.push(entity);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// ── Find Drizzle Table Definitions ──
|
|
143
|
+
for (const varDecl of sourceFile.getVariableDeclarations()) {
|
|
144
|
+
const initializer = varDecl.getInitializer();
|
|
145
|
+
if (!initializer)
|
|
146
|
+
continue;
|
|
147
|
+
// Detect: mysqlTable("tableName", { columns })
|
|
148
|
+
// or: pgTable("tableName", { columns }) or sqliteTable(...)
|
|
149
|
+
if (ts_morph_1.Node.isCallExpression(initializer)) {
|
|
150
|
+
const callExpr = initializer;
|
|
151
|
+
const fnName = callExpr.getExpression().getText();
|
|
152
|
+
if (fnName === "mysqlTable" || fnName === "pgTable" || fnName === "sqliteTable") {
|
|
153
|
+
const args = callExpr.getArguments();
|
|
154
|
+
if (args.length >= 2) {
|
|
155
|
+
const tableName = args[0].getText().replace(/['"]/g, "");
|
|
156
|
+
const columnsObj = args[1];
|
|
157
|
+
// Extract column definitions looking for enums with state-like values
|
|
158
|
+
const states = [];
|
|
159
|
+
if (ts_morph_1.Node.isObjectLiteralExpression(columnsObj)) {
|
|
160
|
+
for (const prop of columnsObj.getProperties()) {
|
|
161
|
+
if (ts_morph_1.Node.isPropertyAssignment(prop)) {
|
|
162
|
+
const propInitializer = prop.getInitializer();
|
|
163
|
+
if (propInitializer && ts_morph_1.Node.isCallExpression(propInitializer)) {
|
|
164
|
+
const colFn = propInitializer.getExpression().getText();
|
|
165
|
+
// mysqlEnum("colName", ["val1", "val2", ...])
|
|
166
|
+
if (colFn === "mysqlEnum" || colFn === "pgEnum") {
|
|
167
|
+
const enumArgs = propInitializer.getArguments();
|
|
168
|
+
if (enumArgs.length >= 2 && ts_morph_1.Node.isArrayLiteralExpression(enumArgs[1])) {
|
|
169
|
+
const enumValues = enumArgs[1].getElements().map(e => e.getText().replace(/['"]/g, ""));
|
|
170
|
+
const colName = prop.getName();
|
|
171
|
+
if (colName === "status" || colName === "state" || colName === "role" || colName === "type" || colName === "stage") {
|
|
172
|
+
states.push(...enumValues);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const entity = {
|
|
181
|
+
name: tableName,
|
|
182
|
+
kind: "entity",
|
|
183
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
184
|
+
states: states.length > 0 ? states : undefined,
|
|
185
|
+
transitions: states.length >= 2 ? states.slice(0, -1).map((s, i) => ({
|
|
186
|
+
from: s,
|
|
187
|
+
to: states[i + 1],
|
|
188
|
+
function: `transition_${tableName}_${s}_to_${states[i + 1]}`.toLowerCase(),
|
|
189
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
190
|
+
lineNumber: varDecl.getStartLineNumber(),
|
|
191
|
+
confidence: 0.4,
|
|
192
|
+
})) : undefined,
|
|
193
|
+
};
|
|
194
|
+
if (!entities.find(e => e.name === tableName)) {
|
|
195
|
+
entities.push(entity);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ── Find Classes (likely services) ──
|
|
202
|
+
for (const classDecl of sourceFile.getClasses()) {
|
|
203
|
+
const name = classDecl.getName();
|
|
204
|
+
if (!name)
|
|
205
|
+
continue;
|
|
206
|
+
// Heuristic: classes with "Service" or "Controller" or "Router" in name
|
|
207
|
+
if (name.includes("Service") || name.includes("Controller") || name.includes("Router") || name.includes("Manager")) {
|
|
208
|
+
const methods = classDecl.getMethods().map(m => m.getName());
|
|
209
|
+
const entity = {
|
|
210
|
+
name,
|
|
211
|
+
kind: name.includes("Controller") || name.includes("Router") ? "controller" : "service",
|
|
212
|
+
file: sourceFile.getFilePath().replace(projectPath + "/", ""),
|
|
213
|
+
states: methods, // Method names as potential state transitions
|
|
214
|
+
transitions: [],
|
|
215
|
+
};
|
|
216
|
+
if (!entities.find(e => e.name === name)) {
|
|
217
|
+
entities.push(entity);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return entities;
|
|
223
|
+
}
|
|
224
|
+
// ══════════════════════════════════════════════
|
|
225
|
+
// L2: FLOW MINING (Call Graph Analysis)
|
|
226
|
+
// ══════════════════════════════════════════════
|
|
227
|
+
/**
|
|
228
|
+
* Build a call graph from the project.
|
|
229
|
+
* Each edge represents "caller calls callee" with a count of occurrences.
|
|
230
|
+
*/
|
|
231
|
+
function buildCallGraph(projectPath) {
|
|
232
|
+
const project = new ts_morph_1.Project({
|
|
233
|
+
tsConfigFilePath: path.join(projectPath, "tsconfig.json"),
|
|
234
|
+
skipAddingFilesFromTsConfig: false,
|
|
235
|
+
});
|
|
236
|
+
const edges = new Map();
|
|
237
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
238
|
+
if (sourceFile.getFilePath().includes("node_modules"))
|
|
239
|
+
continue;
|
|
240
|
+
if (sourceFile.getFilePath().includes(".test."))
|
|
241
|
+
continue;
|
|
242
|
+
const filePath = sourceFile.getFilePath().replace(projectPath + "/", "");
|
|
243
|
+
// Walk all function calls in the file
|
|
244
|
+
sourceFile.forEachDescendant((node) => {
|
|
245
|
+
if (ts_morph_1.Node.isCallExpression(node)) {
|
|
246
|
+
const expression = node.getExpression();
|
|
247
|
+
const calleeName = expression.getText();
|
|
248
|
+
// Find the enclosing function
|
|
249
|
+
let parent = node.getParent();
|
|
250
|
+
while (parent && !ts_morph_1.Node.isFunctionDeclaration(parent) && !ts_morph_1.Node.isMethodDeclaration(parent) && !ts_morph_1.Node.isArrowFunction(parent)) {
|
|
251
|
+
parent = parent.getParent();
|
|
252
|
+
}
|
|
253
|
+
const callerName = parent
|
|
254
|
+
? (ts_morph_1.Node.isMethodDeclaration(parent)
|
|
255
|
+
? parent.getParent()?.getName?.() + "." + parent.getName()
|
|
256
|
+
: parent.getName?.() || "(anonymous)")
|
|
257
|
+
: "(anonymous)";
|
|
258
|
+
const key = `${callerName}→${calleeName}`;
|
|
259
|
+
if (edges.has(key)) {
|
|
260
|
+
edges.get(key).count++;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
edges.set(key, {
|
|
264
|
+
caller: callerName,
|
|
265
|
+
callee: calleeName,
|
|
266
|
+
callerFile: filePath,
|
|
267
|
+
calleeFile: "", // Would need resolution to find
|
|
268
|
+
count: 1,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return Array.from(edges.values())
|
|
275
|
+
.filter(e => e.count >= 2) // Filter noise — only keep edges that appear multiple times
|
|
276
|
+
.sort((a, b) => b.count - a.count);
|
|
277
|
+
}
|
|
278
|
+
// ══════════════════════════════════════════════
|
|
279
|
+
// L3: WORKFLOW DISCOVERY
|
|
280
|
+
// ══════════════════════════════════════════════
|
|
281
|
+
/**
|
|
282
|
+
* From the call graph and entities, discover business workflows.
|
|
283
|
+
* A workflow is a sequence of state transitions that form a coherent business process.
|
|
284
|
+
*/
|
|
285
|
+
function discoverWorkflows(entities, callGraph) {
|
|
286
|
+
const workflows = [];
|
|
287
|
+
// ── Phase 1: Service method ordering (name-based heuristics) ──
|
|
288
|
+
const SERVICE_LIFECYCLE_PATTERNS = {
|
|
289
|
+
// Payment flow pattern
|
|
290
|
+
"payment": ["create", "initiate", "verify", "process", "confirm", "query", "close", "refund"],
|
|
291
|
+
// General CRUD pattern
|
|
292
|
+
"crud": ["create", "read", "update", "delete"],
|
|
293
|
+
// Auth flow pattern
|
|
294
|
+
"auth": ["decode", "verify", "get", "issue", "refresh", "revoke"],
|
|
295
|
+
};
|
|
296
|
+
for (const entity of entities) {
|
|
297
|
+
if (entity.kind !== "service")
|
|
298
|
+
continue;
|
|
299
|
+
if (!entity.states || entity.states.length < 2)
|
|
300
|
+
continue;
|
|
301
|
+
const methods = entity.states;
|
|
302
|
+
const entityNameLower = entity.name.toLowerCase();
|
|
303
|
+
// Detect which lifecycle pattern this service follows
|
|
304
|
+
let pattern = null;
|
|
305
|
+
if (entityNameLower.includes("payment") || entityNameLower.includes("pay")) {
|
|
306
|
+
pattern = SERVICE_LIFECYCLE_PATTERNS["payment"];
|
|
307
|
+
}
|
|
308
|
+
else if (entityNameLower.includes("auth") || entityNameLower.includes("oauth")) {
|
|
309
|
+
pattern = SERVICE_LIFECYCLE_PATTERNS["auth"];
|
|
310
|
+
}
|
|
311
|
+
if (pattern) {
|
|
312
|
+
// Order methods by their position in the lifecycle pattern
|
|
313
|
+
const ordered = pattern
|
|
314
|
+
.map(prefix => methods.find(m => m.toLowerCase().includes(prefix)))
|
|
315
|
+
.filter((m) => !!m);
|
|
316
|
+
if (ordered.length >= 2) {
|
|
317
|
+
workflows.push({
|
|
318
|
+
name: `${entity.name} Lifecycle`,
|
|
319
|
+
entity: entity.name,
|
|
320
|
+
steps: ordered,
|
|
321
|
+
confidence: 0.65,
|
|
322
|
+
source: "naming_convention",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Also add raw method ordering as a fallback workflow
|
|
327
|
+
if (methods.length >= 3 && !workflows.find(w => w.entity === entity.name)) {
|
|
328
|
+
workflows.push({
|
|
329
|
+
name: `${entity.name} Method Sequence`,
|
|
330
|
+
entity: entity.name,
|
|
331
|
+
steps: methods.slice(0, 8),
|
|
332
|
+
confidence: 0.3,
|
|
333
|
+
source: "naming_convention",
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// ── Phase 2: Entity state transitions (existing logic) ──
|
|
338
|
+
for (const entity of entities) {
|
|
339
|
+
if (entity.kind !== "entity" && entity.kind !== "enum")
|
|
340
|
+
continue;
|
|
341
|
+
if (!entity.states || entity.states.length < 2)
|
|
342
|
+
continue;
|
|
343
|
+
const entityName = entity.name.replace(/Status|State|Stage|Step/g, "").toLowerCase();
|
|
344
|
+
const relevantEdges = callGraph.filter(e => {
|
|
345
|
+
const combined = (e.caller + e.callee).toLowerCase();
|
|
346
|
+
return combined.includes(entityName);
|
|
347
|
+
});
|
|
348
|
+
const confirmedTransitions = (entity.transitions || []).filter(t => {
|
|
349
|
+
return relevantEdges.some(e => {
|
|
350
|
+
const edgeText = (e.caller + e.callee).toLowerCase();
|
|
351
|
+
return edgeText.includes(t.from.toLowerCase()) && edgeText.includes(t.to.toLowerCase());
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
if (confirmedTransitions.length >= 2) {
|
|
355
|
+
const steps = [];
|
|
356
|
+
for (const t of confirmedTransitions) {
|
|
357
|
+
if (!steps.includes(t.from))
|
|
358
|
+
steps.push(t.from);
|
|
359
|
+
if (!steps.includes(t.to))
|
|
360
|
+
steps.push(t.to);
|
|
361
|
+
}
|
|
362
|
+
if (!workflows.find(w => w.entity === entity.name)) {
|
|
363
|
+
workflows.push({
|
|
364
|
+
name: `${entity.name} Lifecycle`,
|
|
365
|
+
entity: entity.name,
|
|
366
|
+
steps,
|
|
367
|
+
confidence: confirmedTransitions.length / (entity.transitions?.length || 1),
|
|
368
|
+
source: "call_graph",
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (entity.transitions && entity.transitions.length >= 2) {
|
|
373
|
+
const steps = [];
|
|
374
|
+
for (const t of entity.transitions) {
|
|
375
|
+
if (!steps.includes(t.from))
|
|
376
|
+
steps.push(t.from);
|
|
377
|
+
if (!steps.includes(t.to))
|
|
378
|
+
steps.push(t.to);
|
|
379
|
+
}
|
|
380
|
+
if (!workflows.find(w => w.entity === entity.name)) {
|
|
381
|
+
workflows.push({
|
|
382
|
+
name: `${entity.name} Lifecycle (enum-inferred)`,
|
|
383
|
+
entity: entity.name,
|
|
384
|
+
steps,
|
|
385
|
+
confidence: 0.3,
|
|
386
|
+
source: "enum_ordering",
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return workflows;
|
|
392
|
+
}
|
|
393
|
+
// ══════════════════════════════════════════════
|
|
394
|
+
// L4: POLICY GENERATION
|
|
395
|
+
// ══════════════════════════════════════════════
|
|
396
|
+
/**
|
|
397
|
+
* Generate protocol rules from discovered workflows.
|
|
398
|
+
* This is the output: policy that the engine can enforce.
|
|
399
|
+
*/
|
|
400
|
+
function generatePolicy(entities, workflows) {
|
|
401
|
+
const policy = {
|
|
402
|
+
namespace: "auto_mined",
|
|
403
|
+
states: {},
|
|
404
|
+
rules: {},
|
|
405
|
+
};
|
|
406
|
+
for (const wf of workflows) {
|
|
407
|
+
const ns = wf.entity.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
408
|
+
// Generate state definitions
|
|
409
|
+
for (const step of wf.steps) {
|
|
410
|
+
policy.states[step] = `${wf.name}: ${step}`;
|
|
411
|
+
}
|
|
412
|
+
// Generate transition rules (each step must precede the next)
|
|
413
|
+
for (let i = 0; i < wf.steps.length - 1; i++) {
|
|
414
|
+
const from = wf.steps[i];
|
|
415
|
+
const to = wf.steps[i + 1];
|
|
416
|
+
const ruleName = `auto_${ns}_${from}_to_${to}`.toLowerCase();
|
|
417
|
+
policy.rules[ruleName] = {
|
|
418
|
+
namespace: ns,
|
|
419
|
+
pre_states: [from],
|
|
420
|
+
post_states: [to],
|
|
421
|
+
invalidate: [from],
|
|
422
|
+
description: `[AUTO-MINED] ${from} → ${to} (confidence: ${(wf.confidence * 100).toFixed(0)}%)`,
|
|
423
|
+
confidence: wf.confidence,
|
|
424
|
+
source: wf.source,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return policy;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Run the full Policy Mining pipeline on a project.
|
|
432
|
+
* L1 → L2 → L3 → L4, fully automated.
|
|
433
|
+
*/
|
|
434
|
+
function mineProject(projectPath) {
|
|
435
|
+
console.log("⛏️ Progmune Policy Mining Engine — V3.1");
|
|
436
|
+
console.log(" Project:", projectPath);
|
|
437
|
+
console.log();
|
|
438
|
+
// L1: Entity Discovery
|
|
439
|
+
console.log("L1 · Entity Discovery...");
|
|
440
|
+
const entities = discoverEntities(projectPath);
|
|
441
|
+
const entityNames = entities.filter(e => e.kind === "entity" || e.kind === "enum").map(e => e.name);
|
|
442
|
+
console.log(` Found ${entities.length} entities: ${entityNames.join(", ") || "(none)"}`);
|
|
443
|
+
// L2: Call Graph
|
|
444
|
+
console.log("\nL2 · Flow Mining...");
|
|
445
|
+
const callGraph = buildCallGraph(projectPath);
|
|
446
|
+
console.log(` Found ${callGraph.length} call edges (≥2 occurrences)`);
|
|
447
|
+
if (callGraph.length > 0) {
|
|
448
|
+
const top5 = callGraph.slice(0, 5);
|
|
449
|
+
for (const e of top5) {
|
|
450
|
+
console.log(` ${e.caller} → ${e.callee} (×${e.count})`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// L3: Workflow Discovery
|
|
454
|
+
console.log("\nL3 · Workflow Discovery...");
|
|
455
|
+
const workflows = discoverWorkflows(entities, callGraph);
|
|
456
|
+
console.log(` Found ${workflows.length} workflows`);
|
|
457
|
+
for (const wf of workflows) {
|
|
458
|
+
console.log(` ${wf.name} [${wf.source}] confidence=${(wf.confidence * 100).toFixed(0)}%`);
|
|
459
|
+
console.log(` ${wf.steps.join(" → ")}`);
|
|
460
|
+
}
|
|
461
|
+
// L4: Policy Generation
|
|
462
|
+
console.log("\nL4 · Policy Generation...");
|
|
463
|
+
const generatedPolicy = generatePolicy(entities, workflows);
|
|
464
|
+
const ruleCount = Object.keys(generatedPolicy.rules).length;
|
|
465
|
+
const highConf = Object.values(generatedPolicy.rules).filter(r => r.confidence >= 0.5).length;
|
|
466
|
+
console.log(` Generated ${ruleCount} rules (${highConf} high confidence)`);
|
|
467
|
+
const report = {
|
|
468
|
+
projectPath,
|
|
469
|
+
timestamp: new Date().toISOString(),
|
|
470
|
+
entities,
|
|
471
|
+
callGraph,
|
|
472
|
+
workflows,
|
|
473
|
+
generatedPolicy,
|
|
474
|
+
summary: {
|
|
475
|
+
entitiesFound: entities.length,
|
|
476
|
+
callEdgesFound: callGraph.length,
|
|
477
|
+
workflowsFound: workflows.length,
|
|
478
|
+
rulesGenerated: ruleCount,
|
|
479
|
+
highConfidenceRules: highConf,
|
|
480
|
+
},
|
|
481
|
+
};
|
|
482
|
+
return report;
|
|
483
|
+
}
|
|
484
|
+
// ══════════════════════════════════════════════
|
|
485
|
+
// CLI ENTRY POINT
|
|
486
|
+
// ══════════════════════════════════════════════
|
|
487
|
+
if (require.main === module) {
|
|
488
|
+
const targetProject = process.argv[2];
|
|
489
|
+
if (!targetProject) {
|
|
490
|
+
console.error("Usage: npx ts-node src/policy-miner.ts <project-path>");
|
|
491
|
+
process.exit(1);
|
|
492
|
+
}
|
|
493
|
+
const report = mineProject(targetProject);
|
|
494
|
+
// Write output
|
|
495
|
+
const outputPath = path.join(targetProject, ".progmune_mined_policy.json");
|
|
496
|
+
fs.writeFileSync(outputPath, JSON.stringify(report, null, 2));
|
|
497
|
+
console.log(`\n✅ Mined policy saved to: ${outputPath}`);
|
|
498
|
+
// Summary
|
|
499
|
+
console.log("\n═══ Mining Summary ═══");
|
|
500
|
+
console.log(` Entities: ${report.summary.entitiesFound}`);
|
|
501
|
+
console.log(` Call Edges: ${report.summary.callEdgesFound}`);
|
|
502
|
+
console.log(` Workflows: ${report.summary.workflowsFound}`);
|
|
503
|
+
console.log(` Rules: ${report.summary.rulesGenerated} (${report.summary.highConfidenceRules} high confidence)`);
|
|
504
|
+
console.log();
|
|
505
|
+
}
|