diff --git a/.gitea/workflows/build-and-repair.yml b/.gitea/workflows/build-and-repair.yml new file mode 100644 index 0000000..005935d --- /dev/null +++ b/.gitea/workflows/build-and-repair.yml @@ -0,0 +1,58 @@ +name: Build & Auto-Repair +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: npm ci --no-audit --no-fund + + - name: Install Playwright + run: npx playwright install chromium firefox + + - name: Build check + id: build + continue-on-error: true + run: npx tsc --noEmit + + - name: Run self-healing setup + if: steps.build.outcome == 'failure' + run: node scripts/setup.mjs --self-heal + + - name: Run code repair agent + if: steps.build.outcome == 'failure' + env: + OLLAMA_HOST: ${{ vars.OLLAMA_HOST || 'http://localhost:11434' }} + run: node scripts/code-repair-agent.mjs --ci + + - name: Re-check build after repair + id: rebuild + continue-on-error: true + run: npx tsc --noEmit + + - name: Commit fixes + if: steps.build.outcome == 'failure' && steps.rebuild.outcome == 'success' + run: | + git config user.name "CRM Repair Bot" + git config user.email "bot@coastit.co.za" + git add -A + git diff --cached --quiet || git commit -m "[bot] Auto-repair build errors" + git push + + - name: Build failed — report + if: steps.rebuild.outcome == 'failure' + run: | + echo "::error::Build still failing after auto-repair. Manual intervention required." + exit 1 diff --git a/.setup-templates/registry.json b/.setup-templates/registry.json new file mode 100644 index 0000000..de7ef0f --- /dev/null +++ b/.setup-templates/registry.json @@ -0,0 +1,42 @@ +{ + "version": 2, + "description": "Template registry for self-healing setup. Maps internal import paths to templates.", + "templates": { + "data/stickers": { + "template": "stickers.ts", + "description": "Emoji-based sticker packs for media picker" + }, + "data/constants": { + "template": "constants.ts", + "description": "App-wide constants (lead statuses, roles, event types)" + }, + "lib/utils": { + "template": "utils.ts", + "description": "Utility functions (cn, formatters, helpers)" + }, + "types/index": { + "template": "types-index.ts", + "description": "Core type definitions (User, Lead, DashboardStats)" + }, + "hooks/use-media": { + "template": "hooks/use-media.ts", + "description": "Media query hook" + }, + "hooks/use-debounce": { + "template": "hooks/use-debounce.ts", + "description": "Debounce hook" + }, + "hooks/use-local-storage": { + "template": "hooks/use-local-storage.ts", + "description": "LocalStorage hook with SSR safety" + } + }, + "fallbackTemplates": { + "@/data/*": "data-generic.ts", + "@/lib/*": "lib-generic.ts", + "@/hooks/*": "hook-generic.ts", + "@/types/*": "types-generic.ts", + "@/components/*": "component-generic.tsx", + "@/utils/*": "utils-generic.ts" + } +} \ No newline at end of file diff --git a/.setup-templates/templates/component-generic.tsx b/.setup-templates/templates/component-generic.tsx new file mode 100644 index 0000000..d200bb1 --- /dev/null +++ b/.setup-templates/templates/component-generic.tsx @@ -0,0 +1,7 @@ +// ── Generic Component Template ──────────────────────────────────────── +// Auto-generated by self-healing setup. +// Placeholder for @/components/* imports. Customize as needed. + +export default function GenericComponent() { + return
; +} diff --git a/.setup-templates/templates/constants.ts b/.setup-templates/templates/constants.ts new file mode 100644 index 0000000..17c4217 --- /dev/null +++ b/.setup-templates/templates/constants.ts @@ -0,0 +1,54 @@ +// ── App Constants ──────────────────────────────────────────────────── +// Auto-generated by self-healing setup. Edit .setup-templates/templates/constants.ts to customize. + +export const APP_NAME = "CoastIT CRM"; +export const APP_VERSION = "1.0.0"; + +export const LEAD_STATUSES = { + new: { label: "New", color: "bg-blue-500" }, + contacted: { label: "Contacted", color: "bg-yellow-500" }, + qualified: { label: "Qualified", color: "bg-purple-500" }, + proposal: { label: "Proposal", color: "bg-orange-500" }, + won: { label: "Won", color: "bg-green-500" }, + lost: { label: "Lost", color: "bg-red-500" }, +} as const; + +export const USER_ROLES = { + super_admin: { label: "Super Admin", level: 1 }, + admin: { label: "Admin", level: 2 }, + sales: { label: "Sales", level: 3 }, + dev: { label: "Developer", level: 4 }, +} as const; + +export const EVENT_TYPES = [ + "meeting", + "call", + "email", + "task", + "note", +] as const; + +export const EVENT_STATUSES = [ + "scheduled", + "completed", + "cancelled", + "rescheduled", +] as const; + +export const AI_MODELS = { + chat: "llama3.2:3b", + scraper: "dolphin-llama3:8b", + coder: "qwen2.5-coder:1.5b-base", +} as const; + +export const PAGINATION = { + defaultLimit: 50, + maxLimit: 200, +} as const; + +export const DATE_FORMATS = { + short: "MMM d, yyyy", + long: "MMMM d, yyyy", + time: "h:mm a", + datetime: "MMM d, yyyy h:mm a", +} as const; \ No newline at end of file diff --git a/.setup-templates/templates/data-generic.ts b/.setup-templates/templates/data-generic.ts new file mode 100644 index 0000000..290dc41 --- /dev/null +++ b/.setup-templates/templates/data-generic.ts @@ -0,0 +1,17 @@ +// ── Generic Data Module Template ───────────────────────────────────── +// Auto-generated by self-healing setup. +// Placeholder for @/data/* imports. Customize as needed. + +export interface DataItem { + id: string; + name: string; + [key: string]: unknown; +} + +export function getDataItems(): DataItem[] { + return []; +} + +export function getDataItem(id: string): DataItem | undefined { + return undefined; +} \ No newline at end of file diff --git a/.setup-templates/templates/hook-generic.ts b/.setup-templates/templates/hook-generic.ts new file mode 100644 index 0000000..3ba9a41 --- /dev/null +++ b/.setup-templates/templates/hook-generic.ts @@ -0,0 +1,10 @@ +// ── Generic Hook Template ──────────────────────────────────────────── +// Auto-generated by self-healing setup. +// Placeholder for @/hooks/* imports. Customize as needed. + +import { useState, useEffect } from "react"; + +export function useHookPowered by local AI
+Uncensored sales tips and strategies powered by local AI
+{selectedJob.description}
-{selectedJob.description}
+Pipeline Overview
+Pipeline Overview
Analytics
+Analytics
Connecting to call...
+Connecting to call...
{micError}
+{micError}
)} setDisplayName(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") handleJoin() }} placeholder="Enter your name" - className="bg-[#F5F5F5] dark:bg-[#1A1A1A] border border-[#E0E0E0] dark:border-[#333333] text-[#111111] dark:text-white placeholder-[#AAAAAA] dark:placeholder-[#555555] rounded-xl px-4 py-2.5 text-sm w-full mb-4 outline-none transition-colors focus:border-[#CC0000] dark:focus:border-[#FF4444]" + className="bg-[#FAFAF6] dark:bg-[#1A1A1A] border border-[#D4D8CC] dark:border-[#333333] text-[#2D3020] dark:text-white placeholder-[#8A9078] dark:placeholder-[#555555] rounded-xl px-4 py-2.5 text-sm w-full mb-4 outline-none transition-colors focus:border-[#C84B4B] dark:focus:border-[#FF4444]" />