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
@@ -0,0 +1,253 @@
1
+ import {
2
+ Heading,
3
+ SubHeading,
4
+ Paragraph,
5
+ CodeBlock,
6
+ InlineCode,
7
+ Table,
8
+ BulletList,
9
+ InfoCard,
10
+ } from "./DocSection";
11
+
12
+ export function ComponentsSection() {
13
+ return (
14
+ <>
15
+ <Heading>Components</Heading>
16
+ <Paragraph>
17
+ ClawPort's component tree follows the standard Next.js App Router
18
+ pattern: providers wrap the entire app, layout components handle the
19
+ sidebar and navigation, and each route renders its own page component.
20
+ </Paragraph>
21
+
22
+ <SubHeading>Component Tree</SubHeading>
23
+ <CodeBlock>
24
+ {`RootLayout (app/layout.tsx)
25
+ ThemeProvider (app/providers.tsx)
26
+ SettingsProvider (app/settings-provider.tsx)
27
+ DynamicFavicon
28
+ OnboardingWizard
29
+ Sidebar
30
+ NavLinks
31
+ ThemeToggle
32
+ MobileSidebar
33
+ GlobalSearch
34
+ <main> (page content)
35
+ HomePage ............. / (org chart, grid, feed)
36
+ OrgMap (React Flow)
37
+ AgentNode
38
+ AgentAvatar
39
+ GridView
40
+ FeedView
41
+ ChatPage .............. /chat
42
+ AgentList
43
+ ConversationView
44
+ VoiceMessage
45
+ FileAttachment
46
+ MediaPreview
47
+ AgentDetailPage ....... /agents/[id]
48
+ KanbanPage ............ /kanban
49
+ KanbanBoard
50
+ KanbanColumn
51
+ TicketCard
52
+ TicketDetailPanel
53
+ CreateTicketModal
54
+ AgentPicker
55
+ CronsPage ............. /crons
56
+ WeeklySchedule
57
+ PipelineGraph
58
+ MemoryPage ............ /memory
59
+ DocsPage .............. /docs
60
+ SettingsPage .......... /settings`}
61
+ </CodeBlock>
62
+
63
+ <SubHeading>Providers</SubHeading>
64
+ <InfoCard title="ThemeProvider">
65
+ <BulletList
66
+ items={[
67
+ <>
68
+ <strong style={{ color: "var(--text-primary)" }}>File:</strong>{" "}
69
+ <InlineCode>app/providers.tsx</InlineCode>
70
+ </>,
71
+ "Manages the active theme and applies it via data-theme attribute on <html>",
72
+ <>
73
+ Consumer hook:{" "}
74
+ <InlineCode>{"const { theme, setTheme } = useTheme()"}</InlineCode>
75
+ </>,
76
+ <>
77
+ Persists to <InlineCode>localStorage('clawport-theme')</InlineCode>,
78
+ defaults to 'dark'
79
+ </>,
80
+ ]}
81
+ />
82
+ </InfoCard>
83
+
84
+ <InfoCard title="SettingsProvider">
85
+ <BulletList
86
+ items={[
87
+ <>
88
+ <strong style={{ color: "var(--text-primary)" }}>File:</strong>{" "}
89
+ <InlineCode>app/settings-provider.tsx</InlineCode>
90
+ </>,
91
+ "Central state management for all user-configurable settings",
92
+ <>
93
+ Consumer hook:{" "}
94
+ <InlineCode>{"const { settings, setAccentColor, ... } = useSettings()"}</InlineCode>
95
+ </>,
96
+ "Applies accent color CSS variables directly to document.documentElement",
97
+ <>
98
+ Persists to{" "}
99
+ <InlineCode>localStorage('clawport-settings')</InlineCode>
100
+ </>,
101
+ ]}
102
+ />
103
+ </InfoCard>
104
+
105
+ <SubHeading>Layout Components</SubHeading>
106
+ <Table
107
+ headers={["Component", "File", "Purpose"]}
108
+ rows={[
109
+ [
110
+ "Sidebar",
111
+ <InlineCode key="s">components/Sidebar.tsx</InlineCode>,
112
+ "Desktop sidebar wrapper. Renders NavLinks, ThemeToggle, MobileSidebar, GlobalSearch.",
113
+ ],
114
+ [
115
+ "NavLinks",
116
+ <InlineCode key="n">components/NavLinks.tsx</InlineCode>,
117
+ "Sidebar nav links with icons, badges, and operator identity footer.",
118
+ ],
119
+ [
120
+ "MobileSidebar",
121
+ <InlineCode key="m">components/MobileSidebar.tsx</InlineCode>,
122
+ "Fixed mobile header bar with hamburger menu and slide-out sidebar panel.",
123
+ ],
124
+ [
125
+ "GlobalSearch",
126
+ <InlineCode key="g">components/GlobalSearch.tsx</InlineCode>,
127
+ "Cmd+K search palette with fuzzy search across agents, pages, and crons.",
128
+ ],
129
+ [
130
+ "ThemeToggle",
131
+ <InlineCode key="t">components/ThemeToggle.tsx</InlineCode>,
132
+ "Theme selector rendered as a row of emoji buttons with radiogroup semantics.",
133
+ ],
134
+ ]}
135
+ />
136
+
137
+ <SubHeading>Chat Components</SubHeading>
138
+ <Table
139
+ headers={["Component", "Purpose"]}
140
+ rows={[
141
+ [
142
+ "ConversationView",
143
+ "Main chat: messages, SSE streaming, file attachments, TTS playback, voice recording, markdown rendering.",
144
+ ],
145
+ [
146
+ "AgentList",
147
+ "Agent selection sidebar for chat. Desktop (300px fixed) and mobile (full-width) variants.",
148
+ ],
149
+ [
150
+ "VoiceMessage",
151
+ "Audio waveform playback with play/pause toggle and animated progress bars.",
152
+ ],
153
+ [
154
+ "FileAttachment",
155
+ "File attachment bubble with type-specific icon and download button.",
156
+ ],
157
+ [
158
+ "MediaPreview",
159
+ "Horizontal strip of staged attachment thumbnails before sending.",
160
+ ],
161
+ ]}
162
+ />
163
+
164
+ <SubHeading>Map Components</SubHeading>
165
+ <Table
166
+ headers={["Component", "Purpose"]}
167
+ rows={[
168
+ [
169
+ "OrgMap",
170
+ "React Flow org chart with BFS-based hierarchical layout, edge highlighting, and interactive zoom.",
171
+ ],
172
+ [
173
+ "AgentNode",
174
+ "Custom React Flow node: avatar, name, title, cron health indicator, selection state.",
175
+ ],
176
+ [
177
+ "GridView",
178
+ "Card-based grid with team grouping hierarchy. Responsive: 1/2/3 columns.",
179
+ ],
180
+ [
181
+ "FeedView",
182
+ "Activity feed focused on cron status with stat cards and filter pills.",
183
+ ],
184
+ ]}
185
+ />
186
+
187
+ <SubHeading>Kanban Components</SubHeading>
188
+ <Table
189
+ headers={["Component", "Purpose"]}
190
+ rows={[
191
+ [
192
+ "KanbanBoard",
193
+ "Four-column board (Backlog, In Progress, Review, Done) with agent filter.",
194
+ ],
195
+ [
196
+ "KanbanColumn",
197
+ "Single column with HTML5 drag-and-drop support and drop zone highlight.",
198
+ ],
199
+ [
200
+ "TicketCard",
201
+ "Draggable card: priority dot, title, agent avatar, work state indicator.",
202
+ ],
203
+ [
204
+ "TicketDetailPanel",
205
+ "Slide-in side panel for ticket details and inline agent chat.",
206
+ ],
207
+ [
208
+ "CreateTicketModal",
209
+ "Modal for creating tickets with title, description, priority, agent assignment.",
210
+ ],
211
+ ]}
212
+ />
213
+
214
+ <SubHeading>Other Key Components</SubHeading>
215
+ <Table
216
+ headers={["Component", "Purpose"]}
217
+ rows={[
218
+ [
219
+ "OnboardingWizard",
220
+ "5-step first-run setup wizard (name, theme, accent, voice, overview). Re-runnable from Settings.",
221
+ ],
222
+ [
223
+ "AgentAvatar",
224
+ "Agent avatar: profile image, emoji on colored background, or emoji-only mode.",
225
+ ],
226
+ [
227
+ "DynamicFavicon",
228
+ "Generates favicon from portal emoji/icon using Canvas API.",
229
+ ],
230
+ [
231
+ "ErrorState",
232
+ "Full-screen error display with optional retry button.",
233
+ ],
234
+ [
235
+ "Breadcrumbs",
236
+ "Breadcrumb navigation bar with Lucide ChevronRight separators.",
237
+ ],
238
+ ]}
239
+ />
240
+
241
+ <SubHeading>UI Primitives</SubHeading>
242
+ <Paragraph>
243
+ Radix-based primitive components in{" "}
244
+ <InlineCode>components/ui/</InlineCode> (shadcn/ui-style wrappers):
245
+ </Paragraph>
246
+ <BulletList
247
+ items={[
248
+ "Badge, Button, Card, Dialog, ScrollArea, Separator, Skeleton, Tabs, Tooltip",
249
+ ]}
250
+ />
251
+ </>
252
+ );
253
+ }
@@ -0,0 +1,235 @@
1
+ import {
2
+ Heading,
3
+ SubHeading,
4
+ Paragraph,
5
+ CodeBlock,
6
+ InlineCode,
7
+ Table,
8
+ BulletList,
9
+ Callout,
10
+ } from "./DocSection";
11
+
12
+ export function CronSystemSection() {
13
+ return (
14
+ <>
15
+ <Heading>Cron System</Heading>
16
+ <Paragraph>
17
+ ClawPort provides a full cron monitoring dashboard with three views:
18
+ overview (health donut, attention cards, error banners), weekly schedule
19
+ (7-day calendar grid), and pipeline graph (React Flow dependency
20
+ visualization). Data is fetched from the OpenClaw CLI and auto-refreshes
21
+ every 60 seconds.
22
+ </Paragraph>
23
+
24
+ <SubHeading>CronJob Schema</SubHeading>
25
+ <Table
26
+ headers={["Field", "Type", "Description"]}
27
+ rows={[
28
+ [<InlineCode key="id">id</InlineCode>, "string", "Job identifier"],
29
+ [
30
+ <InlineCode key="n">name</InlineCode>,
31
+ "string",
32
+ "Job name (used to match owning agent by prefix)",
33
+ ],
34
+ [
35
+ <InlineCode key="s">schedule</InlineCode>,
36
+ "string",
37
+ "Raw cron expression",
38
+ ],
39
+ [
40
+ <InlineCode key="sd">scheduleDescription</InlineCode>,
41
+ "string",
42
+ 'Human-readable (e.g., "Daily at 8 AM")',
43
+ ],
44
+ [
45
+ <InlineCode key="tz">timezone</InlineCode>,
46
+ "string | null",
47
+ "Timezone from schedule object, if present",
48
+ ],
49
+ [
50
+ <InlineCode key="st">status</InlineCode>,
51
+ '"ok" | "error" | "idle"',
52
+ "Last run outcome",
53
+ ],
54
+ [
55
+ <InlineCode key="lr">lastRun</InlineCode>,
56
+ "string | null",
57
+ "ISO 8601 timestamp of last execution",
58
+ ],
59
+ [
60
+ <InlineCode key="nr">nextRun</InlineCode>,
61
+ "string | null",
62
+ "ISO 8601 timestamp of next scheduled run",
63
+ ],
64
+ [
65
+ <InlineCode key="le">lastError</InlineCode>,
66
+ "string | null",
67
+ "Error message from last failed run",
68
+ ],
69
+ [
70
+ <InlineCode key="ai">agentId</InlineCode>,
71
+ "string | null",
72
+ "Owning agent ID (matched by job name prefix)",
73
+ ],
74
+ [
75
+ <InlineCode key="en">enabled</InlineCode>,
76
+ "boolean",
77
+ "Whether the job is active",
78
+ ],
79
+ [
80
+ <InlineCode key="dl">delivery</InlineCode>,
81
+ "CronDelivery | null",
82
+ "Delivery config (mode, channel, to)",
83
+ ],
84
+ [
85
+ <InlineCode key="ld">lastDurationMs</InlineCode>,
86
+ "number | null",
87
+ "Duration of last run in milliseconds",
88
+ ],
89
+ [
90
+ <InlineCode key="ce">consecutiveErrors</InlineCode>,
91
+ "number",
92
+ "Count of consecutive failed runs",
93
+ ],
94
+ ]}
95
+ />
96
+
97
+ <SubHeading>CronRun Schema</SubHeading>
98
+ <Paragraph>
99
+ Run history is parsed from JSONL log files at{" "}
100
+ <InlineCode>$WORKSPACE_PATH/../cron/runs/</InlineCode>. Each line in the
101
+ JSONL file represents one run.
102
+ </Paragraph>
103
+ <Table
104
+ headers={["Field", "Type", "Description"]}
105
+ rows={[
106
+ [
107
+ <InlineCode key="ts">ts</InlineCode>,
108
+ "number",
109
+ "Unix timestamp (milliseconds) of the run",
110
+ ],
111
+ [
112
+ <InlineCode key="j">jobId</InlineCode>,
113
+ "string",
114
+ "Job identifier",
115
+ ],
116
+ [
117
+ <InlineCode key="s">status</InlineCode>,
118
+ '"ok" | "error"',
119
+ "Run outcome",
120
+ ],
121
+ [
122
+ <InlineCode key="su">summary</InlineCode>,
123
+ "string | null",
124
+ "Summary of what the run produced",
125
+ ],
126
+ [
127
+ <InlineCode key="e">error</InlineCode>,
128
+ "string | null",
129
+ "Error message if the run failed",
130
+ ],
131
+ [
132
+ <InlineCode key="d">durationMs</InlineCode>,
133
+ "number",
134
+ "Duration in milliseconds",
135
+ ],
136
+ [
137
+ <InlineCode key="ds">deliveryStatus</InlineCode>,
138
+ "string | null",
139
+ "Delivery outcome",
140
+ ],
141
+ ]}
142
+ />
143
+
144
+ <SubHeading>Agent Ownership</SubHeading>
145
+ <Paragraph>
146
+ Cron jobs are matched to agents by job name prefix. When the API fetches
147
+ crons via <InlineCode>openclaw cron list --json</InlineCode>, it
148
+ enriches each job with an <InlineCode>agentId</InlineCode> field by
149
+ checking whether the job name starts with an agent's id. This enables
150
+ the UI to show agent avatars next to cron entries and filter crons by
151
+ agent.
152
+ </Paragraph>
153
+
154
+ <SubHeading>Delivery Configuration</SubHeading>
155
+ <Table
156
+ headers={["Field", "Type", "Description"]}
157
+ rows={[
158
+ [
159
+ <InlineCode key="m">mode</InlineCode>,
160
+ "string",
161
+ "Delivery mode",
162
+ ],
163
+ [
164
+ <InlineCode key="c">channel</InlineCode>,
165
+ "string",
166
+ "Delivery channel",
167
+ ],
168
+ [
169
+ <InlineCode key="t">to</InlineCode>,
170
+ "string | null",
171
+ "Delivery recipient",
172
+ ],
173
+ ]}
174
+ />
175
+
176
+ <SubHeading>Status Types</SubHeading>
177
+ <BulletList
178
+ items={[
179
+ <>
180
+ <strong style={{ color: "var(--system-green)" }}>ok</strong> -- Last
181
+ run completed successfully
182
+ </>,
183
+ <>
184
+ <strong style={{ color: "var(--system-red)" }}>error</strong> -- Last
185
+ run failed (error details in lastError)
186
+ </>,
187
+ <>
188
+ <strong style={{ color: "var(--text-tertiary)" }}>idle</strong> --
189
+ Job has never run or has no recent activity
190
+ </>,
191
+ ]}
192
+ />
193
+
194
+ <SubHeading>Monitoring Views</SubHeading>
195
+ <BulletList
196
+ items={[
197
+ <>
198
+ <strong style={{ color: "var(--text-primary)" }}>Overview</strong>{" "}
199
+ -- Health donut chart (SVG), attention-needed cards for errored
200
+ crons, delivery stats, error banners with expandable details, recent
201
+ runs list
202
+ </>,
203
+ <>
204
+ <strong style={{ color: "var(--text-primary)" }}>Schedule</strong>{" "}
205
+ -- Seven-day calendar grid showing when cron jobs are scheduled to
206
+ run. Current time indicator as a red horizontal line.
207
+ </>,
208
+ <>
209
+ <strong style={{ color: "var(--text-primary)" }}>Pipelines</strong>{" "}
210
+ -- React Flow visualization of cron job pipelines showing
211
+ dependencies between stages
212
+ </>,
213
+ ]}
214
+ />
215
+
216
+ <Callout type="note">
217
+ The cron page auto-refreshes every 60 seconds. The sidebar also fetches
218
+ cron error counts on mount and displays a red pulsing dot badge when
219
+ errors are present.
220
+ </Callout>
221
+
222
+ <SubHeading>API Endpoint</SubHeading>
223
+ <CodeBlock title="terminal">
224
+ {`# Fetch all crons
225
+ curl http://localhost:3000/api/crons
226
+
227
+ # Fetch run history for a specific job
228
+ curl "http://localhost:3000/api/cron-runs?jobId=pulse-daily-digest"
229
+
230
+ # Fetch all run history
231
+ curl http://localhost:3000/api/cron-runs`}
232
+ </CodeBlock>
233
+ </>
234
+ );
235
+ }