atabey 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATABEY.md +1 -1
- package/PRIVACY.md +8 -14
- package/README.md +405 -56
- package/bin/cli.js +72 -5
- package/dist/framework-mcp/src/index.js +988 -63
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/compliance/mask_pii.d.ts +17 -0
- package/dist/framework-mcp/src/tools/compliance/mask_pii.js +56 -0
- package/dist/framework-mcp/src/tools/compliance/mask_pii.js.map +1 -0
- package/dist/framework-mcp/src/tools/definitions.js +10 -9
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
- package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.js +7 -8
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/messaging/approve_operation.d.ts +22 -0
- package/dist/framework-mcp/src/tools/messaging/approve_operation.js +81 -0
- package/dist/framework-mcp/src/tools/messaging/approve_operation.js.map +1 -0
- package/dist/framework-mcp/src/tools/messaging/ask_human.d.ts +15 -0
- package/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
- package/dist/framework-mcp/src/tools/messaging/ask_human.js.map +1 -1
- package/dist/framework-mcp/src/tools/observability/check_ports.d.ts +1 -0
- package/dist/framework-mcp/src/tools/observability/check_ports.js +24 -8
- package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -1
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js.map +1 -1
- package/dist/framework-mcp/src/tools/schemas.d.ts +48 -53
- package/dist/framework-mcp/src/tools/schemas.js +18 -22
- package/dist/framework-mcp/src/tools/schemas.js.map +1 -1
- package/dist/framework-mcp/src/tools/shell/run_command.js +146 -90
- package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -1
- package/dist/framework-mcp/src/tools/types.d.ts +11 -105
- package/dist/framework-mcp/src/tools/types.js +1 -0
- package/dist/framework-mcp/src/tools/types.js.map +1 -1
- package/dist/framework-mcp/src/utils/auth.d.ts +36 -0
- package/dist/framework-mcp/src/utils/auth.js +79 -0
- package/dist/framework-mcp/src/utils/auth.js.map +1 -0
- package/dist/framework-mcp/src/utils/auto-rollback.d.ts +71 -0
- package/dist/framework-mcp/src/utils/auto-rollback.js +266 -0
- package/dist/framework-mcp/src/utils/auto-rollback.js.map +1 -0
- package/dist/framework-mcp/src/utils/compliance.js +12 -4
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
- package/dist/framework-mcp/src/utils/context-optimizer.d.ts +69 -0
- package/dist/framework-mcp/src/utils/context-optimizer.js +157 -0
- package/dist/framework-mcp/src/utils/context-optimizer.js.map +1 -0
- package/dist/framework-mcp/src/utils/discipline.d.ts +68 -0
- package/dist/framework-mcp/src/utils/discipline.js +218 -0
- package/dist/framework-mcp/src/utils/discipline.js.map +1 -0
- package/dist/framework-mcp/src/utils/finops.d.ts +143 -0
- package/dist/framework-mcp/src/utils/finops.js +326 -0
- package/dist/framework-mcp/src/utils/finops.js.map +1 -0
- package/dist/framework-mcp/src/utils/human-in-loop.d.ts +95 -0
- package/dist/framework-mcp/src/utils/human-in-loop.js +216 -0
- package/dist/framework-mcp/src/utils/human-in-loop.js.map +1 -0
- package/dist/framework-mcp/src/utils/license-scanner.d.ts +71 -0
- package/dist/framework-mcp/src/utils/license-scanner.js +284 -0
- package/dist/framework-mcp/src/utils/license-scanner.js.map +1 -0
- package/dist/framework-mcp/src/utils/loop-detector.d.ts +105 -0
- package/dist/framework-mcp/src/utils/loop-detector.js +362 -0
- package/dist/framework-mcp/src/utils/loop-detector.js.map +1 -0
- package/dist/framework-mcp/src/utils/quality.d.ts +19 -0
- package/dist/framework-mcp/src/utils/quality.js +125 -0
- package/dist/framework-mcp/src/utils/quality.js.map +1 -0
- package/dist/framework-mcp/src/utils/rules-engine.d.ts +78 -0
- package/dist/framework-mcp/src/utils/rules-engine.js +232 -0
- package/dist/framework-mcp/src/utils/rules-engine.js.map +1 -0
- package/dist/framework-mcp/src/utils/silent-router.d.ts +49 -0
- package/dist/framework-mcp/src/utils/silent-router.js +155 -0
- package/dist/framework-mcp/src/utils/silent-router.js.map +1 -0
- package/dist/framework-mcp/src/utils/storage.d.ts +1 -0
- package/dist/framework-mcp/src/utils/storage.js +2 -2
- package/dist/framework-mcp/src/utils/storage.js.map +1 -1
- package/dist/framework-mcp/src/utils/telemetry-streamer.d.ts +133 -0
- package/dist/framework-mcp/src/utils/telemetry-streamer.js +397 -0
- package/dist/framework-mcp/src/utils/telemetry-streamer.js.map +1 -0
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js +2 -2
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.js +49 -0
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.js.map +1 -0
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +14 -5
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.js +44 -0
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.js.map +1 -0
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js +44 -14
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js.map +1 -1
- package/dist/framework-mcp/tests/utils/auto-rollback.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/auto-rollback.test.js +178 -0
- package/dist/framework-mcp/tests/utils/auto-rollback.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.js +62 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/finops.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/finops.test.js +157 -0
- package/dist/framework-mcp/tests/utils/finops.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.js +59 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.js +131 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.js +204 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.js +106 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js +201 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js.map +1 -0
- package/dist/src/cli/commands/check.js +16 -1
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/dashboard.js +188 -164
- package/dist/src/cli/commands/dashboard.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +2 -2
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-core.d.ts +2 -0
- package/dist/src/cli/commands/init/scaffold-core.js +16 -1
- package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-ops.js +2 -2
- package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-standards.js +13 -1
- package/dist/src/cli/commands/init/scaffold-standards.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +4 -0
- package/dist/src/cli/commands/init.js +94 -31
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/mcp.js +3 -1
- package/dist/src/cli/commands/mcp.js.map +1 -1
- package/dist/src/cli/commands/quickstart.d.ts +1 -1
- package/dist/src/cli/commands/quickstart.js +12 -24
- package/dist/src/cli/commands/quickstart.js.map +1 -1
- package/dist/src/cli/commands/script.js +8 -1
- package/dist/src/cli/commands/script.js.map +1 -1
- package/dist/src/cli/index.js +24 -23
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/shims.js +7 -7
- package/dist/src/cli/utils/pkg.js +2 -3
- package/dist/src/cli/utils/pkg.js.map +1 -1
- package/dist/src/cli/utils/quality.d.ts +10 -0
- package/dist/src/cli/utils/quality.js +10 -0
- package/dist/src/cli/utils/quality.js.map +1 -0
- package/dist/src/modules/agents/definitions.js +45 -40
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/manager.js +6 -1
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/engines/agent-executor.d.ts +6 -10
- package/dist/src/modules/engines/agent-executor.js +63 -21
- package/dist/src/modules/engines/agent-executor.js.map +1 -1
- package/dist/src/modules/engines/agent-loop.d.ts +34 -0
- package/dist/src/modules/engines/agent-loop.js +102 -0
- package/dist/src/modules/engines/agent-loop.js.map +1 -0
- package/dist/src/modules/engines/evaluation-engine.d.ts +12 -2
- package/dist/src/modules/engines/evaluation-engine.js +78 -11
- package/dist/src/modules/engines/evaluation-engine.js.map +1 -1
- package/dist/src/modules/engines/quality-gate.d.ts +13 -5
- package/dist/src/modules/engines/quality-gate.js +39 -31
- package/dist/src/modules/engines/quality-gate.js.map +1 -1
- package/dist/src/modules/engines/routing-engine.d.ts +5 -3
- package/dist/src/modules/engines/routing-engine.js +16 -9
- package/dist/src/modules/engines/routing-engine.js.map +1 -1
- package/dist/src/modules/gateway/cost-tracker.d.ts +5 -0
- package/dist/src/modules/gateway/cost-tracker.js +71 -0
- package/dist/src/modules/gateway/cost-tracker.js.map +1 -1
- package/dist/src/modules/gateway/gateway.d.ts +4 -0
- package/dist/src/modules/gateway/gateway.js +8 -0
- package/dist/src/modules/gateway/gateway.js.map +1 -1
- package/dist/src/shared/audit.js +3 -2
- package/dist/src/shared/audit.js.map +1 -1
- package/dist/src/shared/pii.d.ts +41 -9
- package/dist/src/shared/pii.js +122 -31
- package/dist/src/shared/pii.js.map +1 -1
- package/dist/src/shared/storage.d.ts +62 -0
- package/dist/src/shared/storage.js +47 -7
- package/dist/src/shared/storage.js.map +1 -1
- package/dist/tests/embedding.test.d.ts +1 -0
- package/dist/tests/embedding.test.js +82 -0
- package/dist/tests/embedding.test.js.map +1 -0
- package/dist/tests/engines/evaluation-engine.test.d.ts +1 -0
- package/dist/tests/engines/evaluation-engine.test.js +71 -0
- package/dist/tests/engines/evaluation-engine.test.js.map +1 -0
- package/dist/tests/engines/planning-engine.test.d.ts +1 -0
- package/dist/tests/engines/planning-engine.test.js +100 -0
- package/dist/tests/engines/planning-engine.test.js.map +1 -0
- package/dist/tests/engines/quality-gate.test.d.ts +1 -0
- package/dist/tests/engines/quality-gate.test.js +59 -0
- package/dist/tests/engines/quality-gate.test.js.map +1 -0
- package/dist/tests/engines/risk-engine.test.d.ts +1 -0
- package/dist/tests/engines/risk-engine.test.js +80 -0
- package/dist/tests/engines/risk-engine.test.js.map +1 -0
- package/dist/tests/engines/routing-engine.test.d.ts +1 -0
- package/dist/tests/engines/routing-engine.test.js +78 -0
- package/dist/tests/engines/routing-engine.test.js.map +1 -0
- package/dist/tests/integration/hermes_locking.test.js +1 -0
- package/dist/tests/integration/hermes_locking.test.js.map +1 -1
- package/dist/tests/modules/engines/agent-executor.test.js +1 -1
- package/dist/tests/modules/engines/agent-executor.test.js.map +1 -1
- package/dist/tests/modules/gateway/cost-tracker.test.js +20 -1
- package/dist/tests/modules/gateway/cost-tracker.test.js.map +1 -1
- package/dist/tests/shared/lock.test.d.ts +1 -0
- package/dist/tests/shared/lock.test.js +95 -0
- package/dist/tests/shared/lock.test.js.map +1 -0
- package/dist/tests/shared/pii.test.d.ts +1 -0
- package/dist/tests/shared/pii.test.js +183 -0
- package/dist/tests/shared/pii.test.js.map +1 -0
- package/framework-mcp/README.md +307 -35
- package/framework-mcp/dist/dashboard/assets/index-B_rK57vi.js +1221 -0
- package/framework-mcp/dist/dashboard/index.html +1 -1
- package/framework-mcp/dist/framework-mcp/src/index.js +988 -63
- package/framework-mcp/dist/framework-mcp/src/tools/compliance/mask_pii.js +55 -0
- package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +10 -9
- package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
- package/framework-mcp/dist/framework-mcp/src/tools/index.js +7 -8
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/approve_operation.js +80 -0
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
- package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +24 -8
- package/framework-mcp/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
- package/framework-mcp/dist/framework-mcp/src/tools/schemas.js +18 -22
- package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +146 -90
- package/framework-mcp/dist/framework-mcp/src/tools/types.js +1 -0
- package/framework-mcp/dist/framework-mcp/src/utils/auth.js +78 -0
- package/framework-mcp/dist/framework-mcp/src/utils/auto-rollback.js +265 -0
- package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +12 -4
- package/framework-mcp/dist/framework-mcp/src/utils/context-optimizer.js +156 -0
- package/framework-mcp/dist/framework-mcp/src/utils/discipline.js +217 -0
- package/framework-mcp/dist/framework-mcp/src/utils/finops.js +325 -0
- package/framework-mcp/dist/framework-mcp/src/utils/human-in-loop.js +215 -0
- package/framework-mcp/dist/framework-mcp/src/utils/license-scanner.js +283 -0
- package/framework-mcp/dist/framework-mcp/src/utils/loop-detector.js +361 -0
- package/framework-mcp/dist/framework-mcp/src/utils/quality.js +124 -0
- package/framework-mcp/dist/framework-mcp/src/utils/rules-engine.js +231 -0
- package/framework-mcp/dist/framework-mcp/src/utils/silent-router.js +154 -0
- package/framework-mcp/dist/framework-mcp/src/utils/storage.js +2 -2
- package/framework-mcp/dist/framework-mcp/src/utils/telemetry-streamer.js +396 -0
- package/framework-mcp/dist/src/cli/platforms/core.js +72 -0
- package/framework-mcp/dist/src/cli/platforms/index.js +5 -0
- package/framework-mcp/dist/src/cli/platforms/paths.js +101 -0
- package/framework-mcp/dist/src/cli/platforms/scaffold.js +72 -0
- package/framework-mcp/dist/src/cli/platforms/utils.js +75 -0
- package/framework-mcp/dist/src/cli/utils/claude.js +57 -0
- package/framework-mcp/dist/src/cli/utils/compliance.js +12 -0
- package/framework-mcp/dist/src/cli/utils/fs.js +138 -0
- package/framework-mcp/dist/src/cli/utils/pkg.js +282 -0
- package/framework-mcp/dist/src/cli/utils/quality.js +9 -0
- package/framework-mcp/dist/src/modules/agents/definitions.js +563 -0
- package/framework-mcp/dist/src/modules/agents/registry/analyst.js +39 -0
- package/framework-mcp/dist/src/modules/agents/registry/architect.js +42 -0
- package/framework-mcp/dist/src/modules/agents/registry/backend.js +50 -0
- package/framework-mcp/dist/src/modules/agents/registry/database.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/devops.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/explorer.js +37 -0
- package/framework-mcp/dist/src/modules/agents/registry/frontend.js +52 -0
- package/framework-mcp/dist/src/modules/agents/registry/git.js +36 -0
- package/framework-mcp/dist/src/modules/agents/registry/manager.js +64 -0
- package/framework-mcp/dist/src/modules/agents/registry/mobile.js +41 -0
- package/framework-mcp/dist/src/modules/agents/registry/native.js +41 -0
- package/framework-mcp/dist/src/modules/agents/registry/quality.js +43 -0
- package/framework-mcp/dist/src/modules/agents/registry/security.js +42 -0
- package/framework-mcp/dist/src/modules/agents/types.js +1 -0
- package/framework-mcp/dist/src/modules/engines/evaluation-engine.js +169 -0
- package/framework-mcp/dist/src/modules/engines/quality-gate.js +92 -0
- package/framework-mcp/dist/src/modules/engines/risk-engine.js +105 -0
- package/framework-mcp/dist/src/modules/engines/routing-engine.js +408 -0
- package/framework-mcp/dist/src/modules/engines/types.js +1 -0
- package/framework-mcp/dist/src/modules/providers/definitions.js +140 -0
- package/framework-mcp/dist/src/modules/providers/registry.js +18 -0
- package/framework-mcp/dist/src/modules/providers/shared.js +104 -0
- package/framework-mcp/dist/src/modules/providers/types.js +1 -0
- package/framework-mcp/dist/src/modules/skills/adapter-skills.js +449 -0
- package/framework-mcp/dist/src/modules/skills/definitions.js +70 -0
- package/framework-mcp/dist/src/shared/audit.js +220 -0
- package/framework-mcp/dist/src/shared/errors.js +68 -0
- package/framework-mcp/dist/src/shared/lock.js +159 -0
- package/framework-mcp/dist/src/shared/pii.js +122 -31
- package/framework-mcp/dist/src/shared/retention.js +170 -0
- package/framework-mcp/dist/src/shared/storage.js +47 -7
- package/framework-mcp/dist/src/shared/string.js +29 -0
- package/framework-mcp/package.json +8 -2
- package/mcp.json +12 -6
- package/package.json +11 -5
- package/templates/full/ATABEY_FULL.md +1 -1
- package/framework-mcp/dist/dashboard/assets/index-BAPGLiWE.js +0 -267
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ─── LOOP DETECTOR ─────────────────────────────────────────────────
|
|
3
|
+
*
|
|
4
|
+
* Detects and prevents AI agents from entering infinite loops.
|
|
5
|
+
* Monitors call patterns across time, file paths, and tools.
|
|
6
|
+
*
|
|
7
|
+
* Detection Patterns:
|
|
8
|
+
* 1. **Consecutive Same Tool** – Same tool called N times in a row
|
|
9
|
+
* 2. **File Churn** – Same file written/read repeatedly
|
|
10
|
+
* 3. **Oscillation** – A → B → A → B alternating pattern
|
|
11
|
+
* 4. **Time-based Throttle** – Too many calls in a short window
|
|
12
|
+
* 5. **Semantic Similarity** – Similar arguments repeated (e.g., same error fix loop)
|
|
13
|
+
* 6. **Content Identity** – Same content being written repeatedly
|
|
14
|
+
*
|
|
15
|
+
* Action:
|
|
16
|
+
* - Cooldown: Block agent for N seconds
|
|
17
|
+
* - Escalate: Notify dashboard/human if loop persists
|
|
18
|
+
* - Kill: Force-stop the agent session
|
|
19
|
+
*
|
|
20
|
+
* Environment Variables:
|
|
21
|
+
* MCP_LOOP_MAX_CONSECUTIVE - Max same tool calls (default: 10)
|
|
22
|
+
* MCP_LOOP_MAX_FILE_CHURN - Max writes to same file (default: 5)
|
|
23
|
+
* MCP_LOOP_COOLDOWN_MS - Cooldown duration (default: 30000)
|
|
24
|
+
* MCP_LOOP_OSCILLATION_WINDOW - Oscillation detection window (default: 6)
|
|
25
|
+
*/
|
|
26
|
+
import path from "path";
|
|
27
|
+
// ─── Configuration ────────────────────────────────────────────────
|
|
28
|
+
const CONFIG = {
|
|
29
|
+
/** Max consecutive same tool calls before action */
|
|
30
|
+
MAX_CONSECUTIVE: parseInt(process.env.MCP_LOOP_MAX_CONSECUTIVE || "10", 10),
|
|
31
|
+
/** Max writes to the same file before action */
|
|
32
|
+
MAX_FILE_CHURN: parseInt(process.env.MCP_LOOP_MAX_FILE_CHURN || "5", 10),
|
|
33
|
+
/** Max reads of the same file before action */
|
|
34
|
+
MAX_FILE_READ_CHURN: parseInt(process.env.MCP_LOOP_MAX_FILE_READ_CHURN || "10", 10),
|
|
35
|
+
/** Oscillation pattern window (min calls to detect A→B→A→B) */
|
|
36
|
+
OSCILLATION_WINDOW: parseInt(process.env.MCP_LOOP_OSCILLATION_WINDOW || "6", 10),
|
|
37
|
+
/** Cooldown duration in ms */
|
|
38
|
+
COOLDOWN_MS: parseInt(process.env.MCP_LOOP_COOLDOWN_MS || "30000", 10),
|
|
39
|
+
/** Max calls to any tool in sliding window */
|
|
40
|
+
MAX_CALLS_IN_WINDOW: parseInt(process.env.MCP_LOOP_MAX_CALLS_IN_WINDOW || "50", 10),
|
|
41
|
+
/** Sliding window size in ms */
|
|
42
|
+
WINDOW_SIZE_MS: parseInt(process.env.MCP_LOOP_WINDOW_MS || "60000", 10),
|
|
43
|
+
/** Enable/disable loop detector */
|
|
44
|
+
ENABLED: process.env.MCP_LOOP_DETECTION !== "false",
|
|
45
|
+
};
|
|
46
|
+
const agentHistories = new Map();
|
|
47
|
+
// ─── Loop Detector ────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Get or create agent history.
|
|
50
|
+
*/
|
|
51
|
+
function getOrCreateHistory(agent) {
|
|
52
|
+
if (!agentHistories.has(agent)) {
|
|
53
|
+
agentHistories.set(agent, {
|
|
54
|
+
calls: [],
|
|
55
|
+
consecutiveToolCalls: new Map(),
|
|
56
|
+
fileWriteCount: new Map(),
|
|
57
|
+
fileReadCount: new Map(),
|
|
58
|
+
lastContentHashes: [],
|
|
59
|
+
inCooldown: false,
|
|
60
|
+
cooldownUntil: 0,
|
|
61
|
+
cooldownCount: 0,
|
|
62
|
+
lastAlert: null,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return agentHistories.get(agent);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Prune old calls from history.
|
|
69
|
+
*/
|
|
70
|
+
function pruneOldCalls(history) {
|
|
71
|
+
const cutoff = Date.now() - CONFIG.WINDOW_SIZE_MS;
|
|
72
|
+
history.calls = history.calls.filter(c => c.timestamp > cutoff);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extract file path from tool args if applicable.
|
|
76
|
+
*/
|
|
77
|
+
function extractFilePath(toolName, args) {
|
|
78
|
+
if (["write_file", "read_file", "replace_text", "patch_file", "batch_surgical_edit"].includes(toolName)) {
|
|
79
|
+
return args.path || args.filePath || undefined;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Compute a simple content hash for identity detection.
|
|
85
|
+
*/
|
|
86
|
+
function computeContentHash(args) {
|
|
87
|
+
if (args.content && typeof args.content === "string") {
|
|
88
|
+
// Use first 100 chars as hash (fast, good enough for identity)
|
|
89
|
+
return args.content.substring(0, 100);
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check for oscillation pattern (A → B → A → B).
|
|
95
|
+
*/
|
|
96
|
+
function detectOscillation(history, currentTool) {
|
|
97
|
+
const recent = history.calls.slice(-CONFIG.OSCILLATION_WINDOW);
|
|
98
|
+
if (recent.length < 4)
|
|
99
|
+
return false;
|
|
100
|
+
const recentToolNames = [...recent.map(c => c.toolName), currentTool];
|
|
101
|
+
// Check alternating pattern: tool[0] === tool[2] === tool[4] && tool[1] === tool[3] === tool[5]
|
|
102
|
+
if (recentToolNames.length >= 4) {
|
|
103
|
+
if (recentToolNames[0] === recentToolNames[2] &&
|
|
104
|
+
recentToolNames[1] === recentToolNames[3] &&
|
|
105
|
+
recentToolNames[0] !== recentToolNames[1]) {
|
|
106
|
+
// Check if pattern extends to 6
|
|
107
|
+
if (recentToolNames.length >= 6) {
|
|
108
|
+
return recentToolNames[0] === recentToolNames[4] && recentToolNames[1] === recentToolNames[5];
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Detect if same content is being written repeatedly.
|
|
117
|
+
*/
|
|
118
|
+
function detectContentIdentity(history, contentHash) {
|
|
119
|
+
if (!contentHash)
|
|
120
|
+
return false;
|
|
121
|
+
const recentHashes = history.lastContentHashes.slice(-5);
|
|
122
|
+
if (recentHashes.length < 3)
|
|
123
|
+
return false;
|
|
124
|
+
// Check if this hash appears 3+ times in last 5
|
|
125
|
+
const hashCount = recentHashes.filter(h => h === contentHash).length;
|
|
126
|
+
if (contentHash === recentHashes[recentHashes.length - 1]) {
|
|
127
|
+
// Count including current
|
|
128
|
+
return hashCount + 1 >= 3;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Record a tool call and check for loop patterns.
|
|
134
|
+
* Returns LoopAlert if a loop pattern is detected, null otherwise.
|
|
135
|
+
*/
|
|
136
|
+
export function recordAndCheck(agent, toolName, args) {
|
|
137
|
+
if (!CONFIG.ENABLED)
|
|
138
|
+
return null;
|
|
139
|
+
const history = getOrCreateHistory(agent);
|
|
140
|
+
// Check cooldown
|
|
141
|
+
if (history.inCooldown) {
|
|
142
|
+
if (Date.now() < history.cooldownUntil) {
|
|
143
|
+
return {
|
|
144
|
+
type: "rate_limit",
|
|
145
|
+
severity: "critical",
|
|
146
|
+
agent,
|
|
147
|
+
detail: `Agent "${agent}" is in cooldown for ${Math.ceil((history.cooldownUntil - Date.now()) / 1000)}s. Loop detected earlier.`,
|
|
148
|
+
timestamp: Date.now(),
|
|
149
|
+
cooldownUntil: history.cooldownUntil,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
history.inCooldown = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const filePath = extractFilePath(toolName, args);
|
|
157
|
+
const contentHash = computeContentHash(args);
|
|
158
|
+
const record = {
|
|
159
|
+
agent,
|
|
160
|
+
toolName,
|
|
161
|
+
args,
|
|
162
|
+
timestamp: Date.now(),
|
|
163
|
+
filePath,
|
|
164
|
+
contentHash,
|
|
165
|
+
};
|
|
166
|
+
// Prune old calls
|
|
167
|
+
pruneOldCalls(history);
|
|
168
|
+
// Check 1: Consecutive same tool
|
|
169
|
+
const currentConsecutive = (history.consecutiveToolCalls.get(toolName) || 0) + 1;
|
|
170
|
+
history.consecutiveToolCalls.set(toolName, currentConsecutive);
|
|
171
|
+
// Reset other tools
|
|
172
|
+
for (const [tool] of history.consecutiveToolCalls) {
|
|
173
|
+
if (tool !== toolName) {
|
|
174
|
+
history.consecutiveToolCalls.set(tool, 0);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (currentConsecutive >= CONFIG.MAX_CONSECUTIVE) {
|
|
178
|
+
const alert = {
|
|
179
|
+
type: "consecutive_same_tool",
|
|
180
|
+
severity: "critical",
|
|
181
|
+
agent,
|
|
182
|
+
detail: `Agent "${agent}" called "${toolName}" ${currentConsecutive} times consecutively. Possible infinite loop.`,
|
|
183
|
+
timestamp: Date.now(),
|
|
184
|
+
cooldownUntil: Date.now() + CONFIG.COOLDOWN_MS,
|
|
185
|
+
};
|
|
186
|
+
applyCooldown(history, alert, agent);
|
|
187
|
+
return alert;
|
|
188
|
+
}
|
|
189
|
+
// Check 2: File churn (for write operations)
|
|
190
|
+
if (filePath) {
|
|
191
|
+
if (["write_file", "replace_text", "patch_file", "batch_surgical_edit"].includes(toolName)) {
|
|
192
|
+
const writeCount = (history.fileWriteCount.get(filePath) || 0) + 1;
|
|
193
|
+
history.fileWriteCount.set(filePath, writeCount);
|
|
194
|
+
if (writeCount >= CONFIG.MAX_FILE_CHURN) {
|
|
195
|
+
const alert = {
|
|
196
|
+
type: "file_churn",
|
|
197
|
+
severity: "critical",
|
|
198
|
+
agent,
|
|
199
|
+
detail: `Agent "${agent}" wrote to "${path.relative(process.cwd(), filePath)}" ${writeCount} times. Possible file churn loop.`,
|
|
200
|
+
timestamp: Date.now(),
|
|
201
|
+
cooldownUntil: Date.now() + CONFIG.COOLDOWN_MS,
|
|
202
|
+
};
|
|
203
|
+
applyCooldown(history, alert, agent);
|
|
204
|
+
return alert;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (toolName === "read_file") {
|
|
208
|
+
const readCount = (history.fileReadCount.get(filePath) || 0) + 1;
|
|
209
|
+
history.fileReadCount.set(filePath, readCount);
|
|
210
|
+
if (readCount >= CONFIG.MAX_FILE_READ_CHURN) {
|
|
211
|
+
const alert = {
|
|
212
|
+
type: "file_churn",
|
|
213
|
+
severity: "warning",
|
|
214
|
+
agent,
|
|
215
|
+
detail: `Agent "${agent}" read "${path.relative(process.cwd(), filePath)}" ${readCount} times. Possible read loop.`,
|
|
216
|
+
timestamp: Date.now(),
|
|
217
|
+
cooldownUntil: null,
|
|
218
|
+
};
|
|
219
|
+
history.lastAlert = alert;
|
|
220
|
+
return alert;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Check 3: Oscillation pattern
|
|
225
|
+
if (detectOscillation(history, toolName)) {
|
|
226
|
+
const alert = {
|
|
227
|
+
type: "oscillation",
|
|
228
|
+
severity: "critical",
|
|
229
|
+
agent,
|
|
230
|
+
detail: `Agent "${agent}" is oscillating between tools. Pattern detected in last ${CONFIG.OSCILLATION_WINDOW} calls.`,
|
|
231
|
+
timestamp: Date.now(),
|
|
232
|
+
cooldownUntil: Date.now() + CONFIG.COOLDOWN_MS,
|
|
233
|
+
};
|
|
234
|
+
applyCooldown(history, alert, agent);
|
|
235
|
+
return alert;
|
|
236
|
+
}
|
|
237
|
+
// Check 4: Rate limit (calls in sliding window)
|
|
238
|
+
if (history.calls.length >= CONFIG.MAX_CALLS_IN_WINDOW) {
|
|
239
|
+
const alert = {
|
|
240
|
+
type: "rate_limit",
|
|
241
|
+
severity: "critical",
|
|
242
|
+
agent,
|
|
243
|
+
detail: `Agent "${agent}" made ${history.calls.length} calls in ${CONFIG.WINDOW_SIZE_MS / 1000}s window. Rate limit exceeded.`,
|
|
244
|
+
timestamp: Date.now(),
|
|
245
|
+
cooldownUntil: Date.now() + CONFIG.COOLDOWN_MS,
|
|
246
|
+
};
|
|
247
|
+
applyCooldown(history, alert, agent);
|
|
248
|
+
return alert;
|
|
249
|
+
}
|
|
250
|
+
// Check 5: Content identity (writing same content)
|
|
251
|
+
if (contentHash && detectContentIdentity(history, contentHash)) {
|
|
252
|
+
const alert = {
|
|
253
|
+
type: "content_identity",
|
|
254
|
+
severity: "critical",
|
|
255
|
+
agent,
|
|
256
|
+
detail: `Agent "${agent}" is writing the same content repeatedly. Possible fix-attempt loop.`,
|
|
257
|
+
timestamp: Date.now(),
|
|
258
|
+
cooldownUntil: Date.now() + CONFIG.COOLDOWN_MS,
|
|
259
|
+
};
|
|
260
|
+
applyCooldown(history, alert, agent);
|
|
261
|
+
return alert;
|
|
262
|
+
}
|
|
263
|
+
// If no detection, record the call
|
|
264
|
+
history.calls.push(record);
|
|
265
|
+
// Track content hashes for identity detection
|
|
266
|
+
if (contentHash) {
|
|
267
|
+
history.lastContentHashes.push(contentHash);
|
|
268
|
+
if (history.lastContentHashes.length > 10) {
|
|
269
|
+
history.lastContentHashes.shift();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Apply cooldown to an agent.
|
|
276
|
+
*/
|
|
277
|
+
function applyCooldown(history, alert, _agent) {
|
|
278
|
+
history.inCooldown = true;
|
|
279
|
+
history.cooldownUntil = alert.cooldownUntil || Date.now() + CONFIG.COOLDOWN_MS;
|
|
280
|
+
history.cooldownCount++;
|
|
281
|
+
history.lastAlert = alert;
|
|
282
|
+
process.stderr.write(`[LOOP DETECT] ${alert.type}: ${alert.detail}\n`);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Check if an agent is currently in cooldown.
|
|
286
|
+
*/
|
|
287
|
+
export function isInCooldown(agent) {
|
|
288
|
+
const history = agentHistories.get(agent);
|
|
289
|
+
if (!history || !history.inCooldown) {
|
|
290
|
+
return { inCooldown: false, remainingMs: 0, reason: null };
|
|
291
|
+
}
|
|
292
|
+
const remaining = history.cooldownUntil - Date.now();
|
|
293
|
+
if (remaining <= 0) {
|
|
294
|
+
history.inCooldown = false;
|
|
295
|
+
return { inCooldown: false, remainingMs: 0, reason: null };
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
inCooldown: true,
|
|
299
|
+
remainingMs: remaining,
|
|
300
|
+
reason: history.lastAlert?.detail || null,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Manually clear cooldown for an agent.
|
|
305
|
+
*/
|
|
306
|
+
export function clearCooldown(agent) {
|
|
307
|
+
const history = agentHistories.get(agent);
|
|
308
|
+
if (history) {
|
|
309
|
+
history.inCooldown = false;
|
|
310
|
+
history.cooldownUntil = 0;
|
|
311
|
+
history.consecutiveToolCalls.clear();
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get loop detection stats for an agent.
|
|
318
|
+
*/
|
|
319
|
+
export function getLoopStats(agent) {
|
|
320
|
+
const history = agentHistories.get(agent);
|
|
321
|
+
if (!history) {
|
|
322
|
+
return {
|
|
323
|
+
totalCalls: 0,
|
|
324
|
+
recentCalls: 0,
|
|
325
|
+
inCooldown: false,
|
|
326
|
+
cooldownCount: 0,
|
|
327
|
+
consecutiveTools: {},
|
|
328
|
+
fileWrites: {},
|
|
329
|
+
fileReads: {},
|
|
330
|
+
lastAlert: null,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
pruneOldCalls(history);
|
|
334
|
+
return {
|
|
335
|
+
totalCalls: history.calls.length + history.cooldownCount * CONFIG.MAX_CALLS_IN_WINDOW,
|
|
336
|
+
recentCalls: history.calls.length,
|
|
337
|
+
inCooldown: history.inCooldown && Date.now() < history.cooldownUntil,
|
|
338
|
+
cooldownCount: history.cooldownCount,
|
|
339
|
+
consecutiveTools: Object.fromEntries(history.consecutiveToolCalls),
|
|
340
|
+
fileWrites: Object.fromEntries(history.fileWriteCount),
|
|
341
|
+
fileReads: Object.fromEntries(history.fileReadCount),
|
|
342
|
+
lastAlert: history.lastAlert,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get all agents' loop stats.
|
|
347
|
+
*/
|
|
348
|
+
export function getAllLoopStats() {
|
|
349
|
+
const stats = {};
|
|
350
|
+
for (const [agentName] of agentHistories) {
|
|
351
|
+
stats[agentName] = getLoopStats(agentName);
|
|
352
|
+
}
|
|
353
|
+
return stats;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Reset all agent histories.
|
|
357
|
+
*/
|
|
358
|
+
export function resetLoopDetection() {
|
|
359
|
+
agentHistories.clear();
|
|
360
|
+
}
|
|
361
|
+
export { CONFIG as LoopDetectorConfig };
|
|
362
|
+
//# sourceMappingURL=loop-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-detector.js","sourceRoot":"","sources":["../../../../framework-mcp/src/utils/loop-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface QualityIssue {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
type: "any-type" | "complexity";
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export interface QualityAnalysisResult {
|
|
8
|
+
totalFiles: number;
|
|
9
|
+
totalIssues: number;
|
|
10
|
+
longFunctions: number;
|
|
11
|
+
deepNesting: number;
|
|
12
|
+
anyTypes: number;
|
|
13
|
+
issues: QualityIssue[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shared Code Quality Heuristic Scanner
|
|
17
|
+
* Evaluates functions lengths, nesting depth, and usage of the forbidden 'any' type.
|
|
18
|
+
*/
|
|
19
|
+
export declare function analyzePathQuality(projectRoot: string, targetPath: string): QualityAnalysisResult;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Shared Code Quality Heuristic Scanner
|
|
5
|
+
* Evaluates functions lengths, nesting depth, and usage of the forbidden 'any' type.
|
|
6
|
+
*/
|
|
7
|
+
export function analyzePathQuality(projectRoot, targetPath) {
|
|
8
|
+
const absolutePath = path.resolve(projectRoot, targetPath);
|
|
9
|
+
const files = [];
|
|
10
|
+
function collectFilesSync(dir, exts) {
|
|
11
|
+
if (!fs.existsSync(dir))
|
|
12
|
+
return;
|
|
13
|
+
try {
|
|
14
|
+
const stat = fs.statSync(dir);
|
|
15
|
+
if (stat.isFile()) {
|
|
16
|
+
if (exts.some(ext => dir.endsWith(ext))) {
|
|
17
|
+
files.push(dir);
|
|
18
|
+
}
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const fullPath = path.join(dir, entry.name);
|
|
24
|
+
if (entry.isDirectory() && !entry.name.startsWith("node_modules") && !entry.name.startsWith(".")) {
|
|
25
|
+
collectFilesSync(fullPath, exts);
|
|
26
|
+
}
|
|
27
|
+
else if (entry.isFile() && exts.some(ext => entry.name.endsWith(ext))) {
|
|
28
|
+
files.push(fullPath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Ignore errors reading files/dirs
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
collectFilesSync(absolutePath, [".ts", ".tsx"]);
|
|
37
|
+
const issues = [];
|
|
38
|
+
let longFunctions = 0;
|
|
39
|
+
let deepNesting = 0;
|
|
40
|
+
let anyTypes = 0;
|
|
41
|
+
files.forEach((f) => {
|
|
42
|
+
try {
|
|
43
|
+
const content = fs.readFileSync(f, "utf8");
|
|
44
|
+
const lines = content.split("\n");
|
|
45
|
+
const relativePath = path.relative(projectRoot, f);
|
|
46
|
+
// Check for `any` type
|
|
47
|
+
lines.forEach((line, idx) => {
|
|
48
|
+
if (line.trim().startsWith("//") || line.trim().startsWith("/*"))
|
|
49
|
+
return;
|
|
50
|
+
if (line.match(/\bany\b/) && !line.includes("// eslint-disable") && !line.includes("as any")) {
|
|
51
|
+
anyTypes++;
|
|
52
|
+
issues.push({
|
|
53
|
+
file: relativePath,
|
|
54
|
+
line: idx + 1,
|
|
55
|
+
type: "any-type",
|
|
56
|
+
message: `Line ${idx + 1}: Usage of 'any' type`
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
// Check for long functions
|
|
61
|
+
let inFunction = false;
|
|
62
|
+
let funcLines = 0;
|
|
63
|
+
let startLine = 0;
|
|
64
|
+
let funcName = "anonymous";
|
|
65
|
+
for (let i = 0; i < lines.length; i++) {
|
|
66
|
+
const line = lines[i];
|
|
67
|
+
// Detect function/method starts using regex
|
|
68
|
+
const funcMatch = line.match(/(?:public|private|protected|static\s+)?(?:async\s+)?(?:function\s+)?(\w+)\s*\([^)]*\)\s*{/);
|
|
69
|
+
const methodMatch = !funcMatch ? line.match(/^\s*(?:public|private|protected|static\s+)?(\w+)\s*\([^)]*\)\s*{/) : null;
|
|
70
|
+
const arrowMatch = !funcMatch && !methodMatch ? line.match(/(?:const|let|var)?\s*(\w+)?\s*=\s*(?:async\s*)?\([^)]*\)\s*=>\s*{/) : null;
|
|
71
|
+
if (funcMatch || methodMatch || arrowMatch) {
|
|
72
|
+
inFunction = true;
|
|
73
|
+
funcLines = 1;
|
|
74
|
+
startLine = i + 1;
|
|
75
|
+
funcName = (funcMatch?.[1] || methodMatch?.[1] || arrowMatch?.[1] || "anonymous").trim();
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (inFunction) {
|
|
79
|
+
funcLines++;
|
|
80
|
+
if (line.includes("}")) {
|
|
81
|
+
if (funcLines > 50) {
|
|
82
|
+
longFunctions++;
|
|
83
|
+
issues.push({
|
|
84
|
+
file: relativePath,
|
|
85
|
+
line: startLine,
|
|
86
|
+
type: "complexity",
|
|
87
|
+
message: `Function '${funcName}' is ${funcLines} lines long (max: 50)`
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
inFunction = false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Check nesting depth
|
|
95
|
+
lines.forEach((line, idx) => {
|
|
96
|
+
const leadingSpaces = line.match(/^(\s*)/)?.[0].length || 0;
|
|
97
|
+
if (leadingSpaces >= 10 && !line.trim().startsWith("//") && !line.trim().startsWith("*")) {
|
|
98
|
+
const indentSize = (leadingSpaces % 4 === 0) ? 4 : 2;
|
|
99
|
+
const depth = Math.floor(leadingSpaces / indentSize);
|
|
100
|
+
if (depth > 4) {
|
|
101
|
+
deepNesting++;
|
|
102
|
+
issues.push({
|
|
103
|
+
file: relativePath,
|
|
104
|
+
line: idx + 1,
|
|
105
|
+
type: "complexity",
|
|
106
|
+
message: `Line ${idx + 1}: Nesting depth ${depth}`
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Ignore files that can't be read
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
totalFiles: files.length,
|
|
118
|
+
totalIssues: issues.length,
|
|
119
|
+
longFunctions,
|
|
120
|
+
deepNesting,
|
|
121
|
+
anyTypes,
|
|
122
|
+
issues
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../../../framework-mcp/src/utils/quality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ─── RULES ENGINE (Prompt Conflict Resolution) ────────────────────
|
|
3
|
+
*
|
|
4
|
+
* Resolves conflicts between AI CLI built-in prompts and Atabey governance rules.
|
|
5
|
+
* Ensures Atabey's critical rules ALWAYS override CLI-level instructions.
|
|
6
|
+
*
|
|
7
|
+
* Priority System:
|
|
8
|
+
* - CRITICAL (P0): Non-bypassable rules (zero any, no console.log, PII masking)
|
|
9
|
+
* - HIGH (P1): Important rules that should not be violated
|
|
10
|
+
* - MEDIUM (P2): Standard best practices
|
|
11
|
+
* - LOW (P3): Recommendations only
|
|
12
|
+
*
|
|
13
|
+
* Enforcement Mechanisms:
|
|
14
|
+
* 1. Pre-execution: Rule validation BEFORE tool runs
|
|
15
|
+
* 2. Post-execution: Scan changed files for violations → auto-rollback
|
|
16
|
+
* 3. CLI System Prompt Override: Inject critical rules at MCP initialization
|
|
17
|
+
*/
|
|
18
|
+
export type RulePriority = "CRITICAL" | "HIGH" | "MEDIUM" | "LOW";
|
|
19
|
+
export interface GovernanceRule {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
priority: RulePriority;
|
|
24
|
+
/** Regex pattern to detect violations in file content */
|
|
25
|
+
detectPattern?: RegExp;
|
|
26
|
+
/** Tool names this rule applies to */
|
|
27
|
+
appliesToTools?: string[];
|
|
28
|
+
/** File extensions this rule applies to (e.g., .ts, .tsx) */
|
|
29
|
+
appliesToExtensions?: string[];
|
|
30
|
+
/** Error message when violated */
|
|
31
|
+
errorMessage: string;
|
|
32
|
+
/** Auto-fix expression (optional) */
|
|
33
|
+
autoFix?: string;
|
|
34
|
+
/** Whether this rule can be bypassed */
|
|
35
|
+
bypassable: boolean;
|
|
36
|
+
}
|
|
37
|
+
declare const GOVERNANCE_RULES: GovernanceRule[];
|
|
38
|
+
/**
|
|
39
|
+
* Get all governance rules.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAllRules(): GovernanceRule[];
|
|
42
|
+
/**
|
|
43
|
+
* Get rules by priority level.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getRulesByPriority(priority: RulePriority): GovernanceRule[];
|
|
46
|
+
/**
|
|
47
|
+
* Get non-bypassable rules (CRITICAL + HIGH non-bypassable).
|
|
48
|
+
*/
|
|
49
|
+
export declare function getNonBypassableRules(): GovernanceRule[];
|
|
50
|
+
/**
|
|
51
|
+
* Scan file content for rule violations.
|
|
52
|
+
* Returns array of violations found.
|
|
53
|
+
*/
|
|
54
|
+
export declare function scanFileForViolations(filePath: string, content: string): Array<{
|
|
55
|
+
rule: GovernanceRule;
|
|
56
|
+
match: string;
|
|
57
|
+
line: number;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Validate tool arguments against governance rules.
|
|
61
|
+
* Returns violation messages if any critical rule is violated.
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateArgsAgainstRules(toolName: string, args: Record<string, unknown>): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Validate tool response for governance violations.
|
|
66
|
+
* Returns violation messages if found.
|
|
67
|
+
*/
|
|
68
|
+
export declare function validateResponseAgainstRules(toolName: string, responseText: string): string | null;
|
|
69
|
+
/**
|
|
70
|
+
* Build system prompt override block for CLI initialization.
|
|
71
|
+
* This is injected into the AI's system prompt at MCP connect time.
|
|
72
|
+
*/
|
|
73
|
+
export declare function buildSystemPromptOverride(): string;
|
|
74
|
+
/**
|
|
75
|
+
* Add a custom governance rule at runtime.
|
|
76
|
+
*/
|
|
77
|
+
export declare function addRule(rule: GovernanceRule): void;
|
|
78
|
+
export { GOVERNANCE_RULES as DefaultGovernanceRules };
|