codeflow-hook 1.2.0 β 1.4.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.
- package/README.md +286 -19
- package/bin/agents.js +324 -0
- package/bin/codeflow-hook.js +201 -28
- package/bin/rag.js +312 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,14 +1,116 @@
|
|
|
1
|
-
# Codeflow
|
|
1
|
+
# Codeflow Commander β Nexus Gateway CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The Command-Line Interface for the Autonomous Engineering Platform**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Your gateway to the Codeflow Commander Nexus Gateway β a comprehensive AI-driven engineering ecosystem that spans the entire software development lifecycle. This CLI tool serves as the entry point to enterprise-wide autonomous engineering capabilities, from intelligent code analysis to organization-scale workflow automation.
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
This is the universal command-line client for interacting with the **Phase 4 Autonomous Engineering Platform**, featuring next-generation components including the Enterprise Knowledge Graph (EKG), Autonomous Agent Network (AAN), Multi-Modal Interface Layer (MMIL), and Predictive Intelligence Engine (PIE).
|
|
8
|
+
|
|
9
|
+
## π Key Capabilities
|
|
10
|
+
|
|
11
|
+
### **Enterprise Knowledge Graph (EKG)**
|
|
12
|
+
- **Cross-Repository Intelligence**: Unified knowledge across all organizational repositories
|
|
13
|
+
- **Semantic Dependency Mapping**: Understand organizational code relationships and patterns
|
|
14
|
+
- **Expert Discovery**: Identify domain experts through code analysis patterns
|
|
15
|
+
- **Supply Chain Intelligence**: Vulnerability tracking and license compliance across repositories
|
|
16
|
+
|
|
17
|
+
### **Autonomous Agent Network (AAN)**
|
|
18
|
+
- **Workflow Automation**: Transform JIRA tickets into validated pull requests automatically
|
|
19
|
+
- **Self-Healing Operations**: Monitor, detect, diagnose, and fix production issues autonomously
|
|
20
|
+
- **Predictive Maintenance**: Scheduled optimization tasks and dependency updates
|
|
21
|
+
- **Multi-Agent Coordination**: Intelligent conflict resolution and approval workflows
|
|
22
|
+
|
|
23
|
+
### **Multi-Modal Interface Layer (MMIL)**
|
|
24
|
+
- **Conversational Code Generation**: Natural language β complex refactorings and implementations
|
|
25
|
+
- **Design-to-Code Pipeline**: Figma designs to validated production code
|
|
26
|
+
- **IDE Ecosystem Integration**: Native support across VSCode, IntelliJ, Vim, and more
|
|
27
|
+
- **API-First Architecture**: REST APIs for all platform capabilities
|
|
28
|
+
|
|
29
|
+
### **Predictive Intelligence Engine (PIE)**
|
|
30
|
+
- **Tech Debt Forecasting**: Predict maintenance hotspots and cost estimates
|
|
31
|
+
- **Performance Prediction**: Identify regressions before deployment
|
|
32
|
+
- **Engineering Analytics**: Data-driven process optimization and insights
|
|
33
|
+
- **Risk Assessment**: Proactive security and compliance monitoring
|
|
34
|
+
|
|
35
|
+
### **Governance Safety Framework (GSF)**
|
|
36
|
+
- **Autonomous Permissions**: Dynamic access control based on context and risk
|
|
37
|
+
- **Real-time Compliance**: Continuous regulatory and policy validation
|
|
38
|
+
- **Emergency Controls**: System-wide safety mechanisms and overrides
|
|
39
|
+
- **Human-in-the-Loop**: Graduated approval workflows for different risk levels
|
|
40
|
+
|
|
41
|
+
### **Distributed Execution Engine (DEE)**
|
|
42
|
+
- **Repository Federation**: Coordinate operations across multiple repositories
|
|
43
|
+
- **Workflow Orchestration**: Complex process execution with dependency management
|
|
44
|
+
- **State Synchronization**: Federated data consistency across the enterprise
|
|
45
|
+
- **Resource Optimization**: Intelligent load balancing and execution management
|
|
46
|
+
|
|
47
|
+
## ποΈ Architecture Overview
|
|
48
|
+
|
|
49
|
+
The CLI serves as your interface to the Codeflow Commander Nexus Gateway β a distributed, autonomous engineering platform designed for enterprise-scale operation.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
53
|
+
β MULTI-MODAL INTERFACE LAYER (MMIL) β
|
|
54
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
55
|
+
β β Conversational β β DesignβCode β β IDE β β
|
|
56
|
+
β β Interfaces β β Pipeline β β Integrationsβ β
|
|
57
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
58
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
59
|
+
β
|
|
60
|
+
βΌ
|
|
61
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
62
|
+
β AUTONOMOUS AGENT NETWORK (AAN) - ORCHESTRATOR β
|
|
63
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
64
|
+
β β Workflow Agents β β Maintenance β β Self-Heal β β
|
|
65
|
+
β β β β Bots β β Agents β β
|
|
66
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
67
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
68
|
+
β
|
|
69
|
+
βΌ
|
|
70
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
71
|
+
β GOVERNANCE & SAFETY FRAMEWORK - RISK CONTROL β
|
|
72
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
73
|
+
β β Permission β β Audit & β β Emergency β β
|
|
74
|
+
β β Engine β β Compliance β β Controls β β
|
|
75
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
76
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
77
|
+
β
|
|
78
|
+
βΌ
|
|
79
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
80
|
+
β ENTERPRISE KNOWLEDGE GRAPH (EKG) - INTELLIGENCE β
|
|
81
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
82
|
+
β β Cross-Repo β β Semantic β β Expert β β
|
|
83
|
+
β β Dependencies β β Mapping β β Discovery β β
|
|
84
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
85
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
86
|
+
β
|
|
87
|
+
βΌ
|
|
88
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
89
|
+
β PREDICTIVE INTELLIGENCE ENGINE (PIE) - FORECASTING β
|
|
90
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
91
|
+
β β Tech Debt β β Performance β β Risk β β
|
|
92
|
+
β β Forecasting β β Prediction β β Analytics β β
|
|
93
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
94
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
95
|
+
β
|
|
96
|
+
βΌ
|
|
97
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
98
|
+
β DISTRIBUTED EXECUTION ENGINE (DEE) - RUNTIME β
|
|
99
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
100
|
+
β β Repository β β Workflow β β State β β
|
|
101
|
+
β β Federation β β Orchestration β β Sync β β
|
|
102
|
+
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
|
|
103
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
104
|
+
β
|
|
105
|
+
βΌ
|
|
106
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
107
|
+
β EXTERNAL SYSTEMS INTEGRATION β
|
|
108
|
+
β βββββββ βββββββ βββββββ βββββββ βββββββ βββββββ β
|
|
109
|
+
β βGitHubβ βGitLabβ βJIRA β βSlackβ βJenkinsβ β
|
|
110
|
+
β βActionsβ β β β β β β β β β
|
|
111
|
+
β βββββββ βββββββ βββββββ βββββββ βββββββ β
|
|
112
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
113
|
+
```
|
|
12
114
|
|
|
13
115
|
## π¦ Installation
|
|
14
116
|
|
|
@@ -65,7 +167,25 @@ This creates:
|
|
|
65
167
|
- `pre-commit`: AI analysis of staged changes
|
|
66
168
|
- `pre-push`: Full CI/CD simulation (tests + AI review)
|
|
67
169
|
|
|
68
|
-
### 3.
|
|
170
|
+
### 3. Index Project Knowledge (RAG Setup)
|
|
171
|
+
|
|
172
|
+
Build a local knowledge base for context-aware analysis:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Index current project files for RAG
|
|
176
|
+
codeflow-hook index
|
|
177
|
+
|
|
178
|
+
# Dry run to see what files would be indexed
|
|
179
|
+
codeflow-hook index --dry-run
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The knowledge base is stored in `.codeflow/index/` and includes:
|
|
183
|
+
- README.md and documentation files
|
|
184
|
+
- Source code files (.ts, .tsx, .js, .jsx, .json)
|
|
185
|
+
- Configuration files (package.json, jest.config.*, etc.)
|
|
186
|
+
- Architecture and design documents
|
|
187
|
+
|
|
188
|
+
### 4. Check Status
|
|
69
189
|
|
|
70
190
|
```bash
|
|
71
191
|
codeflow-hook status
|
|
@@ -73,24 +193,60 @@ codeflow-hook status
|
|
|
73
193
|
|
|
74
194
|
## π οΈ Commands
|
|
75
195
|
|
|
76
|
-
###
|
|
196
|
+
### Core Commands
|
|
197
|
+
|
|
198
|
+
**Index Project Knowledge**:
|
|
199
|
+
```bash
|
|
200
|
+
# Build local RAG knowledge base
|
|
201
|
+
codeflow-hook index
|
|
77
202
|
|
|
78
|
-
|
|
203
|
+
# Preview what will be indexed
|
|
204
|
+
codeflow-hook index --dry-run
|
|
205
|
+
```
|
|
79
206
|
|
|
207
|
+
**Analyze Diff**:
|
|
80
208
|
```bash
|
|
209
|
+
# Analyze staged changes
|
|
81
210
|
git diff --staged | codeflow-hook analyze-diff
|
|
211
|
+
|
|
212
|
+
# Disable RAG context (faster but less precise)
|
|
213
|
+
git diff | codeflow-hook analyze-diff --no-rag
|
|
214
|
+
|
|
215
|
+
# Use legacy monolithic analysis
|
|
216
|
+
git diff | codeflow-hook analyze-diff --legacy
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Configuration & Setup**:
|
|
220
|
+
```bash
|
|
221
|
+
# Configure AI provider
|
|
222
|
+
codeflow-hook config -p gemini -k YOUR_API_KEY
|
|
223
|
+
|
|
224
|
+
# Install git hooks
|
|
225
|
+
codeflow-hook install
|
|
226
|
+
|
|
227
|
+
# Check installation status
|
|
228
|
+
codeflow-hook status
|
|
82
229
|
```
|
|
83
230
|
|
|
84
|
-
###
|
|
231
|
+
### Advanced Options
|
|
85
232
|
|
|
86
233
|
```bash
|
|
234
|
+
# Use legacy mode for backwards compatibility
|
|
235
|
+
codeflow-hook analyze-diff --legacy
|
|
236
|
+
|
|
237
|
+
# Skip RAG for faster analysis
|
|
238
|
+
codeflow-hook analyze-diff --no-rag
|
|
239
|
+
|
|
240
|
+
# Custom hooks directory
|
|
87
241
|
codeflow-hook install --hooks-dir .custom-hooks
|
|
88
242
|
```
|
|
89
243
|
|
|
90
244
|
### View Help
|
|
91
245
|
|
|
92
246
|
```bash
|
|
93
|
-
codeflow-hook --help
|
|
247
|
+
codeflow-hook --help # Main help
|
|
248
|
+
codeflow-hook index --help # Index command help
|
|
249
|
+
codeflow-hook analyze-diff --help # Analysis options
|
|
94
250
|
```
|
|
95
251
|
|
|
96
252
|
## π How It Works
|
|
@@ -113,6 +269,88 @@ codeflow-hook --help
|
|
|
113
269
|
- Best practice recommendations
|
|
114
270
|
- Maintainability evaluation
|
|
115
271
|
|
|
272
|
+
## π¬ Enterprise Technology Stack
|
|
273
|
+
|
|
274
|
+
### **Multi-Modal AI Integration**
|
|
275
|
+
The Nexus Gateway integrates multiple AI modalities for comprehensive engineering intelligence:
|
|
276
|
+
|
|
277
|
+
**π€ Conversational Interface Layer**: Natural language processing for requirement analysis and complex code generation
|
|
278
|
+
**π¨ Design-to-Code Pipeline**: Computer vision and ML models for design artifact ingestion
|
|
279
|
+
**π Predictive Analytics Engine**: Time-series analysis and machine learning for trend forecasting
|
|
280
|
+
**π Semantic Code Analysis**: Advanced NLP for code understanding and pattern recognition
|
|
281
|
+
|
|
282
|
+
### **Autonomous Agent Architecture**
|
|
283
|
+
The core platform intelligence is delivered through specialized agent networks:
|
|
284
|
+
|
|
285
|
+
**π― Workflow Execution Agents**:
|
|
286
|
+
- Ticket-to-PR automation with full engineering lifecycle management
|
|
287
|
+
- Self-healing operations with automated issue detection and remediation
|
|
288
|
+
- Dependency management with intelligent version conflict resolution
|
|
289
|
+
|
|
290
|
+
**π¬ Observational Intelligence Agents**:
|
|
291
|
+
- Predictive maintenance scheduling based on code analysis patterns
|
|
292
|
+
- Performance regression detection using historical benchmarking
|
|
293
|
+
- Risk assessment with real-time compliance monitoring
|
|
294
|
+
|
|
295
|
+
**π€ Collaborative Learning Agents**:
|
|
296
|
+
- Cross-repository knowledge synthesis and pattern mining
|
|
297
|
+
- Expert identification through contribution analysis
|
|
298
|
+
- Team productivity optimization through workflow analysis
|
|
299
|
+
|
|
300
|
+
### **Federated Data Architecture**
|
|
301
|
+
Enterprise-scale data management across distributed repositories:
|
|
302
|
+
|
|
303
|
+
**π Enterprise Knowledge Graph (EKG)**:
|
|
304
|
+
- Multi-modal data integration (code, documentation, metrics, design artifacts)
|
|
305
|
+
- Semantic relationship mapping across the entire organization
|
|
306
|
+
- Real-time knowledge updates with conflict-free replication
|
|
307
|
+
|
|
308
|
+
**π Predictive Intelligence Engine (PIE)**:
|
|
309
|
+
- Time-series analytics for development velocity and quality trends
|
|
310
|
+
- Anomaly detection using unsupervised learning algorithms
|
|
311
|
+
- Forecasting models trained on enterprise development data
|
|
312
|
+
|
|
313
|
+
### **Distributed Execution Framework**
|
|
314
|
+
Coordination of autonomous operations across multiple systems:
|
|
315
|
+
|
|
316
|
+
**β‘ Distributed Execution Engine (DEE)**:
|
|
317
|
+
- Multi-repository workflow orchestration with dependency management
|
|
318
|
+
- Resource optimization through intelligent load balancing
|
|
319
|
+
- Federated state management with eventual consistency guarantees
|
|
320
|
+
|
|
321
|
+
**π Governance Safety Framework (GSF)**:
|
|
322
|
+
- Risk-based permission evaluation with dynamic access controls
|
|
323
|
+
- Multi-level audit trails with blockchain-verified immutability
|
|
324
|
+
- Emergency stop mechanisms with graduated escalation protocols
|
|
325
|
+
|
|
326
|
+
### **Structured Intelligence Output Format**
|
|
327
|
+
Enterprise reporting with actionable insights and automated workflows:
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
π’ Enterprise Code Review Summary:
|
|
331
|
+
π Organization-wide Security risks: 2
|
|
332
|
+
ποΈ Architecture Optimization opportunities: 7
|
|
333
|
+
π Cross-repository Maintainability issues: 15
|
|
334
|
+
π― Predictive Maintenance alerts: 3
|
|
335
|
+
|
|
336
|
+
π Trend Analysis:
|
|
337
|
+
π Code quality velocity: +12% (improving)
|
|
338
|
+
π Tech debt accumulation: -8% (reducing)
|
|
339
|
+
π² Risk exposure index: LOW (confidence: 94%)
|
|
340
|
+
|
|
341
|
+
π Recommended Actions:
|
|
342
|
+
π§ Automated fixes available for 23 issues
|
|
343
|
+
π Cross-repository refactor suggested for auth module
|
|
344
|
+
π
Maintenance window scheduled for Q4 dependency updates
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### **Multi-Repository Analysis Benefits**
|
|
348
|
+
- **Scale**: Analyzes thousands of repositories simultaneously
|
|
349
|
+
- **Intelligence**: Learns organizational patterns and standards
|
|
350
|
+
- **Automation**: Initiates cross-cutting improvements autonomously
|
|
351
|
+
- **Governance**: Ensures compliance across all engineering activities
|
|
352
|
+
- **Prediction**: Forecasts development bottlenecks before they occur
|
|
353
|
+
|
|
116
354
|
## π‘ Usage Examples
|
|
117
355
|
|
|
118
356
|
### Standard Development Workflow
|
|
@@ -240,12 +478,41 @@ MIT License - see LICENSE file for details
|
|
|
240
478
|
|
|
241
479
|
## π Acknowledgments
|
|
242
480
|
|
|
243
|
-
Built with β€οΈ using:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
-
|
|
247
|
-
-
|
|
481
|
+
Built with β€οΈ using enterprise-grade technologies:
|
|
482
|
+
|
|
483
|
+
### **Core Intelligence Stack**
|
|
484
|
+
- **Multi-Modal AI Integration**: Google Gemini, OpenAI GPT-4, Anthropic Claude
|
|
485
|
+
- **Distributed Graph Database**: Neo4j Enterprise for Knowledge Graph operations
|
|
486
|
+
- **Federated Learning Infrastructure**: PyTorch and TensorFlow for ML model training
|
|
487
|
+
- **Container Orchestration**: Kubernetes for enterprise-scale deployment
|
|
488
|
+
|
|
489
|
+
### **Development & CLI Framework**
|
|
490
|
+
- **Commander.js**: Professional CLI experience and command orchestration
|
|
491
|
+
- **Chalk & Ora**: Advanced terminal rendering with progress indicators
|
|
492
|
+
- **Axios**: Enterprise HTTP client with retry logic and circuit breakers
|
|
493
|
+
- **Node.js & TypeScript**: Type-safe, scalable runtime environment
|
|
494
|
+
|
|
495
|
+
### **Enterprise Integrations**
|
|
496
|
+
- **Git Platforms**: Native GitHub, GitLab, and Bitbucket integration
|
|
497
|
+
- **Project Management**: JIRA, Linear, and Azure DevOps workflows
|
|
498
|
+
- **Communication**: Slack, Microsoft Teams, and Discord integrations
|
|
499
|
+
- **Monitoring**: Datadog, New Relic, and Prometheus telemetry
|
|
500
|
+
|
|
501
|
+
### **Security & Governance**
|
|
502
|
+
- **Audit Framework**: Blockchain-verified audit trails
|
|
503
|
+
- **Access Management**: OAuth 2.0, SAML, and LDAP integration
|
|
504
|
+
- **Encryption**: End-to-end encryption with key management
|
|
505
|
+
- **Compliance**: SOC 2, GDPR, and enterprise security standards
|
|
248
506
|
|
|
249
507
|
---
|
|
250
508
|
|
|
251
|
-
|
|
509
|
+
**π Ready to transform your organization's engineering capabilities?**
|
|
510
|
+
|
|
511
|
+
Join the autonomous engineering revolution with Codeflow Commander Nexus Gateway β where AI meets enterprise-scale software development.
|
|
512
|
+
|
|
513
|
+
**Install today and experience organization-wide autonomous engineering:**
|
|
514
|
+
```bash
|
|
515
|
+
npm install -g codeflow-hook
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**Visit [codeflow-commander-nexus-gateway](https://github.com/Sharv619/codeflow-commander---nexus-gateway) to explore the full platform.**
|
package/bin/agents.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// Specialized AI Agents for code review
|
|
2
|
+
// Implements agentic workflow with structured outputs
|
|
3
|
+
|
|
4
|
+
import { callAIProvider } from './codeflow-hook.js';
|
|
5
|
+
|
|
6
|
+
// Security Review Agent
|
|
7
|
+
export async function securityReview(codeBlock, context, config) {
|
|
8
|
+
const prompt = `You are a Security Code Review Specialist. Your mission is to identify security vulnerabilities in the provided code changes.
|
|
9
|
+
|
|
10
|
+
ANALYSIS SCOPE:
|
|
11
|
+
- SQL injection vulnerabilities
|
|
12
|
+
- Cross-site scripting (XSS) attacks
|
|
13
|
+
- Cross-site request forgery (CSRF)
|
|
14
|
+
- Insecure dependencies or outdated packages
|
|
15
|
+
- Key exposure or credential leaks
|
|
16
|
+
- Authentication bypass vulnerabilities
|
|
17
|
+
- Directory traversal attacks
|
|
18
|
+
- Path manipulation flaws
|
|
19
|
+
- Deprecation warnings that could indicate security risks
|
|
20
|
+
|
|
21
|
+
INPUT CODE:
|
|
22
|
+
\`\`\`
|
|
23
|
+
${codeBlock}
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
CONTEXT (Reference Code from Project Knowledge Base):
|
|
27
|
+
${context}
|
|
28
|
+
|
|
29
|
+
You MUST respond with valid JSON in this format. Be thorough but concise:
|
|
30
|
+
[
|
|
31
|
+
{
|
|
32
|
+
"type": "SECURITY",
|
|
33
|
+
"severity": "CRITICAL|HIGH|MEDIUM|LOW",
|
|
34
|
+
"description": "Clear description of the vulnerability",
|
|
35
|
+
"line": "Line number or range where issue occurs, or 'N/A' if not specific"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
If no security issues found, return an empty array: []`;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const response = await callAIProvider(config, prompt);
|
|
43
|
+
const parsed = parseAgentResponse(response);
|
|
44
|
+
return parsed;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.warn(`Security review failed: ${error.message}`);
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Architecture Review Agent
|
|
52
|
+
export async function architectureReview(codeBlock, context, config) {
|
|
53
|
+
const prompt = `You are an Architecture Code Review Specialist. Your mission is to evaluate architectural adherence and code organization.
|
|
54
|
+
|
|
55
|
+
ANALYSIS SCOPE:
|
|
56
|
+
- Design pattern violations or misuse
|
|
57
|
+
- Separation of concerns breaches
|
|
58
|
+
- Business logic in inappropriate layers (e.g., controllers, views)
|
|
59
|
+
- Missing dependency injection where needed
|
|
60
|
+
- Tight coupling between components
|
|
61
|
+
- Cyclomatic complexity issues (>10 branches)
|
|
62
|
+
- Large functions/methods (>50 lines)
|
|
63
|
+
- Singleton pattern misuse
|
|
64
|
+
- Data access patterns and ORM usage
|
|
65
|
+
- Error handling architecture
|
|
66
|
+
|
|
67
|
+
INPUT CODE:
|
|
68
|
+
\`\`\`
|
|
69
|
+
${codeBlock}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
CONTEXT (Reference Code from Project Knowledge Base):
|
|
73
|
+
${context}
|
|
74
|
+
|
|
75
|
+
You MUST respond with valid JSON in this format. Be thorough but concise:
|
|
76
|
+
[
|
|
77
|
+
{
|
|
78
|
+
"type": "ARCHITECTURE",
|
|
79
|
+
"severity": "CRITICAL|HIGH|MEDIUM|LOW",
|
|
80
|
+
"description": "Clear description of the architectural issue",
|
|
81
|
+
"line": "Line number or range where issue occurs, or 'N/A' if not specific"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
If no architectural issues found, return an empty array: []`;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const response = await callAIProvider(config, prompt);
|
|
89
|
+
const parsed = parseAgentResponse(response);
|
|
90
|
+
return parsed;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.warn(`Architecture review failed: ${error.message}`);
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Style and Documentation Review Agent
|
|
98
|
+
export async function styleAndDocReview(codeBlock, context, config) {
|
|
99
|
+
const prompt = `You are a Code Style and Documentation Review Specialist. Your mission is to assess maintainability, readability, and documentation quality.
|
|
100
|
+
|
|
101
|
+
ANALYSIS SCOPE:
|
|
102
|
+
- Missing or inadequate JSDoc/TypeScript documentation
|
|
103
|
+
- Poor variable/function naming conventions
|
|
104
|
+
- Inconsistent code formatting
|
|
105
|
+
- Missing error handling documentation
|
|
106
|
+
- Inadequate function comments for complex logic
|
|
107
|
+
- Violation of language-specific style guides
|
|
108
|
+
- Long parameter lists (>4 parameters)
|
|
109
|
+
- Magic numbers without constants
|
|
110
|
+
- Inconsistent spacing or indentation
|
|
111
|
+
- Missing type annotations (TypeScript)
|
|
112
|
+
|
|
113
|
+
INPUT CODE:
|
|
114
|
+
\`\`\`
|
|
115
|
+
${codeBlock}
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
CONTEXT (Reference Code from Project Knowledge Base):
|
|
119
|
+
${context}
|
|
120
|
+
|
|
121
|
+
You MUST respond with valid JSON in this format. Be thorough but concise:
|
|
122
|
+
[
|
|
123
|
+
{
|
|
124
|
+
"type": "MAINTAINABILITY",
|
|
125
|
+
"severity": "CRITICAL|HIGH|MEDIUM|LOW",
|
|
126
|
+
"description": "Clear description of the style/documentation issue",
|
|
127
|
+
"line": "Line number or range where issue occurs, or 'N/A' if not specific"
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
If no issues found, return an empty array: []`;
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const response = await callAIProvider(config, prompt);
|
|
135
|
+
const parsed = parseAgentResponse(response);
|
|
136
|
+
return parsed;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.warn(`Style/Doc review failed: ${error.message}`);
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Utility function to parse agent responses
|
|
144
|
+
function parseAgentResponse(response) {
|
|
145
|
+
try {
|
|
146
|
+
// Extract JSON from response (agents may add extra text)
|
|
147
|
+
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
148
|
+
if (jsonMatch) {
|
|
149
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
150
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Try parsing the whole response
|
|
154
|
+
const parsed = JSON.parse(response);
|
|
155
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.warn(`Failed to parse agent response: ${error.message}`);
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Code decomposition utilities
|
|
163
|
+
export class CodeDecomposer {
|
|
164
|
+
static decomposeDiff(diffContent) {
|
|
165
|
+
const scopes = [];
|
|
166
|
+
const lines = diffContent.split('\n');
|
|
167
|
+
|
|
168
|
+
let currentFile = null;
|
|
169
|
+
let currentHunk = null;
|
|
170
|
+
let hunkLines = [];
|
|
171
|
+
|
|
172
|
+
for (const line of lines) {
|
|
173
|
+
if (line.startsWith('diff --git')) {
|
|
174
|
+
// New file
|
|
175
|
+
const fileMatch = line.match(/b\/(.+)/);
|
|
176
|
+
if (fileMatch) {
|
|
177
|
+
currentFile = fileMatch[1];
|
|
178
|
+
}
|
|
179
|
+
} else if (line.startsWith('@@')) {
|
|
180
|
+
// New hunk
|
|
181
|
+
if (currentHunk && hunkLines.length > 0) {
|
|
182
|
+
scopes.push(this.analyzeHunk(currentFile, currentHunk, hunkLines));
|
|
183
|
+
}
|
|
184
|
+
currentHunk = line;
|
|
185
|
+
hunkLines = [];
|
|
186
|
+
} else if (line.startsWith('+') || line.startsWith('-')) {
|
|
187
|
+
// Changed line
|
|
188
|
+
hunkLines.push(line);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Process final hunk
|
|
193
|
+
if (currentHunk && hunkLines.length > 0) {
|
|
194
|
+
scopes.push(this.analyzeHunk(currentFile, currentHunk, hunkLines));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return scopes;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static analyzeHunk(filePath, hunkHeader, lines) {
|
|
201
|
+
const addedLines = lines.filter(line => line.startsWith('+')).map(line => line.substring(1));
|
|
202
|
+
const removedLines = lines.filter(line => line.startsWith('-')).map(line => line.substring(1));
|
|
203
|
+
|
|
204
|
+
// Parse hunk header for line numbers
|
|
205
|
+
const lineMatch = hunkHeader.match(/@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
|
|
206
|
+
const startLine = lineMatch ? parseInt(lineMatch[1]) : 1;
|
|
207
|
+
|
|
208
|
+
// Group lines into logical scopes
|
|
209
|
+
return this.groupIntoScopes(addedLines, removedLines, startLine, filePath);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static groupIntoScopes(addedLines, removedLines, startLine, filePath) {
|
|
213
|
+
const scopes = [];
|
|
214
|
+
|
|
215
|
+
// For simplicity, we'll treat all changes as one scope per hunk
|
|
216
|
+
// In a more advanced implementation, we could parse AST to identify functions/classes
|
|
217
|
+
const scope = {
|
|
218
|
+
filePath,
|
|
219
|
+
startLine,
|
|
220
|
+
endLine: startLine + addedLines.length,
|
|
221
|
+
code: addedLines.join('\n'),
|
|
222
|
+
addedLines,
|
|
223
|
+
removedLines,
|
|
224
|
+
type: this.inferScopeType(filePath, addedLines.join('\n'))
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
scopes.push(scope);
|
|
228
|
+
return scopes;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static inferScopeType(filePath, code) {
|
|
232
|
+
if (code.includes('function ') || code.includes('=>') || code.includes('const ') && code.includes('= (')) {
|
|
233
|
+
return 'function';
|
|
234
|
+
}
|
|
235
|
+
if (code.includes('class ')) {
|
|
236
|
+
return 'class';
|
|
237
|
+
}
|
|
238
|
+
if (code.includes('import ')) {
|
|
239
|
+
return 'imports';
|
|
240
|
+
}
|
|
241
|
+
if (code.includes('interface ') || code.includes('type ')) {
|
|
242
|
+
return 'type_definition';
|
|
243
|
+
}
|
|
244
|
+
return 'general';
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Main orchestration function
|
|
249
|
+
export async function orchestrateReview(diffContent, config, projectRoot = process.cwd()) {
|
|
250
|
+
const { decomposeDiff } = CodeDecomposer;
|
|
251
|
+
|
|
252
|
+
// Import retrieveContext dynamically to avoid circular imports
|
|
253
|
+
const { retrieveContext } = await import('./rag.js');
|
|
254
|
+
|
|
255
|
+
// Decompose diff into scopes
|
|
256
|
+
const scopes = decomposeDiff(diffContent);
|
|
257
|
+
const allResults = [];
|
|
258
|
+
|
|
259
|
+
for (const scope of scopes) {
|
|
260
|
+
if (!scope.code.trim()) continue;
|
|
261
|
+
|
|
262
|
+
// Retrieve context for this scope
|
|
263
|
+
const context = await retrieveContext(scope.code, config, projectRoot, 3);
|
|
264
|
+
|
|
265
|
+
// Run all specialized reviews in parallel
|
|
266
|
+
const [securityResults, architectureResults, styleResults] = await Promise.all([
|
|
267
|
+
securityReview(scope.code, context, config),
|
|
268
|
+
architectureReview(scope.code, context, config),
|
|
269
|
+
styleAndDocReview(scope.code, context, config)
|
|
270
|
+
]);
|
|
271
|
+
|
|
272
|
+
// Combine and annotate results
|
|
273
|
+
const scopeResults = [
|
|
274
|
+
...this.annotateResults(securityResults, scope),
|
|
275
|
+
...this.annotateResults(architectureResults, scope),
|
|
276
|
+
...this.annotateResults(styleResults, scope)
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
allResults.push(...scopeResults);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return allResults;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Annotate results with scope information
|
|
286
|
+
function annotateResults(results, scope) {
|
|
287
|
+
return results.map(result => ({
|
|
288
|
+
...result,
|
|
289
|
+
file: scope.filePath,
|
|
290
|
+
lineRange: `${scope.startLine}-${scope.endLine}`,
|
|
291
|
+
scopeType: scope.type
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Version without RAG context retrieval
|
|
296
|
+
export async function orchestrateReviewWithoutRAG(diffContent, config, projectRoot = process.cwd()) {
|
|
297
|
+
const scopes = CodeDecomposer.decomposeDiff(diffContent);
|
|
298
|
+
const allResults = [];
|
|
299
|
+
|
|
300
|
+
for (const scope of scopes) {
|
|
301
|
+
if (!scope.code.trim()) continue;
|
|
302
|
+
|
|
303
|
+
// Skip context retrieval - use empty context
|
|
304
|
+
const context = '';
|
|
305
|
+
|
|
306
|
+
// Run all specialized reviews in parallel
|
|
307
|
+
const [securityResults, architectureResults, styleResults] = await Promise.all([
|
|
308
|
+
securityReview(scope.code, context, config),
|
|
309
|
+
architectureReview(scope.code, context, config),
|
|
310
|
+
styleAndDocReview(scope.code, context, config)
|
|
311
|
+
]);
|
|
312
|
+
|
|
313
|
+
// Combine and annotate results
|
|
314
|
+
const scopeResults = [
|
|
315
|
+
...annotateResults(securityResults, scope),
|
|
316
|
+
...annotateResults(architectureResults, scope),
|
|
317
|
+
...annotateResults(styleResults, scope)
|
|
318
|
+
];
|
|
319
|
+
|
|
320
|
+
allResults.push(...scopeResults);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return allResults;
|
|
324
|
+
}
|
package/bin/codeflow-hook.js
CHANGED
|
@@ -8,13 +8,21 @@ import fs from 'fs';
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import os from 'os'; // Make sure os is imported
|
|
10
10
|
import readline from 'readline';
|
|
11
|
+
import { indexProject } from './rag.js';
|
|
12
|
+
import { orchestrateReview } from './agents.js';
|
|
13
|
+
|
|
14
|
+
// Import CLI integration service
|
|
15
|
+
import { indexProject, analyzeDiff } from '../services/cli-integration/src/index.js';
|
|
16
|
+
|
|
17
|
+
// Export for use in agents module
|
|
18
|
+
export { callAIProvider };
|
|
11
19
|
|
|
12
20
|
const program = new Command();
|
|
13
21
|
|
|
14
22
|
program
|
|
15
23
|
.name('codeflow-hook')
|
|
16
|
-
.description('Interactive CI/CD simulator and AI-powered code reviewer')
|
|
17
|
-
.version('
|
|
24
|
+
.description('Interactive CI/CD simulator and AI-powered code reviewer with EKG backend integration')
|
|
25
|
+
.version('4.0.0');
|
|
18
26
|
|
|
19
27
|
// Configure AI provider settings
|
|
20
28
|
program
|
|
@@ -194,6 +202,38 @@ program
|
|
|
194
202
|
}
|
|
195
203
|
});
|
|
196
204
|
|
|
205
|
+
// Index repository via EKG Ingestion Service (Phase 4)
|
|
206
|
+
program
|
|
207
|
+
.command('index')
|
|
208
|
+
.description('Index repository via EKG Ingestion Service')
|
|
209
|
+
.option('-d, --dry-run', 'Show what would be indexed without actually indexing')
|
|
210
|
+
.action(async (options) => {
|
|
211
|
+
try {
|
|
212
|
+
const spinner = ora('Submitting repository for EKG analysis...').start();
|
|
213
|
+
|
|
214
|
+
const result = await indexProject({
|
|
215
|
+
dryRun: options.dryRun || false
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
spinner.succeed('Repository indexing initiated');
|
|
219
|
+
console.log(chalk.green(`β
${result.message}`));
|
|
220
|
+
|
|
221
|
+
if (result.repositoryId) {
|
|
222
|
+
console.log(chalk.blue(`π Repository ID: ${result.repositoryId}`));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (result.stats) {
|
|
226
|
+
console.log(chalk.gray(`π Stats: ${JSON.stringify(result.stats, null, 2)}`));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log(chalk.cyan('π Repository submitted to EKG Ingestion Service for analysis'));
|
|
230
|
+
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.log(chalk.red(`β Indexing failed: ${error.message}`));
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
197
237
|
// Install git hooks
|
|
198
238
|
program
|
|
199
239
|
.command('install')
|
|
@@ -254,15 +294,15 @@ exit 0
|
|
|
254
294
|
}
|
|
255
295
|
});
|
|
256
296
|
|
|
257
|
-
// Analyze diff with
|
|
297
|
+
// Analyze diff with EKG Query Service context enhancement (Phase 4)
|
|
258
298
|
program
|
|
259
299
|
.command('analyze-diff')
|
|
260
|
-
.description('Analyze git diff
|
|
261
|
-
// CHANGE 2: The argument is now OPTIONAL (square brackets)
|
|
300
|
+
.description('Analyze git diff using EKG context enhancement')
|
|
262
301
|
.argument('[diff]', 'Git diff content')
|
|
263
|
-
.
|
|
302
|
+
.option('--legacy', 'Use legacy analysis instead of EKG-enhanced analysis')
|
|
303
|
+
.action(async (diff, options) => {
|
|
264
304
|
try {
|
|
265
|
-
//
|
|
305
|
+
// Read diff content from stdin or argument
|
|
266
306
|
let diffContent = diff;
|
|
267
307
|
if (!diffContent) {
|
|
268
308
|
const chunks = [];
|
|
@@ -272,37 +312,34 @@ program
|
|
|
272
312
|
diffContent = Buffer.concat(chunks).toString('utf8');
|
|
273
313
|
}
|
|
274
314
|
|
|
275
|
-
const configPath = path.join(os.homedir(), '.codeflow-hook', 'config.json');
|
|
276
|
-
|
|
277
|
-
if (!fs.existsSync(configPath)) {
|
|
278
|
-
console.log(chalk.red('No configuration found. Run: codeflow-hook config -k <api-key>'));
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
283
|
-
|
|
284
315
|
if (diffContent.trim() === '') {
|
|
285
316
|
console.log(chalk.gray('βΉοΈ No changes to analyze'));
|
|
286
317
|
return;
|
|
287
318
|
}
|
|
288
319
|
|
|
289
|
-
|
|
290
|
-
const prompt = generateCodeReviewPrompt(diffContent);
|
|
320
|
+
console.log(chalk.blue('π¬ Analyzing diff with EKG context enhancement...'));
|
|
291
321
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
322
|
+
const result = await analyzeDiff(diffContent, {
|
|
323
|
+
legacy: options.legacy || false,
|
|
324
|
+
outputFormat: 'console'
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (result.success) {
|
|
328
|
+
console.log(chalk.green(`β
${result.message}`));
|
|
329
|
+
displayEKGAnalysisResults(result.analysis);
|
|
330
|
+
|
|
331
|
+
if (result.stats) {
|
|
332
|
+
console.log(chalk.gray(`π EKG Queries: ${result.stats.ekg_queries}`));
|
|
333
|
+
console.log(chalk.gray(`π₯ Similar Repos Found: ${result.stats.similar_repos_found}`));
|
|
334
|
+
console.log(chalk.gray(`β±οΈ Analysis Time: ${result.stats.analysis_time}ms`));
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
console.log(chalk.red(`β Analysis failed: ${result.message}`));
|
|
298
338
|
process.exit(1);
|
|
299
339
|
}
|
|
300
340
|
|
|
301
|
-
spinner.succeed('Analysis complete');
|
|
302
|
-
displayAnalysisResults(result);
|
|
303
|
-
|
|
304
341
|
} catch (error) {
|
|
305
|
-
console.log(chalk.red(
|
|
342
|
+
console.log(chalk.red(`β Analysis error: ${error.message}`));
|
|
306
343
|
process.exit(1);
|
|
307
344
|
}
|
|
308
345
|
});
|
|
@@ -590,5 +627,141 @@ function displayAnalysisResults(result) {
|
|
|
590
627
|
console.log();
|
|
591
628
|
}
|
|
592
629
|
|
|
630
|
+
function displayAgenticResults(results) {
|
|
631
|
+
if (!results || results.length === 0) {
|
|
632
|
+
console.log(chalk.green('β
No issues found in the analysis.'));
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Group results by file and type
|
|
637
|
+
const groupedResults = {};
|
|
638
|
+
const summaryStats = { security: 0, architecture: 0, maintainability: 0 };
|
|
639
|
+
|
|
640
|
+
for (const result of results) {
|
|
641
|
+
const key = `${result.file}:${result.scopeType}`;
|
|
642
|
+
if (!groupedResults[key]) {
|
|
643
|
+
groupedResults[key] = [];
|
|
644
|
+
}
|
|
645
|
+
groupedResults[key].push(result);
|
|
646
|
+
|
|
647
|
+
// Count by severity for summary
|
|
648
|
+
summaryStats[result.type.toLowerCase()]++;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Display summary stats
|
|
652
|
+
console.log(chalk.blue('π Code Review Summary:'));
|
|
653
|
+
console.log(` π Security issues: ${summaryStats.security}`);
|
|
654
|
+
console.log(` ποΈ Architecture issues: ${summaryStats.architecture}`);
|
|
655
|
+
console.log(` π Maintainability issues: ${summaryStats.maintainability}`);
|
|
656
|
+
console.log();
|
|
657
|
+
|
|
658
|
+
// Display detailed results by file and scope
|
|
659
|
+
for (const [scopeKey, scopeResults] of Object.entries(groupedResults)) {
|
|
660
|
+
const [file, scopeType] = scopeKey.split(':');
|
|
661
|
+
console.log(chalk.yellow(`π ${file} (${scopeType})`));
|
|
662
|
+
|
|
663
|
+
for (const result of scopeResults) {
|
|
664
|
+
const severityColor = getSeverityColor(result.severity);
|
|
665
|
+
const typeIcon = getTypeIcon(result.type);
|
|
666
|
+
console.log(` ${severityColor}${typeIcon} ${result.severity}: ${result.description}`);
|
|
667
|
+
if (result.line && result.line !== 'N/A') {
|
|
668
|
+
console.log(chalk.gray(` Line: ${result.lineRange}`));
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
console.log();
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function getSeverityColor(severity) {
|
|
676
|
+
switch (severity?.toUpperCase()) {
|
|
677
|
+
case 'CRITICAL':
|
|
678
|
+
return chalk.red('π΄');
|
|
679
|
+
case 'HIGH':
|
|
680
|
+
return chalk.red('π ');
|
|
681
|
+
case 'MEDIUM':
|
|
682
|
+
return chalk.yellow('π‘');
|
|
683
|
+
case 'LOW':
|
|
684
|
+
return chalk.green('π’');
|
|
685
|
+
default:
|
|
686
|
+
return chalk.gray('βͺ');
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function getTypeIcon(type) {
|
|
691
|
+
switch (type?.toUpperCase()) {
|
|
692
|
+
case 'SECURITY':
|
|
693
|
+
return 'π';
|
|
694
|
+
case 'ARCHITECTURE':
|
|
695
|
+
return 'ποΈ ';
|
|
696
|
+
case 'MAINTAINABILITY':
|
|
697
|
+
return 'π';
|
|
698
|
+
default:
|
|
699
|
+
return 'β';
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Display EKG-enhanced analysis results (Phase 4)
|
|
704
|
+
function displayEKGAnalysisResults(analysis) {
|
|
705
|
+
if (!analysis) {
|
|
706
|
+
console.log(chalk.yellow('β οΈ No analysis results available'));
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Display summary
|
|
711
|
+
if (analysis.summary) {
|
|
712
|
+
console.log(chalk.blue('π Analysis Summary:'));
|
|
713
|
+
console.log(` π Files modified: ${analysis.summary.totalFiles}`);
|
|
714
|
+
console.log(` β Additions: ${analysis.summary.totalAdditions}`);
|
|
715
|
+
console.log(` β Deletions: ${analysis.summary.totalDeletions}`);
|
|
716
|
+
console.log(` π§ EKG enhanced: ${analysis.summary.ekgEnhanced ? 'Yes' : 'No'}`);
|
|
717
|
+
console.log();
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Display EKG context information
|
|
721
|
+
if (analysis.ekg_context) {
|
|
722
|
+
console.log(chalk.blue('π§ EKG Context:'));
|
|
723
|
+
console.log(` π Patterns analyzed: ${analysis.ekg_context.patterns_analyzed || 0}`);
|
|
724
|
+
console.log(` π₯ Similar repositories: ${analysis.ekg_context.similar_repositories_found || 0}`);
|
|
725
|
+
console.log(` π Repository known to EKG: ${analysis.ekg_context.repository_known ? 'Yes' : 'No'}`);
|
|
726
|
+
console.log();
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Display issues
|
|
730
|
+
if (analysis.issues && analysis.issues.length > 0) {
|
|
731
|
+
console.log(chalk.yellow('β οΈ Issues Found:'));
|
|
732
|
+
analysis.issues.forEach(issue => {
|
|
733
|
+
const severityColor = getSeverityColor(issue.severity);
|
|
734
|
+
const typeIcon = getTypeIcon(issue.type);
|
|
735
|
+
console.log(` ${severityColor}${typeIcon} ${issue.severity}: ${issue.description}`);
|
|
736
|
+
});
|
|
737
|
+
console.log();
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Display recommendations
|
|
741
|
+
if (analysis.recommendations && analysis.recommendations.length > 0) {
|
|
742
|
+
console.log(chalk.green('π‘ Recommendations:'));
|
|
743
|
+
analysis.recommendations.forEach(rec => {
|
|
744
|
+
const severityColor = getSeverityColor(rec.severity);
|
|
745
|
+
console.log(` ${severityColor}β’ ${rec.description}`);
|
|
746
|
+
if (rec.file) {
|
|
747
|
+
console.log(chalk.gray(` π File: ${rec.file}`));
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
console.log();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Display file details
|
|
754
|
+
if (analysis.files && analysis.files.length > 0) {
|
|
755
|
+
console.log(chalk.blue('π Files Changed:'));
|
|
756
|
+
analysis.files.forEach(file => {
|
|
757
|
+
const changeType = file.isNew ? 'NEW' : 'MODIFIED';
|
|
758
|
+
const changeColor = file.isNew ? chalk.green : chalk.blue;
|
|
759
|
+
console.log(`${changeColor} ${changeType} ${file.path} (${file.language})`);
|
|
760
|
+
console.log(chalk.gray(` +${file.additions} -${file.deletions} changes`));
|
|
761
|
+
});
|
|
762
|
+
console.log();
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
593
766
|
// Make sure the final line uses parseAsync
|
|
594
767
|
program.parseAsync(process.argv);
|
package/bin/rag.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// RAG (Retrieval-Augmented Generation) implementation for codeflow-hook
|
|
2
|
+
// Provides local vector storage and semantic search capabilities
|
|
3
|
+
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import crypto from 'crypto';
|
|
8
|
+
|
|
9
|
+
// Vector Store: Simple file-based implementation with cosine similarity
|
|
10
|
+
export class LocalVectorStore {
|
|
11
|
+
constructor(projectRoot) {
|
|
12
|
+
this.storePath = path.join(projectRoot, '.codeflow', 'index');
|
|
13
|
+
this.ensureDirectoryExists();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
ensureDirectoryExists() {
|
|
17
|
+
if (!fs.existsSync(this.storePath)) {
|
|
18
|
+
fs.mkdirSync(this.storePath, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Save vectors and metadata to files
|
|
23
|
+
async saveVectors(vectors, metadata) {
|
|
24
|
+
const vectorFile = path.join(this.storePath, 'vectors.json');
|
|
25
|
+
const metadataFile = path.join(this.storePath, 'metadata.json');
|
|
26
|
+
|
|
27
|
+
fs.writeFileSync(vectorFile, JSON.stringify(vectors));
|
|
28
|
+
fs.writeFileSync(metadataFile, JSON.stringify(metadata));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Load vectors and metadata from files
|
|
32
|
+
async loadVectors() {
|
|
33
|
+
const vectorFile = path.join(this.storePath, 'vectors.json');
|
|
34
|
+
const metadataFile = path.join(this.storePath, 'metadata.json');
|
|
35
|
+
|
|
36
|
+
if (!fs.existsSync(vectorFile) || !fs.existsSync(metadataFile)) {
|
|
37
|
+
return { vectors: [], metadata: [] };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const vectors = JSON.parse(fs.readFileSync(vectorFile, 'utf8'));
|
|
41
|
+
const metadata = JSON.parse(fs.readFileSync(metadataFile, 'utf8'));
|
|
42
|
+
|
|
43
|
+
return { vectors, metadata };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Search for top-k similar vectors using cosine similarity
|
|
47
|
+
search(queryVector, k = 3) {
|
|
48
|
+
const { vectors, metadata } = this.loadVectors();
|
|
49
|
+
|
|
50
|
+
if (vectors.length === 0) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Calculate cosine similarity for all vectors
|
|
55
|
+
const similarities = vectors.map((vector, index) => ({
|
|
56
|
+
similarity: cosineSimilarity(queryVector, vector),
|
|
57
|
+
metadata: metadata[index],
|
|
58
|
+
index
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
// Sort by similarity (descending) and return top-k
|
|
62
|
+
return similarities
|
|
63
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
64
|
+
.slice(0, k)
|
|
65
|
+
.map(item => ({
|
|
66
|
+
similarity: item.similarity,
|
|
67
|
+
...item.metadata
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Simple implementation of cosine similarity
|
|
73
|
+
function cosineSimilarity(vecA, vecB) {
|
|
74
|
+
if (vecA.length !== vecB.length) {
|
|
75
|
+
throw new Error('Vectors must be of same length');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let dotProduct = 0;
|
|
79
|
+
let normA = 0;
|
|
80
|
+
let normB = 0;
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < vecA.length; i++) {
|
|
83
|
+
dotProduct += vecA[i] * vecB[i];
|
|
84
|
+
normA += vecA[i] * vecA[i];
|
|
85
|
+
normB += vecB[i] * vecB[i];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
normA = Math.sqrt(normA);
|
|
89
|
+
normB = Math.sqrt(normB);
|
|
90
|
+
|
|
91
|
+
if (normA === 0 || normB === 0) {
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return dotProduct / (normA * normB);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Embedding generation using Gemini API
|
|
99
|
+
export class EmbeddingGenerator {
|
|
100
|
+
constructor(config) {
|
|
101
|
+
this.config = config;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async generateEmbedding(text) {
|
|
105
|
+
try {
|
|
106
|
+
const url = 'https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent?key=' + this.config.apiKey;
|
|
107
|
+
|
|
108
|
+
const response = await axios.post(url, {
|
|
109
|
+
content: {
|
|
110
|
+
parts: [{
|
|
111
|
+
text: text
|
|
112
|
+
}]
|
|
113
|
+
}
|
|
114
|
+
}, {
|
|
115
|
+
headers: {
|
|
116
|
+
'Content-Type': 'application/json'
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return response.data.embedding.values;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw new Error(`Embedding generation failed: ${error.message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Generate embeddings for batch of texts
|
|
127
|
+
async generateBatchEmbeddings(texts) {
|
|
128
|
+
const embeddings = [];
|
|
129
|
+
for (const text of texts) {
|
|
130
|
+
embeddings.push(await this.generateEmbedding(text));
|
|
131
|
+
}
|
|
132
|
+
return embeddings;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Text chunking utilities
|
|
137
|
+
export class TextChunker {
|
|
138
|
+
static chunkText(text, maxChunkSize = 1000, overlap = 200) {
|
|
139
|
+
const chunks = [];
|
|
140
|
+
let start = 0;
|
|
141
|
+
|
|
142
|
+
while (start < text.length) {
|
|
143
|
+
let end = start + maxChunkSize;
|
|
144
|
+
|
|
145
|
+
// Try to find a good breaking point (sentence end)
|
|
146
|
+
if (end < text.length) {
|
|
147
|
+
const lastPeriod = text.lastIndexOf('.', end);
|
|
148
|
+
const lastNewline = text.lastIndexOf('\n', end);
|
|
149
|
+
|
|
150
|
+
if (lastPeriod > start && lastPeriod > end - 100) {
|
|
151
|
+
end = lastPeriod + 1;
|
|
152
|
+
} else if (lastNewline > start && lastNewline > end - 100) {
|
|
153
|
+
end = lastNewline;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
chunks.push(text.slice(start, Math.min(end, text.length)));
|
|
158
|
+
start = Math.max(start + maxChunkSize - overlap, 0);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return chunks;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static extractMetadata(filePath, content) {
|
|
165
|
+
const fileName = path.basename(filePath);
|
|
166
|
+
const extension = path.extname(filePath);
|
|
167
|
+
const relativePath = filePath.replace(process.cwd() + path.sep, '');
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
filePath: relativePath,
|
|
171
|
+
fileName,
|
|
172
|
+
extension,
|
|
173
|
+
contentLength: content.length,
|
|
174
|
+
id: crypto.createHash('md5').update(relativePath + content).digest('hex')
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Main RAG indexer function
|
|
180
|
+
export async function indexProject(config, projectRoot = process.cwd()) {
|
|
181
|
+
const store = new LocalVectorStore(projectRoot);
|
|
182
|
+
const embedder = new EmbeddingGenerator(config);
|
|
183
|
+
|
|
184
|
+
// Identify key project files
|
|
185
|
+
const keyFiles = await findKeyFiles(projectRoot);
|
|
186
|
+
|
|
187
|
+
const allChunks = [];
|
|
188
|
+
const allMetadata = [];
|
|
189
|
+
|
|
190
|
+
for (const filePath of keyFiles) {
|
|
191
|
+
try {
|
|
192
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
193
|
+
const chunks = TextChunker.chunkText(content);
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
196
|
+
allChunks.push(chunks[i]);
|
|
197
|
+
allMetadata.push({
|
|
198
|
+
...TextChunker.extractMetadata(filePath, chunks[i]),
|
|
199
|
+
chunkIndex: i,
|
|
200
|
+
totalChunks: chunks.length
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.warn(`Skipping ${filePath}: ${error.message}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Generate embeddings
|
|
209
|
+
const embeddings = await embedder.generateBatchEmbeddings(allChunks);
|
|
210
|
+
|
|
211
|
+
// Save to vector store
|
|
212
|
+
await store.saveVectors(embeddings, allMetadata);
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
indexedFiles: keyFiles.length,
|
|
216
|
+
totalChunks: allChunks.length
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Find key project files for indexing
|
|
221
|
+
async function findKeyFiles(projectRoot) {
|
|
222
|
+
const keyFiles = [];
|
|
223
|
+
const keyPatterns = [
|
|
224
|
+
'README.md',
|
|
225
|
+
'ARCHITECTURE.md',
|
|
226
|
+
'package.json',
|
|
227
|
+
'tsconfig.json',
|
|
228
|
+
'jest.config.js',
|
|
229
|
+
'jest.config.cjs',
|
|
230
|
+
'webpack.config.js',
|
|
231
|
+
'Dockerfile'
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
// Check for exact key files
|
|
235
|
+
for (const pattern of keyPatterns) {
|
|
236
|
+
const fullPath = path.join(projectRoot, pattern);
|
|
237
|
+
if (fs.existsSync(fullPath)) {
|
|
238
|
+
keyFiles.push(fullPath);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Find source files
|
|
243
|
+
const sourceDirs = ['src', 'components', 'lib', 'utils', 'types'];
|
|
244
|
+
for (const dir of sourceDirs) {
|
|
245
|
+
const fullDir = path.join(projectRoot, dir);
|
|
246
|
+
if (fs.existsSync(fullDir)) {
|
|
247
|
+
keyFiles.push(...findSourceFiles(fullDir));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Find interface/config files in root
|
|
252
|
+
const configPatterns = ['*.ts', '*.js', '*.json'].filter(ext => {
|
|
253
|
+
return fs.readdirSync(projectRoot)
|
|
254
|
+
.filter(file => file.endsWith(ext))
|
|
255
|
+
.filter(file => !keyFiles.some(kf => kf.endsWith(file)))
|
|
256
|
+
.map(file => path.join(projectRoot, file));
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
keyFiles.push(...configPatterns.flat());
|
|
260
|
+
|
|
261
|
+
return [...new Set(keyFiles)]; // Remove duplicates
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function findSourceFiles(dir) {
|
|
265
|
+
const files = [];
|
|
266
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.json', '.md'];
|
|
267
|
+
|
|
268
|
+
const items = fs.readdirSync(dir);
|
|
269
|
+
|
|
270
|
+
for (const item of items) {
|
|
271
|
+
const fullPath = path.join(dir, item);
|
|
272
|
+
const stat = fs.statSync(fullPath);
|
|
273
|
+
|
|
274
|
+
if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') {
|
|
275
|
+
files.push(...findSourceFiles(fullPath));
|
|
276
|
+
} else if (stat.isFile() && extensions.some(ext => item.endsWith(ext))) {
|
|
277
|
+
files.push(fullPath);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return files;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Context retrieval function
|
|
285
|
+
export async function retrieveContext(codeBlock, config, projectRoot = process.cwd(), k = 3) {
|
|
286
|
+
const store = new LocalVectorStore(projectRoot);
|
|
287
|
+
|
|
288
|
+
// Check if index exists
|
|
289
|
+
const { vectors } = store.loadVectors();
|
|
290
|
+
if (vectors.length === 0) {
|
|
291
|
+
return ''; // No context available
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const embedder = new EmbeddingGenerator(config);
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
// Generate embedding for the code block
|
|
298
|
+
const queryVector = await embedder.generateEmbedding(codeBlock);
|
|
299
|
+
|
|
300
|
+
// Search for similar chunks
|
|
301
|
+
const results = store.search(queryVector, k);
|
|
302
|
+
|
|
303
|
+
// Combine top results into context string
|
|
304
|
+
return results
|
|
305
|
+
.map(result => `From ${result.filePath}:\n${result.content}`)
|
|
306
|
+
.join('\n\n---\n\n');
|
|
307
|
+
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.warn(`Context retrieval failed: ${error.message}`);
|
|
310
|
+
return '';
|
|
311
|
+
}
|
|
312
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeflow-hook",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "An interactive CI/CD simulator and lightweight pre-push code reviewer using Gemini AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
"chalk": "^5.3.0",
|
|
32
32
|
"ora": "^7.0.1"
|
|
33
33
|
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^18.0.0"
|
|
36
|
+
},
|
|
34
37
|
"engines": {
|
|
35
38
|
"node": ">=16.0.0"
|
|
36
39
|
}
|