codedev-mcp 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/LICENSE +21 -0
  3. package/README.md +760 -0
  4. package/dist/analyzers/api-contract.d.ts +46 -0
  5. package/dist/analyzers/api-contract.d.ts.map +1 -0
  6. package/dist/analyzers/api-contract.js +319 -0
  7. package/dist/analyzers/api-contract.js.map +1 -0
  8. package/dist/analyzers/architecture.d.ts +37 -0
  9. package/dist/analyzers/architecture.d.ts.map +1 -0
  10. package/dist/analyzers/architecture.js +149 -0
  11. package/dist/analyzers/architecture.js.map +1 -0
  12. package/dist/analyzers/branch-compare.d.ts +46 -0
  13. package/dist/analyzers/branch-compare.d.ts.map +1 -0
  14. package/dist/analyzers/branch-compare.js +128 -0
  15. package/dist/analyzers/branch-compare.js.map +1 -0
  16. package/dist/analyzers/cicd.d.ts +42 -0
  17. package/dist/analyzers/cicd.d.ts.map +1 -0
  18. package/dist/analyzers/cicd.js +237 -0
  19. package/dist/analyzers/cicd.js.map +1 -0
  20. package/dist/analyzers/codebase.d.ts +64 -0
  21. package/dist/analyzers/codebase.d.ts.map +1 -0
  22. package/dist/analyzers/codebase.js +354 -0
  23. package/dist/analyzers/codebase.js.map +1 -0
  24. package/dist/analyzers/complexity-heatmap.d.ts +50 -0
  25. package/dist/analyzers/complexity-heatmap.d.ts.map +1 -0
  26. package/dist/analyzers/complexity-heatmap.js +156 -0
  27. package/dist/analyzers/complexity-heatmap.js.map +1 -0
  28. package/dist/analyzers/context-pack.d.ts +43 -0
  29. package/dist/analyzers/context-pack.d.ts.map +1 -0
  30. package/dist/analyzers/context-pack.js +232 -0
  31. package/dist/analyzers/context-pack.js.map +1 -0
  32. package/dist/analyzers/coverage.d.ts +70 -0
  33. package/dist/analyzers/coverage.d.ts.map +1 -0
  34. package/dist/analyzers/coverage.js +313 -0
  35. package/dist/analyzers/coverage.js.map +1 -0
  36. package/dist/analyzers/db-schema.d.ts +55 -0
  37. package/dist/analyzers/db-schema.d.ts.map +1 -0
  38. package/dist/analyzers/db-schema.js +237 -0
  39. package/dist/analyzers/db-schema.js.map +1 -0
  40. package/dist/analyzers/dead-code.d.ts +34 -0
  41. package/dist/analyzers/dead-code.d.ts.map +1 -0
  42. package/dist/analyzers/dead-code.js +131 -0
  43. package/dist/analyzers/dead-code.js.map +1 -0
  44. package/dist/analyzers/dep-vuln.d.ts +36 -0
  45. package/dist/analyzers/dep-vuln.d.ts.map +1 -0
  46. package/dist/analyzers/dep-vuln.js +342 -0
  47. package/dist/analyzers/dep-vuln.js.map +1 -0
  48. package/dist/analyzers/docs.d.ts +47 -0
  49. package/dist/analyzers/docs.d.ts.map +1 -0
  50. package/dist/analyzers/docs.js +473 -0
  51. package/dist/analyzers/docs.js.map +1 -0
  52. package/dist/analyzers/git.d.ts +115 -0
  53. package/dist/analyzers/git.d.ts.map +1 -0
  54. package/dist/analyzers/git.js +214 -0
  55. package/dist/analyzers/git.js.map +1 -0
  56. package/dist/analyzers/iac.d.ts +39 -0
  57. package/dist/analyzers/iac.d.ts.map +1 -0
  58. package/dist/analyzers/iac.js +233 -0
  59. package/dist/analyzers/iac.js.map +1 -0
  60. package/dist/analyzers/impact.d.ts +51 -0
  61. package/dist/analyzers/impact.d.ts.map +1 -0
  62. package/dist/analyzers/impact.js +235 -0
  63. package/dist/analyzers/impact.js.map +1 -0
  64. package/dist/analyzers/monorepo.d.ts +36 -0
  65. package/dist/analyzers/monorepo.d.ts.map +1 -0
  66. package/dist/analyzers/monorepo.js +233 -0
  67. package/dist/analyzers/monorepo.js.map +1 -0
  68. package/dist/analyzers/notebook.d.ts +53 -0
  69. package/dist/analyzers/notebook.d.ts.map +1 -0
  70. package/dist/analyzers/notebook.js +149 -0
  71. package/dist/analyzers/notebook.js.map +1 -0
  72. package/dist/analyzers/perf-profile.d.ts +39 -0
  73. package/dist/analyzers/perf-profile.d.ts.map +1 -0
  74. package/dist/analyzers/perf-profile.js +222 -0
  75. package/dist/analyzers/perf-profile.js.map +1 -0
  76. package/dist/analyzers/scaffold.d.ts +46 -0
  77. package/dist/analyzers/scaffold.d.ts.map +1 -0
  78. package/dist/analyzers/scaffold.js +313 -0
  79. package/dist/analyzers/scaffold.js.map +1 -0
  80. package/dist/analyzers/security.d.ts +42 -0
  81. package/dist/analyzers/security.d.ts.map +1 -0
  82. package/dist/analyzers/security.js +281 -0
  83. package/dist/analyzers/security.js.map +1 -0
  84. package/dist/analyzers/symbols.d.ts +49 -0
  85. package/dist/analyzers/symbols.d.ts.map +1 -0
  86. package/dist/analyzers/symbols.js +212 -0
  87. package/dist/analyzers/symbols.js.map +1 -0
  88. package/dist/analyzers/tree-sitter.d.ts +71 -0
  89. package/dist/analyzers/tree-sitter.d.ts.map +1 -0
  90. package/dist/analyzers/tree-sitter.js +333 -0
  91. package/dist/analyzers/tree-sitter.js.map +1 -0
  92. package/dist/analyzers/type-flow.d.ts +39 -0
  93. package/dist/analyzers/type-flow.d.ts.map +1 -0
  94. package/dist/analyzers/type-flow.js +75 -0
  95. package/dist/analyzers/type-flow.js.map +1 -0
  96. package/dist/cache/memory-cache.d.ts +130 -0
  97. package/dist/cache/memory-cache.d.ts.map +1 -0
  98. package/dist/cache/memory-cache.js +273 -0
  99. package/dist/cache/memory-cache.js.map +1 -0
  100. package/dist/config.d.ts +32 -0
  101. package/dist/config.d.ts.map +1 -0
  102. package/dist/config.js +57 -0
  103. package/dist/config.js.map +1 -0
  104. package/dist/constants/instructions.d.ts +2 -0
  105. package/dist/constants/instructions.d.ts.map +1 -0
  106. package/dist/constants/instructions.js +82 -0
  107. package/dist/constants/instructions.js.map +1 -0
  108. package/dist/db/connection.d.ts +12 -0
  109. package/dist/db/connection.d.ts.map +1 -0
  110. package/dist/db/connection.js +34 -0
  111. package/dist/db/connection.js.map +1 -0
  112. package/dist/db/json-store.d.ts +111 -0
  113. package/dist/db/json-store.d.ts.map +1 -0
  114. package/dist/db/json-store.js +201 -0
  115. package/dist/db/json-store.js.map +1 -0
  116. package/dist/db/sqlite-store.d.ts +153 -0
  117. package/dist/db/sqlite-store.d.ts.map +1 -0
  118. package/dist/db/sqlite-store.js +388 -0
  119. package/dist/db/sqlite-store.js.map +1 -0
  120. package/dist/index.d.ts +17 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +116 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/resources/health.d.ts +35 -0
  125. package/dist/resources/health.d.ts.map +1 -0
  126. package/dist/resources/health.js +81 -0
  127. package/dist/resources/health.js.map +1 -0
  128. package/dist/schemas/output-schemas.d.ts +517 -0
  129. package/dist/schemas/output-schemas.d.ts.map +1 -0
  130. package/dist/schemas/output-schemas.js +296 -0
  131. package/dist/schemas/output-schemas.js.map +1 -0
  132. package/dist/search/fast-search.d.ts +90 -0
  133. package/dist/search/fast-search.d.ts.map +1 -0
  134. package/dist/search/fast-search.js +387 -0
  135. package/dist/search/fast-search.js.map +1 -0
  136. package/dist/search/semantic.d.ts +26 -0
  137. package/dist/search/semantic.d.ts.map +1 -0
  138. package/dist/search/semantic.js +458 -0
  139. package/dist/search/semantic.js.map +1 -0
  140. package/dist/tools/analysis.d.ts +7 -0
  141. package/dist/tools/analysis.d.ts.map +1 -0
  142. package/dist/tools/analysis.js +491 -0
  143. package/dist/tools/analysis.js.map +1 -0
  144. package/dist/tools/architecture.d.ts +7 -0
  145. package/dist/tools/architecture.d.ts.map +1 -0
  146. package/dist/tools/architecture.js +176 -0
  147. package/dist/tools/architecture.js.map +1 -0
  148. package/dist/tools/devops.d.ts +7 -0
  149. package/dist/tools/devops.d.ts.map +1 -0
  150. package/dist/tools/devops.js +179 -0
  151. package/dist/tools/devops.js.map +1 -0
  152. package/dist/tools/docs.d.ts +7 -0
  153. package/dist/tools/docs.d.ts.map +1 -0
  154. package/dist/tools/docs.js +102 -0
  155. package/dist/tools/docs.js.map +1 -0
  156. package/dist/tools/git.d.ts +7 -0
  157. package/dist/tools/git.d.ts.map +1 -0
  158. package/dist/tools/git.js +475 -0
  159. package/dist/tools/git.js.map +1 -0
  160. package/dist/tools/nav.d.ts +7 -0
  161. package/dist/tools/nav.d.ts.map +1 -0
  162. package/dist/tools/nav.js +275 -0
  163. package/dist/tools/nav.js.map +1 -0
  164. package/dist/tools/notebook.d.ts +7 -0
  165. package/dist/tools/notebook.d.ts.map +1 -0
  166. package/dist/tools/notebook.js +102 -0
  167. package/dist/tools/notebook.js.map +1 -0
  168. package/dist/tools/performance.d.ts +7 -0
  169. package/dist/tools/performance.d.ts.map +1 -0
  170. package/dist/tools/performance.js +59 -0
  171. package/dist/tools/performance.js.map +1 -0
  172. package/dist/tools/quality.d.ts +7 -0
  173. package/dist/tools/quality.d.ts.map +1 -0
  174. package/dist/tools/quality.js +279 -0
  175. package/dist/tools/quality.js.map +1 -0
  176. package/dist/tools/scaffold.d.ts +7 -0
  177. package/dist/tools/scaffold.d.ts.map +1 -0
  178. package/dist/tools/scaffold.js +80 -0
  179. package/dist/tools/scaffold.js.map +1 -0
  180. package/dist/tools/search.d.ts +7 -0
  181. package/dist/tools/search.d.ts.map +1 -0
  182. package/dist/tools/search.js +308 -0
  183. package/dist/tools/search.js.map +1 -0
  184. package/dist/tools/security.d.ts +7 -0
  185. package/dist/tools/security.d.ts.map +1 -0
  186. package/dist/tools/security.js +138 -0
  187. package/dist/tools/security.js.map +1 -0
  188. package/dist/utils/analytics.d.ts +69 -0
  189. package/dist/utils/analytics.d.ts.map +1 -0
  190. package/dist/utils/analytics.js +144 -0
  191. package/dist/utils/analytics.js.map +1 -0
  192. package/dist/utils/concurrency.d.ts +43 -0
  193. package/dist/utils/concurrency.d.ts.map +1 -0
  194. package/dist/utils/concurrency.js +78 -0
  195. package/dist/utils/concurrency.js.map +1 -0
  196. package/dist/utils/fallback.d.ts +52 -0
  197. package/dist/utils/fallback.d.ts.map +1 -0
  198. package/dist/utils/fallback.js +137 -0
  199. package/dist/utils/fallback.js.map +1 -0
  200. package/dist/utils/git-hooks.d.ts +24 -0
  201. package/dist/utils/git-hooks.d.ts.map +1 -0
  202. package/dist/utils/git-hooks.js +108 -0
  203. package/dist/utils/git-hooks.js.map +1 -0
  204. package/dist/utils/languages.d.ts +72 -0
  205. package/dist/utils/languages.d.ts.map +1 -0
  206. package/dist/utils/languages.js +463 -0
  207. package/dist/utils/languages.js.map +1 -0
  208. package/dist/utils/logger.d.ts +13 -0
  209. package/dist/utils/logger.d.ts.map +1 -0
  210. package/dist/utils/logger.js +34 -0
  211. package/dist/utils/logger.js.map +1 -0
  212. package/dist/utils/plugins.d.ts +105 -0
  213. package/dist/utils/plugins.d.ts.map +1 -0
  214. package/dist/utils/plugins.js +325 -0
  215. package/dist/utils/plugins.js.map +1 -0
  216. package/dist/utils/security.d.ts +17 -0
  217. package/dist/utils/security.d.ts.map +1 -0
  218. package/dist/utils/security.js +48 -0
  219. package/dist/utils/security.js.map +1 -0
  220. package/dist/utils/streaming.d.ts +56 -0
  221. package/dist/utils/streaming.d.ts.map +1 -0
  222. package/dist/utils/streaming.js +95 -0
  223. package/dist/utils/streaming.js.map +1 -0
  224. package/dist/version.d.ts +3 -0
  225. package/dist/version.d.ts.map +1 -0
  226. package/dist/version.js +3 -0
  227. package/dist/version.js.map +1 -0
  228. package/mcp.json +100 -0
  229. package/package.json +89 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Tool Usage Analytics
