This commit is contained in:
alorig
2025-11-09 23:17:51 +05:00
parent a622a3ffe3
commit 88fea41e9f
9 changed files with 0 additions and 749 deletions

View File

@@ -1,195 +0,0 @@
# AI Architecture Compliance Check
## ✅ Current Status vs. 4-Stage Plan
### Stage 1: AI Folder Structure & Functional Split ✅
- **Status**: COMPLETE
- **Evidence**:
- All functions in `/ai/functions/`
- Shared modules (`ai_core.py`, `validators.py`, `constants.py`) ✅
- Clean structure with no duplication ✅
### Stage 2: AI Execution & Logging Layer ✅
- **Status**: COMPLETE
- **Evidence**:
- `AICore.run_ai_request()` centralizes all AI requests ✅
- `AICore.generate_image()` centralizes image generation ✅
- All functions use `run_ai_request()` via `AIEngine.execute()`
### Stage 3: Clean Logging, Unified Debug Flow & Step Traceability ✅
- **Status**: COMPLETE (Just Fixed)
- **Evidence**:
- `ConsoleStepTracker` created and integrated ✅
- `AIEngine.execute()` now uses `ConsoleStepTracker`
- `_auto_cluster_keywords_core` uses `ConsoleStepTracker`
- All phases logged: INIT → PREP → AI_CALL → PARSE → SAVE → DONE ✅
### Stage 4: Prompt Registry, Model Unification, and Final Function Hooks ✅
- **Status**: COMPLETE (with legacy compatibility)
- **Evidence**:
- `PromptRegistry.get_prompt()` created ✅
- `MODEL_CONFIG` in `settings.py`
- `AutoClusterFunction` uses `PromptRegistry` and `get_model_config()`
- `AIEngine.execute()` uses `get_model_config()`
---
## ⚠️ Architecture Paths
### NEW PATH (Recommended - Stage 4 Compliant) ✅
**Flow:**
```
API Request → views.py → run_ai_task → AIEngine.execute() → AutoClusterFunction
```
**Uses:**
-`PromptRegistry.get_prompt()` (Stage 4)
-`get_model_config()` (Stage 4)
-`AICore.run_ai_request()` (Stage 2)
-`ConsoleStepTracker` (Stage 3)
-`AutoClusterFunction` class (Stage 1)
**Files:**
- `backend/igny8_core/modules/planner/views.py` - Uses `run_ai_task`
- `backend/igny8_core/ai/tasks.py` - Unified Celery entrypoint
- `backend/igny8_core/ai/engine.py` - Uses new architecture
- `backend/igny8_core/ai/functions/auto_cluster.py` - Uses PromptRegistry
**Status**: ✅ FULLY COMPLIANT with all 4 stages
---
### OLD PATH (Legacy - Partial Compliance) ⚠️
**Flow:**
```
Legacy Celery Task → auto_cluster_keywords_task → _auto_cluster_keywords_core → AIProcessor.cluster_keywords()
```
**Uses:**
-`self.get_prompt()` (OLD method, not PromptRegistry)
- ❌ Hardcoded model settings (not `get_model_config()`)
-`AICore.run_ai_request()` (via `_call_openai()` wrapper)
-`ConsoleStepTracker` (Just added)
-`AIProcessor.cluster_keywords()` (OLD method)
**Files:**
- `backend/igny8_core/modules/planner/tasks.py` - Legacy function
- `backend/igny8_core/utils/ai_processor.py` - Legacy processor
**Status**: ⚠️ PARTIALLY COMPLIANT
- ✅ Console logging added (Stage 3)
- ✅ Prompt placeholder fix (functional fix)
- ❌ Still uses old prompt method (not Stage 4)
- ❌ Still uses old model config (not Stage 4)
**Note**: This path is kept for backward compatibility. The NEW path should be preferred.
---
## 🔍 Issue Analysis
### Issue 1: Console Logging Not Happening ✅ FIXED
**Problem**: Console logging was not happening for AI requests and responses.
**Root Cause**:
- `AIEngine.execute()` was not using `ConsoleStepTracker`
- `_auto_cluster_keywords_core` was not using `ConsoleStepTracker`
**Fix Applied**:
- ✅ Added `ConsoleStepTracker` to `AIEngine.execute()`
- ✅ Added `ConsoleStepTracker` to `_auto_cluster_keywords_core`
- ✅ Passed tracker to `AICore.run_ai_request()`
- ✅ All phases now log to console
**Status**: ✅ RESOLVED
---
### Issue 2: Prompt Placeholder Not Replaced ✅ FIXED
**Problem**: `[IGNY8_KEYWORDS]` placeholder was not being replaced with actual keywords.
**Root Cause**:
- In `AutoClusterFunction.build_prompt()`: Context key is `KEYWORDS` but placeholder is `[IGNY8_KEYWORDS]`
- `PromptRegistry._render_prompt()` should handle this, but let's verify
- In `AIProcessor.cluster_keywords()`: Manual replacement should work, but validation was missing
**Fix Applied**:
- ✅ Added validation in `AIProcessor.cluster_keywords()` to check if placeholder exists
- ✅ Added logging to show when prompt is prepared
- ✅ Verified `PromptRegistry._render_prompt()` handles `[IGNY8_*]` placeholders correctly
**Status**: ✅ RESOLVED
---
## 📊 Compliance Matrix
| Component | Stage 1 | Stage 2 | Stage 3 | Stage 4 | Status |
|-----------|---------|---------|---------|---------|--------|
| **NEW Path (via AIEngine)** | ✅ | ✅ | ✅ | ✅ | **FULLY COMPLIANT** |
| **OLD Path (legacy tasks)** | ✅ | ⚠️ | ✅ | ❌ | **PARTIAL** |
---
## 🎯 Recommendations
### 1. Migrate Legacy Tasks to New Architecture
**Current**: `_auto_cluster_keywords_core` uses `AIProcessor.cluster_keywords()`
**Recommended**: Update to use `AutoClusterFunction` via `AIEngine.execute()`
**Migration Path**:
```python
# OLD (current)
def _auto_cluster_keywords_core(...):
processor = AIProcessor(account=account)
result = processor.cluster_keywords(...)
# NEW (recommended)
def _auto_cluster_keywords_core(...):
from igny8_core.ai.engine import AIEngine
from igny8_core.ai.functions.auto_cluster import AutoClusterFunction
fn = AutoClusterFunction()
engine = AIEngine(account=account)
result = engine.execute(fn, payload)
```
### 2. Update AIProcessor Methods (Optional)
If `AIProcessor` methods need to remain for backward compatibility, update them to use:
- `PromptRegistry.get_prompt()` instead of `self.get_prompt()`
- `get_model_config()` instead of hardcoded settings
**Status**: Not critical - NEW path is preferred
---
## ✅ Summary
### What's Working (NEW Path):
- ✅ All 4 stages fully implemented
- ✅ Console logging working
- ✅ Prompt registry working
- ✅ Model config unified
- ✅ Clean architecture
### What's Working (OLD Path):
- ✅ Console logging added
- ✅ Prompt placeholder fixed
- ⚠️ Still uses old prompt/model methods (but functional)
### Conclusion:
**The NEW path is fully compliant with all 4 stages.** The OLD path is functional but uses legacy methods. Both paths now have console logging and prompt placeholder replacement working.
**Recommendation**: Use the NEW path (`run_ai_task``AIEngine.execute()`) for all new code. The OLD path can remain for backward compatibility but should eventually be deprecated.
---
**Last Updated**: After fixing console logging and prompt placeholder issues

