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,215 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ClawPort -- Auto-detect environment and write .env.local
4
+ // Usage: npm run setup
5
+
6
+ import { execSync } from 'node:child_process'
7
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs'
8
+ import { resolve, join } from 'node:path'
9
+ import { createInterface } from 'node:readline'
10
+ import { homedir } from 'node:os'
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Helpers
14
+ // ---------------------------------------------------------------------------
15
+
16
+ const green = (s) => `\x1b[32m${s}\x1b[0m`
17
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`
18
+ const red = (s) => `\x1b[31m${s}\x1b[0m`
19
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`
20
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`
21
+
22
+ function ask(question) {
23
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
24
+ return new Promise((resolve) => {
25
+ rl.question(question, (answer) => {
26
+ rl.close()
27
+ resolve(answer.trim())
28
+ })
29
+ })
30
+ }
31
+
32
+ function exec(cmd) {
33
+ try {
34
+ return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim()
35
+ } catch {
36
+ return null
37
+ }
38
+ }
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Detectors
42
+ // ---------------------------------------------------------------------------
43
+
44
+ function detectWorkspacePath() {
45
+ const defaultPath = join(homedir(), '.openclaw', 'workspace')
46
+ if (existsSync(defaultPath)) return defaultPath
47
+ return null
48
+ }
49
+
50
+ function detectOpenClawBin() {
51
+ return exec('which openclaw')
52
+ }
53
+
54
+ function detectGatewayToken() {
55
+ const configPath = join(homedir(), '.openclaw', 'openclaw.json')
56
+ if (!existsSync(configPath)) return null
57
+ try {
58
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'))
59
+ const token = config?.gateway?.auth?.token
60
+ return typeof token === 'string' ? token : null
61
+ } catch {
62
+ return null
63
+ }
64
+ }
65
+
66
+ function checkGatewayRunning() {
67
+ const result = exec('curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/ 2>/dev/null')
68
+ return result && result !== '000'
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Main
73
+ // ---------------------------------------------------------------------------
74
+
75
+ async function main() {
76
+ console.log()
77
+ console.log(bold(' ClawPort Setup'))
78
+ console.log(dim(' Auto-detecting your OpenClaw configuration...\n'))
79
+
80
+ // Detect all values
81
+ const detected = {
82
+ WORKSPACE_PATH: detectWorkspacePath(),
83
+ OPENCLAW_BIN: detectOpenClawBin(),
84
+ OPENCLAW_GATEWAY_TOKEN: detectGatewayToken(),
85
+ }
86
+
87
+ const gatewayUp = checkGatewayRunning()
88
+
89
+ // Report findings
90
+ const entries = [
91
+ ['WORKSPACE_PATH', detected.WORKSPACE_PATH],
92
+ ['OPENCLAW_BIN', detected.OPENCLAW_BIN],
93
+ ['OPENCLAW_GATEWAY_TOKEN', detected.OPENCLAW_GATEWAY_TOKEN],
94
+ ]
95
+
96
+ let allFound = true
97
+ for (const [name, value] of entries) {
98
+ if (value) {
99
+ const display = name === 'OPENCLAW_GATEWAY_TOKEN'
100
+ ? value.slice(0, 8) + '...' + value.slice(-4)
101
+ : value
102
+ console.log(` ${green('+')} ${bold(name)}`)
103
+ console.log(` ${dim(display)}`)
104
+ } else {
105
+ allFound = false
106
+ console.log(` ${red('x')} ${bold(name)}`)
107
+ console.log(` ${red('Not found')}`)
108
+ }
109
+ }
110
+
111
+ // Gateway status
112
+ console.log()
113
+ if (gatewayUp) {
114
+ console.log(` ${green('+')} Gateway running at ${dim('localhost:18789')}`)
115
+ } else {
116
+ console.log(` ${yellow('!')} Gateway not responding at localhost:18789`)
117
+ console.log(` ${dim('Start it with: openclaw gateway run')}`)
118
+ }
119
+ console.log()
120
+
121
+ // Handle missing values
122
+ const final = { ...detected }
123
+
124
+ if (!final.WORKSPACE_PATH) {
125
+ const answer = await ask(` ${yellow('?')} Enter your WORKSPACE_PATH: `)
126
+ if (answer && existsSync(answer)) {
127
+ final.WORKSPACE_PATH = answer
128
+ } else if (answer) {
129
+ console.log(` ${yellow('Warning: path does not exist yet')}`)
130
+ final.WORKSPACE_PATH = answer
131
+ } else {
132
+ console.log(`\n ${red('Aborted.')} WORKSPACE_PATH is required.`)
133
+ process.exit(1)
134
+ }
135
+ }
136
+
137
+ if (!final.OPENCLAW_BIN) {
138
+ const answer = await ask(` ${yellow('?')} Enter path to openclaw binary: `)
139
+ if (answer) {
140
+ final.OPENCLAW_BIN = answer
141
+ } else {
142
+ console.log(`\n ${red('Aborted.')} OPENCLAW_BIN is required.`)
143
+ process.exit(1)
144
+ }
145
+ }
146
+
147
+ if (!final.OPENCLAW_GATEWAY_TOKEN) {
148
+ console.log(` ${dim('Find your token in ~/.openclaw/openclaw.json under gateway.auth.token')}`)
149
+ const answer = await ask(` ${yellow('?')} Enter your gateway token: `)
150
+ if (answer) {
151
+ final.OPENCLAW_GATEWAY_TOKEN = answer
152
+ } else {
153
+ console.log(`\n ${red('Aborted.')} OPENCLAW_GATEWAY_TOKEN is required.`)
154
+ process.exit(1)
155
+ }
156
+ }
157
+
158
+ // Check if .env.local already exists
159
+ const envPath = resolve(process.cwd(), '.env.local')
160
+ if (existsSync(envPath)) {
161
+ const overwrite = await ask(` ${yellow('?')} .env.local already exists. Overwrite? (y/N) `)
162
+ if (overwrite.toLowerCase() !== 'y') {
163
+ console.log(`\n ${dim('Keeping existing .env.local')}`)
164
+ process.exit(0)
165
+ }
166
+ }
167
+
168
+ // Confirm
169
+ console.log()
170
+ console.log(dim(' Will write .env.local with:'))
171
+ console.log(` WORKSPACE_PATH=${dim(final.WORKSPACE_PATH)}`)
172
+ console.log(` OPENCLAW_BIN=${dim(final.OPENCLAW_BIN)}`)
173
+ console.log(` OPENCLAW_GATEWAY_TOKEN=${dim(final.OPENCLAW_GATEWAY_TOKEN.slice(0, 8) + '...')}`)
174
+ console.log()
175
+
176
+ const confirm = await ask(` ${bold('Write .env.local?')} (Y/n) `)
177
+ if (confirm.toLowerCase() === 'n') {
178
+ console.log(`\n ${dim('Aborted.')}`)
179
+ process.exit(0)
180
+ }
181
+
182
+ // Write
183
+ const content = [
184
+ '# ClawPort -- generated by npm run setup',
185
+ `# Created: ${new Date().toISOString()}`,
186
+ '',
187
+ '# Required',
188
+ `WORKSPACE_PATH=${final.WORKSPACE_PATH}`,
189
+ `OPENCLAW_BIN=${final.OPENCLAW_BIN}`,
190
+ `OPENCLAW_GATEWAY_TOKEN=${final.OPENCLAW_GATEWAY_TOKEN}`,
191
+ '',
192
+ '# Optional -- uncomment to enable voice features',
193
+ '# ELEVENLABS_API_KEY=',
194
+ '',
195
+ ].join('\n')
196
+
197
+ writeFileSync(envPath, content, 'utf-8')
198
+
199
+ console.log()
200
+ console.log(` ${green('Done!')} .env.local written.`)
201
+ console.log()
202
+ console.log(` Next steps:`)
203
+ if (!gatewayUp) {
204
+ console.log(` 1. Start the gateway: ${dim('openclaw gateway run')}`)
205
+ console.log(` 2. Start ClawPort: ${dim('npm run dev')}`)
206
+ } else {
207
+ console.log(` ${dim('npm run dev')}`)
208
+ }
209
+ console.log()
210
+ }
211
+
212
+ main().catch((err) => {
213
+ console.error(`\n ${red('Error:')} ${err.message}`)
214
+ process.exit(1)
215
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from 'vitest/config'
2
+ import react from '@vitejs/plugin-react'
3
+ import path from 'path'
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ resolve: {
8
+ alias: {
9
+ '@': path.resolve(__dirname, './'),
10
+ },
11
+ },
12
+ test: {
13
+ environment: 'jsdom',
14
+ include: ['**/*.test.ts', '**/*.test.tsx'],
15
+ exclude: ['node_modules', '.next'],
16
+ },
17
+ })