atabey 0.0.13 → 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 (271) hide show
  1. package/ATABEY.md +1 -1
  2. package/README.md +252 -52
  3. package/dist/framework-mcp/src/index.js +914 -62
  4. package/dist/framework-mcp/src/index.js.map +1 -1
  5. package/dist/framework-mcp/src/tools/compliance/mask_pii.d.ts +17 -0
  6. package/dist/framework-mcp/src/tools/compliance/mask_pii.js +56 -0
  7. package/dist/framework-mcp/src/tools/compliance/mask_pii.js.map +1 -0
  8. package/dist/framework-mcp/src/tools/definitions.js +10 -9
  9. package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
  10. package/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
  11. package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -1
  12. package/dist/framework-mcp/src/tools/index.js +7 -8
  13. package/dist/framework-mcp/src/tools/index.js.map +1 -1
  14. package/dist/framework-mcp/src/tools/messaging/approve_operation.d.ts +22 -0
  15. package/dist/framework-mcp/src/tools/messaging/approve_operation.js +81 -0
  16. package/dist/framework-mcp/src/tools/messaging/approve_operation.js.map +1 -0
  17. package/dist/framework-mcp/src/tools/messaging/ask_human.d.ts +15 -0
  18. package/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
  19. package/dist/framework-mcp/src/tools/messaging/ask_human.js.map +1 -1
  20. package/dist/framework-mcp/src/tools/observability/check_ports.js +3 -1
  21. package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -1
  22. package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
  23. package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js.map +1 -1
  24. package/dist/framework-mcp/src/tools/schemas.d.ts +48 -53
  25. package/dist/framework-mcp/src/tools/schemas.js +18 -22
  26. package/dist/framework-mcp/src/tools/schemas.js.map +1 -1
  27. package/dist/framework-mcp/src/tools/shell/run_command.js +10 -0
  28. package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -1
  29. package/dist/framework-mcp/src/tools/types.d.ts +11 -105
  30. package/dist/framework-mcp/src/tools/types.js +1 -0
  31. package/dist/framework-mcp/src/tools/types.js.map +1 -1
  32. package/dist/framework-mcp/src/utils/auth.d.ts +36 -0
  33. package/dist/framework-mcp/src/utils/auth.js +79 -0
  34. package/dist/framework-mcp/src/utils/auth.js.map +1 -0
  35. package/dist/framework-mcp/src/utils/auto-rollback.d.ts +71 -0
  36. package/dist/framework-mcp/src/utils/auto-rollback.js +266 -0
  37. package/dist/framework-mcp/src/utils/auto-rollback.js.map +1 -0
  38. package/dist/framework-mcp/src/utils/compliance.js +12 -4
  39. package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
  40. package/dist/framework-mcp/src/utils/context-optimizer.d.ts +69 -0
  41. package/dist/framework-mcp/src/utils/context-optimizer.js +157 -0
  42. package/dist/framework-mcp/src/utils/context-optimizer.js.map +1 -0
  43. package/dist/framework-mcp/src/utils/discipline.d.ts +68 -0
  44. package/dist/framework-mcp/src/utils/discipline.js +218 -0
  45. package/dist/framework-mcp/src/utils/discipline.js.map +1 -0
  46. package/dist/framework-mcp/src/utils/finops.d.ts +143 -0
  47. package/dist/framework-mcp/src/utils/finops.js +326 -0
  48. package/dist/framework-mcp/src/utils/finops.js.map +1 -0
  49. package/dist/framework-mcp/src/utils/human-in-loop.d.ts +95 -0
  50. package/dist/framework-mcp/src/utils/human-in-loop.js +216 -0
  51. package/dist/framework-mcp/src/utils/human-in-loop.js.map +1 -0
  52. package/dist/framework-mcp/src/utils/license-scanner.d.ts +71 -0
  53. package/dist/framework-mcp/src/utils/license-scanner.js +284 -0
  54. package/dist/framework-mcp/src/utils/license-scanner.js.map +1 -0
  55. package/dist/framework-mcp/src/utils/loop-detector.d.ts +105 -0
  56. package/dist/framework-mcp/src/utils/loop-detector.js +362 -0
  57. package/dist/framework-mcp/src/utils/loop-detector.js.map +1 -0
  58. package/dist/framework-mcp/src/utils/quality.d.ts +19 -0
  59. package/dist/framework-mcp/src/utils/quality.js +124 -0
  60. package/dist/framework-mcp/src/utils/quality.js.map +1 -0
  61. package/dist/framework-mcp/src/utils/rules-engine.d.ts +78 -0
  62. package/dist/framework-mcp/src/utils/rules-engine.js +232 -0
  63. package/dist/framework-mcp/src/utils/rules-engine.js.map +1 -0
  64. package/dist/framework-mcp/src/utils/silent-router.d.ts +47 -0
  65. package/dist/framework-mcp/src/utils/silent-router.js +129 -0
  66. package/dist/framework-mcp/src/utils/silent-router.js.map +1 -0
  67. package/dist/framework-mcp/src/utils/storage.d.ts +1 -0
  68. package/dist/framework-mcp/src/utils/storage.js +2 -2
  69. package/dist/framework-mcp/src/utils/storage.js.map +1 -1
  70. package/dist/framework-mcp/src/utils/telemetry-streamer.d.ts +133 -0
  71. package/dist/framework-mcp/src/utils/telemetry-streamer.js +397 -0
  72. package/dist/framework-mcp/src/utils/telemetry-streamer.js.map +1 -0
  73. package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js +2 -2
  74. package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js.map +1 -1
  75. package/dist/framework-mcp/tests/tools/framework/run_tests.test.d.ts +1 -0
  76. package/dist/framework-mcp/tests/tools/framework/run_tests.test.js +49 -0
  77. package/dist/framework-mcp/tests/tools/framework/run_tests.test.js.map +1 -0
  78. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +14 -5
  79. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
  80. package/dist/framework-mcp/tests/tools/observability/check_ports.test.d.ts +1 -0
  81. package/dist/framework-mcp/tests/tools/observability/check_ports.test.js +30 -0
  82. package/dist/framework-mcp/tests/tools/observability/check_ports.test.js.map +1 -0
  83. package/dist/framework-mcp/tests/tools/shell/run_command.test.js +7 -0
  84. package/dist/framework-mcp/tests/tools/shell/run_command.test.js.map +1 -1
  85. package/dist/framework-mcp/tests/utils/auto-rollback.test.d.ts +7 -0
  86. package/dist/framework-mcp/tests/utils/auto-rollback.test.js +178 -0
  87. package/dist/framework-mcp/tests/utils/auto-rollback.test.js.map +1 -0
  88. package/dist/framework-mcp/tests/utils/context-optimizer.test.d.ts +1 -0
  89. package/dist/framework-mcp/tests/utils/context-optimizer.test.js +62 -0
  90. package/dist/framework-mcp/tests/utils/context-optimizer.test.js.map +1 -0
  91. package/dist/framework-mcp/tests/utils/finops.test.d.ts +7 -0
  92. package/dist/framework-mcp/tests/utils/finops.test.js +157 -0
  93. package/dist/framework-mcp/tests/utils/finops.test.js.map +1 -0
  94. package/dist/framework-mcp/tests/utils/human-in-loop.test.d.ts +1 -0
  95. package/dist/framework-mcp/tests/utils/human-in-loop.test.js +59 -0
  96. package/dist/framework-mcp/tests/utils/human-in-loop.test.js.map +1 -0
  97. package/dist/framework-mcp/tests/utils/license-scanner.test.d.ts +7 -0
  98. package/dist/framework-mcp/tests/utils/license-scanner.test.js +131 -0
  99. package/dist/framework-mcp/tests/utils/license-scanner.test.js.map +1 -0
  100. package/dist/framework-mcp/tests/utils/loop-detector.test.d.ts +7 -0
  101. package/dist/framework-mcp/tests/utils/loop-detector.test.js +204 -0
  102. package/dist/framework-mcp/tests/utils/loop-detector.test.js.map +1 -0
  103. package/dist/framework-mcp/tests/utils/rules-engine.test.d.ts +1 -0
  104. package/dist/framework-mcp/tests/utils/rules-engine.test.js +106 -0
  105. package/dist/framework-mcp/tests/utils/rules-engine.test.js.map +1 -0
  106. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.d.ts +7 -0
  107. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js +201 -0
  108. package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js.map +1 -0
  109. package/dist/src/cli/commands/check.js +16 -1
  110. package/dist/src/cli/commands/check.js.map +1 -1
  111. package/dist/src/cli/commands/dashboard.js +188 -164
  112. package/dist/src/cli/commands/dashboard.js.map +1 -1
  113. package/dist/src/cli/commands/gateway.js +2 -2
  114. package/dist/src/cli/commands/gateway.js.map +1 -1
  115. package/dist/src/cli/commands/init/scaffold-core.d.ts +2 -0
  116. package/dist/src/cli/commands/init/scaffold-core.js +16 -1
  117. package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
  118. package/dist/src/cli/commands/init/scaffold-ops.js +2 -2
  119. package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
  120. package/dist/src/cli/commands/init/scaffold-standards.js +13 -1
  121. package/dist/src/cli/commands/init/scaffold-standards.js.map +1 -1
  122. package/dist/src/cli/commands/init.d.ts +4 -0
  123. package/dist/src/cli/commands/init.js +80 -24
  124. package/dist/src/cli/commands/init.js.map +1 -1
  125. package/dist/src/cli/commands/quickstart.d.ts +1 -1
  126. package/dist/src/cli/commands/quickstart.js +12 -24
  127. package/dist/src/cli/commands/quickstart.js.map +1 -1
  128. package/dist/src/cli/index.js +24 -23
  129. package/dist/src/cli/index.js.map +1 -1
  130. package/dist/src/cli/shims.js +7 -7
  131. package/dist/src/cli/utils/pkg.js +2 -3
  132. package/dist/src/cli/utils/pkg.js.map +1 -1
  133. package/dist/src/cli/utils/quality.d.ts +10 -0
  134. package/dist/src/cli/utils/quality.js +10 -0
  135. package/dist/src/cli/utils/quality.js.map +1 -0
  136. package/dist/src/modules/agents/definitions.js +45 -40
  137. package/dist/src/modules/agents/definitions.js.map +1 -1
  138. package/dist/src/modules/agents/registry/manager.js +6 -1
  139. package/dist/src/modules/agents/registry/manager.js.map +1 -1
  140. package/dist/src/modules/engines/agent-executor.d.ts +6 -10
  141. package/dist/src/modules/engines/agent-executor.js +53 -21
  142. package/dist/src/modules/engines/agent-executor.js.map +1 -1
  143. package/dist/src/modules/engines/agent-loop.d.ts +34 -0
  144. package/dist/src/modules/engines/agent-loop.js +102 -0
  145. package/dist/src/modules/engines/agent-loop.js.map +1 -0
  146. package/dist/src/modules/engines/evaluation-engine.js +2 -2
  147. package/dist/src/modules/engines/evaluation-engine.js.map +1 -1
  148. package/dist/src/modules/engines/quality-gate.d.ts +13 -5
  149. package/dist/src/modules/engines/quality-gate.js +39 -31
  150. package/dist/src/modules/engines/quality-gate.js.map +1 -1
  151. package/dist/src/modules/engines/routing-engine.d.ts +5 -3
  152. package/dist/src/modules/engines/routing-engine.js +16 -9
  153. package/dist/src/modules/engines/routing-engine.js.map +1 -1
  154. package/dist/src/modules/gateway/cost-tracker.d.ts +5 -0
  155. package/dist/src/modules/gateway/cost-tracker.js +71 -0
  156. package/dist/src/modules/gateway/cost-tracker.js.map +1 -1
  157. package/dist/src/modules/gateway/gateway.d.ts +4 -0
  158. package/dist/src/modules/gateway/gateway.js +8 -0
  159. package/dist/src/modules/gateway/gateway.js.map +1 -1
  160. package/dist/src/shared/audit.js +3 -2
  161. package/dist/src/shared/audit.js.map +1 -1
  162. package/dist/src/shared/pii.d.ts +41 -9
  163. package/dist/src/shared/pii.js +122 -31
  164. package/dist/src/shared/pii.js.map +1 -1
  165. package/dist/src/shared/storage.d.ts +19 -0
  166. package/dist/src/shared/storage.js +46 -6
  167. package/dist/src/shared/storage.js.map +1 -1
  168. package/dist/tests/embedding.test.d.ts +1 -0
  169. package/dist/tests/embedding.test.js +82 -0
  170. package/dist/tests/embedding.test.js.map +1 -0
  171. package/dist/tests/engines/evaluation-engine.test.d.ts +1 -0
  172. package/dist/tests/engines/evaluation-engine.test.js +71 -0
  173. package/dist/tests/engines/evaluation-engine.test.js.map +1 -0
  174. package/dist/tests/engines/planning-engine.test.d.ts +1 -0
  175. package/dist/tests/engines/planning-engine.test.js +100 -0
  176. package/dist/tests/engines/planning-engine.test.js.map +1 -0
  177. package/dist/tests/engines/quality-gate.test.d.ts +1 -0
  178. package/dist/tests/engines/quality-gate.test.js +59 -0
  179. package/dist/tests/engines/quality-gate.test.js.map +1 -0
  180. package/dist/tests/engines/risk-engine.test.d.ts +1 -0
  181. package/dist/tests/engines/risk-engine.test.js +80 -0
  182. package/dist/tests/engines/risk-engine.test.js.map +1 -0
  183. package/dist/tests/engines/routing-engine.test.d.ts +1 -0
  184. package/dist/tests/engines/routing-engine.test.js +78 -0
  185. package/dist/tests/engines/routing-engine.test.js.map +1 -0
  186. package/dist/tests/integration/hermes_locking.test.js +1 -0
  187. package/dist/tests/integration/hermes_locking.test.js.map +1 -1
  188. package/dist/tests/modules/gateway/cost-tracker.test.js +20 -1
  189. package/dist/tests/modules/gateway/cost-tracker.test.js.map +1 -1
  190. package/dist/tests/shared/lock.test.d.ts +1 -0
  191. package/dist/tests/shared/lock.test.js +95 -0
  192. package/dist/tests/shared/lock.test.js.map +1 -0
  193. package/dist/tests/shared/pii.test.d.ts +1 -0
  194. package/dist/tests/shared/pii.test.js +183 -0
  195. package/dist/tests/shared/pii.test.js.map +1 -0
  196. package/framework-mcp/README.md +307 -35
  197. package/framework-mcp/dist/dashboard/assets/index-B2mYld0c.js +1221 -0
  198. package/framework-mcp/dist/dashboard/index.html +1 -1
  199. package/framework-mcp/dist/framework-mcp/src/index.js +914 -62
  200. package/framework-mcp/dist/framework-mcp/src/tools/compliance/mask_pii.js +55 -0
  201. package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +10 -9
  202. package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
  203. package/framework-mcp/dist/framework-mcp/src/tools/index.js +7 -8
  204. package/framework-mcp/dist/framework-mcp/src/tools/messaging/approve_operation.js +80 -0
  205. package/framework-mcp/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
  206. package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +3 -1
  207. package/framework-mcp/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
  208. package/framework-mcp/dist/framework-mcp/src/tools/schemas.js +18 -22
  209. package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +10 -0
  210. package/framework-mcp/dist/framework-mcp/src/tools/types.js +1 -0
  211. package/framework-mcp/dist/framework-mcp/src/utils/auth.js +78 -0
  212. package/framework-mcp/dist/framework-mcp/src/utils/auto-rollback.js +265 -0
  213. package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +12 -4
  214. package/framework-mcp/dist/framework-mcp/src/utils/context-optimizer.js +156 -0
  215. package/framework-mcp/dist/framework-mcp/src/utils/discipline.js +217 -0
  216. package/framework-mcp/dist/framework-mcp/src/utils/finops.js +325 -0
  217. package/framework-mcp/dist/framework-mcp/src/utils/human-in-loop.js +215 -0
  218. package/framework-mcp/dist/framework-mcp/src/utils/license-scanner.js +283 -0
  219. package/framework-mcp/dist/framework-mcp/src/utils/loop-detector.js +361 -0
  220. package/framework-mcp/dist/framework-mcp/src/utils/quality.js +123 -0
  221. package/framework-mcp/dist/framework-mcp/src/utils/rules-engine.js +231 -0
  222. package/framework-mcp/dist/framework-mcp/src/utils/silent-router.js +128 -0
  223. package/framework-mcp/dist/framework-mcp/src/utils/storage.js +2 -2
  224. package/framework-mcp/dist/framework-mcp/src/utils/telemetry-streamer.js +396 -0
  225. package/framework-mcp/dist/src/cli/platforms/core.js +72 -0
  226. package/framework-mcp/dist/src/cli/platforms/index.js +5 -0
  227. package/framework-mcp/dist/src/cli/platforms/paths.js +101 -0
  228. package/framework-mcp/dist/src/cli/platforms/scaffold.js +72 -0
  229. package/framework-mcp/dist/src/cli/platforms/utils.js +75 -0
  230. package/framework-mcp/dist/src/cli/utils/claude.js +57 -0
  231. package/framework-mcp/dist/src/cli/utils/compliance.js +12 -0
  232. package/framework-mcp/dist/src/cli/utils/fs.js +138 -0
  233. package/framework-mcp/dist/src/cli/utils/pkg.js +282 -0
  234. package/framework-mcp/dist/src/cli/utils/quality.js +9 -0
  235. package/framework-mcp/dist/src/modules/agents/definitions.js +563 -0
  236. package/framework-mcp/dist/src/modules/agents/registry/analyst.js +39 -0
  237. package/framework-mcp/dist/src/modules/agents/registry/architect.js +42 -0
  238. package/framework-mcp/dist/src/modules/agents/registry/backend.js +50 -0
  239. package/framework-mcp/dist/src/modules/agents/registry/database.js +45 -0
  240. package/framework-mcp/dist/src/modules/agents/registry/devops.js +45 -0
  241. package/framework-mcp/dist/src/modules/agents/registry/explorer.js +37 -0
  242. package/framework-mcp/dist/src/modules/agents/registry/frontend.js +52 -0
  243. package/framework-mcp/dist/src/modules/agents/registry/git.js +36 -0
  244. package/framework-mcp/dist/src/modules/agents/registry/manager.js +64 -0
  245. package/framework-mcp/dist/src/modules/agents/registry/mobile.js +41 -0
  246. package/framework-mcp/dist/src/modules/agents/registry/native.js +41 -0
  247. package/framework-mcp/dist/src/modules/agents/registry/quality.js +43 -0
  248. package/framework-mcp/dist/src/modules/agents/registry/security.js +42 -0
  249. package/framework-mcp/dist/src/modules/agents/types.js +1 -0
  250. package/framework-mcp/dist/src/modules/engines/quality-gate.js +92 -0
  251. package/framework-mcp/dist/src/modules/engines/risk-engine.js +105 -0
  252. package/framework-mcp/dist/src/modules/engines/routing-engine.js +408 -0
  253. package/framework-mcp/dist/src/modules/engines/types.js +1 -0
  254. package/framework-mcp/dist/src/modules/providers/definitions.js +140 -0
  255. package/framework-mcp/dist/src/modules/providers/registry.js +18 -0
  256. package/framework-mcp/dist/src/modules/providers/shared.js +104 -0
  257. package/framework-mcp/dist/src/modules/providers/types.js +1 -0
  258. package/framework-mcp/dist/src/modules/skills/adapter-skills.js +449 -0
  259. package/framework-mcp/dist/src/modules/skills/definitions.js +70 -0
  260. package/framework-mcp/dist/src/shared/audit.js +220 -0
  261. package/framework-mcp/dist/src/shared/errors.js +68 -0
  262. package/framework-mcp/dist/src/shared/lock.js +159 -0
  263. package/framework-mcp/dist/src/shared/pii.js +122 -31
  264. package/framework-mcp/dist/src/shared/retention.js +170 -0
  265. package/framework-mcp/dist/src/shared/storage.js +46 -6
  266. package/framework-mcp/dist/src/shared/string.js +29 -0
  267. package/framework-mcp/package.json +8 -2
  268. package/mcp.json +11 -6
  269. package/package.json +13 -6
  270. package/templates/full/ATABEY_FULL.md +1 -1
  271. package/framework-mcp/dist/dashboard/assets/index-BAPGLiWE.js +0 -267
