feat: SEO web audit, URL fetching, auto web search for SEO mode (v1.6.0)
This commit is contained in:
20
CHANGELOG.md
20
CHANGELOG.md
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.6.0] - 2026-03-18 20:34 UTC
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **SEO Web Audit** — SEO agent can now fetch and analyze live websites
|
||||||
|
- `/api/fetch-url` route extracts: title, meta tags, headings (h1-h6), links (internal/external), images (alt text coverage), canonical URL, OG tags, text content length
|
||||||
|
- Auto-detects URLs in user input when SEO agent is active
|
||||||
|
- Pre-fetches page data before sending to AI for comprehensive audit reports
|
||||||
|
- Supports up to 2 URLs per request
|
||||||
|
- **SEO Auto Web Search** — When SEO agent is active and no URL is provided, web search is automatically triggered
|
||||||
|
- Uses same SearXNG infrastructure as manual web search toggle
|
||||||
|
- No manual toggle needed in SEO mode
|
||||||
|
- **Updated SEO Agent Prompt** — All 4 AI services now instruct SEO agent about web audit and search capabilities
|
||||||
|
- Added `[WEB_AUDIT:url]` and `[WEB_SEARCH:query]` tool markers
|
||||||
|
- Added "WEB TOOLS" section to system prompts
|
||||||
|
|
||||||
|
### Technical Details
|
||||||
|
- Files modified: 5 (AIAssist.tsx, qwen-oauth.ts, ollama-cloud.ts, zai-plan.ts, openrouter.ts)
|
||||||
|
- Files added: 1 (`app/api/fetch-url/route.ts`)
|
||||||
|
- New API endpoint: `GET /api/fetch-url?url=https://example.com`
|
||||||
|
|
||||||
## [1.5.0] - 2026-03-18 20:29 UTC
|
## [1.5.0] - 2026-03-18 20:29 UTC
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# PromptArch: AI Orchestration Platform
|
# PromptArch: AI Orchestration Platform
|
||||||
|
|
||||||
> **Latest Version**: [v1.5.0](CHANGELOG.md#150---2026-03-18) (2026-03-18)
|
> **Latest Version**: [v1.6.0](CHANGELOG.md#160---2026-03-18) (2026-03-18)
|
||||||
|
|
||||||
> **Development Note**: This entire platform was developed exclusively using [TRAE.AI IDE](https://trae.ai) powered by elite [GLM 4.7 model](https://z.ai/subscribe?ic=R0K78RJKNW).
|
> **Development Note**: This entire platform was developed exclusively using [TRAE.AI IDE](https://trae.ai) powered by elite [GLM 4.7 model](https://z.ai/subscribe?ic=R0K78RJKNW).
|
||||||
> **Learn more about this architecture [here](https://z.ai/subscribe?ic=R0K78RJKNW).**
|
> **Learn more about this architecture [here](https://z.ai/subscribe?ic=R0K78RJKNW).**
|
||||||
|
|||||||
117
app/api/fetch-url/route.ts
Normal file
117
app/api/fetch-url/route.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* Next.js API route: Fetch URL content for SEO/web auditing.
|
||||||
|
* Endpoint: GET /api/fetch-url?url=https://example.com
|
||||||
|
* Returns: { title, meta, headings, text, links, status }
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: NextRequest) {
|
||||||
|
const targetUrl = request.nextUrl.searchParams.get("url");
|
||||||
|
|
||||||
|
if (!targetUrl) {
|
||||||
|
return NextResponse.json({ error: "URL parameter required" }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new URL(targetUrl);
|
||||||
|
} catch {
|
||||||
|
return NextResponse.json({ error: "Invalid URL" }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), 12000);
|
||||||
|
|
||||||
|
const res = await fetch(targetUrl, {
|
||||||
|
signal: controller.signal,
|
||||||
|
headers: {
|
||||||
|
"User-Agent": "PromptArch-SEO-Bot/1.5 (https://rommark.dev)",
|
||||||
|
Accept: "text/html,application/xhtml+xml,text/plain;q=0.9",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
return NextResponse.json({ error: `HTTP ${res.status}`, status: res.status });
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = await res.text();
|
||||||
|
|
||||||
|
const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
||||||
|
const title = titleMatch ? titleMatch[1].trim() : "";
|
||||||
|
|
||||||
|
const descMatch = html.match(/<meta[^>]*name\s*=\s*["']description["'][^>]*content\s*=\s*["']([\s\S]*?)["']/i)
|
||||||
|
|| html.match(/<meta[^>]*content\s*=\s*["']([\s\S]*?)["'][^>]*name\s*=\s*["']description["']/i);
|
||||||
|
const metaDescription = descMatch ? descMatch[1].trim() : "";
|
||||||
|
|
||||||
|
const kwMatch = html.match(/<meta[^>]*name\s*=\s*["']keywords["'][^>]*content\s*=\s*["']([\s\S]*?)["']/i)
|
||||||
|
|| html.match(/<meta[^>]*content\s*=\s*["']([\s\S]*?)["'][^>]*name\s*=\s*["']keywords["']/i);
|
||||||
|
const metaKeywords = kwMatch ? kwMatch[1].trim() : "";
|
||||||
|
|
||||||
|
const headings: { level: number; text: string }[] = [];
|
||||||
|
const headingRegex = /<h([1-6])[^>]*>([\s\S]*?)<\/h[1-6]>/gi;
|
||||||
|
let hMatch;
|
||||||
|
while ((hMatch = headingRegex.exec(html)) !== null) {
|
||||||
|
const text = hMatch[2].replace(/<[^>]*>/g, "").trim();
|
||||||
|
if (text) headings.push({ level: parseInt(hMatch[1]), text });
|
||||||
|
}
|
||||||
|
|
||||||
|
const links: { href: string; text: string; internal: boolean }[] = [];
|
||||||
|
const linkRegex = /<a[^>]*href\s*=\s*["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi;
|
||||||
|
let lMatch;
|
||||||
|
const baseDomain = new URL(targetUrl).hostname;
|
||||||
|
while ((lMatch = linkRegex.exec(html)) !== null) {
|
||||||
|
const href = lMatch[1].trim();
|
||||||
|
const text = lMatch[2].replace(/<[^>]*>/g, "").trim().substring(0, 100);
|
||||||
|
if (!href || href.startsWith("#") || href.startsWith("javascript:")) continue;
|
||||||
|
try {
|
||||||
|
const linkDomain = new URL(href, targetUrl).hostname;
|
||||||
|
links.push({ href, text, internal: linkDomain === baseDomain });
|
||||||
|
} catch { continue; }
|
||||||
|
}
|
||||||
|
|
||||||
|
const images: { src: string; alt: string }[] = [];
|
||||||
|
const imgRegex = /<img[^>]*src\s*=\s*["']([^"']*)["'][^>]*alt\s*=\s*["']([^"']*)["'][^>]*\/?>/gi;
|
||||||
|
let iMatch;
|
||||||
|
while ((iMatch = imgRegex.exec(html)) !== null) {
|
||||||
|
images.push({ src: iMatch[1], alt: iMatch[2] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const plainText = html
|
||||||
|
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
||||||
|
.replace(/<style[\s\S]*?<\/style>/gi, "")
|
||||||
|
.replace(/<[^>]*>/g, " ")
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim()
|
||||||
|
.substring(0, 5000);
|
||||||
|
|
||||||
|
const canonicalMatch = html.match(/<link[^>]*rel\s*=\s*["']canonical["'][^>]*href\s*=\s*["']([^"']*)["']/i);
|
||||||
|
const canonical = canonicalMatch ? canonicalMatch[1] : "";
|
||||||
|
|
||||||
|
const ogTitleMatch = html.match(/<meta[^>]*property\s*=\s*["']og:title["'][^>]*content\s*=\s*["']([\s\S]*?)["']/i);
|
||||||
|
const ogTitle = ogTitleMatch ? ogTitleMatch[1].trim() : "";
|
||||||
|
|
||||||
|
const ogDescMatch = html.match(/<meta[^>]*property\s*=\s*["']og:description["'][^>]*content\s*=\s*["']([\s\S]*?)["']/i);
|
||||||
|
const ogDescription = ogDescMatch ? ogDescMatch[1].trim() : "";
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
url: targetUrl,
|
||||||
|
title,
|
||||||
|
metaDescription,
|
||||||
|
metaKeywords,
|
||||||
|
canonical,
|
||||||
|
ogTitle,
|
||||||
|
ogDescription,
|
||||||
|
headings,
|
||||||
|
links: links.slice(0, 100),
|
||||||
|
images: images.slice(0, 50),
|
||||||
|
text: plainText,
|
||||||
|
htmlLength: html.length,
|
||||||
|
status: res.status,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
const msg = error instanceof Error ? error.message : "Fetch failed";
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -361,7 +361,7 @@ function parseStreamingContent(text: string, currentAgent: string) {
|
|||||||
// 3. Clean display text - hide all tag-like sequences and their partials
|
// 3. Clean display text - hide all tag-like sequences and their partials
|
||||||
chatDisplay = text
|
chatDisplay = text
|
||||||
// Hide complete tags (flexible brackets), including SUGGEST_AGENT
|
// Hide complete tags (flexible brackets), including SUGGEST_AGENT
|
||||||
.replace(/\[+(?:AGENT|SUGGEST_AGENT|content|seo|smm|pm|code|design|web|app|PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT|PREV):?[\w-]*:?[\w-]*\]+/gi, "")
|
.replace(/\[+(?:AGENT|SUGGEST_AGENT|content|seo|smm|pm|code|design|web|app|PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT|PREV|WEB_AUDIT|WEB_SEARCH):?[\w-]*:?https?:\/\/[^\]]*\]+/gi, "").replace(/\[+(?:AGENT|SUGGEST_AGENT|content|seo|smm|pm|code|design|web|app|PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT|PREV|WEB_AUDIT|WEB_SEARCH):?[\w-]*:?[\w-]*\]+/gi, "")
|
||||||
// Hide content inside preview block (cleanly)
|
// Hide content inside preview block (cleanly)
|
||||||
.replace(/\[+PREVIEW:[\w-]+:?[\w-]+?\]+[\s\S]*?(?:\[\/(?:PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT)\]+|$)/gi, "")
|
.replace(/\[+PREVIEW:[\w-]+:?[\w-]+?\]+[\s\S]*?(?:\[\/(?:PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT)\]+|$)/gi, "")
|
||||||
// Hide closing tags
|
// Hide closing tags
|
||||||
@@ -695,7 +695,66 @@ export default function AIAssist() {
|
|||||||
setStatus(null);
|
setStatus(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await modelAdapter.generateAIAssistStream(
|
// SEO mode: auto-fetch URLs from user input for live auditing
|
||||||
|
if (currentAgent === "seo") {
|
||||||
|
const urlMatches = [...finalInput.matchAll(/https?:\/\/[^\s<>"')\]]+/gi)].map(m => m[0]);
|
||||||
|
const uniqueUrls = [...new Set(urlMatches)].slice(0, 2);
|
||||||
|
if (uniqueUrls.length > 0) {
|
||||||
|
setStatus("Auditing website" + (uniqueUrls.length > 1 ? "s" : "") + "...");
|
||||||
|
try {
|
||||||
|
for (const url of uniqueUrls) {
|
||||||
|
const auditRes = await fetch("/api/fetch-url?url=" + encodeURIComponent(url));
|
||||||
|
if (auditRes.ok) {
|
||||||
|
const auditData = await auditRes.json();
|
||||||
|
enrichedInput += "\n\n[WEBSITE AUDIT DATA - " + url + "]\n";
|
||||||
|
enrichedInput += "Title: " + (auditData.title || "N/A") + "\n";
|
||||||
|
enrichedInput += "Meta Description: " + (auditData.metaDescription || "N/A") + "\n";
|
||||||
|
enrichedInput += "Meta Keywords: " + (auditData.metaKeywords || "N/A") + "\n";
|
||||||
|
enrichedInput += "Canonical: " + (auditData.canonical || "N/A") + "\n";
|
||||||
|
enrichedInput += "OG Title: " + (auditData.ogTitle || "N/A") + "\n";
|
||||||
|
enrichedInput += "OG Description: " + (auditData.ogDescription || "N/A") + "\n";
|
||||||
|
enrichedInput += "Headings:\n";
|
||||||
|
if (auditData.headings && auditData.headings.length > 0) {
|
||||||
|
for (const h of auditData.headings) {
|
||||||
|
enrichedInput += " H" + h.level + ": " + h.text + "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enrichedInput += " None found\n";
|
||||||
|
}
|
||||||
|
const internalLinks = (auditData.links || []).filter((l: { internal: boolean }) => l.internal);
|
||||||
|
const externalLinks = (auditData.links || []).filter((l: { internal: boolean }) => !l.internal);
|
||||||
|
enrichedInput += "Links: " + internalLinks.length + " internal, " + externalLinks.length + " external (of " + (auditData.links || []).length + " total)\n";
|
||||||
|
const imagesWithAlt = (auditData.images || []).filter((img: { alt: string }) => img.alt && img.alt.trim());
|
||||||
|
const imagesNoAlt = (auditData.images || []).filter((img: { alt: string }) => !img.alt || !img.alt.trim());
|
||||||
|
enrichedInput += "Images: " + (auditData.images || []).length + " total, " + imagesWithAlt.length + " with alt, " + imagesNoAlt.length + " without alt\n";
|
||||||
|
enrichedInput += "Text content length: " + (auditData.text || "").length + " chars\n";
|
||||||
|
enrichedInput += "HTML size: " + (auditData.htmlLength || 0) + " chars\n";
|
||||||
|
enrichedInput += "[/WEBSITE AUDIT DATA]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn("Website audit failed:", e); }
|
||||||
|
setStatus(null);
|
||||||
|
}
|
||||||
|
// If no URL found and web search not enabled, auto-enable web search for SEO
|
||||||
|
if (uniqueUrls.length === 0 && !webSearchEnabled) {
|
||||||
|
try {
|
||||||
|
setStatus("Searching for SEO context...");
|
||||||
|
const searchRes = await fetch("/api/search?q=" + encodeURIComponent(finalInput.split("\n")[0].substring(0, 200)));
|
||||||
|
if (searchRes.ok) {
|
||||||
|
const searchData = await searchRes.json();
|
||||||
|
if (searchData.results && searchData.results.length > 0) {
|
||||||
|
const searchContext = searchData.results.slice(0, 5).map((r: { title: string; url: string; snippet: string }, i: number) =>
|
||||||
|
(i + 1) + ". **" + r.title + "** (" + r.url + ") - " + r.snippet
|
||||||
|
).join("\n");
|
||||||
|
enrichedInput = "[WEB SEARCH CONTEXT - Top 5 relevant results]\n" + searchContext + "\n\n---\nUsing the above search results as reference context, answer the user query. Cite sources when relevant.\n\nUser query: " + finalInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn("SEO web search failed:", e); }
|
||||||
|
setStatus(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await modelAdapter.generateAIAssistStream(
|
||||||
{
|
{
|
||||||
messages: [...formattedHistory, { role: "user" as const, content: enrichedInput, timestamp: new Date() }],
|
messages: [...formattedHistory, { role: "user" as const, content: enrichedInput, timestamp: new Date() }],
|
||||||
currentAgent,
|
currentAgent,
|
||||||
|
|||||||
17
fix_device_array.py
Normal file
17
fix_device_array.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Fix the array that lost all its quotes
|
||||||
|
old = '{([[full, Full], [desktop, Desktop], [tablet, Tablet], [mobile, Mobile]] as const).map(([size, label]) => ('
|
||||||
|
new = '{([["full", "Full"], ["desktop", "Desktop"], ["tablet", "Tablet"], ["mobile", "Mobile"]] as const).map(([size, label]) => ('
|
||||||
|
|
||||||
|
if old in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
print('Fixed array quotes')
|
||||||
|
else:
|
||||||
|
print('WARNING: Could not find array')
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
46
fix_device_buttons.py
Normal file
46
fix_device_buttons.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
changes = 0
|
||||||
|
|
||||||
|
# Fix 1: viewMode === preview -> viewMode === "preview"
|
||||||
|
old = 'viewMode === preview && ('
|
||||||
|
new = 'viewMode === "preview" && ('
|
||||||
|
if old in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changes += 1
|
||||||
|
print('Fix 1: viewMode quote restored')
|
||||||
|
|
||||||
|
# Fix 2: className=flex -> className="flex"
|
||||||
|
old = 'className=flex items-center gap-1 mt-1.5'
|
||||||
|
new = 'className="flex items-center gap-1 mt-1.5"'
|
||||||
|
if old in content:
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
changes += 1
|
||||||
|
print('Fix 2: className quote restored')
|
||||||
|
|
||||||
|
# Fix 3: Restore quotes in the device button className
|
||||||
|
# The issue is the className prop lost its opening quote and the string content lost quotes
|
||||||
|
old_btn_class = '''className={cn(
|
||||||
|
px-2 py-1 text-[9px] font-black uppercase rounded-md transition-all border,
|
||||||
|
deviceSize === size
|
||||||
|
? bg-blue-500 text-white border-blue-500 shadow-md
|
||||||
|
: text-blue-300/50 border-transparent hover:text-blue-200 hover:bg-blue-900/30
|
||||||
|
)}'''
|
||||||
|
new_btn_class = '''className={cn(
|
||||||
|
"px-2 py-1 text-[9px] font-black uppercase rounded-md transition-all border",
|
||||||
|
deviceSize === size
|
||||||
|
? "bg-blue-500 text-white border-blue-500 shadow-md"
|
||||||
|
: "text-blue-300/50 border-transparent hover:text-blue-200 hover:bg-blue-900/30"
|
||||||
|
)}'''
|
||||||
|
if old_btn_class in content:
|
||||||
|
content = content.replace(old_btn_class, new_btn_class, 1)
|
||||||
|
changes += 1
|
||||||
|
print('Fix 3: Button className quotes restored')
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print(f'Applied {changes}/3 fixes')
|
||||||
43
fix_device_size.py
Normal file
43
fix_device_size.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
changes = 0
|
||||||
|
|
||||||
|
# CHANGE 1: Add deviceSize state after viewMode state
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'const [viewMode, setViewMode]' in line and 'useState' in line:
|
||||||
|
new_lines = [
|
||||||
|
line,
|
||||||
|
' const [deviceSize, setDeviceSize] = useState<"full" | "desktop" | "tablet" | "mobile">("full");\n',
|
||||||
|
' const deviceWidths: Record<string, string> = { full: "100%", desktop: "1280px", tablet: "768px", mobile: "375px" };\n',
|
||||||
|
]
|
||||||
|
lines[i:i+1] = new_lines
|
||||||
|
changes += 1
|
||||||
|
print('Change 1: Added deviceSize state')
|
||||||
|
break
|
||||||
|
|
||||||
|
# CHANGE 2: Find canvas wrapper and add device-size wrapper around LiveCanvas
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'flex-1 overflow-auto relative bg-[#050505]' in line and i > 1400:
|
||||||
|
print('Found canvas wrapper at line', i+1)
|
||||||
|
# Find LiveCanvas line
|
||||||
|
for j in range(i, min(i+10, len(lines))):
|
||||||
|
if '<LiveCanvas' in lines[j]:
|
||||||
|
# Insert wrapper div before LiveCanvas
|
||||||
|
indent = ' '
|
||||||
|
wrapper = indent + '<div className="mx-auto transition-all duration-300 h-full"\n'
|
||||||
|
wrapper += indent + ' style={deviceSize !== "full"\n'
|
||||||
|
wrapper += indent + ' ? { width: deviceWidths[deviceSize], maxWidth: "100%", border: "1px solid rgba(30,58,138,0.3)", borderRadius: "12px", overflow: "hidden", boxShadow: "0 20px 60px rgba(0,0,0,0.5)" }\n'
|
||||||
|
wrapper += indent + ' : undefined}>\n'
|
||||||
|
lines[j:j] = [wrapper]
|
||||||
|
changes += 1
|
||||||
|
print('Change 2: Added device wrapper before LiveCanvas')
|
||||||
|
break
|
||||||
|
break
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.writelines(lines)
|
||||||
|
|
||||||
|
print('Applied', changes, 'changes')
|
||||||
33
fix_device_size2.py
Normal file
33
fix_device_size2.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
changes = 0
|
||||||
|
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'flex-1 overflow-hidden relative' in line and i > 1400:
|
||||||
|
lines[i] = ' <div className="flex-1 overflow-auto relative bg-[#050505]">\n'
|
||||||
|
changes += 1
|
||||||
|
print('Fixed overflow at line', i+1)
|
||||||
|
|
||||||
|
for j in range(i, min(i+10, len(lines))):
|
||||||
|
if '<LiveCanvas' in lines[j]:
|
||||||
|
ind = ' '
|
||||||
|
w = ind + '<div className="mx-auto transition-all duration-300 h-full"\n'
|
||||||
|
w += ind + ' style={deviceSize !== "full"\n'
|
||||||
|
w += ind + ' ? { width: deviceWidths[deviceSize], maxWidth: "100%",\n'
|
||||||
|
w += ind + ' border: "1px solid rgba(30,58,138,0.3)",\n'
|
||||||
|
w += ind + ' borderRadius: "12px", overflow: "hidden",\n'
|
||||||
|
w += ind + ' boxShadow: "0 20px 60px rgba(0,0,0,0.5)" }\n'
|
||||||
|
w += ind + ' : undefined}>\n'
|
||||||
|
lines[j:j] = [w]
|
||||||
|
changes += 1
|
||||||
|
print('Added device wrapper before LiveCanvas at line', j+1)
|
||||||
|
break
|
||||||
|
break
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.writelines(lines)
|
||||||
|
|
||||||
|
print('Applied', changes, 'changes')
|
||||||
31
fix_reviewcode.py
Normal file
31
fix_reviewcode.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Fix the broken reviewCode template literal."""
|
||||||
|
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Find and replace the broken reviewPrompt line
|
||||||
|
# The problem: backticks inside template literal need to be escaped with \`
|
||||||
|
old_line = ' const reviewPrompt = `Please review this generated code for bugs, security issues, performance problems, and best practices. Provide specific improvements:\\n\\n\\\\`\\\\`\\\\`${previewData.language || "code"}\\n${previewData.data}\\n\\\\`\\\\`\\\\`';'
|
||||||
|
|
||||||
|
new_line = ' const reviewPrompt = "Please review this generated code for bugs, security issues, performance problems, and best practices. Provide specific improvements:\\n\\n\`\`\`" + (previewData.language || "code") + "\\n" + previewData.data + "\\n\`\`\`";'
|
||||||
|
|
||||||
|
if old_line in content:
|
||||||
|
content = content.replace(old_line, new_line, 1)
|
||||||
|
print("Fixed reviewCode template literal")
|
||||||
|
else:
|
||||||
|
# Try with the actual escaped content
|
||||||
|
# Let's just find it by the function start and replace the whole function
|
||||||
|
print("Trying line-by-line approach...")
|
||||||
|
lines = content.split('\n')
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'const reviewPrompt' in line and 'review this generated code' in line:
|
||||||
|
print(f"Found at line {i+1}: {line[:80]}...")
|
||||||
|
lines[i] = new_line
|
||||||
|
print("Fixed")
|
||||||
|
break
|
||||||
|
content = '\n'.join(lines)
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
18
fix_reviewcode2.py
Normal file
18
fix_reviewcode2.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
bt = chr(96) # backtick character
|
||||||
|
nl = chr(92) + 'n' # \n
|
||||||
|
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'const reviewPrompt' in line and 'review this generated code' in line:
|
||||||
|
new_line = ' const reviewPrompt = "Please review this generated code for bugs, security issues, performance problems, and best practices. Provide specific improvements:" + "' + nl + '" + "' + nl + '" + "' + bt*3 + '" + (previewData.language || "code") + "' + nl + '" + previewData.data + "' + nl + '" + "' + bt*3 + '";\n'
|
||||||
|
lines[i] = new_line
|
||||||
|
print(f'Fixed line {i+1}')
|
||||||
|
print(repr(new_line))
|
||||||
|
break
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.writelines(lines)
|
||||||
210
fix_v1.4.0.py
Normal file
210
fix_v1.4.0.py
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Apply v1.4.0 improvements: model color fix, review button, web search grounding."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
fp = '/home/uroma/promptarch/components/AIAssist.tsx'
|
||||||
|
with open(fp, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
changes = 0
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 1: Fix model selector text color
|
||||||
|
# ============================================================
|
||||||
|
old_option = '{availableModels.map(m => <option key={m} value={m}>{m}</option>)}'
|
||||||
|
new_option = '{availableModels.map(m => <option key={m} value={m} className="bg-[#0b1414] text-white">{m}</option>)}'
|
||||||
|
|
||||||
|
if old_option in content:
|
||||||
|
content = content.replace(old_option, new_option, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 1: Fixed <option> text color to white")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find option map")
|
||||||
|
|
||||||
|
# Also add text-white to the <select> className
|
||||||
|
old_select_class = 'className="text-[10px] font-bold h-8 px-2 rounded-lg border border-blue-100 dark:border-blue-900 bg-white/80 dark:bg-[#0b1414]/80 focus:ring-2 focus:ring-blue-400/30 transition-all outline-none min-w-[120px]"'
|
||||||
|
new_select_class = 'className="text-[10px] font-bold h-8 px-2 rounded-lg border border-blue-100 dark:border-blue-900 bg-white/80 dark:bg-[#0b1414]/80 focus:ring-2 focus:ring-blue-400/30 transition-all outline-none min-w-[120px] text-slate-900 dark:text-white"'
|
||||||
|
|
||||||
|
if old_select_class in content:
|
||||||
|
content = content.replace(old_select_class, new_select_class, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 1b: Added text-white to select element")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find select className")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 2: Add ShieldCheck to lucide-react imports
|
||||||
|
# ============================================================
|
||||||
|
old_import = ' Wand2, LayoutPanelLeft, Play, Orbit, Plus, Key'
|
||||||
|
new_import = ' Wand2, LayoutPanelLeft, Play, Orbit, Plus, Key, ShieldCheck'
|
||||||
|
|
||||||
|
if old_import in content:
|
||||||
|
content = content.replace(old_import, new_import, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 2: Added ShieldCheck to imports")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find lucide import line")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 3: Add reviewCode function after approveAndGenerate
|
||||||
|
# ============================================================
|
||||||
|
old_approve = ''' const approveAndGenerate = () => {
|
||||||
|
setAssistStep("generating");
|
||||||
|
handleSendMessage(undefined, "Approved. Please generate the code according to the plan.", true);
|
||||||
|
};'''
|
||||||
|
|
||||||
|
new_approve = ''' const approveAndGenerate = () => {
|
||||||
|
setAssistStep("generating");
|
||||||
|
handleSendMessage(undefined, "Approved. Please generate the code according to the plan.", true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reviewCode = () => {
|
||||||
|
if (!previewData?.data) return;
|
||||||
|
setAssistStep("generating");
|
||||||
|
const reviewPrompt = `Please review this generated code for bugs, security issues, performance problems, and best practices. Provide specific improvements:\\n\\n\\\`\\\`\\\`${previewData.language || "code"}\\n${previewData.data}\\n\\\`\\\`\\\``;
|
||||||
|
handleSendMessage(undefined, reviewPrompt, true);
|
||||||
|
};'''
|
||||||
|
|
||||||
|
if old_approve in content:
|
||||||
|
content = content.replace(old_approve, new_approve, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 3: Added reviewCode function")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find approveAndGenerate block")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 4: Add Review Code button (grid-cols-2 -> 3)
|
||||||
|
# ============================================================
|
||||||
|
old_grid = '''<div className="mt-4 grid grid-cols-2 gap-2 animate-in zoom-in-95 duration-300">
|
||||||
|
<Button
|
||||||
|
onClick={() => { setShowCanvas(true); setViewMode(isPreviewRenderable(previewData as PreviewData) ? "preview" : "code"); }}
|
||||||
|
className="bg-blue-600 hover:bg-blue-500 text-white font-black uppercase text-[10px] tracking-widest py-4 rounded-xl shadow-lg shadow-blue-500/20"
|
||||||
|
>
|
||||||
|
<Zap className="h-3.5 w-3.5 mr-1.5" /> {t.activateArtifact}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => { setAssistStep("idle"); setInput("Modify this: "); setTimeout(() => { const el = document.querySelector<HTMLInputElement>(`[data-ai-input]`); if (el) el.focus(); }, 100); }}
|
||||||
|
variant="outline"
|
||||||
|
className="bg-slate-500/10 hover:bg-slate-500/20 border-slate-500/20 text-slate-300 font-black uppercase text-[10px] tracking-widest py-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<LayoutPanelLeft className="h-3.5 w-3.5 mr-1.5" /> Request Modifications
|
||||||
|
</Button>
|
||||||
|
</div>'''
|
||||||
|
|
||||||
|
new_grid = '''<div className="mt-4 grid grid-cols-3 gap-2 animate-in zoom-in-95 duration-300">
|
||||||
|
<Button
|
||||||
|
onClick={() => { setShowCanvas(true); setViewMode(isPreviewRenderable(previewData as PreviewData) ? "preview" : "code"); }}
|
||||||
|
className="bg-blue-600 hover:bg-blue-500 text-white font-black uppercase text-[10px] tracking-widest py-4 rounded-xl shadow-lg shadow-blue-500/20"
|
||||||
|
>
|
||||||
|
<Zap className="h-3.5 w-3.5 mr-1.5" /> {t.activateArtifact}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={reviewCode}
|
||||||
|
disabled={!previewData?.data}
|
||||||
|
variant="outline"
|
||||||
|
className="bg-emerald-500/10 hover:bg-emerald-500/20 border-emerald-500/20 text-emerald-300 font-black uppercase text-[10px] tracking-widest py-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<ShieldCheck className="h-3.5 w-3.5 mr-1.5" /> Review Code
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => { setAssistStep("idle"); setInput("Modify this: "); setTimeout(() => { const el = document.querySelector<HTMLInputElement>(`[data-ai-input]`); if (el) el.focus(); }, 100); }}
|
||||||
|
variant="outline"
|
||||||
|
className="bg-slate-500/10 hover:bg-slate-500/20 border-slate-500/20 text-slate-300 font-black uppercase text-[10px] tracking-widest py-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<LayoutPanelLeft className="h-3.5 w-3.5 mr-1.5" /> Request Modifications
|
||||||
|
</Button>
|
||||||
|
</div>'''
|
||||||
|
|
||||||
|
if old_grid in content:
|
||||||
|
content = content.replace(old_grid, new_grid, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 4: Added Review Code button (grid-cols-3)")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find post-coding buttons block")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 5: Add webSearchEnabled state after isProcessing
|
||||||
|
# ============================================================
|
||||||
|
old_state = ' const [isProcessing, setIsProcessing] = useState(false);'
|
||||||
|
new_state = ' const [isProcessing, setIsProcessing] = useState(false);\n const [webSearchEnabled, setWebSearchEnabled] = useState(false);'
|
||||||
|
|
||||||
|
if old_state in content:
|
||||||
|
content = content.replace(old_state, new_state, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 5: Added webSearchEnabled state")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find isProcessing state")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 6: Add web search toggle button in toolbar
|
||||||
|
# (After the model select closing </select> and before the
|
||||||
|
# canvas toggle div)
|
||||||
|
# ============================================================
|
||||||
|
old_toolbar = ''' </select>
|
||||||
|
<div className="flex items-center gap-1 ml-1 border-l border-blue-100 dark:border-blue-900 pl-2">'''
|
||||||
|
|
||||||
|
new_toolbar = ''' </select>
|
||||||
|
<button
|
||||||
|
onClick={() => setWebSearchEnabled(prev => !prev)}
|
||||||
|
className={`flex items-center gap-1 h-8 px-2 rounded-lg text-[10px] font-bold transition-all border ${
|
||||||
|
webSearchEnabled
|
||||||
|
? "bg-amber-500/20 border-amber-500/40 text-amber-300"
|
||||||
|
: "bg-transparent border-transparent text-slate-400/70 hover:text-slate-300 hover:bg-slate-500/10"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Search className="h-3.5 w-3.5" /> {webSearchEnabled ? "ON" : "Search"}
|
||||||
|
</button>
|
||||||
|
<div className="flex items-center gap-1 ml-1 border-l border-blue-100 dark:border-blue-900 pl-2">'''
|
||||||
|
|
||||||
|
if old_toolbar in content:
|
||||||
|
content = content.replace(old_toolbar, new_toolbar, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 6: Added web search toggle button")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find toolbar insertion point")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# CHANGE 7: Add web search enrichment in handleSendMessage
|
||||||
|
# Before generateAIAssistStream call, after formattedHistory
|
||||||
|
# ============================================================
|
||||||
|
old_stream = ''' const response = await modelAdapter.generateAIAssistStream(
|
||||||
|
{
|
||||||
|
messages: [...formattedHistory, { role: "user" as const, content: finalInput, timestamp: new Date() }],'''
|
||||||
|
|
||||||
|
new_stream = ''' // Web search grounding: enrich prompt with search results if enabled
|
||||||
|
let enrichedInput = finalInput;
|
||||||
|
if (webSearchEnabled) {
|
||||||
|
setStatus("Searching the web...");
|
||||||
|
try {
|
||||||
|
const searchRes = await fetch("/api/search?q=" + encodeURIComponent(finalInput.split("\\n")[0].substring(0, 200)));
|
||||||
|
if (searchRes.ok) {
|
||||||
|
const searchData = await searchRes.json();
|
||||||
|
if (searchData.results && searchData.results.length > 0) {
|
||||||
|
const searchContext = searchData.results.slice(0, 5).map((r: { title: string; url: string; snippet: string }, i: number) =>
|
||||||
|
`${i + 1}. **${r.title}** (${r.url}) - ${r.snippet}`
|
||||||
|
).join("\\n");
|
||||||
|
enrichedInput = `[WEB SEARCH CONTEXT - Top 5 relevant results]\\n${searchContext}\\n\\n---\\nUsing the above search results as reference context, answer the user query. Cite sources when relevant.\\n\\nUser query: ${finalInput}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Web search failed:", e);
|
||||||
|
}
|
||||||
|
setStatus(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await modelAdapter.generateAIAssistStream(
|
||||||
|
{
|
||||||
|
messages: [...formattedHistory, { role: "user" as const, content: enrichedInput, timestamp: new Date() }],'''
|
||||||
|
|
||||||
|
if old_stream in content:
|
||||||
|
content = content.replace(old_stream, new_stream, 1)
|
||||||
|
changes += 1
|
||||||
|
print("Change 7: Added web search enrichment before AI call")
|
||||||
|
else:
|
||||||
|
print("WARNING: Could not find generateAIAssistStream call")
|
||||||
|
|
||||||
|
with open(fp, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print(f"\nApplied {changes}/7 changes to AIAssist.tsx")
|
||||||
@@ -852,7 +852,13 @@ When the user asks to "Modify", "Change", or "Adjust" something:
|
|||||||
|
|
||||||
AGENTS & CAPABILITIES:
|
AGENTS & CAPABILITIES:
|
||||||
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
||||||
- seo: SEO Specialist. Create stunning SEO audit reports. **CRITICAL DESIGN REQUIREMENTS:**
|
- seo: SEO Specialist. Create stunning SEO audit reports and perform live website analysis. **BEHAVIOR: Stay in SEO mode and handle ALL requests through an SEO lens. Only suggest switching agents for CLEARLY non-SEO tasks (like "write Python backend code") by adding [SUGGEST_AGENT:code] at the END of your response. Never auto-switch mid-response.**
|
||||||
|
**WEB AUDIT CAPABILITIES (use when user provides a URL):**
|
||||||
|
- When user gives a URL (e.g., "audit example.com", "analyze https://site.com"), tell them you will fetch the page data server-side.
|
||||||
|
- You have access to server-side tools. For URL analysis, respond with [WEB_AUDIT:url] where url is the target URL. The system will fetch: title, meta description, headings (h1-h6), internal/external links count, images with/without alt text, canonical URL, Open Graph tags, word count, and HTML structure.
|
||||||
|
- After receiving audit data, produce a comprehensive SEO audit report as a visual dashboard using [PREVIEW:seo:html].
|
||||||
|
- For competitive analysis, keyword research, or SERP analysis: use [WEB_SEARCH:query] to get live search results, then create an analysis report.
|
||||||
|
**CRITICAL DESIGN REQUIREMENTS:**
|
||||||
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
||||||
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
||||||
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
||||||
@@ -865,6 +871,7 @@ AGENTS & CAPABILITIES:
|
|||||||
- Add animated pulse effects on key metrics
|
- Add animated pulse effects on key metrics
|
||||||
- Full-width responsive layout, max-w-4xl mx-auto
|
- Full-width responsive layout, max-w-4xl mx-auto
|
||||||
- Include inline <script> for animating the progress rings on load
|
- Include inline <script> for animating the progress rings on load
|
||||||
|
|
||||||
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
||||||
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
||||||
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
||||||
|
|||||||
@@ -509,7 +509,25 @@ When the user asks to "Modify", "Change", or "Adjust" something:
|
|||||||
|
|
||||||
AGENTS & CAPABILITIES:
|
AGENTS & CAPABILITIES:
|
||||||
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
||||||
- seo: SEO Specialist. Create stunning SEO audit reports. Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>. DARK THEME. Tailwind CDN. Large animated SVG progress rings. Color-coded scoring. Google-style dashboard aesthetics.
|
- seo: SEO Specialist. Create stunning SEO audit reports and perform live website analysis. **BEHAVIOR: Stay in SEO mode and handle ALL requests through an SEO lens. Only suggest switching agents for CLEARLY non-SEO tasks (like "write Python backend code") by adding [SUGGEST_AGENT:code] at the END of your response. Never auto-switch mid-response.**
|
||||||
|
**WEB AUDIT CAPABILITIES (use when user provides a URL):**
|
||||||
|
- When user gives a URL (e.g., "audit example.com", "analyze https://site.com"), tell them you will fetch the page data server-side.
|
||||||
|
- You have access to server-side tools. For URL analysis, respond with [WEB_AUDIT:url] where url is the target URL. The system will fetch: title, meta description, headings (h1-h6), internal/external links count, images with/without alt text, canonical URL, Open Graph tags, word count, and HTML structure.
|
||||||
|
- After receiving audit data, produce a comprehensive SEO audit report as a visual dashboard using [PREVIEW:seo:html].
|
||||||
|
- For competitive analysis, keyword research, or SERP analysis: use [WEB_SEARCH:query] to get live search results, then create an analysis report.
|
||||||
|
**CRITICAL DESIGN REQUIREMENTS:**
|
||||||
|
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
||||||
|
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
||||||
|
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
||||||
|
- Large animated SVG progress rings for scores (Overall, Technical, Content, Mobile) with stroke-dasharray animations
|
||||||
|
- Color-coded scoring: green (#22c55e) for good, amber (#f59e0b) for warning, red (#ef4444) for poor
|
||||||
|
- Use Tailwind CDN for styling. Include: rounded-3xl, shadow-lg, gradient backgrounds
|
||||||
|
- Section cards with subtle borders (border-white/10) and backdrop-blur
|
||||||
|
- Clear visual hierarchy: large score numbers (text-5xl), section titles (text-lg font-bold), bullet points for recommendations
|
||||||
|
- Add a "Key Recommendations" section with icons (use Lucide or inline SVG)
|
||||||
|
- Add animated pulse effects on key metrics
|
||||||
|
- Full-width responsive layout, max-w-4xl mx-auto
|
||||||
|
- Include inline <script> for animating the progress rings on load
|
||||||
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
||||||
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
||||||
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
||||||
|
|||||||
@@ -1134,7 +1134,13 @@ When the user asks to "Modify", "Change", or "Adjust" something:
|
|||||||
|
|
||||||
AGENTS & CAPABILITIES:
|
AGENTS & CAPABILITIES:
|
||||||
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
||||||
- seo: SEO Specialist. Create stunning SEO audit reports. **CRITICAL DESIGN REQUIREMENTS:**
|
- seo: SEO Specialist. Create stunning SEO audit reports and perform live website analysis. **BEHAVIOR: Stay in SEO mode and handle ALL requests through an SEO lens. Only suggest switching agents for CLEARLY non-SEO tasks (like "write Python backend code") by adding [SUGGEST_AGENT:code] at the END of your response. Never auto-switch mid-response.**
|
||||||
|
**WEB AUDIT CAPABILITIES (use when user provides a URL):**
|
||||||
|
- When user gives a URL (e.g., "audit example.com", "analyze https://site.com"), tell them you will fetch the page data server-side.
|
||||||
|
- You have access to server-side tools. For URL analysis, respond with [WEB_AUDIT:url] where url is the target URL. The system will fetch: title, meta description, headings (h1-h6), internal/external links count, images with/without alt text, canonical URL, Open Graph tags, word count, and HTML structure.
|
||||||
|
- After receiving audit data, produce a comprehensive SEO audit report as a visual dashboard using [PREVIEW:seo:html].
|
||||||
|
- For competitive analysis, keyword research, or SERP analysis: use [WEB_SEARCH:query] to get live search results, then create an analysis report.
|
||||||
|
**CRITICAL DESIGN REQUIREMENTS:**
|
||||||
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
||||||
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
||||||
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
||||||
@@ -1147,6 +1153,7 @@ AGENTS & CAPABILITIES:
|
|||||||
- Add animated pulse effects on key metrics
|
- Add animated pulse effects on key metrics
|
||||||
- Full-width responsive layout, max-w-4xl mx-auto
|
- Full-width responsive layout, max-w-4xl mx-auto
|
||||||
- Include inline <script> for animating the progress rings on load
|
- Include inline <script> for animating the progress rings on load
|
||||||
|
|
||||||
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
||||||
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
||||||
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
||||||
|
|||||||
@@ -865,7 +865,13 @@ When the user asks to "Modify", "Change", or "Adjust" something:
|
|||||||
|
|
||||||
AGENTS & CAPABILITIES:
|
AGENTS & CAPABILITIES:
|
||||||
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
- content: Expert copywriter. Use [PREVIEW:content:markdown] for articles, posts, and long-form text.
|
||||||
- seo: SEO Specialist. Create stunning SEO audit reports. **BEHAVIOR: Stay in SEO mode and handle ALL requests through an SEO lens. Only suggest switching agents for CLEARLY non-SEO tasks (like "write Python backend code") by adding [SUGGEST_AGENT:code] at the END of your response. Never auto-switch mid-response.** **CRITICAL DESIGN REQUIREMENTS:**
|
- seo: SEO Specialist. Create stunning SEO audit reports and perform live website analysis. **BEHAVIOR: Stay in SEO mode and handle ALL requests through an SEO lens. Only suggest switching agents for CLEARLY non-SEO tasks (like "write Python backend code") by adding [SUGGEST_AGENT:code] at the END of your response. Never auto-switch mid-response.**
|
||||||
|
**WEB AUDIT CAPABILITIES (use when user provides a URL):**
|
||||||
|
- When user gives a URL (e.g., "audit example.com", "analyze https://site.com"), tell them you will fetch the page data server-side.
|
||||||
|
- You have access to server-side tools. For URL analysis, respond with [WEB_AUDIT:url] where url is the target URL. The system will fetch: title, meta description, headings (h1-h6), internal/external links count, images with/without alt text, canonical URL, Open Graph tags, word count, and HTML structure.
|
||||||
|
- After receiving audit data, produce a comprehensive SEO audit report as a visual dashboard using [PREVIEW:seo:html].
|
||||||
|
- For competitive analysis, keyword research, or SERP analysis: use [WEB_SEARCH:query] to get live search results, then create an analysis report.
|
||||||
|
**CRITICAL DESIGN REQUIREMENTS:**
|
||||||
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
- Use [PREVIEW:seo:html] with complete HTML5 document including <!DOCTYPE html>
|
||||||
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
- DARK THEME: bg-slate-900 or bg-gray-900 as primary background
|
||||||
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
- Google-style dashboard aesthetics with clean typography (use Google Fonts: Inter, Roboto, or Outfit)
|
||||||
@@ -878,6 +884,7 @@ AGENTS & CAPABILITIES:
|
|||||||
- Add animated pulse effects on key metrics
|
- Add animated pulse effects on key metrics
|
||||||
- Full-width responsive layout, max-w-4xl mx-auto
|
- Full-width responsive layout, max-w-4xl mx-auto
|
||||||
- Include inline <script> for animating the progress rings on load
|
- Include inline <script> for animating the progress rings on load
|
||||||
|
|
||||||
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
- smm: Social Media Manager. Create multi-platform content plans and calendars.
|
||||||
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
- pm: Project Manager. Create PRDs, timelines, and action plans.
|
||||||
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
- code: Software Architect. Provide logic, algorithms, and backend snippets.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "promptarch",
|
"name": "promptarch",
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
"description": "Transform vague ideas into production-ready prompts and PRDs",
|
"description": "Transform vague ideas into production-ready prompts and PRDs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
Reference in New Issue
Block a user