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.
Files changed (132) hide show
  1. package/.env.example +35 -0
  2. package/BRANDING.md +131 -0
  3. package/CLAUDE.md +252 -0
  4. package/README.md +262 -0
  5. package/SETUP.md +337 -0
  6. package/app/agents/[id]/page.tsx +727 -0
  7. package/app/api/agents/route.ts +12 -0
  8. package/app/api/chat/[id]/route.ts +139 -0
  9. package/app/api/cron-runs/route.ts +13 -0
  10. package/app/api/crons/route.ts +12 -0
  11. package/app/api/kanban/chat/[id]/route.ts +119 -0
  12. package/app/api/kanban/chat-history/[ticketId]/route.ts +36 -0
  13. package/app/api/memory/route.ts +12 -0
  14. package/app/api/transcribe/route.ts +37 -0
  15. package/app/api/tts/route.ts +42 -0
  16. package/app/chat/[id]/page.tsx +10 -0
  17. package/app/chat/page.tsx +200 -0
  18. package/app/crons/page.tsx +870 -0
  19. package/app/docs/page.tsx +399 -0
  20. package/app/favicon.ico +0 -0
  21. package/app/globals.css +692 -0
  22. package/app/kanban/page.tsx +327 -0
  23. package/app/layout.tsx +45 -0
  24. package/app/memory/page.tsx +685 -0
  25. package/app/page.tsx +817 -0
  26. package/app/providers.tsx +37 -0
  27. package/app/settings/page.tsx +901 -0
  28. package/app/settings-provider.tsx +209 -0
  29. package/components/AgentAvatar.tsx +54 -0
  30. package/components/AgentNode.tsx +122 -0
  31. package/components/Breadcrumbs.tsx +126 -0
  32. package/components/DynamicFavicon.tsx +62 -0
  33. package/components/ErrorState.tsx +97 -0
  34. package/components/FeedView.tsx +494 -0
  35. package/components/GlobalSearch.tsx +571 -0
  36. package/components/GridView.tsx +532 -0
  37. package/components/ManorMap.tsx +157 -0
  38. package/components/MobileSidebar.tsx +251 -0
  39. package/components/NavLinks.tsx +271 -0
  40. package/components/OnboardingWizard.tsx +1067 -0
  41. package/components/Sidebar.tsx +115 -0
  42. package/components/ThemeToggle.tsx +108 -0
  43. package/components/chat/AgentList.tsx +537 -0
  44. package/components/chat/ConversationView.tsx +1047 -0
  45. package/components/chat/FileAttachment.tsx +140 -0
  46. package/components/chat/MediaPreview.tsx +111 -0
  47. package/components/chat/VoiceMessage.tsx +139 -0
  48. package/components/crons/PipelineGraph.tsx +327 -0
  49. package/components/crons/WeeklySchedule.tsx +630 -0
  50. package/components/docs/AgentsSection.tsx +209 -0
  51. package/components/docs/ApiReferenceSection.tsx +256 -0
  52. package/components/docs/ArchitectureSection.tsx +221 -0
  53. package/components/docs/ComponentsSection.tsx +253 -0
  54. package/components/docs/CronSystemSection.tsx +235 -0
  55. package/components/docs/DocSection.tsx +346 -0
  56. package/components/docs/GettingStartedSection.tsx +169 -0
  57. package/components/docs/ThemingSection.tsx +257 -0
  58. package/components/docs/TroubleshootingSection.tsx +200 -0
  59. package/components/kanban/AgentPicker.tsx +321 -0
  60. package/components/kanban/CreateTicketModal.tsx +333 -0
  61. package/components/kanban/KanbanBoard.tsx +70 -0
  62. package/components/kanban/KanbanColumn.tsx +166 -0
  63. package/components/kanban/TicketCard.tsx +245 -0
  64. package/components/kanban/TicketDetailPanel.tsx +850 -0
  65. package/components/ui/badge.tsx +48 -0
  66. package/components/ui/button.tsx +64 -0
  67. package/components/ui/card.tsx +92 -0
  68. package/components/ui/dialog.tsx +158 -0
  69. package/components/ui/scroll-area.tsx +58 -0
  70. package/components/ui/separator.tsx +28 -0
  71. package/components/ui/skeleton.tsx +27 -0
  72. package/components/ui/tabs.tsx +91 -0
  73. package/components/ui/tooltip.tsx +57 -0
  74. package/components.json +23 -0
  75. package/docs/API.md +648 -0
  76. package/docs/COMPONENTS.md +1059 -0
  77. package/docs/THEMING.md +795 -0
  78. package/lib/agents-registry.ts +35 -0
  79. package/lib/agents.json +282 -0
  80. package/lib/agents.test.ts +367 -0
  81. package/lib/agents.ts +32 -0
  82. package/lib/anthropic.test.ts +422 -0
  83. package/lib/anthropic.ts +220 -0
  84. package/lib/api-error.ts +16 -0
  85. package/lib/audio-recorder.test.ts +72 -0
  86. package/lib/audio-recorder.ts +169 -0
  87. package/lib/conversations.test.ts +331 -0
  88. package/lib/conversations.ts +117 -0
  89. package/lib/cron-pipelines.test.ts +69 -0
  90. package/lib/cron-pipelines.ts +58 -0
  91. package/lib/cron-runs.test.ts +118 -0
  92. package/lib/cron-runs.ts +67 -0
  93. package/lib/cron-utils.test.ts +222 -0
  94. package/lib/cron-utils.ts +160 -0
  95. package/lib/crons.test.ts +502 -0
  96. package/lib/crons.ts +114 -0
  97. package/lib/env.test.ts +44 -0
  98. package/lib/env.ts +14 -0
  99. package/lib/kanban/automation.test.ts +245 -0
  100. package/lib/kanban/automation.ts +143 -0
  101. package/lib/kanban/chat-store.test.ts +149 -0
  102. package/lib/kanban/chat-store.ts +81 -0
  103. package/lib/kanban/store.test.ts +238 -0
  104. package/lib/kanban/store.ts +98 -0
  105. package/lib/kanban/types.ts +50 -0
  106. package/lib/kanban/useAgentWork.ts +78 -0
  107. package/lib/memory.ts +45 -0
  108. package/lib/multimodal.test.ts +219 -0
  109. package/lib/multimodal.ts +68 -0
  110. package/lib/pipeline.integration.test.ts +343 -0
  111. package/lib/sanitize.ts +194 -0
  112. package/lib/settings.test.ts +137 -0
  113. package/lib/settings.ts +94 -0
  114. package/lib/styles.ts +24 -0
  115. package/lib/themes.ts +9 -0
  116. package/lib/transcribe.test.ts +141 -0
  117. package/lib/transcribe.ts +111 -0
  118. package/lib/types.ts +66 -0
  119. package/lib/utils.ts +6 -0
  120. package/lib/validation.test.ts +132 -0
  121. package/lib/validation.ts +80 -0
  122. package/next.config.ts +7 -0
  123. package/package.json +56 -0
  124. package/postcss.config.mjs +7 -0
  125. package/public/file.svg +1 -0
  126. package/public/globe.svg +1 -0
  127. package/public/next.svg +1 -0
  128. package/public/vercel.svg +1 -0
  129. package/public/window.svg +1 -0
  130. package/scripts/setup.mjs +215 -0
  131. package/tsconfig.json +34 -0
  132. 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