aura-ai
Version:
AI-powered marketing strategist CLI tool for developers
215 lines (203 loc) • 6.28 kB
JavaScript
import { exec } from "child_process";
import { promisify } from "util";
import { openai } from "@ai-sdk/openai";
import { generateText, streamText } from "ai";
import dotenv from "dotenv";
import fs from "fs/promises";
const execAsync = promisify(exec);
class GitService {
async getTodayCommits() {
try {
const { stdout } = await execAsync('git log --since="00:00" --format="%H|%s|%an|%ai"');
if (!stdout.trim()) {
return [];
}
const commits = stdout.trim().split("\n").map((line) => {
const [hash, message, author, date] = line.split("|");
return {
hash: hash.substring(0, 7),
message,
author,
date: new Date(date).toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit"
})
};
});
return commits;
} catch (error) {
console.error("Error fetching commits:", error);
return [];
}
}
formatCommitsForAI(commits) {
return commits.map((c) => `[${c.date}] ${c.message}`).join("\n");
}
}
const gitService = new GitService();
dotenv.config({ path: ".env.local" });
dotenv.config();
class SyncAIService {
constructor() {
this.apiKey = process.env.OPENAI_API_KEY;
this.model = "gpt-4o-mini";
}
async generateDailyReport(commits) {
if (!this.apiKey || this.apiKey === "your_openai_api_key_here") {
throw new Error("OpenAI API key not configured");
}
if (commits.length === 0) {
return {
summary: "No commits today yet. Start coding to track your progress!",
highlights: [],
markdown: "# 📅 Daily Progress Report\n\nNo commits found today."
};
}
const prompt = `Analyze these git commits from today and create a concise daily progress report.
Git commits:
${commits}
Instructions:
1. Write a ONE sentence executive summary of what was accomplished today
2. List 3-5 key highlights (what would impress a manager or client)
3. Ignore generic commits like "update", "fix", "commit" unless they're part of something bigger
4. Use plain English that non-developers can understand
5. Focus on business value and user-facing improvements
6. Be concise but enthusiastic
Output JSON format:
{
"summary": "One sentence summary here",
"highlights": [
"First achievement",
"Second achievement",
"Third achievement"
]
}
IMPORTANT: Return ONLY valid JSON, no markdown formatting or extra text.`;
try {
const result = await generateText({
model: openai(this.model),
prompt,
temperature: 0.7,
maxTokens: 500
});
let parsed;
try {
const cleanJson = result.text.replace(/```json\n?|\n?```/g, "").trim();
parsed = JSON.parse(cleanJson);
} catch (e) {
console.error("Failed to parse AI response:", e);
return {
summary: "Made several improvements to the project today.",
highlights: ["Various updates and improvements"],
markdown: this.generateFallbackMarkdown(commits)
};
}
const markdown = this.generateMarkdown(parsed);
return {
...parsed,
markdown
};
} catch (error) {
console.error("Error generating AI report:", error);
throw error;
}
}
generateMarkdown(report) {
const date = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
let markdown = `# 📅 Daily Progress Report
`;
markdown += `**${date}**
`;
markdown += `${report.summary}
`;
if (report.highlights && report.highlights.length > 0) {
markdown += `### ✨ Key Achievements
`;
report.highlights.forEach((highlight) => {
markdown += `• ${highlight}
`;
});
}
return markdown;
}
generateFallbackMarkdown(commits) {
const date = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
return `# 📅 Daily Progress Report
**${date}**
## Today's Commits
${commits}`;
}
}
const syncAIService = new SyncAIService();
dotenv.config({ path: ".env.local" });
dotenv.config();
class ChatService {
constructor() {
this.apiKey = process.env.OPENAI_API_KEY;
this.model = process.env.AI_MODEL || "gpt-4o-mini";
this.temperature = parseFloat(process.env.AI_TEMPERATURE || "0.7");
this.maxTokens = parseInt(process.env.AI_MAX_TOKENS || "200");
}
async checkAuraConfig() {
try {
await fs.access("./aura.md");
return true;
} catch {
return false;
}
}
async getSystemPrompt() {
const hasConfig = await this.checkAuraConfig();
if (hasConfig) {
try {
const auraContent = await fs.readFile("./aura.md", "utf-8");
return `You are Aura, an AI marketing strategist. You have analyzed the user's product and created a personalized marketing strategy.
Product Analysis:
${auraContent}
Provide specific, actionable marketing advice based on this product analysis. Be concise and practical.`;
} catch (error) {
console.error("Error reading aura.md:", error);
}
}
return `You are Aura, an AI marketing strategist. The user hasn't run product analysis yet.
Provide general marketing advice and encourage them to run /init for personalized insights.
Keep responses concise and actionable.`;
}
async sendMessage(messages) {
if (!this.apiKey || this.apiKey === "your_openai_api_key_here") {
throw new Error("OpenAI API key not configured. Please set OPENAI_API_KEY in .env file");
}
try {
const systemPrompt = await this.getSystemPrompt();
const result = await streamText({
model: openai(this.model),
system: systemPrompt,
messages,
temperature: this.temperature,
maxTokens: this.maxTokens
});
return result;
} catch (error) {
console.error("Error calling OpenAI API:", error);
throw error;
}
}
}
const chatService = new ChatService();
export {
chatService as c,
gitService as g,
syncAIService as s
};
//# sourceMappingURL=chatService-7b3Ru5ZZ.js.map