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.
Files changed (356) hide show
  1. package/README.md +108 -468
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. 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
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
  306. package/package.json +74 -7
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. 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
+ }