3
+ * Tracks which tools are called most, response times, cache hit rates.
4
+ * Exposed via server://stats resource.
5
+ */
6
+ class Analytics {
7
+ calls = [];
8
+ startTime = Date.now();
9
+ /** Keep last 5000 calls */
10
+ maxHistory = 5000;
11
+ /**
12
+ * Record a tool call.
13
+ * @param tool - Tool name.
14
+ * @param durationMs - Duration in milliseconds.
15
+ * @param success - Whether the call succeeded.
16
+ * @param cached - Whether the result was from cache.
17
+ */
18
+ record(tool, durationMs, success, cached = false) {
19
+ this.calls.push({ tool, timestamp: Date.now(), durationMs, success, cached });
20
+ // Trim old history
21
+ if (this.calls.length > this.maxHistory) {
22
+ this.calls = this.calls.slice(-this.maxHistory);
23
+ }
24
+ // Persist async (fire and forget)
25
+ import('../db/connection.js').then(({ getDb }) => {
26
+ // Lazy import to avoid circular dep if any
27
+ getDb()
28
+ .then((db) => {
29
+ db.logUsage(tool, durationMs, success, cached);
30
+ db.save().catch(() => {
31
+ /* Silently ignore save errors to avoid polluting structured logs */
32
+ });
33
+ })
34
+ .catch(() => { });
35
+ });
36
+ }
37
+ /**
38
+ * Wrap an async tool handler with timing and recording.
39
+ * @param tool - Tool name.
40
+ * @param fn - The async function to wrap.
41
+ * @param cached - Whether the result is from cache.
42
+ * @returns The result of the wrapped function.
43
+ */
44
+ async track(tool, fn, cached = false) {
45
+ const start = Date.now();
46
+ try {
47
+ const result = await fn();
48
+ this.record(tool, Date.now() - start, true, cached);
49
+ return result;
50
+ }
51
+ catch (error) {
52
+ this.record(tool, Date.now() - start, false, cached);
53
+ throw error;
54
+ }
55
+ }
56
+ /**
57
+ * Get full analytics report.
58
+ * @returns The analytics report with uptime, totals, and per-tool stats.
59
+ */
60
+ getReport() {
61
+ const uptimeMs = Date.now() - this.startTime;
62
+ const hours = Math.floor(uptimeMs / 3600000);
63
+ const mins = Math.floor((uptimeMs % 3600000) / 60000);
64
+ const secs = Math.floor((uptimeMs % 60000) / 1000);
65
+ // Aggregate by tool
66
+ const toolMap = new Map();
67
+ for (const call of this.calls) {
68
+ if (!toolMap.has(call.tool))
69
+ toolMap.set(call.tool, []);
70
+ toolMap.get(call.tool).push(call);
71
+ }
72
+ const toolStats = Array.from(toolMap.entries())
73
+ .map(([tool, calls]) => ({
74
+ tool,
75
+ callCount: calls.length,
76
+ avgDurationMs: Math.round(calls.reduce((sum, c) => sum + c.durationMs, 0) / calls.length),
77
+ maxDurationMs: Math.max(...calls.map((c) => c.durationMs)),
78
+ errorCount: calls.filter((c) => !c.success).length,
79
+ cacheHits: calls.filter((c) => c.cached).length,
80
+ lastCalled: new Date(calls[calls.length - 1].timestamp).toISOString(),
81
+ }))
82
+ .sort((a, b) => b.callCount - a.callCount);
83
+ const totalCalls = this.calls.length;
84
+ const totalErrors = this.calls.filter((c) => !c.success).length;
85
+ const totalCached = this.calls.filter((c) => c.cached).length;
86
+ const avgResponseMs = totalCalls > 0 ? Math.round(this.calls.reduce((sum, c) => sum + c.durationMs, 0) / totalCalls) : 0;
87
+ // Recent 10 calls
88
+ const recentCalls = this.calls
89
+ .slice(-10)
90
+ .reverse()
91
+ .map((c) => ({
92
+ tool: c.tool,
93
+ durationMs: c.durationMs,
94
+ timestamp: new Date(c.timestamp).toISOString(),
95
+ }));
96
+ return {
97
+ uptime: `${hours}h ${mins}m ${secs}s`,
98
+ totalCalls,
99
+ totalErrors,
100
+ avgResponseMs,
101
+ cacheHitRate: totalCalls > 0 ? `${Math.round((totalCached / totalCalls) * 100)}%` : '0%',
102
+ toolStats,
103
+ recentCalls,
104
+ };
105
+ }
106
+ /**
107
+ * Get suggested actions based on analytics and codebase state.
108
+ * @returns A list of suggested actions.
109
+ */
110
+ getSuggestedActions() {
111
+ const suggestions = [];
112
+ const report = this.getReport();
113
+ if (report.totalCalls === 0) {
114
+ suggestions.push('Start with "codebase_map" to get an overview of the project.');
115
+ suggestions.push('Use "security_scan" to check for common vulnerabilities.');
116
+ suggestions.push('Run "code_health_check" prompt for a complete health audit.');
117
+ return suggestions;
118
+ }
119
+ // Check what hasn't been used
120
+ const usedTools = new Set(report.toolStats.map((s) => s.tool));
121
+ if (!usedTools.has('security_scan'))
122
+ suggestions.push('Run "security_scan" to check for vulnerabilities.');
123
+ if (!usedTools.has('test_coverage'))
124
+ suggestions.push('Check "test_coverage" to see what needs more tests.');
125
+ if (!usedTools.has('dead_code'))
126
+ suggestions.push('Use "dead_code" to find unused exports and orphan files.');
127
+ if (!usedTools.has('code_docs'))
128
+ suggestions.push('Use "code_docs" with action "undocumented" to find undocumented APIs.');
129
+ // High error tools
130
+ for (const stat of report.toolStats) {
131
+ if (stat.errorCount > stat.callCount * 0.3) {
132
+ suggestions.push(`Tool "${stat.tool}" has a ${Math.round((stat.errorCount / stat.callCount) * 100)}% error rate — check the parameters.`);
133
+ }
134
+ }
135
+ // Performance suggestions
136
+ if (report.avgResponseMs > 2000) {
137
+ suggestions.push('Average response time is high — consider narrowing search queries with file_glob or directory parameters.');
138
+ }
139
+ return suggestions.slice(0, 5);
140
+ }
141
+ }
142
+ // Singleton instance
143
+ export const analytics = new Analytics();
144
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/utils/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Concurrency limiter for parallel tool calls.
3
+ * Prevents resource exhaustion when MCP clients send many requests at once.
4
+ */
5
+ /**
6
+ * Semaphore for limiting concurrent operations.
7
+ */
8
+ export declare class Semaphore {
9
+ private readonly maxConcurrent;
10
+ private current;
11
+ private queue;
12
+ /**
13
+ * Create a new Semaphore with a maximum concurrency limit.
14
+ * @param maxConcurrent - Maximum number of concurrent operations allowed.
15
+ */
16
+ constructor(maxConcurrent: number);
17
+ /**
18
+ * Acquire a semaphore slot. Waits if at capacity.
19
+ */
20
+ acquire(): Promise<void>;
21
+ /**
22
+ * Release a semaphore slot, allowing the next queued operation to proceed.
23
+ */
24
+ release(): void;
25
+ /**
26
+ * Wrap an async function with semaphore acquire/release.
27
+ * @param fn - The async function to run under concurrency control.
28
+ * @returns The result of the wrapped function.
29
+ */
30
+ run<T>(fn: () => Promise<T>): Promise<T>;
31
+ /**
32
+ * Get the number of queued operations waiting for a slot.
33
+ * @returns The number of pending operations.
34
+ */
35
+ get pending(): number;
36
+ /**
37
+ * Get the number of currently active operations.
38
+ * @returns The number of active operations.
39
+ */
40
+ get active(): number;
41
+ }
42
+ export declare const toolLimiter: Semaphore;
43
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/utils/concurrency.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,qBAAa,SAAS;IAQR,OAAO,CAAC,QAAQ,CAAC,aAAa;IAP1C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,KAAK,CAAsB;IAEnC;;;OAGG;gBAC0B,aAAa,EAAE,MAAM;IAElD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;;;OAIG;IACG,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS9C;;;OAGG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;OAGG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAQD,eAAO,MAAM,WAAW,WAAgC,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Concurrency limiter for parallel tool calls.
3
+ * Prevents resource exhaustion when MCP clients send many requests at once.
4
+ */
5
+ /**
6
+ * Semaphore for limiting concurrent operations.
7
+ */
8
+ export class Semaphore {
9
+ maxConcurrent;
10
+ current = 0;
11
+ queue = [];
12
+ /**
13
+ * Create a new Semaphore with a maximum concurrency limit.
14
+ * @param maxConcurrent - Maximum number of concurrent operations allowed.
15
+ */
16
+ constructor(maxConcurrent) {
17
+ this.maxConcurrent = maxConcurrent;
18
+ }
19
+ /**
20
+ * Acquire a semaphore slot. Waits if at capacity.
21
+ */
22
+ async acquire() {
23
+ if (this.current < this.maxConcurrent) {
24
+ this.current++;
25
+ return;
26
+ }
27
+ return new Promise((resolve) => {
28
+ this.queue.push(resolve);
29
+ });
30
+ }
31
+ /**
32
+ * Release a semaphore slot, allowing the next queued operation to proceed.
33
+ */
34
+ release() {
35
+ this.current--;
36
+ const next = this.queue.shift();
37
+ if (next) {
38
+ this.current++;
39
+ next();
40
+ }
41
+ }
42
+ /**
43
+ * Wrap an async function with semaphore acquire/release.
44
+ * @param fn - The async function to run under concurrency control.
45
+ * @returns The result of the wrapped function.
46
+ */
47
+ async run(fn) {
48
+ await this.acquire();
49
+ try {
50
+ return await fn();
51
+ }
52
+ finally {
53
+ this.release();
54
+ }
55
+ }
56
+ /**
57
+ * Get the number of queued operations waiting for a slot.
58
+ * @returns The number of pending operations.
59
+ */
60
+ get pending() {
61
+ return this.queue.length;
62
+ }
63
+ /**
64
+ * Get the number of currently active operations.
65
+ * @returns The number of active operations.
66
+ */
67
+ get active() {
68
+ return this.current;
69
+ }
70
+ }
71
+ /**
72
+ * Global tool concurrency limiter.
73
+ * Defaults to 8 concurrent tool executions — enough for parallel use
74
+ * while preventing filesystem/ripgrep thrashing on large codebases.
75
+ */
76
+ const MAX_CONCURRENT = parseInt(process.env.CODEDEV_MAX_CONCURRENT || '8', 10);
77
+ export const toolLimiter = new Semaphore(MAX_CONCURRENT);
78
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/utils/concurrency.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,OAAO,SAAS;IAQS;IAPrB,OAAO,GAAG,CAAC,CAAC;IACZ,KAAK,GAAmB,EAAE,CAAC;IAEnC;;;OAGG;IACH,YAA6B,aAAqB;QAArB,kBAAa,GAAb,aAAa,CAAQ;IAAG,CAAC;IAEtD;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,EAAE,CAAC;QACT,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAG,CAAI,EAAoB;QAC/B,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Fallback Utilities
3
+ * Provides graceful degradation when external binaries are unavailable
4
+ */
5
+ /**
6
+ * Check if a binary is available
7
+ * @param binary - The binary name to check.
8
+ * @returns True if the binary is available in PATH.
9
+ */
10
+ export declare function isBinaryAvailable(binary: string): boolean;
11
+ /**
12
+ * Native file listing fallback when fd is unavailable
13
+ * @param dir - The directory to list files from.
14
+ * @param options - Options for filtering.
15
+ * @param options.glob - Glob pattern to match files.
16
+ * @param options.depth - Maximum directory depth to traverse.
17
+ * @param options.type - File type filter: 'file', 'directory', or 'any'.
18
+ * @returns An array of relative file paths.
19
+ */
20
+ export declare function listFilesNative(dir: string, options?: {
21
+ glob?: string;
22
+ depth?: number;
23
+ type?: 'file' | 'directory' | 'any';
24
+ }): Promise<string[]>;
25
+ /**
26
+ * Native grep fallback when ripgrep is unavailable
27
+ * @param dir - The directory to search in.
28
+ * @param pattern - The search pattern.
29
+ * @param options - Search options.
30
+ * @param options.isRegex - Whether the pattern is a regex.
31
+ * @param options.caseSensitive - Whether the search is case-sensitive.
32
+ * @returns An array of matching results with file, line number, and text.
33
+ */
34
+ export declare function grepNative(dir: string, pattern: string, options?: {
35
+ isRegex?: boolean;
36
+ caseSensitive?: boolean;
37
+ }): Promise<{
38
+ file: string;
39
+ line: number;
40
+ text: string;
41
+ }[]>;
42
+ /**
43
+ * Get appropriate search function based on binary availability
44
+ * @returns The search strategy to use.
45
+ */
46
+ export declare function getSearchStrategy(): 'ripgrep' | 'native';
47
+ /**
48
+ * Get appropriate file listing strategy
49
+ * @returns The file listing strategy to use.
50
+ */
51
+ export declare function getListStrategy(): 'fd' | 'native';
52
+ //# sourceMappingURL=fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../src/utils/fallback.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAczD;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,KAAK,CAAA;CAAE,GAC/E,OAAO,CAAC,MAAM,EAAE,CAAC,CA+CnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACvD,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CA8BzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,SAAS,GAAG,QAAQ,CAExD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,GAAG,QAAQ,CAEjD"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Fallback Utilities
3
+ * Provides graceful degradation when external binaries are unavailable
4
+ */
5
+ import { execSync } from 'node:child_process';
6
+ import { readdir, readFile } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ import { logger } from './logger.js';
9
+ // Cache binary availability checks
10
+ const binaryCache = new Map();
11
+ /**
12
+ * Check if a binary is available
13
+ * @param binary - The binary name to check.
14
+ * @returns True if the binary is available in PATH.
15
+ */
16
+ export function isBinaryAvailable(binary) {
17
+ if (binaryCache.has(binary)) {
18
+ return binaryCache.get(binary);
19
+ }
20
+ try {
21
+ execSync(`which ${binary}`, { stdio: 'pipe' });
22
+ binaryCache.set(binary, true);
23
+ return true;
24
+ }
25
+ catch {
26
+ binaryCache.set(binary, false);
27
+ logger.warn(`Binary not available: ${binary}, using fallback`);
28
+ return false;
29
+ }
30
+ }
31
+ /**
32
+ * Native file listing fallback when fd is unavailable
33
+ * @param dir - The directory to list files from.
34
+ * @param options - Options for filtering.
35
+ * @param options.glob - Glob pattern to match files.
36
+ * @param options.depth - Maximum directory depth to traverse.
37
+ * @param options.type - File type filter: 'file', 'directory', or 'any'.
38
+ * @returns An array of relative file paths.
39
+ */
40
+ export async function listFilesNative(dir, options) {
41
+ const results = [];
42
+ const maxDepth = options?.depth ?? 10;
43
+ const type = options?.type ?? 'file';
44
+ async function walk(currentDir, depth) {
45
+ if (depth > maxDepth)
46
+ return;
47
+ try {
48
+ const entries = await readdir(currentDir, { withFileTypes: true });
49
+ for (const entry of entries) {
50
+ // Skip hidden and common ignore patterns
51
+ if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === '__pycache__') {
52
+ continue;
53
+ }
54
+ const fullPath = join(currentDir, entry.name);
55
+ const relativePath = fullPath.replace(dir + '/', '');
56
+ if (entry.isDirectory()) {
57
+ if (type === 'directory' || type === 'any') {
58
+ results.push(relativePath);
59
+ }
60
+ await walk(fullPath, depth + 1);
61
+ }
62
+ else if (entry.isFile()) {
63
+ if (type === 'file' || type === 'any') {
64
+ // Apply glob filter if provided
65
+ if (options?.glob) {
66
+ const pattern = options.glob.replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*');
67
+ if (new RegExp(pattern).test(relativePath)) {
68
+ results.push(relativePath);
69
+ }
70
+ }
71
+ else {
72
+ results.push(relativePath);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ catch {
79
+ // Ignore permission errors
80
+ }
81
+ }
82
+ await walk(dir, 0);
83
+ // Limit results
84
+ return results.slice(0, 10000);
85
+ }
86
+ /**
87
+ * Native grep fallback when ripgrep is unavailable
88
+ * @param dir - The directory to search in.
89
+ * @param pattern - The search pattern.
90
+ * @param options - Search options.
91
+ * @param options.isRegex - Whether the pattern is a regex.
92
+ * @param options.caseSensitive - Whether the search is case-sensitive.
93
+ * @returns An array of matching results with file, line number, and text.
94
+ */
95
+ export async function grepNative(dir, pattern, options) {
96
+ const results = [];
97
+ const files = await listFilesNative(dir, { type: 'file' });
98
+ const regex = options?.isRegex
99
+ ? new RegExp(pattern, options?.caseSensitive ? '' : 'i')
100
+ : new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), options?.caseSensitive ? '' : 'i');
101
+ for (const file of files.slice(0, 500)) {
102
+ try {
103
+ const content = await readFile(join(dir, file), 'utf-8');
104
+ const lines = content.split('\n');
105
+ for (let i = 0; i < lines.length; i++) {
106
+ if (regex.test(lines[i])) {
107
+ results.push({
108
+ file,
109
+ line: i + 1,
110
+ text: lines[i].slice(0, 200),
111
+ });
112
+ if (results.length >= 100)
113
+ return results;
114
+ }
115
+ }
116
+ }
117
+ catch {
118
+ // Skip files that can't be read
119
+ }
120
+ }
121
+ return results;
122
+ }
123
+ /**
124
+ * Get appropriate search function based on binary availability
125
+ * @returns The search strategy to use.
126
+ */
127
+ export function getSearchStrategy() {
128
+ return isBinaryAvailable('rg') ? 'ripgrep' : 'native';
129
+ }
130
+ /**
131
+ * Get appropriate file listing strategy
132
+ * @returns The file listing strategy to use.
133
+ */
134
+ export function getListStrategy() {
135
+ return isBinaryAvailable('fd') ? 'fd' : 'native';
136
+ }
137
+ //# sourceMappingURL=fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback.js","sourceRoot":"","sources":["../../src/utils/fallback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Git Hooks Integration
3
+ * Generates pre-commit hooks and provides dry-run preview mode.
4
+ */
5
+ export interface HookResult {
6
+ action: 'generate' | 'preview' | 'status';
7
+ hookPath?: string;
8
+ hookContent?: string;
9
+ installed?: boolean;
10
+ existingHook?: boolean;
11
+ previewFindings?: {
12
+ check: string;
13
+ count: number;
14
+ examples: string[];
15
+ }[];
16
+ }
17
+ /**
18
+ * Manage git hooks: generate, preview, or check status.
19
+ * @param cwd - The working directory (git repository root).
20
+ * @param action - The action to perform: 'generate', 'preview', or 'status'.
21
+ * @returns The hook result with relevant information for the action.
22
+ */
23
+ export declare function manageGitHooks(cwd: string, action: 'generate' | 'preview' | 'status'): Promise<HookResult>;
24
+ //# sourceMappingURL=git-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.d.ts","sourceRoot":"","sources":["../../src/utils/git-hooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CAC1E;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAsFhH"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Git Hooks Integration
3
+ * Generates pre-commit hooks and provides dry-run preview mode.
4
+ */
5
+ import { execFile } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ import { readFile } from 'node:fs/promises';
8
+ import { existsSync } from 'node:fs';
9
+ import path from 'node:path';
10
+ const execFilePromisified = promisify(execFile);
11
+ /**
12
+ * Manage git hooks: generate, preview, or check status.
13
+ * @param cwd - The working directory (git repository root).
14
+ * @param action - The action to perform: 'generate', 'preview', or 'status'.
15
+ * @returns The hook result with relevant information for the action.
16
+ */
17
+ export async function manageGitHooks(cwd, action) {
18
+ const hookPath = path.join(cwd, '.git', 'hooks', 'pre-commit');
19
+ if (action === 'status') {
20
+ const installed = existsSync(hookPath);
21
+ let content = '';
22
+ if (installed)
23
+ content = await readFile(hookPath, 'utf-8').catch(() => '');
24
+ return {
25
+ action: 'status',
26
+ hookPath,
27
+ installed,
28
+ existingHook: installed && !content.includes('codedev-mcp'),
29
+ hookContent: installed ? content : undefined,
30
+ };
31
+ }
32
+ if (action === 'preview') {
33
+ const findings = [];
34
+ try {
35
+ const { stdout } = await execFilePromisified('git', ['diff', '--cached', '--name-only', '--diff-filter=ACM'], {
36
+ cwd,
37
+ });
38
+ const staged = stdout
39
+ .trim()
40
+ .split('\n')
41
+ .filter((f) => /\.(ts|tsx|js|jsx|py|java|go|rs|rb|php|cs)$/.test(f));
42
+ if (staged.length === 0)
43
+ return {
44
+ action: 'preview',
45
+ previewFindings: [{ check: 'info', count: 0, examples: ['No staged source files'] }],
46
+ };
47
+ for (const file of staged.slice(0, 20)) {
48
+ try {
49
+ const content = await readFile(path.resolve(cwd, file), 'utf-8');
50
+ const lines = content.split('\n');
51
+ const secrets = lines.filter((l) => /(password|secret|api_key|token)\s*[:=]\s*["'][^${}]/.test(l));
52
+ if (secrets.length) {
53
+ const e = findings.find((f) => f.check === 'secrets');
54
+ if (e)
55
+ e.count += secrets.length;
56
+ else
57
+ findings.push({ check: 'secrets', count: secrets.length, examples: [`${file}`] });
58
+ }
59
+ const logs = lines.filter((l) => /console\.(log|debug|info)|print\(|fmt\.Print/.test(l));
60
+ if (logs.length) {
61
+ const e = findings.find((f) => f.check === 'console_logs');
62
+ if (e)
63
+ e.count += logs.length;
64
+ else
65
+ findings.push({ check: 'console_logs', count: logs.length, examples: [`${file}: ${logs.length}`] });
66
+ }
67
+ const todos = lines.filter((l) => /TODO|FIXME|HACK|XXX/.test(l));
68
+ if (todos.length) {
69
+ const e = findings.find((f) => f.check === 'todos');
70
+ if (e)
71
+ e.count += todos.length;
72
+ else
73
+ findings.push({ check: 'todos', count: todos.length, examples: [`${file}: ${todos.length}`] });
74
+ }
75
+ }
76
+ catch {
77
+ /* skip */
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ /* not git repo */
83
+ }
84
+ return { action: 'preview', previewFindings: findings };
85
+ }
86
+ // Generate hook script
87
+ const hookContent = [
88
+ '#!/bin/sh',
89
+ '# codedev-mcp pre-commit hook',
90
+ 'echo "Running pre-commit checks..."',
91
+ 'STAGED=$(git diff --cached --name-only --diff-filter=ACM)',
92
+ 'ERRORS=0',
93
+ '',
94
+ '# Check for hardcoded secrets',
95
+ 'SECRETS=$(echo "$STAGED" | xargs grep -nE "(password|secret|api_key|token)\\s*[:=]\\s*[\\x22\\x27][^\\$]" 2>/dev/null || true)',
96
+ 'if [ -n "$SECRETS" ]; then echo "SECRETS DETECTED:"; echo "$SECRETS" | head -5; ERRORS=$((ERRORS+1)); fi',
97
+ '',
98
+ '# Check for debug statements',
99
+ 'DEBUG=$(echo "$STAGED" | xargs grep -nE "console\\.(log|debug)|print\\(" 2>/dev/null || true)',
100
+ 'if [ -n "$DEBUG" ]; then echo "Debug statements:"; echo "$DEBUG" | head -5; fi',
101
+ '',
102
+ 'if [ $ERRORS -gt 0 ]; then echo "Pre-commit failed"; exit 1; fi',
103
+ 'echo "Pre-commit passed"',
104
+ 'exit 0',
105
+ ].join('\n');
106
+ return { action: 'generate', hookPath, hookContent, installed: false, existingHook: existsSync(hookPath) };
107
+ }
108
+ //# sourceMappingURL=git-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.js","sourceRoot":"","sources":["../../src/utils/git-hooks.ts"],"names":[],"mappings":"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"}