Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ GOOGLE_API_KEY='your-google-api-key'

WORKSPACE_PATH='./workspace' # default local workspace path for tools that write to disk, can be overridden by tools with custom paths or when using AgentFS

BETTER_AUTH_URL='https://localhost:3000' # Base App URL
BETTER_AUTH_URL='http://localhost:3000' # Base App URL
NEXT_PUBLIC_BETTER_AUTH_URL='http://localhost:3000' # Browser-side Better Auth base URL
BETTER_AUTH_SECRET='KQh7DvS4PtsNqJ1PZSoYheGOo1k13SUZqUBwNazc28U=' # openssl rand -base64 32 <--- run this to make ur own
DEV_AUTH_ENABLED=true # Set to false to disable authentication in development (not recommended, but can be useful for quick testing)
# Next.js + Mastra Client SDK
Expand All @@ -29,20 +30,17 @@ DISCORD_CLIENT_ID='your_discord_client_id_here'
DISCORD_SECRET_KEY='your_discord_secret_key_here'
DISCORD_WEBHOOK_URL='your_discord_webhook_url_here'
GOOGLE_CLIENT_ID="******************-**********************.apps.googleusercontent.com"
NEXT_PUBLIC_GOOGLE_CLIENT_ID="******************-**********************.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET="fake_google_client_secret_for_local_dev"
GOOGLE_CLIENT_CALLBACK_URL="https://localhost:3000/api/callback"
GOOGLE_CLIENT_CALLBACK_URL="http://localhost:3000/api/auth/callback/google"

#Authorized redirect URIs

#https://localhost:3000/api/callback
#http://localhost:3000/api/auth/callback/google

#https://localhost:3000/callback
#http://127.0.0.1:3000/api/auth/callback/google

#https://127.0.0.1:3000/api/callback

#http://127.0.0.1:3000/api/callback

#https://127.0.0.1:3000/callback
#https://your-domain.com/api/auth/callback/google


