atabey 0.0.12 → 0.0.14

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 (432) hide show
  1. package/ATABEY.md +45 -499
  2. package/PRIVACY.md +161 -0
  3. package/README.md +553 -88
  4. package/bin/validate-al-registry.js +4 -4
  5. package/dist/framework-mcp/src/index.js +914 -62
  6. package/dist/framework-mcp/src/index.js.map +1 -1
  7. package/dist/framework-mcp/src/tools/compliance/mask_pii.d.ts +17 -0
  8. package/dist/framework-mcp/src/tools/compliance/mask_pii.js +56 -0
  9. package/dist/framework-mcp/src/tools/compliance/mask_pii.js.map +1 -0
  10. package/dist/framework-mcp/src/tools/definitions.js +24 -1
  11. package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
  12. package/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
  13. package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -1
  14. package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.d.ts +19 -0
  15. package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js +138 -0
  16. package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js.map +1 -0
  17. package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.d.ts +8 -0
  18. package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js +91 -0
  19. package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js.map +1 -0
  20. package/dist/framework-mcp/src/tools/index.d.ts +1 -1
  21. package/dist/framework-mcp/src/tools/index.js +34 -20
  22. package/dist/framework-mcp/src/tools/index.js.map +1 -1
  23. package/dist/framework-mcp/src/tools/messaging/approve_operation.d.ts +22 -0
  24. package/dist/framework-mcp/src/tools/messaging/approve_operation.js +81 -0
  25. package/dist/framework-mcp/src/tools/messaging/approve_operation.js.map +1 -0
  26. package/dist/framework-mcp/src/tools/messaging/ask_human.d.ts +15 -0
  27. package/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
  28. package/dist/framework-mcp/src/tools/messaging/ask_human.js.map +1 -1
  29. package/dist/framework-mcp/src/tools/observability/check_ports.js +3 -1
  30. package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -1
  31. package/dist/framework-mcp/src/tools/quality/analyze_code_quality.d.ts +11 -0
  32. package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +115 -0
  33. package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js.map +1 -0
  34. package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.d.ts +11 -0
  35. package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js +135 -0
  36. package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js.map +1 -0
  37. package/dist/framework-mcp/src/tools/schemas.d.ts +90 -15
  38. package/dist/framework-mcp/src/tools/schemas.js +32 -7
  39. package/dist/framework-mcp/src/tools/schemas.js.map +1 -1
  40. package/dist/framework-mcp/src/tools/shell/run_command.js +12 -2
  41. package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -1
  42. package/dist/framework-mcp/src/tools/types.d.ts +11 -105
  43. package/dist/framework-mcp/src/tools/types.js +1 -0
  44. package/dist/framework-mcp/src/tools/types.js.map +1 -1
  45. package/dist/framework-mcp/src/utils/auth.d.ts +36 -0
  46. package/dist/framework-mcp/src/utils/auth.js +79 -0
  47. package/dist/framework-mcp/src/utils/auth.js.map +1 -0
  48. package/dist/framework-mcp/src/utils/auto-rollback.d.ts +71 -0
  49. package/dist/framework-mcp/src/utils/auto-rollback.js +266 -0
  50. package/dist/framework-mcp/src/utils/auto-rollback.js.map +1 -0
  51. package/dist/framework-mcp/src/utils/compliance.js +12 -4
  52. package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
  53. package/dist/framework-mcp/src/utils/context-optimizer.d.ts +69 -0
  54. package/dist/framework-mcp/src/utils/context-optimizer.js +157 -0
  55. package/dist/framework-mcp/src/utils/context-optimizer.js.map +1 -0
  56. package/dist/framework-mcp/src/utils/discipline.d.ts +68 -0
  57. package/dist/framework-mcp/src/utils/discipline.js +218 -0
  58. package/dist/framework-mcp/src/utils/discipline.js.map +1 -0
  59. package/dist/framework-mcp/src/utils/finops.d.ts +143 -0
  60. package/dist/framework-mcp/src/utils/finops.js +326 -0
  61. package/dist/framework-mcp/src/utils/finops.js.map +1 -0
  62. package/dist/framework-mcp/src/utils/human-in-loop.d.ts +95 -0
  63. package/dist/framework-mcp/src/utils/human-in-loop.js +216 -0
  64. package/dist/framework-mcp/src/utils/human-in-loop.js.map +1 -0
  65. package/dist/framework-mcp/src/utils/license-scanner.d.ts +71 -0
  66. package/dist/framework-mcp/src/utils/license-scanner.js +284 -0
  67. package/dist/framework-mcp/src/utils/license-scanner.js.map +1 -0
  68. package/dist/framework-mcp/src/utils/loop-detector.d.ts +105 -0
  69. package/dist/framework-mcp/src/utils/loop-detector.js +362 -0
  70. package/dist/framework-mcp/src/utils/loop-detector.js.map +1 -0
  71. package/dist/framework-mcp/src/utils/quality.d.ts +19 -0
  72. package/dist/framework-mcp/src/utils/quality.js +124 -0
  73. package/dist/framework-mcp/src/utils/quality.js.map +1 -0
  74. package/dist/framework-mcp/src/utils/rules-engine.d.ts +78 -0
  75. package/dist/framework-mcp/src/utils/rules-engine.js +232 -0
  76. package/dist/framework-mcp/src/utils/rules-engine.js.map +1 -0
  77. package/dist/framework-mcp/src/utils/silent-router.d.ts +47 -0
  78. package/dist/framework-mcp/src/utils/silent-router.js +129 -0
  79. package/dist/framework-mcp/src/utils/silent-router.js.map +1 -0
  80. package/dist/framework-mcp/src/utils/storage.d.ts +1 -0
  81. package/dist/framework-mcp/src/utils/storage.js +2 -2
  82. package/dist/framework-mcp/src/utils/storage.js.map +1 -1
  83. package/dist/framework-mcp/src/utils/telemetry-streamer.d.ts +133 -0
  84. package/dist/framework-mcp/src/utils/telemetry-streamer.js +397 -0
  85. package/dist/framework-mcp/src/utils/telemetry-streamer.js.map +1 -0
  86. package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js +2 -2
  87. package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js.map +1 -1
  88. package/dist/framework-mcp/tests/tools/framework/run_tests.test.d.ts +1 -0
  89. package/dist/framework-mcp/tests/tools/framework/run_tests.test.js +49 -0
  90. package/dist/framework-mcp/tests/tools/framework/run_tests.test.js.map +1 -0
  91. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +14 -5
  92. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
  93. package/dist/framework-mcp/tests/tools/observability/check_ports.test.d.ts +1 -0
  94. package/dist/framework-mcp/tests/tools/observability/check_ports.test.js +30 -0
  95. package/dist/framework-mcp/tests/tools/observability/check_ports.test.js.map +1 -0
  96. package/dist/framework-mcp/tests/tools/shell/run_command.test.js +7 -0
  97. package/dist/framework-mcp/tests/tools/shell/run_command.test.js.map +1 -1
  98. package/dist/framework-mcp/tests/utils/auto-rollback.test.d.ts +7 -0
  99. package/dist/framework-mcp/tests/utils/auto-rollback.test.js +178 -0
  100. package/dist/framework-mcp/tests/utils/auto-rollback.test.js.map +1 -0
  101. package/dist/framework-mcp/tests/utils/context-optimizer.test.d.ts +1 -0
  102. package/dist/framework-mcp/tests/utils/context-optimizer.test.js +62 -0
  103. package/dist/framework-mcp/tests/utils/context-optimizer.test.js.map +1 -0
  104. package/dist/framework-mcp/tests/utils/finops.test.d.ts +7 -0
  105. package/dist/framework-mcp/tests/utils/finops.test.js +157 -0
  106. package/dist/framework-mcp/tests/utils/finops.test.js.map +1 -0
  107. package/dist/framework-mcp/tests/utils/human-in-loop.test.d.ts +1 -0
  108. package/dist/framework-mcp/tests/utils/human-in-loop.test.js +59 -0
  109. package/dist/framework-mcp/tests/utils/human-in-loop.test.js.map +1 -0
  110. package/dist/framework-mcp/tests/utils/license-scanner.test.d.ts +7 -0
  111. package/dist/framework-mcp/tests/utils/license-scanner.test.js +131 -0
  112. package/dist/framework-mcp/tests/utils/license-scanner.test.js.map +1 -0
  113. package/dist/framework-mcp/tests/utils/loop-detector.test.d.ts +7 -0
  114. package/dist/framework-mcp/tests/utils/loop-detector.test.js +204 -0
  115. package/dist/framework-mcp/tests/utils/loop-detector.test.js.map +1 -0
  116. package/dist/framework-mcp/tests/utils/rules-engine.test.d.ts +1 -0
  117. package/dist/framework-mcp/tests/utils/rules-engine.test.js +106 -0
  118. package/dist/framework-mcp/tests/utils/rules-engine.test.js.map +1 -0
  119. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.d.ts +7 -0
  120. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js +201 -0
  121. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js.map +1 -0
  122. package/dist/src/cli/commands/check.js +18 -3
  123. package/dist/src/cli/commands/check.js.map +1 -1
  124. package/dist/src/cli/commands/dashboard.d.ts +1 -1
  125. package/dist/src/cli/commands/dashboard.js +343 -96
  126. package/dist/src/cli/commands/dashboard.js.map +1 -1
  127. package/dist/src/cli/commands/gateway.d.ts +1 -0
  128. package/dist/src/cli/commands/gateway.js +172 -0
  129. package/dist/src/cli/commands/gateway.js.map +1 -0
  130. package/dist/src/cli/commands/init/create-agent.js +3 -3
  131. package/dist/src/cli/commands/init/create-agent.js.map +1 -1
  132. package/dist/src/cli/commands/init/scaffold-core.d.ts +3 -1
  133. package/dist/src/cli/commands/init/scaffold-core.js +17 -2
  134. package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
  135. package/dist/src/cli/commands/init/scaffold-ops.js +2 -2
  136. package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
  137. package/dist/src/cli/commands/init/scaffold-standards.js +13 -1
  138. package/dist/src/cli/commands/init/scaffold-standards.js.map +1 -1
  139. package/dist/src/cli/commands/init.d.ts +6 -0
  140. package/dist/src/cli/commands/init.js +163 -25
  141. package/dist/src/cli/commands/init.js.map +1 -1
  142. package/dist/src/cli/commands/mcp.d.ts +7 -0
  143. package/dist/src/cli/commands/mcp.js +45 -22
  144. package/dist/src/cli/commands/mcp.js.map +1 -1
  145. package/dist/src/cli/commands/orchestrate.d.ts +8 -7
  146. package/dist/src/cli/commands/orchestrate.js +2 -1
  147. package/dist/src/cli/commands/orchestrate.js.map +1 -1
  148. package/dist/src/cli/commands/quickstart.d.ts +5 -5
  149. package/dist/src/cli/commands/quickstart.js +30 -42
  150. package/dist/src/cli/commands/quickstart.js.map +1 -1
  151. package/dist/src/cli/index.js +228 -317
  152. package/dist/src/cli/index.js.map +1 -1
  153. package/dist/src/cli/platforms/core.d.ts +12 -0
  154. package/dist/src/cli/platforms/core.js +73 -0
  155. package/dist/src/cli/platforms/core.js.map +1 -0
  156. package/dist/src/cli/platforms/index.d.ts +5 -0
  157. package/dist/src/cli/platforms/index.js +6 -0
  158. package/dist/src/cli/platforms/index.js.map +1 -0
  159. package/dist/src/cli/platforms/paths.d.ts +15 -0
  160. package/dist/src/cli/platforms/paths.js +102 -0
  161. package/dist/src/cli/platforms/paths.js.map +1 -0
  162. package/dist/src/cli/platforms/scaffold.d.ts +2 -0
  163. package/dist/src/cli/platforms/scaffold.js +73 -0
  164. package/dist/src/cli/platforms/scaffold.js.map +1 -0
  165. package/dist/src/cli/platforms/utils.d.ts +4 -0
  166. package/dist/src/cli/platforms/utils.js +76 -0
  167. package/dist/src/cli/platforms/utils.js.map +1 -0
  168. package/dist/src/cli/shims.js +11 -11
  169. package/dist/src/cli/utils/fs.d.ts +1 -1
  170. package/dist/src/cli/utils/fs.js +1 -1
  171. package/dist/src/cli/utils/fs.js.map +1 -1
  172. package/dist/src/cli/utils/pkg.js +2 -3
  173. package/dist/src/cli/utils/pkg.js.map +1 -1
  174. package/dist/src/cli/utils/quality.d.ts +10 -0
  175. package/dist/src/cli/utils/quality.js +10 -0
  176. package/dist/src/cli/utils/quality.js.map +1 -0
  177. package/dist/src/modules/agents/definitions.d.ts +2 -2
  178. package/dist/src/modules/agents/definitions.js +104 -63
  179. package/dist/src/modules/agents/definitions.js.map +1 -1
  180. package/dist/src/modules/agents/registry/manager.js +6 -1
  181. package/dist/src/modules/agents/registry/manager.js.map +1 -1
  182. package/dist/src/modules/contracts/api.d.ts +178 -0
  183. package/dist/src/modules/contracts/api.js +56 -0
  184. package/dist/src/modules/contracts/api.js.map +1 -0
  185. package/dist/src/modules/contracts/index.d.ts +5 -0
  186. package/dist/src/modules/contracts/index.js +6 -0
  187. package/dist/src/modules/contracts/index.js.map +1 -0
  188. package/dist/src/modules/engines/agent-executor.d.ts +25 -30
  189. package/dist/src/modules/engines/agent-executor.js +133 -73
  190. package/dist/src/modules/engines/agent-executor.js.map +1 -1
  191. package/dist/src/modules/engines/agent-loop.d.ts +34 -0
  192. package/dist/src/modules/engines/agent-loop.js +102 -0
  193. package/dist/src/modules/engines/agent-loop.js.map +1 -0
  194. package/dist/src/modules/engines/evaluation-engine.js +2 -2
  195. package/dist/src/modules/engines/evaluation-engine.js.map +1 -1
  196. package/dist/src/modules/engines/quality-gate.d.ts +16 -8
  197. package/dist/src/modules/engines/quality-gate.js +42 -34
  198. package/dist/src/modules/engines/quality-gate.js.map +1 -1
  199. package/dist/src/modules/engines/routing-engine.d.ts +21 -28
  200. package/dist/src/modules/engines/routing-engine.js +83 -50
  201. package/dist/src/modules/engines/routing-engine.js.map +1 -1
  202. package/dist/src/modules/gateway/circuit-breaker.d.ts +40 -0
  203. package/dist/src/modules/gateway/circuit-breaker.js +163 -0
  204. package/dist/src/modules/gateway/circuit-breaker.js.map +1 -0
  205. package/dist/src/modules/gateway/cost-tracker.d.ts +60 -0
  206. package/dist/src/modules/gateway/cost-tracker.js +198 -0
  207. package/dist/src/modules/gateway/cost-tracker.js.map +1 -0
  208. package/dist/src/modules/gateway/gateway.d.ts +72 -0
  209. package/dist/src/modules/gateway/gateway.js +243 -0
  210. package/dist/src/modules/gateway/gateway.js.map +1 -0
  211. package/dist/src/modules/gateway/index.d.ts +19 -0
  212. package/dist/src/modules/gateway/index.js +19 -0
  213. package/dist/src/modules/gateway/index.js.map +1 -0
  214. package/dist/src/modules/gateway/load-balancer.d.ts +86 -0
  215. package/dist/src/modules/gateway/load-balancer.js +230 -0
  216. package/dist/src/modules/gateway/load-balancer.js.map +1 -0
  217. package/dist/src/modules/gateway/providers/anthropic.d.ts +14 -0
  218. package/dist/src/modules/gateway/providers/anthropic.js +169 -0
  219. package/dist/src/modules/gateway/providers/anthropic.js.map +1 -0
  220. package/dist/src/modules/gateway/providers/base.d.ts +38 -0
  221. package/dist/src/modules/gateway/providers/base.js +42 -0
  222. package/dist/src/modules/gateway/providers/base.js.map +1 -0
  223. package/dist/src/modules/gateway/providers/google.d.ts +18 -0
  224. package/dist/src/modules/gateway/providers/google.js +176 -0
  225. package/dist/src/modules/gateway/providers/google.js.map +1 -0
  226. package/dist/src/modules/gateway/providers/grok.d.ts +14 -0
  227. package/dist/src/modules/gateway/providers/grok.js +166 -0
  228. package/dist/src/modules/gateway/providers/grok.js.map +1 -0
  229. package/dist/src/modules/gateway/providers/index.d.ts +21 -0
  230. package/dist/src/modules/gateway/providers/index.js +38 -0
  231. package/dist/src/modules/gateway/providers/index.js.map +1 -0
  232. package/dist/src/modules/gateway/providers/ollama.d.ts +23 -0
  233. package/dist/src/modules/gateway/providers/ollama.js +187 -0
  234. package/dist/src/modules/gateway/providers/ollama.js.map +1 -0
  235. package/dist/src/modules/gateway/providers/openai.d.ts +14 -0
  236. package/dist/src/modules/gateway/providers/openai.js +170 -0
  237. package/dist/src/modules/gateway/providers/openai.js.map +1 -0
  238. package/dist/src/modules/gateway/rate-limiter.d.ts +41 -0
  239. package/dist/src/modules/gateway/rate-limiter.js +119 -0
  240. package/dist/src/modules/gateway/rate-limiter.js.map +1 -0
  241. package/dist/src/modules/gateway/types.d.ts +114 -0
  242. package/dist/src/modules/gateway/types.js +8 -0
  243. package/dist/src/modules/gateway/types.js.map +1 -0
  244. package/dist/src/modules/memory/core.d.ts +4 -12
  245. package/dist/src/modules/memory/core.js +10 -17
  246. package/dist/src/modules/memory/core.js.map +1 -1
  247. package/dist/src/modules/memory/embedding.d.ts +28 -0
  248. package/dist/src/modules/memory/embedding.js +131 -0
  249. package/dist/src/modules/memory/embedding.js.map +1 -0
  250. package/dist/src/modules/providers/definitions.d.ts +9 -0
  251. package/dist/src/modules/providers/definitions.js +141 -0
  252. package/dist/src/modules/providers/definitions.js.map +1 -0
  253. package/dist/src/modules/providers/registry.d.ts +12 -0
  254. package/dist/src/modules/providers/registry.js +19 -0
  255. package/dist/src/modules/providers/registry.js.map +1 -0
  256. package/dist/src/modules/providers/shared.d.ts +1 -0
  257. package/dist/src/modules/providers/shared.js +105 -0
  258. package/dist/src/modules/providers/shared.js.map +1 -0
  259. package/dist/src/modules/providers/types.d.ts +14 -0
  260. package/dist/src/modules/providers/types.js +2 -0
  261. package/dist/src/modules/providers/types.js.map +1 -0
  262. package/dist/src/modules/skills/adapter-skills.d.ts +68 -0
  263. package/dist/src/modules/skills/adapter-skills.js +450 -0
  264. package/dist/src/modules/skills/adapter-skills.js.map +1 -0
  265. package/dist/src/shared/audit.d.ts +105 -0
  266. package/dist/src/shared/audit.js +221 -0
  267. package/dist/src/shared/audit.js.map +1 -0
  268. package/dist/src/shared/fs.js +4 -2
  269. package/dist/src/shared/fs.js.map +1 -1
  270. package/dist/src/shared/lock.d.ts +82 -0
  271. package/dist/src/shared/lock.js +160 -0
  272. package/dist/src/shared/lock.js.map +1 -0
  273. package/dist/src/shared/logger.d.ts +2 -0
  274. package/dist/src/shared/logger.js +15 -5
  275. package/dist/src/shared/logger.js.map +1 -1
  276. package/dist/src/shared/pii.d.ts +69 -0
  277. package/dist/src/shared/pii.js +213 -0
  278. package/dist/src/shared/pii.js.map +1 -0
  279. package/dist/src/shared/retention.d.ts +63 -0
  280. package/dist/src/shared/retention.js +171 -0
  281. package/dist/src/shared/retention.js.map +1 -0
  282. package/dist/src/shared/storage.d.ts +22 -1
  283. package/dist/src/shared/storage.js +49 -7
  284. package/dist/src/shared/storage.js.map +1 -1
  285. package/dist/tests/adapter.test.js +1 -1
  286. package/dist/tests/adapter.test.js.map +1 -1
  287. package/dist/tests/adapters/paths.test.js +4 -4
  288. package/dist/tests/adapters/paths.test.js.map +1 -1
  289. package/dist/tests/cli/commands/dashboard-coverage.test.d.ts +1 -0
  290. package/dist/tests/cli/commands/dashboard-coverage.test.js +88 -0
  291. package/dist/tests/cli/commands/dashboard-coverage.test.js.map +1 -0
  292. package/dist/tests/cli/init/adapter_init.test.js +4 -5
  293. package/dist/tests/cli/init/adapter_init.test.js.map +1 -1
  294. package/dist/tests/cli/init/unified_init.test.js +5 -7
  295. package/dist/tests/cli/init/unified_init.test.js.map +1 -1
  296. package/dist/tests/embedding.test.d.ts +1 -0
  297. package/dist/tests/embedding.test.js +82 -0
  298. package/dist/tests/embedding.test.js.map +1 -0
  299. package/dist/tests/engines/evaluation-engine.test.d.ts +1 -0
  300. package/dist/tests/engines/evaluation-engine.test.js +71 -0
  301. package/dist/tests/engines/evaluation-engine.test.js.map +1 -0
  302. package/dist/tests/engines/planning-engine.test.d.ts +1 -0
  303. package/dist/tests/engines/planning-engine.test.js +100 -0
  304. package/dist/tests/engines/planning-engine.test.js.map +1 -0
  305. package/dist/tests/engines/quality-gate.test.d.ts +1 -0
  306. package/dist/tests/engines/quality-gate.test.js +59 -0
  307. package/dist/tests/engines/quality-gate.test.js.map +1 -0
  308. package/dist/tests/engines/risk-engine.test.d.ts +1 -0
  309. package/dist/tests/engines/risk-engine.test.js +80 -0
  310. package/dist/tests/engines/risk-engine.test.js.map +1 -0
  311. package/dist/tests/engines/routing-engine.test.d.ts +1 -0
  312. package/dist/tests/engines/routing-engine.test.js +78 -0
  313. package/dist/tests/engines/routing-engine.test.js.map +1 -0
  314. package/dist/tests/integration/agent_flow.test.js +14 -8
  315. package/dist/tests/integration/agent_flow.test.js.map +1 -1
  316. package/dist/tests/integration/hermes_locking.test.js +1 -0
  317. package/dist/tests/integration/hermes_locking.test.js.map +1 -1
  318. package/dist/tests/modules/adapters/adapters.test.js +2 -2
  319. package/dist/tests/modules/adapters/adapters.test.js.map +1 -1
  320. package/dist/tests/modules/contracts/contracts.test.d.ts +1 -0
  321. package/dist/tests/modules/contracts/contracts.test.js +73 -0
  322. package/dist/tests/modules/contracts/contracts.test.js.map +1 -0
  323. package/dist/tests/modules/engines/agent-executor.test.js +30 -23
  324. package/dist/tests/modules/engines/agent-executor.test.js.map +1 -1
  325. package/dist/tests/modules/gateway/circuit-breaker.test.d.ts +1 -0
  326. package/dist/tests/modules/gateway/circuit-breaker.test.js +124 -0
  327. package/dist/tests/modules/gateway/circuit-breaker.test.js.map +1 -0
  328. package/dist/tests/modules/gateway/cost-tracker.test.d.ts +1 -0
  329. package/dist/tests/modules/gateway/cost-tracker.test.js +93 -0
  330. package/dist/tests/modules/gateway/cost-tracker.test.js.map +1 -0
  331. package/dist/tests/modules/gateway/load-balancer.test.d.ts +1 -0
  332. package/dist/tests/modules/gateway/load-balancer.test.js +70 -0
  333. package/dist/tests/modules/gateway/load-balancer.test.js.map +1 -0
  334. package/dist/tests/modules/gateway/rate-limiter.test.d.ts +1 -0
  335. package/dist/tests/modules/gateway/rate-limiter.test.js +62 -0
  336. package/dist/tests/modules/gateway/rate-limiter.test.js.map +1 -0
  337. package/dist/tests/orchestrator-dependencies.test.js +23 -6
  338. package/dist/tests/orchestrator-dependencies.test.js.map +1 -1
  339. package/dist/tests/shared/audit.test.d.ts +1 -0
  340. package/dist/tests/shared/audit.test.js +53 -0
  341. package/dist/tests/shared/audit.test.js.map +1 -0
  342. package/dist/tests/shared/lock.test.d.ts +1 -0
  343. package/dist/tests/shared/lock.test.js +95 -0
  344. package/dist/tests/shared/lock.test.js.map +1 -0
  345. package/dist/tests/shared/pii.test.d.ts +1 -0
  346. package/dist/tests/shared/pii.test.js +183 -0
  347. package/dist/tests/shared/pii.test.js.map +1 -0
  348. package/dist/tests/storage-operations.test.d.ts +1 -0
  349. package/dist/tests/storage-operations.test.js +116 -0
  350. package/dist/tests/storage-operations.test.js.map +1 -0
  351. package/framework-mcp/README.md +596 -77
  352. package/framework-mcp/dist/dashboard/assets/index-B2mYld0c.js +1221 -0
  353. package/framework-mcp/dist/dashboard/index.html +15 -0
  354. package/framework-mcp/dist/framework-mcp/src/index.js +914 -62
  355. package/framework-mcp/dist/framework-mcp/src/tools/compliance/mask_pii.js +55 -0
  356. package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +24 -1
  357. package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
  358. package/framework-mcp/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js +137 -0
  359. package/framework-mcp/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js +90 -0
  360. package/framework-mcp/dist/framework-mcp/src/tools/index.js +34 -20
  361. package/framework-mcp/dist/framework-mcp/src/tools/messaging/approve_operation.js +80 -0
  362. package/framework-mcp/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
  363. package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +3 -1
  364. package/framework-mcp/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +114 -0
  365. package/framework-mcp/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js +134 -0
  366. package/framework-mcp/dist/framework-mcp/src/tools/schemas.js +32 -7
  367. package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +12 -2
  368. package/framework-mcp/dist/framework-mcp/src/tools/types.js +1 -0
  369. package/framework-mcp/dist/framework-mcp/src/utils/auth.js +78 -0
  370. package/framework-mcp/dist/framework-mcp/src/utils/auto-rollback.js +265 -0
  371. package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +12 -4
  372. package/framework-mcp/dist/framework-mcp/src/utils/context-optimizer.js +156 -0
  373. package/framework-mcp/dist/framework-mcp/src/utils/discipline.js +217 -0
  374. package/framework-mcp/dist/framework-mcp/src/utils/finops.js +325 -0
  375. package/framework-mcp/dist/framework-mcp/src/utils/human-in-loop.js +215 -0
  376. package/framework-mcp/dist/framework-mcp/src/utils/license-scanner.js +283 -0
  377. package/framework-mcp/dist/framework-mcp/src/utils/loop-detector.js +361 -0
  378. package/framework-mcp/dist/framework-mcp/src/utils/quality.js +123 -0
  379. package/framework-mcp/dist/framework-mcp/src/utils/rules-engine.js +231 -0
  380. package/framework-mcp/dist/framework-mcp/src/utils/silent-router.js +128 -0
  381. package/framework-mcp/dist/framework-mcp/src/utils/storage.js +2 -2
  382. package/framework-mcp/dist/framework-mcp/src/utils/telemetry-streamer.js +396 -0
  383. package/framework-mcp/dist/src/cli/platforms/core.js +72 -0
  384. package/framework-mcp/dist/src/cli/platforms/index.js +5 -0
  385. package/framework-mcp/dist/src/cli/platforms/paths.js +101 -0
  386. package/framework-mcp/dist/src/cli/platforms/scaffold.js +72 -0
  387. package/framework-mcp/dist/src/cli/platforms/utils.js +75 -0
  388. package/framework-mcp/dist/src/cli/utils/claude.js +57 -0
  389. package/framework-mcp/dist/src/cli/utils/compliance.js +12 -0
  390. package/framework-mcp/dist/src/cli/utils/fs.js +138 -0
  391. package/framework-mcp/dist/src/cli/utils/pkg.js +282 -0
  392. package/framework-mcp/dist/src/cli/utils/quality.js +9 -0
  393. package/framework-mcp/dist/src/modules/agents/definitions.js +563 -0
  394. package/framework-mcp/dist/src/modules/agents/registry/analyst.js +39 -0
  395. package/framework-mcp/dist/src/modules/agents/registry/architect.js +42 -0
  396. package/framework-mcp/dist/src/modules/agents/registry/backend.js +50 -0
  397. package/framework-mcp/dist/src/modules/agents/registry/database.js +45 -0
  398. package/framework-mcp/dist/src/modules/agents/registry/devops.js +45 -0
  399. package/framework-mcp/dist/src/modules/agents/registry/explorer.js +37 -0
  400. package/framework-mcp/dist/src/modules/agents/registry/frontend.js +52 -0
  401. package/framework-mcp/dist/src/modules/agents/registry/git.js +36 -0
  402. package/framework-mcp/dist/src/modules/agents/registry/manager.js +64 -0
  403. package/framework-mcp/dist/src/modules/agents/registry/mobile.js +41 -0
  404. package/framework-mcp/dist/src/modules/agents/registry/native.js +41 -0
  405. package/framework-mcp/dist/src/modules/agents/registry/quality.js +43 -0
  406. package/framework-mcp/dist/src/modules/agents/registry/security.js +42 -0
  407. package/framework-mcp/dist/src/modules/agents/types.js +1 -0
  408. package/framework-mcp/dist/src/modules/engines/quality-gate.js +92 -0
  409. package/framework-mcp/dist/src/modules/engines/risk-engine.js +105 -0
  410. package/framework-mcp/dist/src/modules/engines/routing-engine.js +408 -0
  411. package/framework-mcp/dist/src/modules/engines/types.js +1 -0
  412. package/framework-mcp/dist/src/modules/memory/core.js +10 -17
  413. package/framework-mcp/dist/src/modules/memory/embedding.js +130 -0
  414. package/framework-mcp/dist/src/modules/providers/definitions.js +140 -0
  415. package/framework-mcp/dist/src/modules/providers/registry.js +18 -0
  416. package/framework-mcp/dist/src/modules/providers/shared.js +104 -0
  417. package/framework-mcp/dist/src/modules/providers/types.js +1 -0
  418. package/framework-mcp/dist/src/modules/skills/adapter-skills.js +449 -0
  419. package/framework-mcp/dist/src/modules/skills/definitions.js +70 -0
  420. package/framework-mcp/dist/src/shared/audit.js +220 -0
  421. package/framework-mcp/dist/src/shared/errors.js +68 -0
  422. package/framework-mcp/dist/src/shared/fs.js +4 -2
  423. package/framework-mcp/dist/src/shared/lock.js +159 -0
  424. package/framework-mcp/dist/src/shared/logger.js +15 -5
  425. package/framework-mcp/dist/src/shared/pii.js +212 -0
  426. package/framework-mcp/dist/src/shared/retention.js +170 -0
  427. package/framework-mcp/dist/src/shared/storage.js +49 -7
  428. package/framework-mcp/dist/src/shared/string.js +29 -0
  429. package/framework-mcp/package.json +8 -2
  430. package/mcp.json +11 -6
  431. package/package.json +22 -9
  432. package/templates/full/ATABEY_FULL.md +515 -0
