diff --git a/.github/release_template.md b/.github/release_template.md new file mode 100644 index 0000000..a89d394 --- /dev/null +++ b/.github/release_template.md @@ -0,0 +1,26 @@ +## Eggent v{{VERSION}} - {{NAME}} + +One-line summary of what changed and why it matters. + +### Highlights + +- Highlight 1 +- Highlight 2 +- Highlight 3 + +### Platform Coverage + +- Dashboard: +- API: +- Integrations: + +### Upgrade Notes + +- Compatibility: +- Migration: +- Operational changes: + +### Links + +- Full notes: `docs/releases/{{FILE}}` +- README: `README.md` diff --git a/.gitignore b/.gitignore index 59d627d..004fef7 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts +# python +__pycache__/ +*.py[cod] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1aa04c0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.1.1] - 2026-03-03 + +### Added +- `PUT /api/projects/[id]/mcp` endpoint for saving raw MCP config content. +- Inline MCP JSON editor with save/reset in `Dashboard -> MCP`. +- Inline MCP JSON editor with save/reset in project details context panel. +- Editable project instructions with save/reset in project details. +- Release documentation set in `docs/releases/`. + +### Changed +- MCP content validation and normalization before writing `.meta/mcp/servers.json`. +- Package/app health version updated to `0.1.1`. diff --git a/README.md b/README.md index 8d3650f..eb88642 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ Built-in platform capabilities: The app runs as a Next.js service and stores runtime state on disk (`./data`). +## Releases + +- Latest release snapshot: [0.1.1 - Unified Context](./docs/releases/0.1.1-unified-context.md) +- GitHub release body (ready to paste): [v0.1.1](./docs/releases/github-v0.1.1.md) +- Release archive: [docs/releases/README.md](./docs/releases/README.md) + ## Contributing and Support - Contributing guide: [CONTRIBUTING.md](./CONTRIBUTING.md) diff --git a/docs/releases/0.1.1-unified-context.md b/docs/releases/0.1.1-unified-context.md new file mode 100644 index 0000000..9948f5e --- /dev/null +++ b/docs/releases/0.1.1-unified-context.md @@ -0,0 +1,82 @@ +# Eggent 0.1.1 - Unified Context + +Date: 2026-03-03 +Type: Generalized release snapshot + +## Release Name +`Unified Context` + +This release combines current platform capabilities into one coherent milestone: project-centric agent work, persistent memory and knowledge, MCP/skills extensibility, scheduled automation, and external integrations. + +## What Is Included + +### 1) Workspace and Projects +- Multi-project workspace with chat isolation by project. +- Project profile: name, description, instructions, memory mode (`isolated`/`global`). +- Full project details page with project context, cron jobs, and knowledge base in one place. +- First-run onboarding flow: credentials, first project, model setup, Telegram, and starter skills. + +### 2) Agent Runtime and Tooling +- Agent chat loop with tool calls and persistent chat history. +- Built-in tool families: code execution, memory operations, knowledge search, web search, cron automation, subordinate-agent call support. +- Per-project work directory and context-aware routing. + +### 3) Memory and Knowledge +- Persistent vector memory with search and deletion UI. +- Project knowledge ingestion via file upload. +- Supported ingestion formats: `txt`, `md`, `json`, `csv`, `pdf`, `docx`, `xlsx`, `xls`, images (`png`, `jpg`, `jpeg`, `gif`, `bmp`, `webp`). +- Knowledge chunk inspection and memory browsing in dashboard. + +### 4) Skills Platform +- Bundled skills catalog with per-project installation. +- Installed project skills inspection with full `SKILL.md` view. +- Current bundled catalog size: `38` skills. +- Bundled skills included: `bear-notes`, `bluebubbles`, `camsnap`, `canvas`, `coding-agent`, `discord`, `excalidraw`, `gemini`, `gh-issues`, `gifgrep`, `github`, `healthcheck`, `imsg`, `last30days`, `mcporter`, `model-usage`, `nano-banana-pro`, `nano-pdf`, `notion`, `obsidian`, `openai-image-gen`, `openai-whisper`, `openai-whisper-api`, `openhue`, `oracle`, `ordercli`, `playwright-cli`, `remotion`, `session-logs`, `skill-creator`, `slack`, `summarize`, `things-mac`, `tmux`, `trello`, `video-frames`, `voice-call`, `weather`. + +### 5) MCP Integration +- MCP configuration storage per project at `.meta/mcp/servers.json`. +- MCP server normalization for Cursor-style `mcpServers` and legacy `servers` formats. +- MCP browser/editor page for all projects. +- Project details context panel with inline MCP editing. + +### 6) Cron Automation +- Per-project cron jobs with three schedule modes: one-time (`at`), interval (`every`), cron expression (`cron`). +- Manual run, enable/disable, delete, and run history inspection. +- Optional Telegram delivery target and per-job timeout. + +### 7) External API and Session Context +- External message endpoint: `POST /api/external/message`. +- Project context resolution across messages and sessions. +- External API token management with rotation UI. + +### 8) Messenger Integration +- Telegram integration management in dashboard. +- Webhook setup/reconnect/disconnect flows. +- Access-code gating and allowlist management. +- Telegram command set: `/start`, `/help`, `/code `, `/new`. + +### 9) Settings, Models, and Security +- Model configuration wizards for chat and embeddings. +- Provider support: OpenAI, Anthropic, Google, OpenRouter, Ollama, custom. +- Code execution controls (enable/timeout/max output). +- Memory and search provider controls (Tavily, SearXNG, disabled). +- Dashboard credentials management (`/api/auth/credentials`). + +### 10) Operations and Delivery +- Install modes: one-command installer, local production, Docker production, manual. +- Health endpoint: `GET /api/health`. +- Realtime UI sync endpoint and disk-first data persistence under `./data`. + +## New in 0.1.1 + +- Added `PUT /api/projects/[id]/mcp` for saving raw MCP config content. +- Added MCP raw JSON editing with save/reset on `Dashboard -> MCP` and project details context section. +- Added editable project instructions with save/reset on project details page. +- Added MCP content validation and normalization before writing `servers.json`. +- Bumped package version to `0.1.1`. +- Updated health endpoint version response to `0.1.1`. + +## Coverage Checklist (No Module Left Out) + +- Dashboard pages included in this release: `chat`, `projects`, `memory`, `skills`, `mcp`, `cron`, `settings`, `api`, `messengers`. +- API surface included in this release: auth, chat, projects, skills, MCP, memory, knowledge, cron, external API, Telegram integration, files, models, settings, health, events. diff --git a/docs/releases/README.md b/docs/releases/README.md new file mode 100644 index 0000000..577adbc --- /dev/null +++ b/docs/releases/README.md @@ -0,0 +1,7 @@ +# Releases + +This directory contains release summaries and publish-ready notes. + +| Version | Name | Date | Notes | +| --- | --- | --- | --- | +| `0.1.1` | Unified Context | 2026-03-03 | [Full snapshot](./0.1.1-unified-context.md), [GitHub body](./github-v0.1.1.md) | diff --git a/docs/releases/github-v0.1.1.md b/docs/releases/github-v0.1.1.md new file mode 100644 index 0000000..102c4ca --- /dev/null +++ b/docs/releases/github-v0.1.1.md @@ -0,0 +1,29 @@ +## Eggent v0.1.1 - Unified Context + +Generalized release that consolidates the full platform surface into one project-centric workflow: chat + tools, memory + knowledge, skills + MCP, cron automation, and external messaging integrations. + +### Highlights + +- Added raw MCP config save endpoint: `PUT /api/projects/[id]/mcp`. +- Added direct `servers.json` editing with save/reset in `Dashboard -> MCP`. +- Added same MCP editing controls in project details context panel. +- Added editable project instructions with save/reset in project details. +- Added MCP content validation/normalization before writing `.meta/mcp/servers.json`. +- Version bump to `0.1.1` across package metadata and health response. + +### Platform Coverage + +- Dashboard modules: `chat`, `projects`, `memory`, `skills`, `mcp`, `cron`, `settings`, `api`, `messengers`. +- API modules: auth, chat, projects, skills, MCP, memory, knowledge, cron, external API, Telegram integration, files, models, settings, health, realtime events. +- Bundled skills catalog: `38` skills available for per-project install. + +### Upgrade Notes + +- Existing MCP configs continue to work (Cursor `mcpServers` and legacy `servers` are both supported). +- `GET /api/health` now reports version `0.1.1`. +- No migration step required for existing `data/` projects. + +### Links + +- Full release snapshot: `docs/releases/0.1.1-unified-context.md` +- Installation and update guide: `README.md` diff --git a/package-lock.json b/package-lock.json index d61cdc3..10cbb4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "design-vibe", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "design-vibe", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@ai-sdk/anthropic": "^3.0.37", "@ai-sdk/google": "^3.0.21", diff --git a/package.json b/package.json index c7b0a30..4daf924 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "design-vibe", - "version": "0.1.0", + "version": "0.1.1", "private": true, "scripts": { "dev": "next dev", diff --git a/src/app/api/health/route.ts b/src/app/api/health/route.ts index 64017d4..ad7359a 100644 --- a/src/app/api/health/route.ts +++ b/src/app/api/health/route.ts @@ -2,6 +2,6 @@ export async function GET() { return Response.json({ status: "ok", timestamp: new Date().toISOString(), - version: "0.1.0", + version: "0.1.1", }); } diff --git a/src/app/api/projects/[id]/mcp/route.ts b/src/app/api/projects/[id]/mcp/route.ts index 7b6ea4c..216f3dc 100644 --- a/src/app/api/projects/[id]/mcp/route.ts +++ b/src/app/api/projects/[id]/mcp/route.ts @@ -4,6 +4,7 @@ import { getProject, getProjectMcpServersPath, loadProjectMcpServers, + saveProjectMcpServersContent, } from "@/lib/storage/project-store"; function isNotFoundError(error: unknown): boolean { @@ -41,3 +42,42 @@ export async function GET( ); } } + +export async function PUT( + req: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + const { id } = await params; + const project = await getProject(id); + if (!project) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + + let body: unknown; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: "Invalid JSON payload" }, { status: 400 }); + } + + const content = + body && typeof body === "object" && "content" in body + ? (body as { content?: unknown }).content + : undefined; + if (typeof content !== "string") { + return NextResponse.json( + { error: 'Field "content" must be a string.' }, + { status: 400 } + ); + } + + const result = await saveProjectMcpServersContent(id, content); + if (!result.success) { + return NextResponse.json({ error: result.error }, { status: 400 }); + } + + return NextResponse.json({ + content: result.content, + servers: result.servers, + }); +} diff --git a/src/app/dashboard/mcp/page.tsx b/src/app/dashboard/mcp/page.tsx index cb2a8e0..12d5ded 100644 --- a/src/app/dashboard/mcp/page.tsx +++ b/src/app/dashboard/mcp/page.tsx @@ -4,6 +4,7 @@ import { useEffect, useMemo, useState } from "react"; import { AppSidebar } from "@/components/app-sidebar"; import { SiteHeader } from "@/components/site-header"; import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; +import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Globe, Loader2, Terminal, Wrench } from "lucide-react"; import { useAppStore } from "@/store/app-store"; @@ -74,14 +75,19 @@ function normalizeServers(input: unknown): McpServerItem[] { return servers; } +const EMPTY_MCP_JSON = JSON.stringify({ mcpServers: {} }, null, 2); + export default function McpPage() { const { projects, setProjects, activeProjectId } = useAppStore(); const [selectedProjectId, setSelectedProjectId] = useState(""); const [servers, setServers] = useState([]); const [rawContent, setRawContent] = useState(null); + const [draftContent, setDraftContent] = useState(EMPTY_MCP_JSON); const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); const [projectsLoading, setProjectsLoading] = useState(false); const [statusMessage, setStatusMessage] = useState(null); + const [statusTone, setStatusTone] = useState<"success" | "error" | null>(null); const [search, setSearch] = useState(""); useEffect(() => { @@ -131,7 +137,9 @@ export default function McpPage() { if (!projectId) { setServers([]); setRawContent(null); + setDraftContent(EMPTY_MCP_JSON); setStatusMessage(null); + setStatusTone(null); setLoading(false); return; } @@ -139,6 +147,7 @@ export default function McpPage() { try { setLoading(true); setStatusMessage(null); + setStatusTone(null); const res = await fetch(`/api/projects/${encodeURIComponent(projectId)}/mcp`); const payload = await res.json(); @@ -148,22 +157,75 @@ export default function McpPage() { ? payload.error : "Failed to load MCP servers"; setStatusMessage(message); + setStatusTone("error"); setServers([]); setRawContent(null); + setDraftContent(EMPTY_MCP_JSON); return; } - setRawContent(typeof payload?.content === "string" ? payload.content : null); + const content = + typeof payload?.content === "string" ? payload.content : null; + setRawContent(content); + setDraftContent(content ?? EMPTY_MCP_JSON); setServers(normalizeServers(payload?.servers)); } catch { setStatusMessage("Failed to load MCP servers"); + setStatusTone("error"); setServers([]); setRawContent(null); + setDraftContent(EMPTY_MCP_JSON); } finally { setLoading(false); } } + async function handleSaveRawContent() { + if (!selectedProjectId) return; + + try { + setSaving(true); + setStatusMessage(null); + setStatusTone(null); + + const res = await fetch( + `/api/projects/${encodeURIComponent(selectedProjectId)}/mcp`, + { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ content: draftContent }), + } + ); + const payload = await res.json(); + if (!res.ok) { + throw new Error( + typeof payload?.error === "string" + ? payload.error + : "Failed to save MCP servers" + ); + } + + const content = + typeof payload?.content === "string" ? payload.content : draftContent; + setRawContent(content); + setDraftContent(content); + setServers(normalizeServers(payload?.servers)); + setStatusMessage("MCP configuration saved."); + setStatusTone("success"); + } catch (error) { + setStatusMessage( + error instanceof Error ? error.message : "Failed to save MCP servers" + ); + setStatusTone("error"); + } finally { + setSaving(false); + } + } + + const baselineContent = rawContent ?? EMPTY_MCP_JSON; + const hasDraftChanges = draftContent !== baselineContent; + const canSaveDraft = rawContent === null || hasDraftChanges; + const filteredServers = useMemo(() => { const query = search.trim().toLowerCase(); if (!query) return servers; @@ -188,7 +250,7 @@ export default function McpPage() {

MCP Servers

- View MCP servers configured for each project from + View and edit MCP servers configured for each project from .meta/mcp/servers.json and switch between projects.

@@ -224,7 +286,15 @@ export default function McpPage() {
{statusMessage && ( -
+
{statusMessage}
)} @@ -322,15 +392,53 @@ export default function McpPage() { )}
- {rawContent ? ( + {selectedProjectId ? (
-
+

Raw servers.json

+ {!loading && ( + + Edit JSON directly + + )}
-
-
-                      {rawContent}
-                    
+
+ {!loading && !rawContent && ( +

+ `servers.json` does not exist yet for this project. Save to create it. +

+ )} +