View File

@@ -1,202 +0,0 @@
# 🔍 PROOF: Lazy Loading Works - Only Keywords Page Loads
## 📊 Evidence Summary
**Date:** November 9, 2025
**Page Tested:** `/planner/keywords`
**Conclusion:****Only the Keywords page component loads, NOT all pages**
---
## 1⃣ Network Requests Analysis
### ✅ **LOADED: Keywords Page Only**
From the network requests, here's what was **actually loaded**:
```
✅ src/pages/Planner/Keywords.tsx (78.89 KB)
✅ src/templates/TablePageTemplate.tsx (155.89 KB)
✅ src/config/pages/keywords.config.tsx (59.52 KB)
✅ src/config/pages/delete-modal.config.ts (7.64 KB)
✅ src/config/pages/bulk-action-modal.config.ts (16.24 KB)
✅ src/config/pages/table-actions.config.tsx (31.23 KB)
```
**Total Keywords-specific code:** ~350 KB
### ❌ **NOT LOADED: All Other Pages**
The following pages were **NOT** found in network requests:
#### Writer Module (6 pages - NOT LOADED)
-`src/pages/Writer/Dashboard.tsx`
-`src/pages/Writer/Tasks.tsx`
-`src/pages/Writer/Content.tsx`
-`src/pages/Writer/Drafts.tsx`
-`src/pages/Writer/Images.tsx`
-`src/pages/Writer/Published.tsx`
#### Thinker Module (5 pages - NOT LOADED)
-`src/pages/Thinker/Dashboard.tsx`
-`src/pages/Thinker/Prompts.tsx`
-`src/pages/Thinker/AuthorProfiles.tsx`
-`src/pages/Thinker/Strategies.tsx`
-`src/pages/Thinker/ImageTesting.tsx`
#### Settings Module (10+ pages - NOT LOADED)
-`src/pages/Settings/General.tsx`
-`src/pages/Settings/Plans.tsx`
-`src/pages/Settings/Integration.tsx`
-`src/pages/Settings/ImportExport.tsx`
-`src/pages/Settings/Sites.tsx`
-`src/pages/Settings/Users.tsx`
-`src/pages/Settings/System.tsx`
-`src/pages/Settings/Account.tsx`
-`src/pages/Settings/Modules.tsx`
-`src/pages/Settings/AI.tsx`
-`src/pages/Settings/Status.tsx`
-`src/pages/Settings/Subscriptions.tsx`
#### Billing Module (3 pages - NOT LOADED)
-`src/pages/Billing/Credits.tsx`
-`src/pages/Billing/Transactions.tsx`
-`src/pages/Billing/Usage.tsx`
#### Planner Module (Other pages - NOT LOADED)
-`src/pages/Planner/Dashboard.tsx`
-`src/pages/Planner/Clusters.tsx`
-`src/pages/Planner/Ideas.tsx`
-`src/pages/Planner/KeywordOpportunities.tsx`
#### Analytics (NOT LOADED)
-`src/pages/Analytics.tsx`
#### Other Pages (NOT LOADED)
-`src/pages/Schedules.tsx`
-`src/pages/Reference/SeedKeywords.tsx`
-`src/pages/Reference/Industries.tsx`
-`src/pages/Help/Help.tsx`
-`src/pages/Help/Docs.tsx`
- ❌ All UI Elements pages (20+ pages)
---
## 2⃣ Code Evidence from App.tsx
Looking at `frontend/src/App.tsx`, all pages are wrapped with `React.lazy()`:
```typescript
// ✅ Lazy loaded - only loads when route is accessed
const Keywords = lazy(() => import("./pages/Planner/Keywords"));
const WriterDashboard = lazy(() => import("./pages/Writer/Dashboard"));
const Tasks = lazy(() => import("./pages/Writer/Tasks"));
const Content = lazy(() => import("./pages/Writer/Content"));
// ... etc for all pages
```
**This means:**
- Pages are **NOT** bundled in the initial JavaScript
- Each page is a **separate chunk** that loads on-demand
- Only the current route's page component loads
---
## 3⃣ Network Request Count
**Total Resources Loaded:** 168 files
**Page Components Loaded:** 1 (Keywords.tsx only)
**Other Page Components:** 0
**Breakdown:**
- Core app files: 63 files (shared across all pages)
- Node modules: 16 files (React, React Router, etc.)
- Icons: 56 files (SVG icons)
- Keywords page: 1 file (78.89 KB)
- Keywords dependencies: ~20 files (modals, configs, etc.)
---
## 4⃣ Performance Impact
### If ALL pages loaded (without lazy loading):
- **Estimated size:** ~2-3 MB of JavaScript
- **Load time:** 5-10 seconds on slow connections
- **Memory usage:** High (all components in memory)
### With lazy loading (current):
- **Keywords page only:** ~350 KB
- **Load time:** <1 second
- **Memory usage:** Low (only current page in memory)
**Savings:** ~85-90% reduction in initial load size
---
## 5⃣ How to Verify Yourself
### Method 1: Browser DevTools Network Tab
1. Open Chrome DevTools (F12)
2. Go to **Network** tab
3. Filter by **JS** files
4. Navigate to `/planner/keywords`
5. **Check:** You'll see `Keywords.tsx` but NOT `Writer/Tasks.tsx`, `Thinker/Prompts.tsx`, etc.
### Method 2: Check Network Requests
Run this in browser console:
```javascript
const resources = performance.getEntriesByType('resource');
const pageFiles = resources.filter(r =>
r.name.includes('/pages/') &&
!r.name.includes('AuthPages') &&
!r.name.includes('NotFound')
);
console.log('Loaded page components:', pageFiles.map(r => r.name));
```
**Expected output:** Only `Keywords.tsx` appears
### Method 3: Navigate to Another Page
1. Navigate to `/writer/tasks`
2. Check Network tab again
3. **You'll see:** `Tasks.tsx` loads, but `Keywords.tsx` is NOT loaded again (cached)
4. **You'll see:** Other pages still NOT loaded
---
## 6⃣ Conclusion
**PROOF CONFIRMED:** Lazy loading is working correctly.
- **Only 1 page component** loads when visiting `/planner/keywords`
- **24+ other page components** remain unloaded
- **Code splitting** is functioning as designed
- **Performance** is optimized (85-90% reduction in initial load)
The system is **NOT** loading all pages upfront. Each page loads only when the user navigates to it.
---
## 📝 Network Request Sample
Here's a sample of actual network requests (from browser DevTools):
```
✅ GET /src/pages/Planner/Keywords.tsx
✅ GET /src/templates/TablePageTemplate.tsx
✅ GET /src/config/pages/keywords.config.tsx
❌ (NO) GET /src/pages/Writer/Tasks.tsx
❌ (NO) GET /src/pages/Thinker/Prompts.tsx
❌ (NO) GET /src/pages/Settings/General.tsx
❌ (NO) GET /src/pages/Billing/Credits.tsx
... (24+ other pages NOT loaded)
```
---
**Generated:** November 9, 2025
**Verified:** Browser DevTools Network Analysis + Code Review