# Opencode Zen API Key
Expand Down
18 changes: 17 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ gha-creds-*.json
.zencoder/rules/*.md

# Stakpak local files
.stakpak
.stakpak/session*
stakpak.backup
stakpak.exe
opnapi.json
Expand Down Expand Up @@ -208,3 +208,19 @@ src/mastra/public/workspace/workspace/iran-war-report.md
.env.local.bak
thoughts/ledgers/CONTINUITY_ses_303c.md
thoughts/ledgers/CONTINUITY_ses_303d.md
.mastra-project.json
start-server.js
start-dev.js
.playwright-mcp/page-2026-04-15T07-03-10-932Z.yml
.playwright-mcp/page-2026-04-15T07-04-06-556Z.yml
.playwright-mcp/page-2026-04-15T08-44-34-033Z.yml
.playwright-mcp/page-2026-04-15T07-36-00-846Z.yml
.playwright-mcp/page-2026-04-15T07-34-28-100Z.yml
.gitignore
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The .gitignore file is configured to ignore itself. This is typically unintended, as it prevents future modifications to this file from being tracked by Git. This could lead to files that should be ignored being accidentally committed in the future. Please consider removing this line.

.playwright-mcp/page-2026-04-15T07-29-52-207Z.yml
.playwright-mcp/page-2026-04-15T07-17-59-962Z.yml
.playwright-mcp/page-2026-04-15T07-31-15-475Z.yml
.playwright-mcp/page-2026-04-15T07-26-05-653Z.yml
.playwright-mcp/page-2026-04-15T07-24-17-682Z.yml
.playwright-mcp/page-2026-04-15T07-20-32-715Z.yml
.playwright-mcp/page-2026-04-15T07-18-30-461Z.yml
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

## Development
![Networks Custom Tool v1.0.0](networksCustomToolv1.png)
![Home Page v1.0.0](page-2026-04-15T07-04-23-082Z.png)

<!-- Core Project Badges -->

Expand Down
14 changes: 14 additions & 0 deletions app/chat/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

# App/Chat

## Recent Update (2026-04-15)

- Settings pages are now modular route groups instead of two monolithic screens:
- `/chat/user` overview + focused routes for profile, security, sessions, API keys, and danger zone
- `/chat/admin` overview + focused routes for runtime and user operations
- Use `app/chat/components/chat-settings-shell.tsx` when a chat route needs the shared `ChatProvider` + `ChatPageShell` + `MainSidebar` composition plus an in-section settings nav.
- Use the same shared shell composition for non-settings dashboard surfaces that need the persistent chat sidebar; the current wrapped set includes datasets, evaluation, observability, tools, logs, harness, MCP/A2A, workflows, and workflow detail pages.
- `UserSettingsPanel` and `AdminSettingsPanel` now support section-based rendering so new routes can reuse the same Better Auth mutations without duplicating form logic.
- `useWorkspaces()` in `lib/hooks/use-mastra-query.ts` now returns normalized `WorkspaceItem[]`; new chat UI code should consume that array directly instead of re-decoding `{ workspaces: [...] }` response shapes in components.
- Prefer shared tooltip and scroll affordances on high-density chat surfaces:
- add tooltip descriptions for navigation items and overview cards when a route’s purpose is not obvious
- use `ScrollArea` for long sidebars, thread lists, or horizontally dense settings navs rather than letting layout overflow
- keep shell spacing consistent through `ChatPageShell` instead of per-page padding drift

## Overview

The `/chat` route provides a rich AI chat interface built with **AI Elements** (52 components) integrated with **26+ Mastra agents**. Uses `@ai-sdk/react` with `useChat` and `DefaultChatTransport` to stream responses from Mastra's `/chat` route.
Expand Down
27 changes: 20 additions & 7 deletions app/chat/admin/_components/admin-management-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type PasswordFormState = {
}

type AdminRole = 'user' | 'admin'
export type AdminSettingsPanelSection = 'all' | 'runtime' | 'users'

const pageSize = 20

Expand Down Expand Up @@ -183,7 +184,11 @@ function mapUserToEditForm(user: AdminUser | null | undefined): EditUserFormStat
/**
* Admin user-management panel powered entirely by Better Auth hooks.
*/
export function AdminSettingsPanel() {
export function AdminSettingsPanel({
section = 'all',
}: {
section?: AdminSettingsPanelSection
}) {
const { data: authSession } = useAuthQuery()
const { data: modelProvidersData } = useAgentModelProviders()
const [search, setSearch] = React.useState('')
Expand Down Expand Up @@ -366,6 +371,8 @@ export function AdminSettingsPanel() {

const refreshDisabled = usersQuery.isFetching
const detailBusy = selectedUserQuery.isLoading || selectedSessionsQuery.isLoading
const showRuntime = section === 'all' || section === 'runtime'
const showUsers = section === 'all' || section === 'users'

return (
<TooltipProvider>
Expand Down Expand Up @@ -549,7 +556,8 @@ export function AdminSettingsPanel() {
</div>
</section>

<Card>
{showUsers ? (
<Card>
<CardHeader>
<CardTitle>Find users</CardTitle>
<CardDescription>
Expand Down Expand Up @@ -626,9 +634,11 @@ export function AdminSettingsPanel() {
</div>
</div>
</CardContent>
</Card>
</Card>
) : null}

<Card>
{showRuntime ? (
<Card>
<CardHeader>
<CardTitle>Runtime context</CardTitle>
<CardDescription>
Expand Down Expand Up @@ -672,9 +682,11 @@ export function AdminSettingsPanel() {
</Tooltip>
))}
</CardContent>
</Card>
</Card>
) : null}

<section className="grid gap-6 xl:grid-cols-[1.15fr_0.85fr]">
{showUsers ? (
<section className="grid gap-6 xl:grid-cols-[1.15fr_0.85fr]">
<Card>
<CardHeader>
<CardTitle>Users</CardTitle>
Expand Down Expand Up @@ -1041,7 +1053,8 @@ export function AdminSettingsPanel() {
</CardContent>
</Card>
</div>
</section>
</section>
) : null}
</div>
</TooltipProvider>
)
Expand Down
39 changes: 39 additions & 0 deletions app/chat/admin/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import type { ReactNode } from 'react'

import { ChatSettingsShell } from '../components/chat-settings-shell'

const adminSettingsSections = [
{
href: '/chat/admin',
title: 'Overview',
description: 'Start from the admin summary and branch into runtime or user operations.',
},
{
href: '/chat/admin/runtime',
title: 'Runtime',
description: 'Inspect active auth/runtime context and connected model providers.',
},
{
href: '/chat/admin/users',
title: 'Users',
description: 'Search users, change roles, moderate access, impersonate, and revoke sessions.',
},
] as const

export default function AdminSettingsLayout({
children,
}: {
children: ReactNode
}) {
return (
<ChatSettingsShell
title="Admin settings"
description="Operate Better Auth administration and live Mastra runtime context from focused admin routes."
sections={[...adminSettingsSections]}
>
{children}
</ChatSettingsShell>
)
}
58 changes: 47 additions & 11 deletions app/chat/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
import { ChatPageShell } from '../components/chat-page-shell'
import { MainSidebar } from '../components/main-sidebar'
import { AdminSettingsPanel } from './_components/admin-management-panel'
import Link from 'next/link'

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/ui/card'
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/ui/tooltip'

/**
* Admin settings page for chat operators.
* Admin settings overview for chat operators.
*/
export default function AdminPage() {
const sections = [
{
href: '/chat/admin/runtime',
title: 'Runtime context',
description: 'Inspect the live Better Auth session and Mastra provider inventory.',
},
{
href: '/chat/admin/users',
title: 'Users',
description: 'Search users, edit records, manage roles, moderate bans, and revoke sessions.',
},
] as const

return (
<ChatPageShell
title="Admin settings"
description="Manage the chat admin console, future moderation tools, and access policies."
sidebar={<MainSidebar />}
>
<AdminSettingsPanel />
</ChatPageShell>
<TooltipProvider delayDuration={150}>
<div className="grid gap-4 lg:grid-cols-2">
{sections.map((section) => (
<Tooltip key={section.href}>
<TooltipTrigger asChild>
<Link href={section.href}>
<Card className="h-full border-border/60 bg-card/80 transition-colors hover:border-primary/30 hover:bg-primary/5">
<CardHeader className="space-y-2">
<CardTitle>{section.title}</CardTitle>
<CardDescription>{section.description}</CardDescription>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
Open the focused {section.title.toLowerCase()} admin route.
</CardContent>
</Card>
</Link>
</TooltipTrigger>
<TooltipContent className="max-w-xs">
{section.description}
</TooltipContent>
</Tooltip>
))}
</div>
</TooltipProvider>
)
}
5 changes: 5 additions & 0 deletions app/chat/admin/runtime/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AdminSettingsPanel } from '../_components/admin-management-panel'

export default function AdminRuntimeSettingsPage() {
return <AdminSettingsPanel section="runtime" />
}
5 changes: 5 additions & 0 deletions app/chat/admin/users/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AdminSettingsPanel } from '../_components/admin-management-panel'

export default function AdminUsersSettingsPage() {
return <AdminSettingsPanel section="users" />
}
35 changes: 24 additions & 11 deletions app/chat/components/chat-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ChatInput } from './chat-input'
import { ChatSidebar } from './chat-sidebar'
import { MainSidebar } from './main-sidebar'
import { SidebarProvider, SidebarInset } from '@/ui/sidebar'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/ui/resizable'
import { useChatContext } from '../providers/chat-context-hooks'
import { cn } from '@/lib/utils'

Expand All @@ -23,18 +24,30 @@ export function ChatLayout() {
<SidebarProvider className="flex flex-1 overflow-hidden min-h-0 bg-background w-full">
<MainSidebar />
<SidebarInset className="flex flex-1 flex-col overflow-hidden bg-background m-0 rounded-none border-x-0 relative min-w-0">
<div className="flex h-full w-full flex-1 overflow-hidden">
<div className="flex flex-1 flex-col overflow-hidden relative min-w-0">
<ChatMessages />
<ChatInput />
</div>

{!isFocusMode && (
<div className="w-95 h-full border-l bg-card/30 backdrop-blur-xl overflow-hidden min-w-95 shrink-0">
<ChatSidebar />
<ResizablePanelGroup className="flex h-full w-full min-h-0 min-w-0 overflow-hidden">
<ResizablePanel defaultSize={72} minSize={55} className="min-w-0">
<div className="flex h-full min-h-0 flex-col overflow-hidden relative min-w-0">
<ChatMessages />
<ChatInput />
</div>
)}
</div>
</ResizablePanel>

{!isFocusMode ? (
<>
<ResizableHandle withHandle className="hidden xl:flex" />
<ResizablePanel
defaultSize={28}
minSize={20}
maxSize={40}
className="min-w-80 border-l bg-card/30 backdrop-blur-xl"
>
<div className="h-full min-h-0 overflow-hidden">
<ChatSidebar />
</div>
</ResizablePanel>
</>
) : null}
</ResizablePanelGroup>
</SidebarInset>
</SidebarProvider>
</main>
Expand Down
Loading
Loading