@@ -0,0 +1,265 @@
1
+ /**
2
+ * ─── AUTO-ROLLBACK + REGENERATE ───────────────────────────────────
3
+ *
4
+ * When the AI generates code that violates governance rules (e.g., `any` type,
5
+ * console.log, copyleft license), this module:
6
+ * 1. Captures the file content before the write
7
+ * 2. Validates the new content against governance rules
8
+ * 3. If violation found: blocks the write, restores original, and sends
9
+ * a regenerate instruction back to the AI via MCP notification
10
+ *
11
+ * Flow:
12
+ * [Pre-Write Snapshot] → [Validate Content] → [Violation?] ─yes→ [Rollback] → [Notify AI]
13
+ * └─no─→ [Allow Write]
14
+ *
15
+ * Key Innovation: Unlike simple blocking, this tells the AI WHY it was
16
+ * blocked and gives it specific instructions to self-correct.
17
+ */
18
+ import fs from "fs";
19
+ import path from "path";
20
+ class SnapshotManager {
21
+ snapshots = new Map();
22
+ /**
23
+ * Capture a pre-write snapshot of a file.
24
+ */
25
+ capture(filePath, traceId) {
26
+ const resolvedPath = path.resolve(filePath);
27
+ let originalContent = null;
28
+ try {
29
+ if (fs.existsSync(resolvedPath)) {
30
+ originalContent = fs.readFileSync(resolvedPath, "utf8");
31
+ }
32
+ }
33
+ catch { /* file doesn't exist yet (new file) */ }
34
+ this.snapshots.set(resolvedPath, {
35
+ filePath: resolvedPath,
36
+ originalContent,
37
+ timestamp: Date.now(),
38
+ traceId,
39
+ restored: false,
40
+ });
41
+ }
42
+ /**
43
+ * Get a snapshot for a file.
44
+ */
45
+ get(filePath) {
46
+ return this.snapshots.get(path.resolve(filePath));
47
+ }
48
+ /**
49
+ * Restore a file to its pre-write state.
50
+ * Returns true if restored, false if no snapshot exists.
51
+ */
52
+ restore(filePath) {
53
+ const resolvedPath = path.resolve(filePath);
54
+ const snapshot = this.snapshots.get(resolvedPath);
55
+ if (!snapshot || snapshot.restored)
56
+ return false;
57
+ try {
58
+ if (snapshot.originalContent !== null) {
59
+ // File existed before – restore original
60
+ fs.writeFileSync(resolvedPath, snapshot.originalContent, "utf8");
61
+ process.stderr.write(`[ROLLBACK] Restored: ${path.relative(process.cwd(), resolvedPath)}\n`);
62
+ }
63
+ else {
64
+ // File was new – delete it
65
+ if (fs.existsSync(resolvedPath)) {
66
+ fs.unlinkSync(resolvedPath);
67
+ process.stderr.write(`[ROLLBACK] Deleted (new file): ${path.relative(process.cwd(), resolvedPath)}\n`);
68
+ }
69
+ }
70
+ snapshot.restored = true;
71
+ return true;
72
+ }
73
+ catch (error) {
74
+ process.stderr.write(`[ROLLBACK] Failed to restore ${resolvedPath}: ${error}\n`);
75
+ return false;
76
+ }
77
+ }
78
+ /**
79
+ * Clean up old snapshots.
80
+ */
81
+ cleanup(maxAgeMs = 300000) {
82
+ const cutoff = Date.now() - maxAgeMs;
83
+ for (const [filePath, snapshot] of this.snapshots) {
84
+ if (snapshot.timestamp < cutoff) {
85
+ this.snapshots.delete(filePath);
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Get all active snapshots.
91
+ */
92
+ getAll() {
93
+ return Array.from(this.snapshots.values());
94
+ }
95
+ }
96
+ // ─── Auto-Rollback Engine ─────────────────────────────────────────
97
+ export class AutoRollback {
98
+ static snapshots = new SnapshotManager();
99
+ /**
100
+ * Initialize the auto-rollback system.
101
+ * Sets up file watcher cleanup.
102
+ */
103
+ static initialize() {
104
+ // Periodic cleanup of old snapshots (every 5 minutes)
105
+ setInterval(() => {
106
+ AutoRollback.snapshots.cleanup();
107
+ }, 300000);
108
+ }
109
+ /**
110
+ * Prepare for a file write by capturing the current state.
111
+ * Call this BEFORE the tool handler writes to the file.
112
+ */
113
+ static prepareWrite(filePath, traceId) {
114
+ AutoRollback.snapshots.capture(filePath, traceId);
115
+ }
116
+ /**
117
+ * Validate content and rollback if violations are found.
118
+ * This is called after the tool handler writes the file, but
119
+ * BEFORE the response is returned to the AI.
120
+ *
121
+ * Returns:
122
+ * - null if content is clean
123
+ * - ViolationRecord[] if violations were found and rolled back
124
+ */
125
+ static validateAndRollback(filePath, content, violations) {
126
+ if (violations.length === 0)
127
+ return null;
128
+ // Restore the original file
129
+ const restored = AutoRollback.snapshots.restore(filePath);
130
+ if (restored) {
131
+ process.stderr.write(`[ROLLBACK] Rolled back ${path.relative(process.cwd(), filePath)} due to ${violations.length} violation(s)\n`);
132
+ }
133
+ return violations;
134
+ }
135
+ /**
136
+ * Build a regenerate instruction for the AI.
137
+ * This is what gets sent back to the AI to tell it to fix its output.
138
+ */
139
+ static buildRegenerateInstruction(violations, toolName) {
140
+ const criticalViolations = violations.filter(v => v.severity === "CRITICAL");
141
+ const lines = [
142
+ "## ⛔ AI Output Blocked – Governance Violation",
143
+ "",
144
+ `The code you generated for tool "${toolName}" has been BLOCKED and ROLLED BACK.`,
145
+ "The file has been restored to its previous state.",
146
+ "",
147
+ ];
148
+ if (criticalViolations.length > 0) {
149
+ lines.push(`### 🔴 Critical Violations (${criticalViolations.length})`);
150
+ lines.push("");
151
+ for (const v of criticalViolations) {
152
+ lines.push(`- **${v.rule}** (${v.filePath}:${v.line})`);
153
+ lines.push(` - Detail: ${v.detail}`);
154
+ lines.push(` - Fix: ${v.regenerateInstruction}`);
155
+ lines.push("");
156
+ }
157
+ }
158
+ const otherViolations = violations.filter(v => v.severity !== "CRITICAL");
159
+ if (otherViolations.length > 0) {
160
+ lines.push(`### 🟠 Other Violations (${otherViolations.length})`);
161
+ lines.push("");
162
+ for (const v of otherViolations) {
163
+ lines.push(`- **${v.rule}** (${v.filePath}:${v.line})`);
164
+ lines.push(` - Detail: ${v.detail}`);
165
+ lines.push(` - Fix: ${v.regenerateInstruction}`);
166
+ lines.push("");
167
+ }
168
+ }
169
+ lines.push("---");
170
+ lines.push("> **Instruction:** Please regenerate the code for this operation.");
171
+ lines.push("> Address ALL violations listed above.");
172
+ lines.push("> Do NOT reintroduce the same violations.");
173
+ return lines.join("\n");
174
+ }
175
+ /**
176
+ * Validate tool response content against governance rules.
177
+ * Used by the MCP middleware to check file write content before returning.
178
+ */
179
+ static checkWriteContent(filePath, content, traceId) {
180
+ const ext = path.extname(filePath).toLowerCase();
181
+ const violations = [];
182
+ // Only check source files
183
+ if (![".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".java", ".rs", ".swift", ".kt"].includes(ext)) {
184
+ return { allowed: true, violations: [], instruction: null };
185
+ }
186
+ const lines = content.split("\n");
187
+ // 1. Check for `any` type (CRITICAL)
188
+ if ([".ts", ".tsx"].includes(ext)) {
189
+ for (let i = 0; i < lines.length; i++) {
190
+ const anyMatch = lines[i].match(/:\s*any\b/);
191
+ if (anyMatch) {
192
+ violations.push({
193
+ rule: "No `any` Type",
194
+ severity: "CRITICAL",
195
+ filePath,
196
+ line: i + 1,
197
+ detail: `Line ${i + 1}: ${anyMatch[0].substring(0, 60)}`,
198
+ regenerateInstruction: "Replace `any` with `unknown` and add proper type guards. Or use a specific interface/type.",
199
+ });
200
+ }
201
+ }
202
+ }
203
+ // 2. Check for console.log (CRITICAL)
204
+ for (let i = 0; i < lines.length; i++) {
205
+ const consoleMatch = lines[i].match(/console\.(log|error|warn|debug)\s*\(/);
206
+ if (consoleMatch) {
207
+ // Check if file is exempt
208
+ if (!filePath.includes("logger.ts") && !filePath.includes("cli.ts") && !filePath.includes("compliance.ts")) {
209
+ violations.push({
210
+ rule: "No Console Log",
211
+ severity: "CRITICAL",
212
+ filePath,
213
+ line: i + 1,
214
+ detail: `Line ${i + 1}: ${consoleMatch[0].substring(0, 60)}`,
215
+ regenerateInstruction: "Replace with the project's logger (import from the appropriate logger module).",
216
+ });
217
+ }
218
+ }
219
+ }
220
+ // 3. Check for hardcoded secrets (HIGH)
221
+ const secretPatterns = [
222
+ { pattern: /(['"])sk-[a-zA-Z0-9]{20,}['"]/, name: "OpenAI API Key" },
223
+ { pattern: /(['"])ghp_[a-zA-Z0-9]{36,}['"]/, name: "GitHub Token" },
224
+ { pattern: /(['"])AIza[0-9A-Za-z_-]{35}['"]/, name: "Google API Key" },
225
+ ];
226
+ for (let i = 0; i < lines.length; i++) {
227
+ for (const { pattern, name } of secretPatterns) {
228
+ if (pattern.test(lines[i])) {
229
+ violations.push({
230
+ rule: `Hardcoded Secret: ${name}`,
231
+ severity: "HIGH",
232
+ filePath,
233
+ line: i + 1,
234
+ detail: `Potential ${name} hardcoded at line ${i + 1}`,
235
+ regenerateInstruction: `Use environment variables (process.env.*) instead of hardcoding ${name}.`,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ // If violations found, prepare snapshot and rollback
241
+ if (violations.length > 0) {
242
+ AutoRollback.prepareWrite(filePath, traceId);
243
+ const rolledBack = AutoRollback.validateAndRollback(filePath, content, violations);
244
+ const instruction = AutoRollback.buildRegenerateInstruction(violations, "write_file");
245
+ return {
246
+ allowed: false,
247
+ violations: rolledBack || violations,
248
+ instruction,
249
+ };
250
+ }
251
+ return { allowed: true, violations: [], instruction: null };
252
+ }
253
+ /**
254
+ * Get snapshot stats.
255
+ */
256
+ static getSnapshotStats() {
257
+ const all = AutoRollback.snapshots.getAll();
258
+ return {
259
+ total: all.length,
260
+ restored: all.filter(s => s.restored).length,
261
+ pending: all.filter(s => !s.restored).length,
262
+ };
263
+ }
264
+ }
265
+ export { AutoRollback as AutoRollbackEngine };
@@ -53,7 +53,14 @@ export function verifyCorporateCompliance(content, filePath) {
53
53
  }
54
54
  // 5. Secure CLI Policy (No direct child_process)
55
55
  if (moduleSpecifier.text === "child_process") {
56
- errors.push(`[ERROR] Corporate Compliance Breach: Direct 'child_process' usage is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}. Use secure framework APIs.`);
56
+ const isExempt = filePath.includes("src/cli/commands/") ||
57
+ filePath.includes("shared/fs.ts") ||
58
+ filePath.includes("shared/lock.ts") ||
59
+ filePath.includes("quality-gate.ts") ||
60
+ filePath.includes("providers/shared.ts");
61
+ if (!isExempt) {
62
+ errors.push(`[ERROR] Corporate Compliance Breach: Direct 'child_process' usage is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}. Use secure framework APIs.`);
63
+ }
57
64
  }
58
65
  }
59
66
  }
@@ -75,10 +82,11 @@ export function verifyCorporateCompliance(content, filePath) {
75
82
  const prop = node.expression;
76
83
  if (ts.isIdentifier(prop.expression) && prop.expression.text === "fs") {
77
84
  if (["writeFileSync", "appendFileSync"].includes(prop.name.text)) {
78
- // Lock files are exempt
85
+ // Lock files, core atomic fs wrapper, and mcp configs are exempt
79
86
  const args = node.arguments;
80
87
  const firstArgText = args.length > 0 ? args[0].getText(sourceFile).toLowerCase() : "";
81
- if (!firstArgText.includes("lock")) {
88
+ const isExemptFile = filePath.includes("shared/fs.ts") || filePath.includes("src/cli/commands/mcp.ts");
89
+ if (!firstArgText.includes("lock") && !isExemptFile) {
82
90
  errors.push(`[ERROR] Corporate Compliance Breach: Raw 'fs.${prop.name.text}' mutation detected at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}. Use atomic utilities instead.`);
83
91
  }
84
92
  }
@@ -118,7 +126,7 @@ export function scanProjectCompliance(targetDir = "src") {
118
126
  const files = getAllFiles(targetDir);
119
127
  for (const file of files) {
120
128
  // Skip exempt files
121
- if (file.includes("compliance") || file.includes("definitions") || file.includes("logger") || file.includes("cli/index.ts"))
129
+ if (file.includes("compliance") || file.includes("definitions") || file.includes("logger") || file.includes("cli/index.ts") || file.includes("shared/fs.ts") || file.includes("shared/lock.ts"))
122
130
  continue;
123
131
  const content = fs.readFileSync(file, "utf8");
124
132
  try {
@@ -0,0 +1,156 @@
1
+ /**
2
+ * ─── CONTEXT OPTIMIZER ─────────────────────────────────────────────
3
+ *
4
+ * Prevents context poisoning and runaway token consumption by AI CLIs.
5
+ * Acts as a Circuit Breaker at the MCP middleware layer.
6
+ *
7
+ * Features:
8
+ * - Token Budget Enforcer: Max tokens per tool call response
9
+ * - File Read Limiter: Auto-truncate large file reads
10
+ * - Token-Based Rate Limiter: Max token spend per window
11
+ * - Response Size Governor: Truncates oversized responses
12
+ *
13
+ * [KVKK/GDPR] Also prevents PII leakage via oversized responses.
14
+ */
15
+ // ─── Configuration ────────────────────────────────────────────────
16
+ const CONFIG = {
17
+ /** Max tokens allowed in a single tool response */
18
+ MAX_TOKENS_PER_CALL: parseInt(process.env.MCP_MAX_TOKENS_PER_CALL || "4000", 10),
19
+ /** Max tokens per minute across all calls for an agent */
20
+ MAX_TOKENS_PER_MINUTE: parseInt(process.env.MCP_MAX_TOKENS_PER_MINUTE || "20000", 10),
21
+ /** Max tokens per hour across all calls for an agent */
22
+ MAX_TOKENS_PER_HOUR: parseInt(process.env.MCP_MAX_TOKENS_PER_HOUR || "100000", 10),
23
+ /** Max file size in bytes before auto-truncation (100KB) */
24
+ MAX_FILE_READ_SIZE: parseInt(process.env.MCP_MAX_FILE_READ_SIZE || "102400", 10),
25
+ /** Max lines to return for truncated files */
26
+ MAX_FILE_LINES: parseInt(process.env.MCP_MAX_FILE_LINES || "200", 10),
27
+ /** Token estimation ratio (chars per token) */
28
+ CHARS_PER_TOKEN: 4,
29
+ };
30
+ const agentBudgets = new Map();
31
+ function getOrCreateBudget(agent) {
32
+ if (!agentBudgets.has(agent)) {
33
+ agentBudgets.set(agent, {
34
+ records: [],
35
+ totalTokens: 0,
36
+ lastWarning: 0,
37
+ blockedUntil: null,
38
+ });
39
+ }
40
+ return agentBudgets.get(agent);
41
+ }
42
+ function pruneOldRecords(agent) {
43
+ const oneHourAgo = Date.now() - 3600000;
44
+ agent.records = agent.records.filter(r => r.timestamp > oneHourAgo);
45
+ }
46
+ function sumTokensInWindow(agent, windowMs) {
47
+ const cutoff = Date.now() - windowMs;
48
+ return agent.records
49
+ .filter(r => r.timestamp > cutoff)
50
+ .reduce((sum, r) => sum + r.tokens, 0);
51
+ }
52
+ /**
53
+ * Estimate token count from text.
54
+ * Uses 4 chars per token as a conservative estimate.
55
+ */
56
+ export function estimateTokens(text) {
57
+ if (!text)
58
+ return 0;
59
+ return Math.ceil(text.length / CONFIG.CHARS_PER_TOKEN);
60
+ }
61
+ /**
62
+ * Check if a tool response is within token budget.
63
+ * Returns null if allowed, or an error message if blocked.
64
+ */
65
+ export function checkTokenBudget(agent, toolName, responseText) {
66
+ const budget = getOrCreateBudget(agent);
67
+ // Check if agent is currently blocked
68
+ if (budget.blockedUntil && Date.now() < budget.blockedUntil) {
69
+ const remaining = Math.ceil((budget.blockedUntil - Date.now()) / 1000);
70
+ return `[TOKEN BUDGET] Agent ${agent} is blocked for ${remaining}s. Token limit exceeded.`;
71
+ }
72
+ const estimatedTokens = estimateTokens(responseText);
73
+ // 1. Check per-call limit
74
+ if (estimatedTokens > CONFIG.MAX_TOKENS_PER_CALL) {
75
+ return `[TOKEN BUDGET] Response too large: ~${estimatedTokens} tokens (max: ${CONFIG.MAX_TOKENS_PER_CALL}). Truncate your request.`;
76
+ }
77
+ // Record the token usage
78
+ budget.records.push({
79
+ tokens: estimatedTokens,
80
+ timestamp: Date.now(),
81
+ toolName,
82
+ });
83
+ budget.totalTokens += estimatedTokens;
84
+ // Prune old records
85
+ pruneOldRecords(budget);
86
+ // 2. Check per-minute limit
87
+ const minuteTokens = sumTokensInWindow(budget, 60000);
88
+ if (minuteTokens > CONFIG.MAX_TOKENS_PER_MINUTE) {
89
+ budget.blockedUntil = Date.now() + 30000; // 30s cooldown
90
+ return `[TOKEN BUDGET] Agent ${agent} exceeded ${CONFIG.MAX_TOKENS_PER_MINUTE} tokens/min. Cooldown 30s.`;
91
+ }
92
+ // 3. Check per-hour limit
93
+ const hourTokens = sumTokensInWindow(budget, 3600000);
94
+ if (hourTokens > CONFIG.MAX_TOKENS_PER_HOUR) {
95
+ budget.blockedUntil = Date.now() + 120000; // 2min cooldown
96
+ return `[TOKEN BUDGET] Agent ${agent} exceeded ${CONFIG.MAX_TOKENS_PER_HOUR} tokens/hour. Cooldown 2min.`;
97
+ }
98
+ // 4. Warning at 80% of per-minute limit
99
+ if (minuteTokens > CONFIG.MAX_TOKENS_PER_MINUTE * 0.8) {
100
+ const now = Date.now();
101
+ if (now - budget.lastWarning > 10000) { // Throttle warnings to once per 10s
102
+ budget.lastWarning = now;
103
+ process.stderr.write(`[TOKEN BUDGET WARNING] Agent ${agent} at ${Math.round(minuteTokens / CONFIG.MAX_TOKENS_PER_MINUTE * 100)}% of minute token budget.\n`);
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ /**
109
+ * Truncate file content to fit within token budget.
110
+ * Returns truncated content with a header note.
111
+ */
112
+ export function truncateFileContent(content, filePath, maxTokens = CONFIG.MAX_TOKENS_PER_CALL) {
113
+ const estimatedTokens = estimateTokens(content);
114
+ if (estimatedTokens <= maxTokens)
115
+ return content;
116
+ const lines = content.split("\n");
117
+ const maxLines = Math.min(CONFIG.MAX_FILE_LINES, Math.floor(maxTokens * CONFIG.CHARS_PER_TOKEN / 80));
118
+ const truncated = lines.slice(0, maxLines).join("\n");
119
+ const remaining = lines.length - maxLines;
120
+ return `[TRUNCATED] File "${filePath}" is too large (~${estimatedTokens} tokens). Showing first ${maxLines}/${lines.length} lines.\n\n${truncated}\n\n[... ${remaining} more lines truncated. Use grep_search for targeted queries.]`;
121
+ }
122
+ /**
123
+ * Get token budget stats for an agent.
124
+ */
125
+ export function getTokenBudgetStats(agent) {
126
+ const budget = agentBudgets.get(agent);
127
+ if (!budget) {
128
+ return { totalTokens: 0, recentMinute: 0, recentHour: 0, blocked: false, blockedRemaining: 0, callCount: 0 };
129
+ }
130
+ pruneOldRecords(budget);
131
+ return {
132
+ totalTokens: budget.totalTokens,
133
+ recentMinute: sumTokensInWindow(budget, 60000),
134
+ recentHour: sumTokensInWindow(budget, 3600000),
135
+ blocked: budget.blockedUntil !== null && Date.now() < budget.blockedUntil,
136
+ blockedRemaining: budget.blockedUntil ? Math.max(0, budget.blockedUntil - Date.now()) : 0,
137
+ callCount: budget.records.length,
138
+ };
139
+ }
140
+ /**
141
+ * Get all agents' token budget stats.
142
+ */
143
+ export function getAllTokenBudgetStats() {
144
+ const stats = {};
145
+ for (const [agent] of agentBudgets) {
146
+ stats[agent] = getTokenBudgetStats(agent);
147
+ }
148
+ return stats;
149
+ }
150
+ /**
151
+ * Reset all token budgets.
152
+ */
153
+ export function resetTokenBudgets() {
154
+ agentBudgets.clear();
155
+ }
156
+ export { CONFIG as TokenBudgetConfig };
@@ -0,0 +1,217 @@
1
+ /**
2
+ * ─── AI DISCIPLINE ENGINE ─────────────────────────────────────────
3
+ *
4
+ * Enforces strict rules on AI behavior at the MCP middleware layer.
5
+ * Unlike agent instructions (which AI can ignore), these are enforced
6
+ * at the tool level - AI cannot bypass them.
7
+ *
8
+ * Features:
9
+ * - Tool call rate limiting (prevents abuse)
10
+ * - File size limits (prevents reading/writing huge files)
11
+ * - Call frequency tracking (detects loops)
12
+ * - Tool blacklist per agent
13
+ * - Agent-based tool whitelist
14
+ * - Response content validation
15
+ * - Max concurrent operations
16
+ */
17
+ import fs from "fs";
18
+ import path from "path";
19
+ // Per-agent discipline tracking
20
+ const agentDiscipline = new Map();
21
+ // ─── Configuration (from env or defaults) ─────────────────────────
22
+ const CONFIG = {
23
+ MAX_CALLS_PER_MINUTE: parseInt(process.env.MCP_MAX_CALLS_PER_MINUTE || "60", 10),
24
+ MAX_TOTAL_CALLS: parseInt(process.env.MCP_MAX_TOTAL_CALLS || "500", 10),
25
+ MAX_FILE_SIZE: parseInt(process.env.MCP_MAX_FILE_SIZE || "1048576", 10),
26
+ MAX_ARGS_SIZE: parseInt(process.env.MCP_MAX_ARGS_SIZE || "102400", 10),
27
+ COOLDOWN_MS: parseInt(process.env.MCP_COOLDOWN_MS || "30000", 10),
28
+ MAX_RESPONSE_SIZE: parseInt(process.env.MCP_MAX_RESPONSE_SIZE || "512000", 10), // 500KB max response
29
+ MAX_CONSECUTIVE_SAME_TOOL: parseInt(process.env.MCP_MAX_CONSECUTIVE_SAME_TOOL || "10", 10),
30
+ RESTRICTED_TOOLS: (process.env.MCP_RESTRICTED_TOOLS || "")
31
+ .split(",").map(t => t.trim()).filter(Boolean),
32
+ // Agent-based tool whitelist (format: agent1:tool1,tool2;agent2:tool3,tool4)
33
+ AGENT_TOOL_WHITELIST: parseAgentWhitelist(process.env.MCP_AGENT_TOOL_WHITELIST || ""),
34
+ };
35
+ function parseAgentWhitelist(input) {
36
+ const map = new Map();
37
+ if (!input)
38
+ return map;
39
+ input.split(";").forEach(pair => {
40
+ const [agent, tools] = pair.split(":");
41
+ if (agent && tools) {
42
+ map.set(agent.trim(), new Set(tools.split(",").map(t => t.trim())));
43
+ }
44
+ });
45
+ return map;
46
+ }
47
+ const cooldowns = new Map();
48
+ function getOrCreateAgent(agent) {
49
+ if (!agentDiscipline.has(agent)) {
50
+ const whitelist = CONFIG.AGENT_TOOL_WHITELIST.get(agent) || null;
51
+ agentDiscipline.set(agent, {
52
+ totalCalls: 0,
53
+ calls: [],
54
+ lastReset: Date.now(),
55
+ blacklistedTools: new Set(),
56
+ whitelistedTools: whitelist,
57
+ violations: 0,
58
+ lastViolation: null,
59
+ });
60
+ }
61
+ return agentDiscipline.get(agent);
62
+ }
63
+ function pruneOldCalls(agent, windowMs = 60000) {
64
+ const cutoff = Date.now() - windowMs;
65
+ agent.calls = agent.calls.filter(c => c.timestamp > cutoff);
66
+ }
67
+ function isInCooldown(agent) {
68
+ const until = cooldowns.get(agent);
69
+ if (!until)
70
+ return false;
71
+ if (Date.now() > until) {
72
+ cooldowns.delete(agent);
73
+ return false;
74
+ }
75
+ return true;
76
+ }
77
+ function recordViolation(agent, reason) {
78
+ const discipline = agentDiscipline.get(agent);
79
+ if (discipline) {
80
+ discipline.violations++;
81
+ discipline.lastViolation = reason;
82
+ }
83
+ }
84
+ /**
85
+ * Enforce discipline on a tool call before execution.
86
+ * Returns error message if blocked, null if allowed.
87
+ */
88
+ export async function enforceDiscipline(agent, toolName, args) {
89
+ const discipline = getOrCreateAgent(agent);
90
+ // 1. Check cooldown
91
+ if (isInCooldown(agent)) {
92
+ const until = cooldowns.get(agent);
93
+ const remaining = Math.ceil((until - Date.now()) / 1000);
94
+ return `[DISCIPLINE] Agent ${agent} is in cooldown for ${remaining}s. Too many requests.`;
95
+ }
96
+ // 2. Check restricted tools (global blacklist)
97
+ if (CONFIG.RESTRICTED_TOOLS.includes(toolName)) {
98
+ recordViolation(agent, `Attempted to use restricted tool: ${toolName}`);
99
+ return `[DISCIPLINE] Tool "${toolName}" is restricted. Agent ${agent} cannot use it.`;
100
+ }
101
+ // 3. Check agent-specific whitelist
102
+ if (discipline.whitelistedTools && !discipline.whitelistedTools.has(toolName)) {
103
+ recordViolation(agent, `Attempted to use non-whitelisted tool: ${toolName}`);
104
+ const allowed = Array.from(discipline.whitelistedTools).join(", ");
105
+ return `[DISCIPLINE] Agent ${agent} is not allowed to use "${toolName}". Allowed tools: ${allowed}`;
106
+ }
107
+ // 4. Check total call limit
108
+ if (discipline.totalCalls >= CONFIG.MAX_TOTAL_CALLS) {
109
+ cooldowns.set(agent, Date.now() + CONFIG.COOLDOWN_MS);
110
+ recordViolation(agent, `Exceeded max total calls (${CONFIG.MAX_TOTAL_CALLS})`);
111
+ return `[DISCIPLINE] Agent ${agent} exceeded max total calls (${CONFIG.MAX_TOTAL_CALLS}). Cooldown ${CONFIG.COOLDOWN_MS / 1000}s.`;
112
+ }
113
+ // 5. Check rate limit (calls per minute)
114
+ pruneOldCalls(discipline);
115
+ if (discipline.calls.length >= CONFIG.MAX_CALLS_PER_MINUTE) {
116
+ cooldowns.set(agent, Date.now() + CONFIG.COOLDOWN_MS);
117
+ recordViolation(agent, `Rate limit exceeded (${CONFIG.MAX_CALLS_PER_MINUTE}/min)`);
118
+ return `[DISCIPLINE] Agent ${agent} exceeded rate limit (${CONFIG.MAX_CALLS_PER_MINUTE}/min). Cooldown ${CONFIG.COOLDOWN_MS / 1000}s.`;
119
+ }
120
+ // 6. Check consecutive same tool (prevents loops)
121
+ if (discipline.calls.length >= CONFIG.MAX_CONSECUTIVE_SAME_TOOL) {
122
+ const lastCalls = discipline.calls.slice(-CONFIG.MAX_CONSECUTIVE_SAME_TOOL);
123
+ const allSame = lastCalls.every(c => c.tool === toolName);
124
+ if (allSame) {
125
+ cooldowns.set(agent, Date.now() + CONFIG.COOLDOWN_MS);
126
+ recordViolation(agent, `Consecutive same tool limit: ${toolName} x${CONFIG.MAX_CONSECUTIVE_SAME_TOOL}`);
127
+ return `[DISCIPLINE] Agent ${agent} called "${toolName}" ${CONFIG.MAX_CONSECUTIVE_SAME_TOOL} times in a row. Possible loop. Cooldown.`;
128
+ }
129
+ }
130
+ // 7. Check args size
131
+ const argsStr = JSON.stringify(args);
132
+ if (argsStr.length > CONFIG.MAX_ARGS_SIZE) {
133
+ recordViolation(agent, `Args too large: ${argsStr.length} bytes`);
134
+ return `[DISCIPLINE] Tool call args too large (${argsStr.length} bytes, max: ${CONFIG.MAX_ARGS_SIZE}).`;
135
+ }
136
+ // 8. Check file size for read/write operations
137
+ if ((toolName === "read_file" || toolName === "write_file") && args.path) {
138
+ try {
139
+ const projectRoot = process.env.ATABEY_PROJECT_ROOT || process.cwd();
140
+ const filePath = path.resolve(projectRoot, args.path);
141
+ if (fs.existsSync(filePath)) {
142
+ const stat = fs.statSync(filePath);
143
+ if (stat.size > CONFIG.MAX_FILE_SIZE) {
144
+ return `[DISCIPLINE] File too large (${(stat.size / 1024 / 1024).toFixed(1)}MB, max: ${(CONFIG.MAX_FILE_SIZE / 1024 / 1024).toFixed(1)}MB). Use grep_search instead.`;
145
+ }
146
+ }
147
+ }
148
+ catch { /* ignore */ }
149
+ }
150
+ // Record the call
151
+ discipline.totalCalls++;
152
+ discipline.calls.push({
153
+ tool: toolName,
154
+ timestamp: Date.now(),
155
+ argsSize: argsStr.length,
156
+ });
157
+ return null;
158
+ }
159
+ /**
160
+ * Validate tool response content before returning to AI.
161
+ * Returns error message if blocked, null if allowed.
162
+ */
163
+ export function validateResponse(toolName, result) {
164
+ if (!result || !result.content)
165
+ return null;
166
+ for (const block of result.content) {
167
+ if (block.type !== "text" || !block.text)
168
+ continue;
169
+ // Check response size
170
+ if (block.text.length > CONFIG.MAX_RESPONSE_SIZE) {
171
+ return `[DISCIPLINE] Response too large (${(block.text.length / 1024).toFixed(1)}KB, max: ${(CONFIG.MAX_RESPONSE_SIZE / 1024).toFixed(1)}KB).`;
172
+ }
173
+ // Block binary/gibberish content in text responses
174
+ const nonPrintable = (block.text.match(/[^\x20-\x7E\n\r\t]/g) || []).length;
175
+ if (nonPrintable > block.text.length * 0.3) {
176
+ return `[DISCIPLINE] Response contains too much binary data (${nonPrintable} non-printable chars). Blocked.`;
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ /**
182
+ * Get discipline stats for an agent.
183
+ */
184
+ export function getDisciplineStats(agent) {
185
+ const discipline = agentDiscipline.get(agent);
186
+ if (!discipline) {
187
+ return { totalCalls: 0, recentCalls: 0, inCooldown: false, cooldownRemaining: 0, violations: 0, lastViolation: null };
188
+ }
189
+ pruneOldCalls(discipline);
190
+ const cooldownUntil = cooldowns.get(agent);
191
+ return {
192
+ totalCalls: discipline.totalCalls,
193
+ recentCalls: discipline.calls.length,
194
+ inCooldown: isInCooldown(agent),
195
+ cooldownRemaining: cooldownUntil ? Math.max(0, cooldownUntil - Date.now()) : 0,
196
+ violations: discipline.violations,
197
+ lastViolation: discipline.lastViolation,
198
+ };
199
+ }
200
+ /**
201
+ * Get all agents' discipline stats.
202
+ */
203
+ export function getAllDisciplineStats() {
204
+ const stats = {};
205
+ for (const [agent, _discipline] of agentDiscipline) {
206
+ stats[agent] = getDisciplineStats(agent);
207
+ }
208
+ return stats;
209
+ }
210
+ /**
211
+ * Reset discipline for all agents.
212
+ */
213
+ export function resetDiscipline() {
214
+ agentDiscipline.clear();
215
+ cooldowns.clear();
216
+ }
217
+ export { CONFIG as DisciplineConfig };