View File

@@ -1,271 +0,0 @@
# 🚀 Performance Optimizations Applied
## Summary
Applied comprehensive optimizations to reduce the Keywords page size from **4.34 MB** to an estimated **~2.5-3 MB** (saving ~1-1.5 MB).
---
## ✅ Optimizations Implemented
### 1. **Enhanced Vite Code Splitting** ✅
**Changes:**
- **Separated React Router** into its own chunk (`vendor-react-router`)
- Only loads when navigation occurs, not on initial page load
- Saves ~330 KB on initial load
- **Split React Core** from React Router
- Better caching - React core changes less frequently
- React core: `vendor-react-core`
- React Router: `vendor-react-router`
- **Granular Vendor Chunking:**
- `vendor-react-core` - React & React DOM (~872 KB)
- `vendor-react-router` - React Router (~331 KB)
- `vendor-charts` - ApexCharts (lazy-loaded, only when needed)
- `vendor-calendar` - FullCalendar (lazy-loaded, only when needed)
- `vendor-maps` - React JVectorMap (lazy-loaded, only when needed)
- `vendor-dnd` - React DnD (lazy-loaded, only when needed)
- `vendor-swiper` - Swiper (lazy-loaded, only when needed)
- `vendor-ui` - Radix UI, Framer Motion
- `vendor-state` - Zustand
- `vendor-helmet` - React Helmet
- `vendor-other` - Other smaller libraries
**Impact:** Better caching, smaller initial bundle
---
### 2. **Excluded Heavy Dependencies from Pre-bundling** ✅
**Excluded (will lazy-load when needed):**
- `@fullcalendar/*` (~200 KB) - Only used in Calendar page
- `apexcharts` & `react-apexcharts` (~150 KB) - Only used in chart components
- `@react-jvectormap/*` (~100 KB) - Only used in map components
- `react-dnd` & `react-dnd-html5-backend` (~80 KB) - Only used in drag-drop features
- `swiper` (~50 KB) - Only used in carousel components
**Impact:** Saves ~580 KB on initial page load
---
### 3. **Optimized Dependency Pre-bundling** ✅
**Only pre-bundle small, frequently used libraries:**
- `clsx` - Utility for className merging
- `tailwind-merge` - Tailwind class merging
- `zustand` - State management (used everywhere)
**Impact:** Faster initial load, smaller pre-bundle
---
### 4. **Icon Chunk Splitting** ✅
**Icons are now in a separate chunk:**
- All SVG icons are grouped into `icons` chunk
- Icons load separately from main bundle
- Can be cached independently
**Impact:** Better caching, icons don't block main bundle
---
### 5. **Build Optimizations** ✅
**Enabled:**
- **Minification:** `esbuild` (faster than terser)
- **CSS Code Splitting:** CSS is split per page
- **Compressed Size Reporting:** Better visibility into bundle sizes
- **Chunk Size Warning:** Reduced to 600 KB (from 1000 KB) for better optimization
**Impact:** Smaller production bundles, better compression
---
### 6. **Lazy Icon Loader** ✅
**Created:** `frontend/src/icons/lazy.ts`
**Purpose:**
- Provides lazy-loaded icon components
- Icons only load when actually used
- Reduces initial bundle size
**Usage (optional - for future optimization):**
```typescript
import { lazyIcon } from '@/icons/lazy';
import { Suspense } from 'react';
const PlusIcon = lazyIcon('plus');
// Use with Suspense
<Suspense fallback={<span>...</span>}>
<PlusIcon />
</Suspense>
```
**Note:** Current icon imports still work. This is available for future optimization if needed.
---
## 📊 Expected Results
### Before Optimization:
- **Total:** 4.34 MB
- **Vendor Libraries:** 2.09 MB (48%)
- **Core App:** 0.77 MB (18%)
- **Keywords-Specific:** 0.44 MB (10%)
- **Other:** 0.82 MB (19%)
- **Images:** 0.22 MB (5%)
### After Optimization (Estimated):
- **Total:** ~2.5-3 MB (saving ~1-1.5 MB)
- **Vendor Libraries:** ~1.2-1.5 MB (React Router lazy-loaded)
- **Core App:** ~0.7 MB (slightly optimized)
- **Keywords-Specific:** ~0.4 MB (unchanged)
- **Other:** ~0.5 MB (icons split, optimized)
- **Images:** ~0.2 MB (unchanged)
### Key Improvements:
1.**React Router lazy-loaded** - Saves ~330 KB on initial load
2.**Heavy dependencies excluded** - Saves ~580 KB on initial load
3.**Better code splitting** - Better caching, smaller chunks
4.**Icons separated** - Better caching
5.**Optimized pre-bundling** - Faster initial load
---
## 🎯 What Loads on Keywords Page Now
### Initial Load (Keywords Page):
1. ✅ React Core (~872 KB)
2. ✅ Core App Files (~700 KB)
3. ✅ Keywords-Specific Files (~440 KB)
4. ✅ Icons Chunk (~200 KB)
5. ✅ Other Shared Files (~500 KB)
**Total Initial:** ~2.7 MB (down from 4.34 MB)
### Lazy-Loaded (Only When Needed):
- ❌ React Router (~331 KB) - Only when navigating
- ❌ ApexCharts (~150 KB) - Only on pages with charts
- ❌ FullCalendar (~200 KB) - Only on Calendar page
- ❌ React DnD (~80 KB) - Only on drag-drop pages
- ❌ Maps (~100 KB) - Only on map pages
- ❌ Swiper (~50 KB) - Only on carousel pages
**Total Saved:** ~911 KB on initial load
---
## 📝 Next Steps (Optional Further Optimizations)
### 1. **Lazy Load Icons** (Future)
- Convert icon imports to use `lazyIcon()` helper
- Only load icons when actually rendered
- Could save ~100-200 KB
### 2. **Image Optimization**
- Use WebP format for images
- Lazy load images below the fold
- Could save ~50-100 KB
### 3. **Font Optimization**
- Subset fonts to only include used characters
- Use `font-display: swap` for faster rendering
- Could save ~50-100 KB
### 4. **Tree Shaking**
- Ensure unused code is eliminated
- Check for unused dependencies
- Could save ~100-200 KB
### 5. **Service Worker / Caching**
- Implement service worker for offline support
- Cache vendor chunks for faster subsequent loads
- Better user experience
---
## 🔍 How to Verify
### 1. **Check Bundle Sizes:**
```bash
cd frontend
npm run build
```
Look for chunk sizes in the build output. You should see:
- Smaller `vendor-react-core` chunk
- Separate `vendor-react-router` chunk
- Separate chunks for heavy dependencies (only when used)
### 2. **Check Network Tab:**
1. Open DevTools → Network tab
2. Hard refresh the Keywords page
3. Check total size loaded
4. Should see ~2.5-3 MB instead of 4.34 MB
### 3. **Check Lazy Loading:**
1. Navigate to a page with charts (e.g., Dashboard)
2. Check Network tab
3. Should see `vendor-charts` chunk loading on demand
---
## ⚠️ Important Notes
1. **Development vs Production:**
- These optimizations are most effective in **production builds**
- Development mode may still show larger sizes due to source maps and HMR
2. **First Load vs Subsequent Loads:**
- First load: All chunks download
- Subsequent loads: Cached chunks are reused (much faster)
3. **Browser Caching:**
- Vendor chunks are cached separately
- When React updates, only React chunk needs to re-download
- Other vendor chunks remain cached
4. **Code Splitting Trade-offs:**
- More chunks = more HTTP requests
- But better caching and parallel loading
- Modern browsers handle this well
---
## ✅ Files Modified
1. **`frontend/vite.config.ts`**
- Enhanced code splitting
- Excluded heavy dependencies
- Optimized pre-bundling
- Icon chunk splitting
2. **`frontend/src/icons/lazy.ts`** (New)
- Lazy icon loader utility
- Available for future optimization
---
## 🎉 Summary
**Optimizations applied successfully!**
- ✅ Better code splitting
- ✅ Heavy dependencies lazy-loaded
- ✅ React Router separated
- ✅ Icons chunked separately
- ✅ Build optimizations enabled
**Expected improvement:** ~1-1.5 MB reduction (from 4.34 MB to ~2.5-3 MB)
**Next:** Test in production build and verify actual size reduction.
---
**Generated:** November 9, 2025

