clawport-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +35 -0
- package/BRANDING.md +131 -0
- package/CLAUDE.md +252 -0
- package/README.md +262 -0
- package/SETUP.md +337 -0
- package/app/agents/[id]/page.tsx +727 -0
- package/app/api/agents/route.ts +12 -0
- package/app/api/chat/[id]/route.ts +139 -0
- package/app/api/cron-runs/route.ts +13 -0
- package/app/api/crons/route.ts +12 -0
- package/app/api/kanban/chat/[id]/route.ts +119 -0
- package/app/api/kanban/chat-history/[ticketId]/route.ts +36 -0
- package/app/api/memory/route.ts +12 -0
- package/app/api/transcribe/route.ts +37 -0
- package/app/api/tts/route.ts +42 -0
- package/app/chat/[id]/page.tsx +10 -0
- package/app/chat/page.tsx +200 -0
- package/app/crons/page.tsx +870 -0
- package/app/docs/page.tsx +399 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +692 -0
- package/app/kanban/page.tsx +327 -0
- package/app/layout.tsx +45 -0
- package/app/memory/page.tsx +685 -0
- package/app/page.tsx +817 -0
- package/app/providers.tsx +37 -0
- package/app/settings/page.tsx +901 -0
- package/app/settings-provider.tsx +209 -0
- package/components/AgentAvatar.tsx +54 -0
- package/components/AgentNode.tsx +122 -0
- package/components/Breadcrumbs.tsx +126 -0
- package/components/DynamicFavicon.tsx +62 -0
- package/components/ErrorState.tsx +97 -0
- package/components/FeedView.tsx +494 -0
- package/components/GlobalSearch.tsx +571 -0
- package/components/GridView.tsx +532 -0
- package/components/ManorMap.tsx +157 -0
- package/components/MobileSidebar.tsx +251 -0
- package/components/NavLinks.tsx +271 -0
- package/components/OnboardingWizard.tsx +1067 -0
- package/components/Sidebar.tsx +115 -0
- package/components/ThemeToggle.tsx +108 -0
- package/components/chat/AgentList.tsx +537 -0
- package/components/chat/ConversationView.tsx +1047 -0
- package/components/chat/FileAttachment.tsx +140 -0
- package/components/chat/MediaPreview.tsx +111 -0
- package/components/chat/VoiceMessage.tsx +139 -0
- package/components/crons/PipelineGraph.tsx +327 -0
- package/components/crons/WeeklySchedule.tsx +630 -0
- package/components/docs/AgentsSection.tsx +209 -0
- package/components/docs/ApiReferenceSection.tsx +256 -0
- package/components/docs/ArchitectureSection.tsx +221 -0
- package/components/docs/ComponentsSection.tsx +253 -0
- package/components/docs/CronSystemSection.tsx +235 -0
- package/components/docs/DocSection.tsx +346 -0
- package/components/docs/GettingStartedSection.tsx +169 -0
- package/components/docs/ThemingSection.tsx +257 -0
- package/components/docs/TroubleshootingSection.tsx +200 -0
- package/components/kanban/AgentPicker.tsx +321 -0
- package/components/kanban/CreateTicketModal.tsx +333 -0
- package/components/kanban/KanbanBoard.tsx +70 -0
- package/components/kanban/KanbanColumn.tsx +166 -0
- package/components/kanban/TicketCard.tsx +245 -0
- package/components/kanban/TicketDetailPanel.tsx +850 -0
- package/components/ui/badge.tsx +48 -0
- package/components/ui/button.tsx +64 -0
- package/components/ui/card.tsx +92 -0
- package/components/ui/dialog.tsx +158 -0
- package/components/ui/scroll-area.tsx +58 -0
- package/components/ui/separator.tsx +28 -0
- package/components/ui/skeleton.tsx +27 -0
- package/components/ui/tabs.tsx +91 -0
- package/components/ui/tooltip.tsx +57 -0
- package/components.json +23 -0
- package/docs/API.md +648 -0
- package/docs/COMPONENTS.md +1059 -0
- package/docs/THEMING.md +795 -0
- package/lib/agents-registry.ts +35 -0
- package/lib/agents.json +282 -0
- package/lib/agents.test.ts +367 -0
- package/lib/agents.ts +32 -0
- package/lib/anthropic.test.ts +422 -0
- package/lib/anthropic.ts +220 -0
- package/lib/api-error.ts +16 -0
- package/lib/audio-recorder.test.ts +72 -0
- package/lib/audio-recorder.ts +169 -0
- package/lib/conversations.test.ts +331 -0
- package/lib/conversations.ts +117 -0
- package/lib/cron-pipelines.test.ts +69 -0
- package/lib/cron-pipelines.ts +58 -0
- package/lib/cron-runs.test.ts +118 -0
- package/lib/cron-runs.ts +67 -0
- package/lib/cron-utils.test.ts +222 -0
- package/lib/cron-utils.ts +160 -0
- package/lib/crons.test.ts +502 -0
- package/lib/crons.ts +114 -0
- package/lib/env.test.ts +44 -0
- package/lib/env.ts +14 -0
- package/lib/kanban/automation.test.ts +245 -0
- package/lib/kanban/automation.ts +143 -0
- package/lib/kanban/chat-store.test.ts +149 -0
- package/lib/kanban/chat-store.ts +81 -0
- package/lib/kanban/store.test.ts +238 -0
- package/lib/kanban/store.ts +98 -0
- package/lib/kanban/types.ts +50 -0
- package/lib/kanban/useAgentWork.ts +78 -0
- package/lib/memory.ts +45 -0
- package/lib/multimodal.test.ts +219 -0
- package/lib/multimodal.ts +68 -0
- package/lib/pipeline.integration.test.ts +343 -0
- package/lib/sanitize.ts +194 -0
- package/lib/settings.test.ts +137 -0
- package/lib/settings.ts +94 -0
- package/lib/styles.ts +24 -0
- package/lib/themes.ts +9 -0
- package/lib/transcribe.test.ts +141 -0
- package/lib/transcribe.ts +111 -0
- package/lib/types.ts +66 -0
- package/lib/utils.ts +6 -0
- package/lib/validation.test.ts +132 -0
- package/lib/validation.ts +80 -0
- package/next.config.ts +7 -0
- package/package.json +56 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/scripts/setup.mjs +215 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +17 -0
package/.env.example
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# ClawPort — Environment Configuration
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Copy this file to .env.local and fill in your values:
|
|
5
|
+
# cp .env.example .env.local
|
|
6
|
+
#
|
|
7
|
+
# See SETUP.md for detailed instructions on finding each value.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# Required
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
# Path to your OpenClaw workspace directory.
|
|
15
|
+
# Default location: ~/.openclaw/workspace
|
|
16
|
+
# Find yours: ls ~/.openclaw/workspace
|
|
17
|
+
WORKSPACE_PATH=/Users/yourname/.openclaw/workspace
|
|
18
|
+
|
|
19
|
+
# Path to the openclaw CLI binary.
|
|
20
|
+
# Find yours: which openclaw
|
|
21
|
+
OPENCLAW_BIN=/usr/local/bin/openclaw
|
|
22
|
+
|
|
23
|
+
# OpenClaw gateway authentication token.
|
|
24
|
+
# All API calls (chat, vision, TTS, transcription) use this token.
|
|
25
|
+
# Find yours: openclaw gateway status
|
|
26
|
+
OPENCLAW_GATEWAY_TOKEN=your-gateway-token-here
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Optional
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
# ElevenLabs API key — enables voice indicators on agent profiles.
|
|
33
|
+
# Get one at: https://elevenlabs.io
|
|
34
|
+
# Leave blank or remove this line if you don't need voice features.
|
|
35
|
+
# ELEVENLABS_API_KEY=sk_your-elevenlabs-key-here
|
package/BRANDING.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Branding Reference
|
|
2
|
+
|
|
3
|
+
Current brand name: **ClawPort**
|
|
4
|
+
|
|
5
|
+
This document maps every location in the codebase where the brand name appears. Use it as a checklist when rebranding.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. User-Facing Text (UI strings, page titles)
|
|
10
|
+
|
|
11
|
+
These are what end users see. Change these first during a rebrand.
|
|
12
|
+
|
|
13
|
+
| File | Line(s) | What | Current Value |
|
|
14
|
+
|------|---------|------|---------------|
|
|
15
|
+
| `app/layout.tsx` | ~10 | `<title>` metadata | `"ClawPort -- Command Centre"` |
|
|
16
|
+
| `components/Sidebar.tsx` | ~84 | Sidebar header fallback name | `'ClawPort'` |
|
|
17
|
+
| `components/MobileSidebar.tsx` | ~138, ~226 | Mobile sidebar fallback name | `'ClawPort'` |
|
|
18
|
+
| `components/OnboardingWizard.tsx` | ~271 | Welcome screen heading | `"Welcome to ClawPort"` |
|
|
19
|
+
| `components/OnboardingWizard.tsx` | ~282 | Welcome screen description | `"A visual command centre for your AI agent team..."` |
|
|
20
|
+
| `components/OnboardingWizard.tsx` | ~572 | Name input placeholder | `"ClawPort"` |
|
|
21
|
+
| `components/OnboardingWizard.tsx` | ~675 | Sidebar preview fallback | `'ClawPort'` |
|
|
22
|
+
| `components/GlobalSearch.tsx` | ~349, ~389-390 | Search modal aria-label + placeholder | `"Search ClawPort"` / `"Search ClawPort..."` |
|
|
23
|
+
| `app/chat/page.tsx` | ~173 | Chat page header | `"ClawPort Messages"` |
|
|
24
|
+
| `lib/agents.json` | ~5, ~14 | Default root agent title + description | `"ClawPort Orchestrator"` |
|
|
25
|
+
| `scripts/setup.mjs` | ~77 | Setup script banner | `"ClawPort Setup"` |
|
|
26
|
+
| `scripts/setup.mjs` | ~184 | Generated .env.local comment | `"# ClawPort -- generated by npm run setup"` |
|
|
27
|
+
| `scripts/setup.mjs` | ~205 | Post-setup instructions | `"Start ClawPort"` |
|
|
28
|
+
| `.env.example` | ~2 | File header comment | `"# ClawPort -- Environment Configuration"` |
|
|
29
|
+
|
|
30
|
+
## 2. Internal Code Identifiers
|
|
31
|
+
|
|
32
|
+
TypeScript interfaces, function names, component names, and variable names. These are developer-facing only. Renaming requires updating all imports and references.
|
|
33
|
+
|
|
34
|
+
| Identifier | Files | Notes |
|
|
35
|
+
|------------|-------|-------|
|
|
36
|
+
| `ClawPortSettings` (interface) | `lib/settings.ts`, `app/settings-provider.tsx`, `docs/THEMING.md`, `docs/COMPONENTS.md` | Core settings type. 20+ references. |
|
|
37
|
+
| `portalName` (field) | `lib/settings.ts`, `app/settings-provider.tsx`, `components/Sidebar.tsx`, `MobileSidebar.tsx`, `OnboardingWizard.tsx`, `app/settings/page.tsx`, `DynamicFavicon.tsx` | Settings field for custom name. |
|
|
38
|
+
| `portalSubtitle` (field) | Same as `portalName` | Settings field for subtitle. |
|
|
39
|
+
| `portalEmoji` (field) | Same as `portalName` | Settings field for emoji. |
|
|
40
|
+
| `portalIcon` (field) | Same as `portalName` | Settings field for uploaded icon image. |
|
|
41
|
+
| `setPortalName` (setter) | `app/settings-provider.tsx`, `OnboardingWizard.tsx`, `app/settings/page.tsx` | Context setter callback. |
|
|
42
|
+
| `setPortalSubtitle` (setter) | Same as `setPortalName` | |
|
|
43
|
+
| `setPortalEmoji` (setter) | Same as `setPortalName` | |
|
|
44
|
+
| `setPortalIcon` (setter) | Same as `setPortalName` | |
|
|
45
|
+
| `OrgMap` (component) | `components/ManorMap.tsx`, `app/page.tsx`, `docs/COMPONENTS.md` | React Flow org chart component. |
|
|
46
|
+
| `OrgMapProps` (interface) | `components/ManorMap.tsx` | Props type for OrgMap. |
|
|
47
|
+
| `HomePage` (component) | `app/page.tsx` | Home page component. |
|
|
48
|
+
| `handleIconUpload` (function) | `app/settings/page.tsx` | Icon upload handler. |
|
|
49
|
+
| `iconInputRef` (ref) | `app/settings/page.tsx` | File input ref. |
|
|
50
|
+
|
|
51
|
+
## 3. localStorage Keys
|
|
52
|
+
|
|
53
|
+
Changing these breaks existing users' saved data. Requires a migration function or accept data loss.
|
|
54
|
+
|
|
55
|
+
| Key | File(s) | Purpose |
|
|
56
|
+
|-----|---------|---------|
|
|
57
|
+
| `clawport-settings` | `lib/settings.ts` | All user settings (name, subtitle, emoji, icon, accent, etc.) |
|
|
58
|
+
| `clawport-theme` | `app/providers.tsx` | Selected theme ID |
|
|
59
|
+
| `clawport-onboarded` | `components/OnboardingWizard.tsx` | First-run completion flag |
|
|
60
|
+
| `clawport-conversations` | `lib/conversations.ts` | Chat message history per agent |
|
|
61
|
+
| `clawport-kanban` | `lib/kanban/store.ts` | Kanban board state |
|
|
62
|
+
|
|
63
|
+
## 4. Custom Events
|
|
64
|
+
|
|
65
|
+
| Event Name | File(s) | Purpose |
|
|
66
|
+
|------------|---------|---------|
|
|
67
|
+
| `clawport:open-search` | `components/Sidebar.tsx`, `components/GlobalSearch.tsx` | Triggers Cmd+K search modal |
|
|
68
|
+
|
|
69
|
+
## 5. API / Session Keys
|
|
70
|
+
|
|
71
|
+
| Key | File | Purpose |
|
|
72
|
+
|-----|------|---------|
|
|
73
|
+
| `agent:main:clawport` | `lib/anthropic.ts` | Default session key for OpenClaw gateway calls |
|
|
74
|
+
| `clawport-${Date.now()}-...` | `lib/anthropic.ts` | Idempotency key prefix for chat.send |
|
|
75
|
+
|
|
76
|
+
## 6. Package / Repository
|
|
77
|
+
|
|
78
|
+
| Location | Current Value |
|
|
79
|
+
|----------|---------------|
|
|
80
|
+
| `package.json` `name` | `clawport` |
|
|
81
|
+
| `package-lock.json` `name` | `clawport` |
|
|
82
|
+
| Git clone URLs in docs | `https://github.com/openclaw/clawport.git` |
|
|
83
|
+
|
|
84
|
+
## 7. Workspace Paths
|
|
85
|
+
|
|
86
|
+
The user's agent registry override lives at `$WORKSPACE_PATH/clawport/agents.json`. This path is referenced in:
|
|
87
|
+
|
|
88
|
+
| File | What |
|
|
89
|
+
|------|------|
|
|
90
|
+
| `lib/agents-registry.ts` | `join(workspacePath, 'clawport', 'agents.json')` |
|
|
91
|
+
| Multiple test files | Mock paths like `/tmp/test-workspace/clawport/agents.json` |
|
|
92
|
+
| Documentation | Setup instructions referencing `$WORKSPACE_PATH/clawport/` |
|
|
93
|
+
|
|
94
|
+
## 8. Documentation Files
|
|
95
|
+
|
|
96
|
+
Every `.md` file contains brand references. Full list:
|
|
97
|
+
|
|
98
|
+
| File | Approximate Occurrences |
|
|
99
|
+
|------|------------------------|
|
|
100
|
+
| `README.md` | ~20 |
|
|
101
|
+
| `SETUP.md` | ~25 |
|
|
102
|
+
| `CLAUDE.md` | ~20 |
|
|
103
|
+
| `docs/API.md` | ~5 |
|
|
104
|
+
| `docs/THEMING.md` | ~30 |
|
|
105
|
+
| `docs/COMPONENTS.md` | ~35 |
|
|
106
|
+
| `.env.example` | 1 |
|
|
107
|
+
|
|
108
|
+
## 9. Test Files
|
|
109
|
+
|
|
110
|
+
Tests reference brand strings in mock data and localStorage keys:
|
|
111
|
+
|
|
112
|
+
| File | What |
|
|
113
|
+
|------|------|
|
|
114
|
+
| `lib/settings.test.ts` | `clawport-settings` key, `portalName`/`portalSubtitle`/`portalEmoji`/`portalIcon` fields |
|
|
115
|
+
| `lib/agents.test.ts` | `clawport/agents.json` paths, "ClawPort Orchestrator" in mock data |
|
|
116
|
+
| `lib/conversations.test.ts` | `clawport-conversations` key |
|
|
117
|
+
| `lib/kanban/store.test.ts` | `clawport-kanban` key |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Rebrand Checklist
|
|
122
|
+
|
|
123
|
+
1. **User-facing text** (Section 1) -- find-and-replace the display name
|
|
124
|
+
2. **Documentation** (Section 8) -- update all .md files
|
|
125
|
+
3. **Package name** (Section 6) -- update package.json, re-run npm install
|
|
126
|
+
4. **Internal identifiers** (Section 2) -- rename interfaces, components, functions, fields
|
|
127
|
+
5. **localStorage keys** (Section 3) -- add migration in `loadSettings()` to read old keys
|
|
128
|
+
6. **Custom events** (Section 4) -- rename event strings
|
|
129
|
+
7. **API keys** (Section 5) -- update session key and idempotency prefix
|
|
130
|
+
8. **Workspace paths** (Section 7) -- update `agents-registry.ts` path, support both old/new
|
|
131
|
+
9. **Test files** (Section 9) -- update all mock data and key references
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# ClawPort -- Developer Guide
|
|
2
|
+
|
|
3
|
+
## Quick Reference
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run setup # Auto-detect OpenClaw config, write .env.local
|
|
7
|
+
npm run dev # Start dev server (Turbopack, port 3000)
|
|
8
|
+
npm test # Run all 288 tests via Vitest (17 suites)
|
|
9
|
+
npx tsc --noEmit # Type-check (expect 0 errors)
|
|
10
|
+
npx next build # Production build
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Project Overview
|
|
14
|
+
|
|
15
|
+
ClawPort is a Next.js 16 dashboard for managing OpenClaw AI agents. It provides an org chart (Org Map), direct agent chat with multimodal support, cron monitoring, and memory browsing. All AI calls route through the OpenClaw gateway -- no separate API keys needed.
|
|
16
|
+
|
|
17
|
+
## Tech Stack
|
|
18
|
+
|
|
19
|
+
- Next.js 16.1.6 (App Router, Turbopack)
|
|
20
|
+
- React 19.2.3, TypeScript 5
|
|
21
|
+
- Tailwind CSS 4 with CSS custom properties for theming
|
|
22
|
+
- Vitest 4 with jsdom environment
|
|
23
|
+
- OpenAI SDK (routed to Claude via OpenClaw gateway at localhost:18789)
|
|
24
|
+
- React Flow (@xyflow/react) for org chart
|
|
25
|
+
|
|
26
|
+
## Environment Variables
|
|
27
|
+
|
|
28
|
+
```env
|
|
29
|
+
WORKSPACE_PATH # Required -- path to .openclaw/workspace
|
|
30
|
+
OPENCLAW_BIN # Required -- path to openclaw binary
|
|
31
|
+
OPENCLAW_GATEWAY_TOKEN # Required -- gateway auth token
|
|
32
|
+
ELEVENLABS_API_KEY # Optional -- voice indicators
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run `npm run setup` to auto-detect all required values from your local OpenClaw installation.
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
### Agent Registry Resolution
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
loadRegistry() checks:
|
|
43
|
+
1. $WORKSPACE_PATH/clawport/agents.json (user override)
|
|
44
|
+
2. Bundled lib/agents.json (default)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`lib/agents-registry.ts` exports `loadRegistry()`. `lib/agents.ts` calls it to build the full agent list (merging in SOUL.md content from the workspace). Users customize their agent team by dropping an `agents.json` into their workspace -- no source edits needed.
|
|
48
|
+
|
|
49
|
+
### operatorName Flow
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
OnboardingWizard / Settings page
|
|
53
|
+
-> ClawPortSettings.operatorName (localStorage)
|
|
54
|
+
-> settings-provider.tsx (React context)
|
|
55
|
+
-> NavLinks.tsx (dynamic initials + display name)
|
|
56
|
+
-> ConversationView.tsx (sends operatorName in POST body)
|
|
57
|
+
-> /api/chat/[id] route (injects into system prompt: "You are speaking with {operatorName}")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
No hardcoded operator names anywhere. Falls back to "Operator" / "??" when unset.
|
|
61
|
+
|
|
62
|
+
### Chat Pipeline (Text)
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Client -> POST /api/chat/[id] -> OpenAI SDK -> localhost:18789/v1/chat/completions -> Claude
|
|
66
|
+
(streaming SSE response)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Chat Pipeline (Images/Vision)
|
|
70
|
+
|
|
71
|
+
The gateway's HTTP endpoint strips image_url content. Vision uses the CLI agent pipeline:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Client resizes image to 1200px max (Canvas API)
|
|
75
|
+
-> base64 data URL in message
|
|
76
|
+
-> POST /api/chat/[id]
|
|
77
|
+
-> Detects image in LATEST user message only (not history)
|
|
78
|
+
-> execFile: openclaw gateway call chat.send --params <json> --token <token>
|
|
79
|
+
-> Polls: openclaw gateway call chat.history every 2s
|
|
80
|
+
-> Matches response by timestamp >= sendTs
|
|
81
|
+
-> Returns assistant text via SSE
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Key files: `lib/anthropic.ts` (send + poll logic), `app/api/chat/[id]/route.ts` (routing)
|
|
85
|
+
|
|
86
|
+
**Why send-then-poll?** `chat.send` is async -- it returns `{runId, status: "started"}` immediately. The `--expect-final` flag doesn't block for this method. We poll `chat.history` until the assistant's response appears.
|
|
87
|
+
|
|
88
|
+
**Why CLI and not WebSocket?** The gateway WebSocket requires device keypair signing for `operator.write` scope (needed by `chat.send`). The CLI has the device keys; custom clients don't.
|
|
89
|
+
|
|
90
|
+
**Why resize to 1200px?** macOS ARG_MAX is 1MB. Unresized photos can produce multi-MB base64 that exceeds CLI argument limits (E2BIG error). 1200px JPEG at 0.85 quality keeps base64 well under 1MB.
|
|
91
|
+
|
|
92
|
+
### Voice Message Pipeline
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
Browser MediaRecorder (webm/opus or mp4)
|
|
96
|
+
-> AudioContext AnalyserNode captures waveform (40-60 samples)
|
|
97
|
+
-> Stop -> audioBlob + waveform data
|
|
98
|
+
-> POST /api/transcribe (Whisper via gateway)
|
|
99
|
+
-> Transcription text sent as message content
|
|
100
|
+
-> Audio data URL + waveform stored in message for playback
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Key files: `lib/audio-recorder.ts`, `lib/transcribe.ts`, `components/chat/VoiceMessage.tsx`
|
|
104
|
+
|
|
105
|
+
### Conversation Persistence
|
|
106
|
+
|
|
107
|
+
Messages stored in localStorage as JSON. Media attachments are base64 data URLs (not blob URLs -- those don't survive reload). The `conversations.ts` module provides `addMessage()`, `updateLastMessage()`, and `parseMedia()`.
|
|
108
|
+
|
|
109
|
+
### Theming
|
|
110
|
+
|
|
111
|
+
Five themes defined via CSS custom properties in `app/globals.css`:
|
|
112
|
+
- Dark (default), Glass, Color, Light, System
|
|
113
|
+
- Components use semantic tokens: `--bg`, `--text-primary`, `--accent`, `--separator`, etc.
|
|
114
|
+
- Theme state managed by `app/providers.tsx` ThemeProvider (localStorage)
|
|
115
|
+
|
|
116
|
+
## Onboarding
|
|
117
|
+
|
|
118
|
+
`components/OnboardingWizard.tsx` -- 5-step first-run setup wizard:
|
|
119
|
+
|
|
120
|
+
1. **Welcome** -- portal name, subtitle, operator name (with live sidebar preview)
|
|
121
|
+
2. **Theme** -- pick from available themes (applies live)
|
|
122
|
+
3. **Accent Color** -- color preset grid
|
|
123
|
+
4. **Voice Chat** -- microphone permission test (optional)
|
|
124
|
+
5. **Overview** -- feature summary (Agent Map, Chat, Kanban, Crons, Memory)
|
|
125
|
+
|
|
126
|
+
**First-run detection:** checks `localStorage('clawport-onboarded')`. If absent, wizard shows automatically.
|
|
127
|
+
|
|
128
|
+
**Mounting:** `OnboardingWizard` is rendered in `app/layout.tsx` (always present, self-hides when not needed).
|
|
129
|
+
|
|
130
|
+
**Re-run:** settings page has a button that renders `<OnboardingWizard forceOpen onClose={...} />`. When `forceOpen` is true, the wizard pre-populates from current settings and does not set `clawport-onboarded` on completion.
|
|
131
|
+
|
|
132
|
+
## Environment Safety
|
|
133
|
+
|
|
134
|
+
`lib/env.ts` exports `requireEnv(name)` -- throws a clear error with the missing variable name and a pointer to `.env.example`.
|
|
135
|
+
|
|
136
|
+
**Critical pattern:** call `requireEnv()` inside functions, never at module top level. This prevents imports from crashing during `next build` or test runs when env vars are not set.
|
|
137
|
+
|
|
138
|
+
Used by: `lib/memory.ts`, `lib/cron-runs.ts`, `lib/kanban/chat-store.ts`, `lib/crons.ts`
|
|
139
|
+
|
|
140
|
+
## File Map
|
|
141
|
+
|
|
142
|
+
### API Routes
|
|
143
|
+
|
|
144
|
+
| Route | Method | Purpose |
|
|
145
|
+
|-------|--------|---------|
|
|
146
|
+
| `/api/agents` | GET | All agents from registry + SOUL.md |
|
|
147
|
+
| `/api/chat/[id]` | POST | Agent chat -- text (streaming) or vision (send+poll) |
|
|
148
|
+
| `/api/crons` | GET | Cron jobs via `openclaw cron list --json` |
|
|
149
|
+
| `/api/memory` | GET | Memory files from workspace |
|
|
150
|
+
| `/api/tts` | POST | Text-to-speech via OpenClaw |
|
|
151
|
+
| `/api/transcribe` | POST | Audio transcription via Whisper |
|
|
152
|
+
|
|
153
|
+
### Core Libraries
|
|
154
|
+
|
|
155
|
+
| File | Purpose |
|
|
156
|
+
|------|---------|
|
|
157
|
+
| `lib/agents.ts` | Agent list builder -- calls `loadRegistry()`, merges SOUL.md |
|
|
158
|
+
| `lib/agents-registry.ts` | `loadRegistry()` -- workspace override -> bundled fallback |
|
|
159
|
+
| `lib/agents.json` | Bundled default agent registry |
|
|
160
|
+
| `lib/anthropic.ts` | Vision pipeline: `hasImageContent`, `extractImageAttachments`, `buildTextPrompt`, `sendViaOpenClaw` (send + poll), `execCli` |
|
|
161
|
+
| `lib/audio-recorder.ts` | `createAudioRecorder()` -- MediaRecorder + waveform via AnalyserNode |
|
|
162
|
+
| `lib/conversations.ts` | Conversation store with localStorage persistence |
|
|
163
|
+
| `lib/crons.ts` | Cron data fetching via CLI |
|
|
164
|
+
| `lib/env.ts` | `requireEnv(name)` -- safe env var access with clear errors |
|
|
165
|
+
| `lib/multimodal.ts` | `buildApiContent()` -- converts Message+Media to OpenAI API format |
|
|
166
|
+
| `lib/settings.ts` | `ClawPortSettings` type, `loadSettings()`, `saveSettings()` (localStorage) |
|
|
167
|
+
| `lib/transcribe.ts` | `transcribe(audioBlob)` -- Whisper API with graceful fallback |
|
|
168
|
+
| `lib/validation.ts` | `validateChatMessages()` -- validates text + multimodal content arrays |
|
|
169
|
+
|
|
170
|
+
### Chat Components
|
|
171
|
+
|
|
172
|
+
| Component | Purpose |
|
|
173
|
+
|-----------|---------|
|
|
174
|
+
| `ConversationView.tsx` | Main chat: messages, input, recording, paste/drop, file staging. Sends `operatorName` in POST body. |
|
|
175
|
+
| `VoiceMessage.tsx` | Waveform playback: play/pause + animated bar visualization |
|
|
176
|
+
| `FileAttachment.tsx` | File bubble: icon by type + name + size + download |
|
|
177
|
+
| `MediaPreview.tsx` | Pre-send strip of staged attachments with remove buttons |
|
|
178
|
+
| `AgentList.tsx` | Desktop agent sidebar with unread badges |
|
|
179
|
+
|
|
180
|
+
### Other Components
|
|
181
|
+
|
|
182
|
+
| Component | Purpose |
|
|
183
|
+
|-----------|---------|
|
|
184
|
+
| `OnboardingWizard.tsx` | 5-step first-run setup wizard (name, theme, accent, mic, overview) |
|
|
185
|
+
| `NavLinks.tsx` | Sidebar nav with dynamic operator initials + name from settings |
|
|
186
|
+
| `Sidebar.tsx` | Sidebar layout shell |
|
|
187
|
+
| `AgentAvatar.tsx` | Agent emoji/image avatar with optional background |
|
|
188
|
+
| `DynamicFavicon.tsx` | Updates favicon based on portal emoji/icon settings |
|
|
189
|
+
|
|
190
|
+
### Scripts
|
|
191
|
+
|
|
192
|
+
| File | Purpose |
|
|
193
|
+
|------|---------|
|
|
194
|
+
| `scripts/setup.mjs` | `npm run setup` -- auto-detects WORKSPACE_PATH, OPENCLAW_BIN, gateway token; writes `.env.local` |
|
|
195
|
+
|
|
196
|
+
## Testing
|
|
197
|
+
|
|
198
|
+
17 test suites, 288 tests total. All in `lib/` directory.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npx vitest run # All tests
|
|
202
|
+
npx vitest run lib/anthropic.test.ts # Single suite
|
|
203
|
+
npx vitest --watch # Watch mode
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Key test patterns:
|
|
207
|
+
- `vi.mock('child_process')` for CLI tests (anthropic.ts)
|
|
208
|
+
- `vi.useFakeTimers({ shouldAdvanceTime: true })` for polling tests
|
|
209
|
+
- `vi.stubEnv()` for environment variable tests
|
|
210
|
+
- jsdom environment for DOM-dependent tests
|
|
211
|
+
|
|
212
|
+
## Conventions
|
|
213
|
+
|
|
214
|
+
- No external charting/media libraries -- native Web APIs (Canvas, MediaRecorder, AudioContext)
|
|
215
|
+
- Base64 data URLs for all persisted media (not blob URLs)
|
|
216
|
+
- CSS custom properties for theming -- no Tailwind color classes directly
|
|
217
|
+
- Inline styles referencing CSS vars (e.g., `style={{ color: 'var(--text-primary)' }}`)
|
|
218
|
+
- Tests colocated with source: `lib/foo.ts` + `lib/foo.test.ts`
|
|
219
|
+
- Agent chat uses `claude-sonnet-4-6` model via OpenClaw gateway
|
|
220
|
+
- No em dashes in agent responses (enforced via system prompt)
|
|
221
|
+
- Call `requireEnv()` inside functions, not at module top level
|
|
222
|
+
- No hardcoded operator names -- use `operatorName` from settings context
|
|
223
|
+
|
|
224
|
+
## Common Tasks
|
|
225
|
+
|
|
226
|
+
### Add a new agent
|
|
227
|
+
Edit `lib/agents.json` (or drop a custom `agents.json` into `$WORKSPACE_PATH/clawport/`). Auto-appears in map, chat, and detail pages.
|
|
228
|
+
|
|
229
|
+
### Customize agents for your workspace
|
|
230
|
+
Create `$WORKSPACE_PATH/clawport/agents.json` with your own agent entries. ClawPort loads this instead of the bundled default. Format matches `lib/agents.json`.
|
|
231
|
+
|
|
232
|
+
### Re-run onboarding wizard
|
|
233
|
+
Go to Settings page and click "Re-run Setup Wizard". This opens the wizard with `forceOpen` so it pre-populates current values and does not reset the `clawport-onboarded` flag.
|
|
234
|
+
|
|
235
|
+
### Add a new setting field
|
|
236
|
+
1. Add the field to `ClawPortSettings` interface in `lib/settings.ts`
|
|
237
|
+
2. Add a default value in `DEFAULTS`
|
|
238
|
+
3. Add parsing logic in `loadSettings()`
|
|
239
|
+
4. Add a setter method in `app/settings-provider.tsx`
|
|
240
|
+
5. Consume via `useSettings()` hook in components
|
|
241
|
+
|
|
242
|
+
### Change the chat model
|
|
243
|
+
Edit `app/api/chat/[id]/route.ts` -- change the `model` field in `openai.chat.completions.create()`.
|
|
244
|
+
|
|
245
|
+
### Add a new theme
|
|
246
|
+
Add a `[data-theme="name"]` block in `app/globals.css` with all CSS custom properties. Add the theme ID to `lib/themes.ts`.
|
|
247
|
+
|
|
248
|
+
### Debug image pipeline
|
|
249
|
+
1. Check server console for `sendViaOpenClaw execFile error:` or `sendViaOpenClaw: timed out`
|
|
250
|
+
2. Test CLI directly: `openclaw gateway call chat.send --params '{"sessionKey":"agent:main:clawport","idempotencyKey":"test","message":"describe","attachments":[]}' --token <token> --json`
|
|
251
|
+
3. Check history: `openclaw gateway call chat.history --params '{"sessionKey":"agent:main:clawport"}' --token <token> --json`
|
|
252
|
+
4. Verify gateway is running: `openclaw gateway call health --token <token>`
|
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# ClawPort
|
|
2
|
+
|
|
3
|
+
A visual command centre for your AI agent team.
|
|
4
|
+
|
|
5
|
+
ClawPort is an open-source dashboard for managing, monitoring, and talking directly to your [OpenClaw](https://openclaw.ai) AI agents. Built with Next.js 16, React 19, and a dark command-centre aesthetic with five themes.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
|
|
11
|
+
### Prerequisites
|
|
12
|
+
|
|
13
|
+
- [Node.js 22+](https://nodejs.org) (LTS recommended)
|
|
14
|
+
- [OpenClaw](https://openclaw.ai) installed and running
|
|
15
|
+
- OpenClaw gateway started (`openclaw gateway run`)
|
|
16
|
+
|
|
17
|
+
### Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Clone the repo
|
|
21
|
+
git clone https://github.com/openclaw/clawport.git
|
|
22
|
+
cd clawport
|
|
23
|
+
|
|
24
|
+
# Install dependencies
|
|
25
|
+
npm install
|
|
26
|
+
|
|
27
|
+
# Auto-detect your OpenClaw config and write .env.local
|
|
28
|
+
npm run setup
|
|
29
|
+
|
|
30
|
+
# Start the dev server
|
|
31
|
+
npm run dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Open [http://localhost:3000](http://localhost:3000). On first launch you'll see the **onboarding wizard**, which walks you through naming your portal, choosing a theme, and personalizing agent avatars.
|
|
35
|
+
|
|
36
|
+
See [SETUP.md](SETUP.md) for detailed environment configuration and troubleshooting.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
### Org Map
|
|
43
|
+
Interactive org chart of your entire agent team. Nodes show hierarchy, cron status, voice capabilities, and relationships at a glance. Powered by React Flow with BFS-based auto-layout.
|
|
44
|
+
|
|
45
|
+
### Chat (Call Box)
|
|
46
|
+
Full-featured messenger for direct agent conversations:
|
|
47
|
+
- **Streaming text chat** via Claude (through the OpenClaw gateway)
|
|
48
|
+
- **Image attachments** with vision -- agents can see and describe images
|
|
49
|
+
- **Voice messages** -- hold-to-record with waveform playback
|
|
50
|
+
- **File attachments** -- PDFs, docs, text files with type-aware rendering
|
|
51
|
+
- **Clipboard paste and drag-and-drop** for images
|
|
52
|
+
- **Clear chat** per agent
|
|
53
|
+
- Conversations persist to localStorage
|
|
54
|
+
|
|
55
|
+
### Agent Detail
|
|
56
|
+
Full profile: SOUL.md viewer, tool list, hierarchy, associated crons, voice ID, and direct chat link.
|
|
57
|
+
|
|
58
|
+
### Kanban
|
|
59
|
+
Task board for managing work across your agent team. Drag-and-drop cards with agent assignment and chat context.
|
|
60
|
+
|
|
61
|
+
### Cron Monitor
|
|
62
|
+
Live status of all scheduled jobs. Filter by status (all/ok/error/idle), sort errors to top, expand for error details. Auto-refreshes every 60 seconds.
|
|
63
|
+
|
|
64
|
+
### Memory Browser
|
|
65
|
+
Read team memory, long-term memory, and daily logs. Markdown rendering and JSON syntax highlighting built-in. Search, copy, and download support.
|
|
66
|
+
|
|
67
|
+
### Settings
|
|
68
|
+
Personalize your portal: custom name, subtitle, logo/emoji, accent color, agent avatar overrides, and theme selection. All settings persist in your browser.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
### Required Environment Variables
|
|
75
|
+
|
|
76
|
+
| Variable | Description |
|
|
77
|
+
|----------|-------------|
|
|
78
|
+
| `WORKSPACE_PATH` | Path to your OpenClaw workspace directory (default: `~/.openclaw/workspace`) |
|
|
79
|
+
| `OPENCLAW_BIN` | Path to the `openclaw` CLI binary |
|
|
80
|
+
| `OPENCLAW_GATEWAY_TOKEN` | Token that authenticates all API calls to the gateway |
|
|
81
|
+
|
|
82
|
+
### Optional Environment Variables
|
|
83
|
+
|
|
84
|
+
| Variable | Description |
|
|
85
|
+
|----------|-------------|
|
|
86
|
+
| `ELEVENLABS_API_KEY` | ElevenLabs API key for voice/TTS indicators on agent profiles |
|
|
87
|
+
|
|
88
|
+
No separate AI API keys are needed. All AI calls (chat, vision, TTS, transcription) route through the OpenClaw gateway.
|
|
89
|
+
|
|
90
|
+
See [SETUP.md](SETUP.md) for how to find each value.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Agent Customization
|
|
95
|
+
|
|
96
|
+
ClawPort ships with a bundled agent registry (`lib/agents.json`) as a working example. To use your own agents, create a file at:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
$WORKSPACE_PATH/clawport/agents.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
ClawPort checks for this file on every request. If it exists, it takes priority over the bundled registry. If it's missing or malformed, the bundled default is used as a fallback.
|
|
103
|
+
|
|
104
|
+
Each agent entry looks like this:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"id": "my-agent",
|
|
109
|
+
"name": "My Agent",
|
|
110
|
+
"title": "What they do",
|
|
111
|
+
"reportsTo": "parent-agent-id",
|
|
112
|
+
"directReports": [],
|
|
113
|
+
"soulPath": "agents/my-agent/SOUL.md",
|
|
114
|
+
"voiceId": null,
|
|
115
|
+
"color": "#06b6d4",
|
|
116
|
+
"emoji": "🤖",
|
|
117
|
+
"tools": ["read", "write"],
|
|
118
|
+
"memoryPath": null,
|
|
119
|
+
"description": "One-liner description of this agent."
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
See [SETUP.md](SETUP.md) for the full field reference and examples.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Architecture
|
|
128
|
+
|
|
129
|
+
### How Chat Works
|
|
130
|
+
|
|
131
|
+
Text messages go through the OpenClaw gateway's OpenAI-compatible endpoint (`/v1/chat/completions`) for streaming responses.
|
|
132
|
+
|
|
133
|
+
Image messages use a different pipeline because the gateway's HTTP endpoint strips image data. Instead, ClawPort uses the same path as Discord/Telegram channels:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
User attaches image
|
|
137
|
+
→ Client resizes to 1200px max (fits within OS arg limits)
|
|
138
|
+
→ Client converts to base64 data URL
|
|
139
|
+
→ POST /api/chat/[id] detects image in latest message
|
|
140
|
+
→ Server calls `openclaw gateway call chat.send` via CLI
|
|
141
|
+
→ Server polls `openclaw gateway call chat.history` every 2s
|
|
142
|
+
→ Agent processes image + text through Anthropic vision API
|
|
143
|
+
→ Response returned to client as SSE
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Voice messages are recorded in-browser using the MediaRecorder API, transcribed server-side via Whisper (through the gateway's `/v1/audio/transcriptions` endpoint), and sent as text with the audio waveform preserved for playback.
|
|
147
|
+
|
|
148
|
+
### Directory Structure
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
app/
|
|
152
|
+
page.tsx — Org Map (React Flow org chart)
|
|
153
|
+
chat/page.tsx — Multi-agent messenger
|
|
154
|
+
agents/[id]/page.tsx — Agent detail profile
|
|
155
|
+
kanban/page.tsx — Task board
|
|
156
|
+
crons/page.tsx — Cron job monitor
|
|
157
|
+
memory/page.tsx — Memory file browser
|
|
158
|
+
settings/page.tsx — ClawPort personalization
|
|
159
|
+
api/
|
|
160
|
+
agents/route.ts — GET agents from registry
|
|
161
|
+
chat/[id]/route.ts — POST chat (text + vision)
|
|
162
|
+
crons/route.ts — GET crons via CLI
|
|
163
|
+
memory/route.ts — GET memory files
|
|
164
|
+
tts/route.ts — POST text-to-speech
|
|
165
|
+
transcribe/route.ts — POST audio transcription
|
|
166
|
+
|
|
167
|
+
components/
|
|
168
|
+
OrgMap.tsx — React Flow graph with auto-layout
|
|
169
|
+
AgentNode.tsx — Custom node for the org chart
|
|
170
|
+
Sidebar.tsx — Desktop navigation sidebar
|
|
171
|
+
MobileSidebar.tsx — Mobile hamburger menu
|
|
172
|
+
ThemeToggle.tsx — Theme switcher (5 themes)
|
|
173
|
+
GlobalSearch.tsx — Cmd+K agent search
|
|
174
|
+
chat/
|
|
175
|
+
ConversationView.tsx — Message history + input with media
|
|
176
|
+
AgentList.tsx — Agent sidebar for chat
|
|
177
|
+
VoiceMessage.tsx — Waveform playback component
|
|
178
|
+
FileAttachment.tsx — File bubble with icon + download
|
|
179
|
+
MediaPreview.tsx — Pre-send attachment strip
|
|
180
|
+
|
|
181
|
+
lib/
|
|
182
|
+
agents.ts — Agent registry + SOUL.md reader
|
|
183
|
+
agents-registry.ts — Registry loader (workspace override or bundled)
|
|
184
|
+
agents.json — Bundled default agent registry
|
|
185
|
+
anthropic.ts — OpenClaw vision pipeline (chat.send + poll)
|
|
186
|
+
audio-recorder.ts — MediaRecorder + waveform extraction
|
|
187
|
+
conversations.ts — Client-side conversation store (localStorage)
|
|
188
|
+
crons.ts — Cron data via openclaw CLI
|
|
189
|
+
env.ts — Environment variable helper
|
|
190
|
+
memory.ts — Memory file reader
|
|
191
|
+
multimodal.ts — Message → API content format converter
|
|
192
|
+
sanitize.ts — HTML/markdown sanitization
|
|
193
|
+
settings.ts — ClawPort settings (localStorage)
|
|
194
|
+
transcribe.ts — Whisper transcription with fallback
|
|
195
|
+
validation.ts — Chat message validation
|
|
196
|
+
types.ts — Shared TypeScript types
|
|
197
|
+
themes.ts — Theme definitions
|
|
198
|
+
styles.ts — Semantic style constants
|
|
199
|
+
utils.ts — Tailwind merge utility
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Key Design Decisions
|
|
203
|
+
|
|
204
|
+
- **No separate API keys** -- All AI calls (chat, vision, TTS, transcription) route through the OpenClaw gateway. One subscription, one token.
|
|
205
|
+
- **No external charting/media libraries** -- Voice waveforms use plain div bars (not canvas), images resize via native Canvas API, all CSS uses Tailwind custom properties.
|
|
206
|
+
- **Client-side persistence** -- Conversations stored in localStorage with base64 data URLs. Blob URLs don't survive page reload; data URLs do.
|
|
207
|
+
- **Image resize before send** -- Images are resized client-side to max 1200px longest side before base64 encoding. This keeps the CLI argument payload under macOS's 1MB `ARG_MAX` limit.
|
|
208
|
+
- **Send-then-poll for vision** -- The gateway's `chat.send` is async (returns immediately). We poll `chat.history` every 2 seconds until the assistant response appears, matched by timestamp.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Themes
|
|
213
|
+
|
|
214
|
+
Five built-in themes, toggled via the sidebar button:
|
|
215
|
+
|
|
216
|
+
| Theme | Description |
|
|
217
|
+
|-------|-------------|
|
|
218
|
+
| **Dark** | Apple Dark Mode with warm blacks, gold accent |
|
|
219
|
+
| **Glass** | Frosted translucent panels on deep blue-black |
|
|
220
|
+
| **Color** | Vibrant purple-indigo gradients |
|
|
221
|
+
| **Light** | Apple Light Mode, clean whites |
|
|
222
|
+
| **System** | Follows OS preference |
|
|
223
|
+
|
|
224
|
+
All themes use CSS custom properties. Components reference semantic tokens (`--bg`, `--text-primary`, `--accent`, etc.) so every theme is automatic.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Stack
|
|
229
|
+
|
|
230
|
+
- [Next.js 16](https://nextjs.org) (App Router, Turbopack)
|
|
231
|
+
- [React 19](https://react.dev)
|
|
232
|
+
- [TypeScript 5](https://typescriptlang.org)
|
|
233
|
+
- [Tailwind CSS 4](https://tailwindcss.com)
|
|
234
|
+
- [React Flow (@xyflow/react)](https://reactflow.dev) -- Org chart
|
|
235
|
+
- [OpenAI SDK](https://github.com/openai/openai-node) -- Gateway client (routed to Claude via OpenClaw)
|
|
236
|
+
- [Vitest 4](https://vitest.dev) -- Test runner
|
|
237
|
+
- [OpenClaw](https://openclaw.ai) -- AI gateway, agent runtime, vision pipeline
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Development
|
|
242
|
+
|
|
243
|
+
See [CLAUDE.md](CLAUDE.md) for the full developer guide: architecture deep-dives, test patterns, common tasks, and contribution conventions.
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
npm run dev # Start dev server (Turbopack, port 3000)
|
|
247
|
+
npm test # Run all tests via Vitest
|
|
248
|
+
npx tsc --noEmit # Type-check (expect 0 errors)
|
|
249
|
+
npx next build # Production build
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Built by
|
|
255
|
+
|
|
256
|
+
[John Rice](https://github.com/johnrice) with [Jarvis](https://openclaw.ai) (OpenClaw AI)
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT
|