Spaces:
Paused
Paused
OMEGA: Add Self-Healing + fix npm ci
Browse files- Dockerfile +1 -1
- HF_SETUP_INSTRUCTIONS.md +180 -0
- README.md +1 -1
- apps/backend/src/services/MetricsService.ts +20 -0
- apps/backend/src/services/SelfHealingAdapter.ts +126 -126
- check_space_status.py +41 -0
- deploy_space.py +110 -0
- fetch_hf_logs.py +54 -0
- package-lock.json +0 -0
- package.json +63 -12
Dockerfile
CHANGED
|
@@ -24,7 +24,7 @@ COPY packages/domain-types/package*.json ./packages/domain-types/
|
|
| 24 |
COPY packages/mcp-types/package*.json ./packages/mcp-types/
|
| 25 |
|
| 26 |
# Install dependencies
|
| 27 |
-
RUN npm
|
| 28 |
|
| 29 |
# Copy source
|
| 30 |
COPY packages/ ./packages/
|
|
|
|
| 24 |
COPY packages/mcp-types/package*.json ./packages/mcp-types/
|
| 25 |
|
| 26 |
# Install dependencies
|
| 27 |
+
RUN npm ci --include=dev
|
| 28 |
|
| 29 |
# Copy source
|
| 30 |
COPY packages/ ./packages/
|
HF_SETUP_INSTRUCTIONS.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
╔══════════════════════════════════════════════════════════════╗
|
| 2 |
+
║ HUGGING FACE SPACE DEPLOYMENT - STEP BY STEP ║
|
| 3 |
+
╚══════════════════════════════════════════════════════════════╝
|
| 4 |
+
|
| 5 |
+
STATUS: ✅ Code committed (296 files, 63,820 lines)
|
| 6 |
+
⏳ Awaiting Space creation on Hugging Face
|
| 7 |
+
|
| 8 |
+
═══════════════════════════════════════════════════════════════
|
| 9 |
+
|
| 10 |
+
STEP 1: CREATE SPACE
|
| 11 |
+
════════════════════════════════════════════════════════════
|
| 12 |
+
|
| 13 |
+
1. Open: https://huggingface.co/new-space
|
| 14 |
+
|
| 15 |
+
2. Fill in form:
|
| 16 |
+
┌─────────────────────────────────────────────────────┐
|
| 17 |
+
│ Owner: Kraft102 │
|
| 18 |
+
│ Space name: widgetdc-cortex │
|
| 19 |
+
│ License: MIT │
|
| 20 |
+
│ SDK: Docker │
|
| 21 |
+
│ Visibility: Public (or Private if preferred) │
|
| 22 |
+
└─────────────────────────────────────────────────────┘
|
| 23 |
+
|
| 24 |
+
3. Click "Create Space"
|
| 25 |
+
|
| 26 |
+
═══════════════════════════════════════════════════════════════
|
| 27 |
+
|
| 28 |
+
STEP 2: PUSH CODE TO SPACE
|
| 29 |
+
════════════════════════════════════════════════════════════
|
| 30 |
+
|
| 31 |
+
After Space is created, run these commands:
|
| 32 |
+
|
| 33 |
+
```powershell
|
| 34 |
+
cd C:\Users\claus\Projects\WidgeTDC\widgetdc-cortex
|
| 35 |
+
git push hf main --force
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
Or if you prefer to start fresh:
|
| 39 |
+
```powershell
|
| 40 |
+
cd C:\Users\claus\Projects\WidgeTDC\widgetdc-cortex
|
| 41 |
+
git remote remove hf
|
| 42 |
+
git remote add hf https://huggingface.co/spaces/Kraft102/widgetdc-cortex
|
| 43 |
+
git push -u hf main
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
═══════════════════════════════════════════════════════════════
|
| 47 |
+
|
| 48 |
+
STEP 3: CONFIGURE ENVIRONMENT VARIABLES
|
| 49 |
+
════════════════════════════════════════════════════════════
|
| 50 |
+
|
| 51 |
+
1. Go to Space Settings → Variables
|
| 52 |
+
URL: https://huggingface.co/spaces/Kraft102/widgetdc-cortex/settings
|
| 53 |
+
|
| 54 |
+
2. Add these variables (click "New variable" for each):
|
| 55 |
+
|
| 56 |
+
┌─────────────────────────────────────────────────────────────┐
|
| 57 |
+
│ REQUIRED VARIABLES │
|
| 58 |
+
├─────────────────────────────────────────────────────────────┤
|
| 59 |
+
│ │
|
| 60 |
+
│ Name: OPENAI_API_KEY │
|
| 61 |
+
│ Value: sk-proj-EmjpmRMQF-ZV8cwBavB2pmd8v73HPeGY2BAT... │
|
| 62 |
+
│ │
|
| 63 |
+
│ Name: DATABASE_URL │
|
| 64 |
+
│ Value: postgresql://neondb_owner:npg_3tJWPqo9kRsf@ep-... │
|
| 65 |
+
│ │
|
| 66 |
+
│ Name: NEO4J_URI │
|
| 67 |
+
│ Value: neo4j+s://054eff27.databases.neo4j.io │
|
| 68 |
+
│ │
|
| 69 |
+
│ Name: NEO4J_USER │
|
| 70 |
+
│ Value: neo4j │
|
| 71 |
+
│ │
|
| 72 |
+
│ Name: NEO4J_PASSWORD │
|
| 73 |
+
│ Value: Qrt37mkb0xBZ7_ts5tG1J70K2mVDGPMF2L7Njlm7cg8 │
|
| 74 |
+
│ │
|
| 75 |
+
│ Name: JWT_SECRET │
|
| 76 |
+
│ Value: WidgeTDC_Neural_Key_2025_Secure │
|
| 77 |
+
│ │
|
| 78 |
+
└─────────────────────────────────────────────────────────────┘
|
| 79 |
+
|
| 80 |
+
┌──────────────────���──────────────────────────────────────────┐
|
| 81 |
+
│ OPTIONAL VARIABLES (Add for full functionality) │
|
| 82 |
+
├─────────────────────────────────────────────────────────────┤
|
| 83 |
+
│ │
|
| 84 |
+
│ Name: ANTHROPIC_API_KEY │
|
| 85 |
+
│ Value: sk-ant-api03-DpwskH4q6M-kSlU0WZWOA1yw7ZBTUYK... │
|
| 86 |
+
│ │
|
| 87 |
+
│ Name: GEMINI_API_KEY │
|
| 88 |
+
│ Value: AIzaSyDsrLIwhYEK4gC1PYqWsMuMgGVi0n02N-w │
|
| 89 |
+
│ │
|
| 90 |
+
│ Name: DEEPSEEK_API_KEY │
|
| 91 |
+
│ Value: sk-a3f8e6b48271466b981396dc97fd904a │
|
| 92 |
+
│ │
|
| 93 |
+
│ Name: FIRECRAWL_API_KEY │
|
| 94 |
+
│ Value: fc-c3c0b8aca44e49e48f052e49eb68f034 │
|
| 95 |
+
│ │
|
| 96 |
+
└─────────────────────────────────────────────────────────────┘
|
| 97 |
+
|
| 98 |
+
═══════════════════════════════════════════════════════════════
|
| 99 |
+
|
| 100 |
+
STEP 4: WAIT FOR BUILD
|
| 101 |
+
════════════════════════════════════════════════════════════
|
| 102 |
+
|
| 103 |
+
1. HF will automatically start building Docker image
|
| 104 |
+
2. Build takes ~5-10 minutes
|
| 105 |
+
3. Watch build logs in Space UI
|
| 106 |
+
4. Wait for "Running" status
|
| 107 |
+
|
| 108 |
+
═══════════════════════════════════════════════════════════════
|
| 109 |
+
|
| 110 |
+
STEP 5: VERIFY DEPLOYMENT
|
| 111 |
+
════════════════════════════════════════════════════════════
|
| 112 |
+
|
| 113 |
+
Once Space shows "Running", test it:
|
| 114 |
+
|
| 115 |
+
```powershell
|
| 116 |
+
curl https://kraft102-widgetdc-cortex.hf.space/health
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
Expected response:
|
| 120 |
+
```json
|
| 121 |
+
{
|
| 122 |
+
"status": "healthy",
|
| 123 |
+
"timestamp": "2025-12-14T23:00:00.000Z",
|
| 124 |
+
"services": {
|
| 125 |
+
"neo4j": "connected",
|
| 126 |
+
"database": "connected"
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
Test MCP endpoint:
|
| 132 |
+
```powershell
|
| 133 |
+
curl https://kraft102-widgetdc-cortex.hf.space/api/mcp/route
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
═══════════════════════════════════════════════════════════════
|
| 137 |
+
|
| 138 |
+
TROUBLESHOOTING
|
| 139 |
+
════════════════════════════════════════════════════════════
|
| 140 |
+
|
| 141 |
+
If build fails:
|
| 142 |
+
1. Check build logs in HF Space
|
| 143 |
+
2. Verify Dockerfile syntax
|
| 144 |
+
3. Check environment variables are set
|
| 145 |
+
4. Verify database connections
|
| 146 |
+
|
| 147 |
+
If Space won't start:
|
| 148 |
+
1. Check PORT is set to 7860 (default for HF)
|
| 149 |
+
2. Verify health check endpoint exists
|
| 150 |
+
3. Check memory requirements (upgrade tier if needed)
|
| 151 |
+
|
| 152 |
+
Common issues:
|
| 153 |
+
- Missing environment variables → Add in Settings
|
| 154 |
+
- Database connection timeout → Check firewall rules
|
| 155 |
+
- Build timeout → Image might be too large
|
| 156 |
+
|
| 157 |
+
═══════════════════════════════════════════════════════════════
|
| 158 |
+
|
| 159 |
+
NEXT STEPS AFTER DEPLOYMENT
|
| 160 |
+
════════════════════════════════════════════════════════════
|
| 161 |
+
|
| 162 |
+
1. Update frontend environment variables:
|
| 163 |
+
VITE_API_URL=https://kraft102-widgetdc-cortex.hf.space
|
| 164 |
+
|
| 165 |
+
2. Deploy frontend to Vercel:
|
| 166 |
+
cd C:\Users\claus\Projects\WidgeTDC\WidgeTDC\apps\frontend
|
| 167 |
+
vercel deploy --prod
|
| 168 |
+
|
| 169 |
+
3. Test end-to-end integration
|
| 170 |
+
|
| 171 |
+
═══════════════════════════════════════════════════════════════
|
| 172 |
+
|
| 173 |
+
READY TO START?
|
| 174 |
+
════════════════════════════════════════════════════════════
|
| 175 |
+
|
| 176 |
+
✅ Code is committed and ready
|
| 177 |
+
✅ Remote is configured
|
| 178 |
+
⏳ Awaiting Space creation
|
| 179 |
+
|
| 180 |
+
Next action: Go to https://huggingface.co/new-space and create Space!
|
README.md
CHANGED
|
@@ -5,7 +5,7 @@ colorFrom: purple
|
|
| 5 |
colorTo: blue
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
-
license:
|
| 9 |
app_port: 7860
|
| 10 |
---
|
| 11 |
|
|
|
|
| 5 |
colorTo: blue
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
+
license: MIT
|
| 9 |
app_port: 7860
|
| 10 |
---
|
| 11 |
|
apps/backend/src/services/MetricsService.ts
CHANGED
|
@@ -59,6 +59,26 @@ export class MetricsService {
|
|
| 59 |
});
|
| 60 |
}
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
/**
|
| 63 |
* Get current value of a counter
|
| 64 |
*/
|
|
|
|
| 59 |
});
|
| 60 |
}
|
| 61 |
|
| 62 |
+
/**
|
| 63 |
+
* Record a histogram metric (for latency/duration tracking)
|
| 64 |
+
*/
|
| 65 |
+
async recordHistogram(name: string, value: number, labels: MetricLabels = {}): Promise<void> {
|
| 66 |
+
const key = this.buildKey(`${name}_histogram`, labels);
|
| 67 |
+
|
| 68 |
+
// Store histogram as a gauge with the latest value
|
| 69 |
+
// For proper histogram, you'd want buckets - this is a simplified version
|
| 70 |
+
this.gauges.set(key, value);
|
| 71 |
+
|
| 72 |
+
this.recordToHistory({
|
| 73 |
+
name: `${name}_histogram`,
|
| 74 |
+
value,
|
| 75 |
+
labels,
|
| 76 |
+
timestamp: Date.now()
|
| 77 |
+
});
|
| 78 |
+
|
| 79 |
+
console.log(`📊 [Metrics] ${name} histogram: ${value}ms`, labels);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
/**
|
| 83 |
* Get current value of a counter
|
| 84 |
*/
|
apps/backend/src/services/SelfHealingAdapter.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
| 1 |
-
import {
|
| 2 |
-
import {
|
| 3 |
-
import { neo4jService } from '
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
|
| 12 |
private static instance: SelfHealingAdapter;
|
| 13 |
-
private
|
| 14 |
-
private
|
| 15 |
-
private isHealing: boolean = false;
|
| 16 |
|
| 17 |
private constructor() {
|
| 18 |
-
|
| 19 |
-
this.
|
| 20 |
}
|
| 21 |
|
| 22 |
public static getInstance(): SelfHealingAdapter {
|
|
@@ -26,134 +29,131 @@ export class SelfHealingAdapter {
|
|
| 26 |
return SelfHealingAdapter.instance;
|
| 27 |
}
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
}
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
}
|
| 44 |
-
return { passed: false, issues };
|
| 45 |
}
|
| 46 |
-
|
| 47 |
-
this.logger.info('✅ Startup validation passed.');
|
| 48 |
-
return { passed: true, issues: [] };
|
| 49 |
}
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
err.message.includes('Pool is closed'),
|
| 59 |
-
action: async () => {
|
| 60 |
-
this.logger.warn('⚠️ Initiating Neo4j connection reset sequence...');
|
| 61 |
-
try {
|
| 62 |
-
await neo4jService.close();
|
| 63 |
-
await neo4jService.connect();
|
| 64 |
-
const health = await neo4jService.healthCheck();
|
| 65 |
-
return health;
|
| 66 |
-
} catch (e) {
|
| 67 |
-
this.logger.error('Failed to reset Neo4j connection via strategy.');
|
| 68 |
-
return false;
|
| 69 |
-
}
|
| 70 |
-
}
|
| 71 |
-
});
|
| 72 |
|
| 73 |
-
|
| 74 |
-
this.registerStrategy({
|
| 75 |
-
name: 'Memory Flush',
|
| 76 |
-
condition: (err) => err.message.includes('Heap limit') || err.message.includes('OOM'),
|
| 77 |
-
action: async () => {
|
| 78 |
-
if (global.gc) {
|
| 79 |
-
this.logger.info('🧹 Triggering manual Garbage Collection (Emergency)');
|
| 80 |
-
global.gc();
|
| 81 |
-
await new Promise(resolve => setTimeout(resolve, 500));
|
| 82 |
-
return true;
|
| 83 |
-
} else {
|
| 84 |
-
this.logger.warn('⚠️ Cannot trigger GC. Run node with --expose-gc');
|
| 85 |
-
return false;
|
| 86 |
-
}
|
| 87 |
-
}
|
| 88 |
-
});
|
| 89 |
-
|
| 90 |
-
this.logger.info(`🚑 Immune System Initialized with ${this.strategies.length} active antibodies.`);
|
| 91 |
-
}
|
| 92 |
-
|
| 93 |
-
public registerStrategy(strategy: HealingStrategy) {
|
| 94 |
-
this.strategies.push(strategy);
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
public async handleError(error: Error, context: string): Promise<boolean> {
|
| 98 |
-
this.logger.error(`🚨 Anomaly detected in [${context}]: ${error.message}`);
|
| 99 |
-
|
| 100 |
-
metrics.incrementCounter('system_error_count', {
|
| 101 |
-
context,
|
| 102 |
-
errorType: error.name
|
| 103 |
-
});
|
| 104 |
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
}
|
| 109 |
|
| 110 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
}
|
| 112 |
|
| 113 |
-
private
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
if (strategy) {
|
| 121 |
-
this.logger.info(`💉 Applying healing strategy: [${strategy.name}]`);
|
| 122 |
-
healed = await strategy.action();
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
metrics.incrementCounter('unhandled_error_anomaly');
|
| 131 |
-
}
|
| 132 |
-
} catch (criticalError) {
|
| 133 |
-
this.logger.error('🔥 CRITICAL: Immune system failure during healing process.');
|
| 134 |
-
} finally {
|
| 135 |
-
this.isHealing = false;
|
| 136 |
-
}
|
| 137 |
-
return healed;
|
| 138 |
}
|
| 139 |
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
return {
|
| 143 |
-
overallHealth: 'HEALTHY',
|
| 144 |
-
services: [],
|
| 145 |
-
healingStats: { failures: 0, successRate: 100 },
|
| 146 |
-
lastUpdate: new Date().toISOString()
|
| 147 |
-
};
|
| 148 |
}
|
| 149 |
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
}
|
| 158 |
|
| 159 |
-
export const selfHealing = SelfHealingAdapter.getInstance();
|
|
|
|
| 1 |
+
import { metricsService } from './MetricsService';
|
| 2 |
+
import { hyperLog } from './HyperLog'; // Antager vi har denne service
|
| 3 |
+
// import { neo4jService } from './Neo4jService'; // Cirkulær afhængighed undgås ved lazy loading eller events
|
| 4 |
+
|
| 5 |
+
type HealingStrategy = 'RETRY' | 'RECONNECT' | 'RESTART_SERVICE' | 'IGNORE' | 'CIRCUIT_BREAK';
|
| 6 |
+
type ErrorSignature = string;
|
| 7 |
+
|
| 8 |
+
interface HealingResult {
|
| 9 |
+
healed: boolean;
|
| 10 |
+
strategyUsed: HealingStrategy;
|
| 11 |
+
attempts: number;
|
| 12 |
+
latency: number;
|
| 13 |
}
|
| 14 |
|
| 15 |
+
class SelfHealingAdapter {
|
| 16 |
private static instance: SelfHealingAdapter;
|
| 17 |
+
private retryLimits: Map<ErrorSignature, number> = new Map();
|
| 18 |
+
private circuitBreakers: Map<string, boolean> = new Map(); // True = OPEN (Broken)
|
|
|
|
| 19 |
|
| 20 |
private constructor() {
|
| 21 |
+
console.log('💚 [LAZARUS CORE] Self-Healing Engine Initialized');
|
| 22 |
+
this.setupProcessWatchdogs();
|
| 23 |
}
|
| 24 |
|
| 25 |
public static getInstance(): SelfHealingAdapter {
|
|
|
|
| 29 |
return SelfHealingAdapter.instance;
|
| 30 |
}
|
| 31 |
|
| 32 |
+
/**
|
| 33 |
+
* 🛡️ THE OMEGA SHIELD: Main entry point for all system errors.
|
| 34 |
+
* Wraps any operation in a Lazarus Loop.
|
| 35 |
+
*/
|
| 36 |
+
public async guard<T>(
|
| 37 |
+
operationName: string,
|
| 38 |
+
operation: () => Promise<T>,
|
| 39 |
+
context: any = {}
|
| 40 |
+
): Promise<T> {
|
| 41 |
+
const startTime = Date.now();
|
| 42 |
+
|
| 43 |
+
// 1. Check Circuit Breaker
|
| 44 |
+
if (this.circuitBreakers.get(operationName)) {
|
| 45 |
+
metricsService.incrementCounter('healing_circuit_blocked');
|
| 46 |
+
throw new Error(`[CIRCUIT_BREAKER] Operation '${operationName}' is blocked due to repeated failures.`);
|
| 47 |
}
|
| 48 |
|
| 49 |
+
try {
|
| 50 |
+
// 2. Execute Operation
|
| 51 |
+
const result = await operation();
|
| 52 |
+
|
| 53 |
+
// 3. Success Metrics
|
| 54 |
+
metricsService.recordHistogram('operation_latency', Date.now() - startTime);
|
| 55 |
+
metricsService.incrementCounter('operation_success');
|
| 56 |
+
return result;
|
| 57 |
+
|
| 58 |
+
} catch (error: any) {
|
| 59 |
+
// 4. FAILURE DETECTED -> INITIATE HEALING
|
| 60 |
+
console.warn(`⚡ [LAZARUS] Failure in '${operationName}': ${error.message}`);
|
| 61 |
+
metricsService.incrementCounter('operation_failure');
|
| 62 |
+
|
| 63 |
+
const solution = await this.heal(error, operationName, context);
|
| 64 |
+
|
| 65 |
+
if (solution.healed) {
|
| 66 |
+
// 5. RESURRECTION SUCCESSFUL
|
| 67 |
+
console.log(`💚 [LAZARUS] Successfully healed '${operationName}' via ${solution.strategyUsed}`);
|
| 68 |
+
metricsService.incrementCounter('healing_success');
|
| 69 |
+
|
| 70 |
+
// Recursive Retry (The Lazarus Loop)
|
| 71 |
+
// Beware of infinite loops; logic inside heal() handles limits.
|
| 72 |
+
return this.guard(operationName, operation, context);
|
| 73 |
+
} else {
|
| 74 |
+
// 6. DEATH (Rethrow)
|
| 75 |
+
metricsService.incrementCounter('healing_failed');
|
| 76 |
+
await hyperLog.logEvent('CRITICAL_FAILURE', {
|
| 77 |
+
source: 'SelfHealingAdapter',
|
| 78 |
+
error: error.message,
|
| 79 |
+
operation: operationName
|
| 80 |
+
});
|
| 81 |
+
throw error;
|
| 82 |
}
|
|
|
|
| 83 |
}
|
|
|
|
|
|
|
|
|
|
| 84 |
}
|
| 85 |
|
| 86 |
+
/**
|
| 87 |
+
* 🚑 THE HOSPITAL: Diagnoses and treats errors.
|
| 88 |
+
*/
|
| 89 |
+
public async heal(error: Error, source: string, context: any): Promise<HealingResult> {
|
| 90 |
+
const startTime = Date.now();
|
| 91 |
+
const errorType = this.diagnoseError(error);
|
| 92 |
+
const strategy = this.prescribeStrategy(errorType, source);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
+
metricsService.incrementCounter(`strategy_triggered_${strategy}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
|
| 96 |
+
// Execute Strategy
|
| 97 |
+
let healed = false;
|
| 98 |
+
switch (strategy) {
|
| 99 |
+
case 'RETRY':
|
| 100 |
+
await this.wait(1000); // Exponential backoff logic her i v2
|
| 101 |
+
healed = true; // Vi giver den et skud til
|
| 102 |
+
break;
|
| 103 |
+
|
| 104 |
+
case 'RECONNECT':
|
| 105 |
+
console.log('🔌 [LAZARUS] Attempting DB Reconnect...');
|
| 106 |
+
// Logic to force Neo4j driver reset
|
| 107 |
+
// await neo4jService.resetDriver();
|
| 108 |
+
await this.wait(2000);
|
| 109 |
+
healed = true;
|
| 110 |
+
break;
|
| 111 |
+
|
| 112 |
+
case 'CIRCUIT_BREAK':
|
| 113 |
+
console.error(`💥 [LAZARUS] Circuit Breaker Activated for ${source}`);
|
| 114 |
+
this.circuitBreakers.set(source, true);
|
| 115 |
+
setTimeout(() => this.circuitBreakers.set(source, false), 30000); // 30s cooldown
|
| 116 |
+
healed = false;
|
| 117 |
+
break;
|
| 118 |
+
|
| 119 |
+
default:
|
| 120 |
+
healed = false;
|
| 121 |
}
|
| 122 |
|
| 123 |
+
return {
|
| 124 |
+
healed,
|
| 125 |
+
strategyUsed: strategy,
|
| 126 |
+
attempts: 1,
|
| 127 |
+
latency: Date.now() - startTime
|
| 128 |
+
};
|
| 129 |
}
|
| 130 |
|
| 131 |
+
private diagnoseError(error: any): string {
|
| 132 |
+
if (error.code === 'ECONNREFUSED') return 'CONNECTION_LOST';
|
| 133 |
+
if (error.code === 'SessionExpired') return 'SESSION_EXPIRED';
|
| 134 |
+
if (error.message.includes('Rate limit')) return 'RATE_LIMIT';
|
| 135 |
+
return 'UNKNOWN_TRAUMA';
|
| 136 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
|
| 138 |
+
private prescribeStrategy(errorType: string, source: string): HealingStrategy {
|
| 139 |
+
// Omega Logic: Dynamic Strategy Selection
|
| 140 |
+
if (errorType === 'CONNECTION_LOST') return 'RECONNECT';
|
| 141 |
+
if (errorType === 'SESSION_EXPIRED') return 'RETRY';
|
| 142 |
+
if (errorType === 'RATE_LIMIT') return 'CIRCUIT_BREAK';
|
| 143 |
+
return 'RETRY'; // Default aggressive persistence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
}
|
| 145 |
|
| 146 |
+
private wait(ms: number) {
|
| 147 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
}
|
| 149 |
|
| 150 |
+
private setupProcessWatchdogs() {
|
| 151 |
+
process.on('unhandledRejection', (reason, p) => {
|
| 152 |
+
console.error('💀 [LAZARUS] Unhandled Rejection at:', p, 'reason:', reason);
|
| 153 |
+
metricsService.incrementCounter('process_crash_prevented');
|
| 154 |
+
// Her kunne vi logge til HyperLog
|
| 155 |
+
});
|
| 156 |
+
}
|
| 157 |
}
|
| 158 |
|
| 159 |
+
export const selfHealing = SelfHealingAdapter.getInstance();
|
check_space_status.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Check Hugging Face Space build status and logs
|
| 3 |
+
"""
|
| 4 |
+
from huggingface_hub import HfApi
|
| 5 |
+
import time
|
| 6 |
+
|
| 7 |
+
api = HfApi()
|
| 8 |
+
REPO_ID = "Kraft102/widgetdc-cortex"
|
| 9 |
+
|
| 10 |
+
print("=" * 70)
|
| 11 |
+
print(" CHECKING SPACE BUILD STATUS")
|
| 12 |
+
print("=" * 70)
|
| 13 |
+
print()
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
# Get space runtime info
|
| 17 |
+
runtime = api.get_space_runtime(repo_id=REPO_ID)
|
| 18 |
+
|
| 19 |
+
print(f"📊 Space: {REPO_ID}")
|
| 20 |
+
print(f" Stage: {runtime.stage}")
|
| 21 |
+
print(f" Hardware: {runtime.hardware}")
|
| 22 |
+
print(f" Storage: {runtime.storage}")
|
| 23 |
+
|
| 24 |
+
if hasattr(runtime, 'error_message') and runtime.error_message:
|
| 25 |
+
print(f"\n❌ ERROR:")
|
| 26 |
+
print(f" {runtime.error_message}")
|
| 27 |
+
|
| 28 |
+
print()
|
| 29 |
+
print("🌐 Space URL: https://huggingface.co/spaces/Kraft102/widgetdc-cortex")
|
| 30 |
+
print("📋 Logs: https://huggingface.co/spaces/Kraft102/widgetdc-cortex/logs")
|
| 31 |
+
|
| 32 |
+
except Exception as e:
|
| 33 |
+
print(f"⚠️ Could not fetch runtime info: {e}")
|
| 34 |
+
print()
|
| 35 |
+
print("Try manually:")
|
| 36 |
+
print("1. Visit: https://huggingface.co/spaces/Kraft102/widgetdc-cortex")
|
| 37 |
+
print("2. Check logs tab for build errors")
|
| 38 |
+
print("3. Verify environment variables are set")
|
| 39 |
+
|
| 40 |
+
print()
|
| 41 |
+
print("=" * 70)
|
deploy_space.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
WidgeTDC Cortex - Automated Hugging Face Space Deployment
|
| 3 |
+
Uses huggingface_hub API to create and configure Space
|
| 4 |
+
"""
|
| 5 |
+
import os
|
| 6 |
+
import subprocess
|
| 7 |
+
from huggingface_hub import HfApi, create_repo
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
# Configuration
|
| 11 |
+
SPACE_NAME = "widgetdc-cortex"
|
| 12 |
+
USERNAME = "Kraft102"
|
| 13 |
+
REPO_ID = f"{USERNAME}/{SPACE_NAME}"
|
| 14 |
+
|
| 15 |
+
print("=" * 60)
|
| 16 |
+
print(" NEURAL NETWORK DEPLOYMENT - HUGGING FACE SPACE")
|
| 17 |
+
print("=" * 60)
|
| 18 |
+
print()
|
| 19 |
+
|
| 20 |
+
# Initialize API
|
| 21 |
+
api = HfApi()
|
| 22 |
+
|
| 23 |
+
print("[1/5] Creating Hugging Face Space...")
|
| 24 |
+
try:
|
| 25 |
+
# Create Space repository
|
| 26 |
+
repo_url = create_repo(
|
| 27 |
+
repo_id=REPO_ID,
|
| 28 |
+
repo_type="space",
|
| 29 |
+
space_sdk="docker",
|
| 30 |
+
private=False,
|
| 31 |
+
exist_ok=True
|
| 32 |
+
)
|
| 33 |
+
print(f"✅ Space created/verified: {repo_url}")
|
| 34 |
+
except Exception as e:
|
| 35 |
+
print(f"⚠️ Space might already exist or error: {e}")
|
| 36 |
+
repo_url = f"https://huggingface.co/spaces/{REPO_ID}"
|
| 37 |
+
|
| 38 |
+
print(f"\n[2/5] Pushing code to Space...")
|
| 39 |
+
repo_path = Path(r"C:\Users\claus\Projects\WidgeTDC\widgetdc-cortex")
|
| 40 |
+
os.chdir(repo_path)
|
| 41 |
+
|
| 42 |
+
# Configure git remote if needed
|
| 43 |
+
try:
|
| 44 |
+
subprocess.run(
|
| 45 |
+
["git", "remote", "remove", "hf"],
|
| 46 |
+
capture_output=True,
|
| 47 |
+
check=False
|
| 48 |
+
)
|
| 49 |
+
except:
|
| 50 |
+
pass
|
| 51 |
+
|
| 52 |
+
subprocess.run(
|
| 53 |
+
["git", "remote", "add", "hf", f"https://huggingface.co/spaces/{REPO_ID}"],
|
| 54 |
+
check=False
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
# Push to HF
|
| 58 |
+
print(" Pushing to Hugging Face...")
|
| 59 |
+
result = subprocess.run(
|
| 60 |
+
["git", "push", "hf", "main", "--force"],
|
| 61 |
+
capture_output=True,
|
| 62 |
+
text=True
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
if result.returncode == 0:
|
| 66 |
+
print("✅ Code pushed successfully!")
|
| 67 |
+
else:
|
| 68 |
+
print(f"⚠️ Push output: {result.stderr}")
|
| 69 |
+
|
| 70 |
+
print(f"\n[3/5] Configuring environment variables...")
|
| 71 |
+
|
| 72 |
+
# Environment variables to set
|
| 73 |
+
secrets = {
|
| 74 |
+
"OPENAI_API_KEY": "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",
|
| 75 |
+
"DATABASE_URL": "postgresql://neondb_owner:npg_3tJWPqo9kRsf@ep-fancy-field-aedyuut2-pooler.c-2.us-east-2.aws.neon.tech/neondb?channel_binding=require&sslmode=require",
|
| 76 |
+
"NEO4J_URI": "neo4j+s://054eff27.databases.neo4j.io",
|
| 77 |
+
"NEO4J_USER": "neo4j",
|
| 78 |
+
"NEO4J_PASSWORD": "Qrt37mkb0xBZ7_ts5tG1J70K2mVDGPMF2L7Njlm7cg8",
|
| 79 |
+
"JWT_SECRET": "WidgeTDC_Neural_Key_2025_Secure",
|
| 80 |
+
"ANTHROPIC_API_KEY": "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",
|
| 81 |
+
"GEMINI_API_KEY": "AIzaSyDsrLIwhYEK4gC1PYqWsMuMgGVi0n02N-w",
|
| 82 |
+
"DEEPSEEK_API_KEY": "sk-a3f8e6b48271466b981396dc97fd904a"
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
try:
|
| 86 |
+
for key, value in secrets.items():
|
| 87 |
+
api.add_space_secret(
|
| 88 |
+
repo_id=REPO_ID,
|
| 89 |
+
key=key,
|
| 90 |
+
value=value
|
| 91 |
+
)
|
| 92 |
+
print(f" ✅ {key} configured")
|
| 93 |
+
except Exception as e:
|
| 94 |
+
print(f"⚠️ Could not set secrets via API: {e}")
|
| 95 |
+
print(" You may need to set them manually in Space Settings")
|
| 96 |
+
|
| 97 |
+
print(f"\n[4/5] Space URL:")
|
| 98 |
+
print(f" 🌐 https://huggingface.co/spaces/{REPO_ID}")
|
| 99 |
+
print(f" 📊 Settings: https://huggingface.co/spaces/{REPO_ID}/settings")
|
| 100 |
+
|
| 101 |
+
print(f"\n[5/5] Deployment initiated!")
|
| 102 |
+
print(f" HF will now build Docker image (~5-10 minutes)")
|
| 103 |
+
print(f" Watch build: https://huggingface.co/spaces/{REPO_ID}")
|
| 104 |
+
|
| 105 |
+
print("\n" + "=" * 60)
|
| 106 |
+
print(" DEPLOYMENT STATUS: INITIATED")
|
| 107 |
+
print("=" * 60)
|
| 108 |
+
print()
|
| 109 |
+
print("Next: Wait for build to complete, then test:")
|
| 110 |
+
print(f"curl https://{USERNAME}-{SPACE_NAME}.hf.space/health")
|
fetch_hf_logs.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Fetch Hugging Face Space build logs and analyze errors with DeepSeek
|
| 3 |
+
"""
|
| 4 |
+
from huggingface_hub import HfApi
|
| 5 |
+
import requests
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
api = HfApi()
|
| 9 |
+
REPO_ID = "Kraft102/widgetdc-cortex"
|
| 10 |
+
|
| 11 |
+
print("=" * 80)
|
| 12 |
+
print(" FETCHING HUGGING FACE SPACE BUILD LOGS")
|
| 13 |
+
print("=" * 80)
|
| 14 |
+
print()
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
# Get space info
|
| 18 |
+
space_info = api.space_info(repo_id=REPO_ID)
|
| 19 |
+
|
| 20 |
+
print(f"📊 Space: {REPO_ID}")
|
| 21 |
+
print(f" Runtime: {space_info.runtime}")
|
| 22 |
+
print()
|
| 23 |
+
|
| 24 |
+
# Try to get logs via API
|
| 25 |
+
token = os.getenv("HF_TOKEN")
|
| 26 |
+
if token:
|
| 27 |
+
headers = {"Authorization": f"Bearer {token}"}
|
| 28 |
+
logs_url = f"https://huggingface.co/api/spaces/{REPO_ID}/logs"
|
| 29 |
+
|
| 30 |
+
response = requests.get(logs_url, headers=headers)
|
| 31 |
+
if response.status_code == 200:
|
| 32 |
+
logs = response.text
|
| 33 |
+
print("📋 BUILD LOGS:")
|
| 34 |
+
print("-" * 80)
|
| 35 |
+
print(logs)
|
| 36 |
+
print("-" * 80)
|
| 37 |
+
else:
|
| 38 |
+
print(f"⚠️ Could not fetch logs: HTTP {response.status_code}")
|
| 39 |
+
else:
|
| 40 |
+
print("⚠️ HF_TOKEN not set - cannot fetch detailed logs")
|
| 41 |
+
print()
|
| 42 |
+
print("Manual steps:")
|
| 43 |
+
print("1. Visit: https://huggingface.co/spaces/Kraft102/widgetdc-cortex")
|
| 44 |
+
print("2. Click 'Logs' tab")
|
| 45 |
+
print("3. Copy build error messages")
|
| 46 |
+
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"❌ Error: {e}")
|
| 49 |
+
print()
|
| 50 |
+
print("Visit Space manually:")
|
| 51 |
+
print("https://huggingface.co/spaces/Kraft102/widgetdc-cortex")
|
| 52 |
+
|
| 53 |
+
print()
|
| 54 |
+
print("=" * 80)
|
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
CHANGED
|
@@ -1,28 +1,79 @@
|
|
| 1 |
{
|
| 2 |
-
"name": "
|
| 3 |
-
"version": "
|
| 4 |
"type": "module",
|
| 5 |
"private": true,
|
| 6 |
"workspaces": [
|
| 7 |
"apps/backend",
|
|
|
|
| 8 |
"packages/*"
|
| 9 |
],
|
| 10 |
"scripts": {
|
| 11 |
-
"dev": "
|
| 12 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
"build:backend": "cd apps/backend && npm run build",
|
| 14 |
"build:shared": "npm run build:domain-types && npm run build:mcp-types",
|
| 15 |
-
"build:domain-types": "cd packages/domain-types && npm run build",
|
| 16 |
-
"build:mcp-types": "cd packages/mcp-types && npm run build",
|
| 17 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
},
|
| 19 |
"dependencies": {
|
| 20 |
-
"axios": "^1.
|
| 21 |
-
"cheerio": "^1.
|
| 22 |
-
"dotenv": "^
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
},
|
| 24 |
"devDependencies": {
|
| 25 |
-
"@
|
| 26 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
}
|
| 28 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"name": "widget-tdc-monorepo",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
"type": "module",
|
| 5 |
"private": true,
|
| 6 |
"workspaces": [
|
| 7 |
"apps/backend",
|
| 8 |
+
"apps/matrix-frontend",
|
| 9 |
"packages/*"
|
| 10 |
],
|
| 11 |
"scripts": {
|
| 12 |
+
"dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
|
| 13 |
+
"start": "powershell -ExecutionPolicy Bypass -File scripts/dev.ps1",
|
| 14 |
+
"kill-ports": "powershell -Command \"Get-NetTCPConnection -LocalPort 3001,8080 -State Listen 2>$null | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }\"",
|
| 15 |
+
"dev:frontend": "cd apps/matrix-frontend && npm run dev",
|
| 16 |
+
"dev:backend": "cd apps/backend && npm run dev",
|
| 17 |
+
"dev:desktop": "npm run build:frontend && cd desktop-app && npm run start:dev",
|
| 18 |
+
"build": "npm run build:shared && npm run build:backend && npm run build:frontend",
|
| 19 |
+
"build:frontend": "cd apps/matrix-frontend && npm run build",
|
| 20 |
"build:backend": "cd apps/backend && npm run build",
|
| 21 |
"build:shared": "npm run build:domain-types && npm run build:mcp-types",
|
| 22 |
+
"build:domain-types": "cd packages/domain-types && npm install && npm run build",
|
| 23 |
+
"build:mcp-types": "cd packages/mcp-types && npm install && npm run build",
|
| 24 |
+
"build:desktop": "npm run build:frontend && cd desktop-app && npm run build",
|
| 25 |
+
"build:desktop:win": "npm run build:frontend && cd desktop-app && npm run build:win",
|
| 26 |
+
"build:desktop:mac": "npm run build:frontend && cd desktop-app && npm run build:mac",
|
| 27 |
+
"build:desktop:linux": "npm run build:frontend && cd desktop-app && npm run build:linux",
|
| 28 |
+
"preview": "vite preview",
|
| 29 |
+
"test": "vitest",
|
| 30 |
+
"test:ui": "vitest --ui",
|
| 31 |
+
"test:coverage": "vitest --coverage",
|
| 32 |
+
"test:run": "vitest run",
|
| 33 |
+
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
|
| 34 |
+
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
|
| 35 |
+
"lint:frontend": "cd apps/matrix-frontend && npm run lint",
|
| 36 |
+
"typecheck:frontend": "cd apps/matrix-frontend && npm run typecheck",
|
| 37 |
+
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
| 38 |
+
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
| 39 |
+
"ci:frontend": "npm run typecheck:frontend && npm run lint:frontend && npm run build:frontend"
|
| 40 |
},
|
| 41 |
"dependencies": {
|
| 42 |
+
"axios": "^1.13.2",
|
| 43 |
+
"cheerio": "^1.1.2",
|
| 44 |
+
"dotenv": "^17.2.3",
|
| 45 |
+
"sharp": "0.32.6"
|
| 46 |
+
},
|
| 47 |
+
"overrides": {
|
| 48 |
+
"semver": "^7.5.2"
|
| 49 |
},
|
| 50 |
"devDependencies": {
|
| 51 |
+
"@playwright/test": "^1.56.1",
|
| 52 |
+
"@testing-library/dom": "^10.4.1",
|
| 53 |
+
"@testing-library/jest-dom": "^6.9.1",
|
| 54 |
+
"@testing-library/react": "^16.3.0",
|
| 55 |
+
"@testing-library/user-event": "^14.6.1",
|
| 56 |
+
"@types/node": "^22.14.0",
|
| 57 |
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
| 58 |
+
"@typescript-eslint/parser": "^8.46.4",
|
| 59 |
+
"@vitejs/plugin-react": "^5.1.1",
|
| 60 |
+
"@vitest/ui": "^4.0.8",
|
| 61 |
+
"concurrently": "^8.2.2",
|
| 62 |
+
"eslint": "^9.39.1",
|
| 63 |
+
"eslint-config-prettier": "^10.1.8",
|
| 64 |
+
"eslint-plugin-react": "^7.37.5",
|
| 65 |
+
"eslint-plugin-react-hooks": "^7.0.1",
|
| 66 |
+
"eslint-plugin-security": "^3.0.1",
|
| 67 |
+
"jsdom": "^27.2.0",
|
| 68 |
+
"prettier": "^3.6.2",
|
| 69 |
+
"typescript": "~5.8.2",
|
| 70 |
+
"vite": "^7.2.4",
|
| 71 |
+
"vitest": "^4.0.8"
|
| 72 |
+
},
|
| 73 |
+
"lint-staged": {
|
| 74 |
+
"*.{ts,tsx}": [
|
| 75 |
+
"tsc --noEmit",
|
| 76 |
+
"eslint --fix"
|
| 77 |
+
]
|
| 78 |
}
|
| 79 |
}
|