@@ -0,0 +1,78 @@
1
+ /**
2
+ * ─── MCP AUTHENTICATION ──────────────────────────────────────────
3
+ *
4
+ * Simple API key authentication for MCP server.
5
+ * When MCP_AUTH_TOKEN is set, all MCP and API requests require
6
+ * Authorization: Bearer <token> header.
7
+ *
8
+ * Environment Variables:
9
+ * MCP_AUTH_TOKEN - API key for authentication (optional)
10
+ * MCP_AUTH_USERS - Comma-separated list of user:token pairs (optional)
11
+ * Example: "alice:key1,bob:key2"
12
+ *
13
+ * If neither is set, authentication is disabled (open access).
14
+ */
15
+ let authUsers = [];
16
+ let masterToken = null;
17
+ /**
18
+ * Initialize authentication from environment variables.
19
+ */
20
+ export function initAuth() {
21
+ masterToken = process.env.MCP_AUTH_TOKEN || null;
22
+ const usersStr = process.env.MCP_AUTH_USERS || "";
23
+ if (usersStr) {
24
+ authUsers = usersStr.split(",").map(pair => {
25
+ const [name, token] = pair.split(":");
26
+ return { name: name?.trim() || "unknown", token: token?.trim() || "" };
27
+ }).filter(u => u.token);
28
+ }
29
+ if (masterToken) {
30
+ console.error(`[AUTH] Master token configured (${masterToken.length} chars)`);
31
+ }
32
+ if (authUsers.length > 0) {
33
+ console.error(`[AUTH] ${authUsers.length} user(s) configured: ${authUsers.map(u => u.name).join(", ")}`);
34
+ }
35
+ if (!masterToken && authUsers.length === 0) {
36
+ console.error("[AUTH] No authentication configured - OPEN ACCESS");
37
+ console.error("[AUTH] Set MCP_AUTH_TOKEN=<key> or MCP_AUTH_USERS=user1:key1,user2:key2 to enable");
38
+ }
39
+ }
40
+ /**
41
+ * Authenticate a request using the Authorization header.
42
+ * Returns the authenticated user name or null if unauthorized.
43
+ */
44
+ export function authenticate(req) {
45
+ if (!masterToken && authUsers.length === 0) {
46
+ // Auth disabled - allow all
47
+ return { authenticated: true, user: "anonymous" };
48
+ }
49
+ const authHeader = req.headers["authorization"];
50
+ if (!authHeader) {
51
+ return { authenticated: false, user: "" };
52
+ }
53
+ // Support both "Bearer <key>" and "<key>" formats
54
+ const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
55
+ // Check master token first
56
+ if (masterToken && token === masterToken) {
57
+ return { authenticated: true, user: "admin" };
58
+ }
59
+ // Check user tokens
60
+ for (const user of authUsers) {
61
+ if (token === user.token) {
62
+ return { authenticated: true, user: user.name };
63
+ }
64
+ }
65
+ return { authenticated: false, user: "" };
66
+ }
67
+ /**
68
+ * Generate authentication headers for MCP client configuration.
69
+ */
70
+ export function getAuthHeader(user, token) {
71
+ return `Bearer ${token}`;
72
+ }
73
+ /**
74
+ * Check if authentication is enabled.
75
+ */
76
+ export function isAuthEnabled() {
77
+ return !!masterToken || authUsers.length > 0;
78
+ }
@@ -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 };