View File

@@ -1,26 +0,0 @@
#!/bin/bash
# Commands to check Docker container logs for debugging restart issues
echo "=== Backend Django Logs (last 100 lines) ==="
docker logs igny8_backend --tail 100
echo ""
echo "=== Celery Worker Logs (last 100 lines) ==="
docker logs igny8_celery_worker --tail 100
echo ""
echo "=== Celery Beat Logs (last 100 lines) ==="
docker logs igny8_celery_beat --tail 100
echo ""
echo "=== Backend Status ==="
docker ps -a | grep igny8_backend
echo ""
echo "=== Celery Worker Status ==="
docker ps -a | grep igny8_celery_worker
echo ""
echo "=== Celery Beat Status ==="
docker ps -a | grep igny8_celery_beat

View File

View File

@@ -1,55 +0,0 @@
#!/bin/bash
# Script to push igny8 repository to Gitea
set -e
REPO_NAME="igny8"
GITEA_URL="http://git.igny8.com"
echo "🚀 Pushing igny8 repository to Gitea..."
echo ""
# Check if remote exists
if git remote get-url origin >/dev/null 2>&1; then
echo "✅ Remote 'origin' already configured"
git remote -v
else
echo "📝 Adding remote origin..."
# Try different URL formats
git remote add origin "${GITEA_URL}/${REPO_NAME}/${REPO_NAME}.git" 2>/dev/null || \
git remote add origin "${GITEA_URL}/root/${REPO_NAME}.git" 2>/dev/null || \
git remote add origin "${GITEA_URL}/admin/${REPO_NAME}.git" 2>/dev/null || \
echo "⚠️ Could not determine correct URL format"
fi
echo ""
echo "📤 Pushing to Gitea..."
echo ""
# Try to push
if git push -u origin main 2>&1; then
echo ""
echo "✅ Successfully pushed to Gitea!"
echo "📍 Repository URL: ${GITEA_URL}/${REPO_NAME}/${REPO_NAME}"
else
echo ""
echo "❌ Push failed. This usually means:"
echo " 1. The repository doesn't exist yet in Gitea"
echo " 2. Authentication is required"
echo ""
echo "📋 To create the repository:"
echo " 1. Visit ${GITEA_URL}"
echo " 2. Sign in or create an account"
echo " 3. Click '+' → 'New Repository'"
echo " 4. Name it '${REPO_NAME}' and create it"
echo " 5. Then run this script again: ./push-to-gitea.sh"
echo ""
echo "💡 Or create it via API with a token:"
echo " curl -X POST '${GITEA_URL}/api/v1/user/repos' \\"
echo " -H 'Authorization: token YOUR_TOKEN' \\"
echo " -H 'Content-Type: application/json' \\"
echo " -d '{\"name\":\"${REPO_NAME}\",\"private\":false}'"
exit 1
fi