clawport-ui 0.2.4 → 0.3.1
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/README.md +6 -3
- package/app/globals.css +11 -11
- package/app/settings/page.tsx +2 -2
- package/bin/clawport.mjs +158 -18
- package/components/MobileSidebar.tsx +2 -2
- package/components/OnboardingWizard.tsx +3 -3
- package/components/Sidebar.tsx +1 -1
- package/components/docs/GettingStartedSection.tsx +6 -1
- package/package.json +17 -1
- package/scripts/setup.mjs +15 -7
- package/BRANDING.md +0 -132
- package/CLAUDE.md +0 -266
- package/SETUP.md +0 -353
- package/components.json +0 -23
- package/vitest.config.ts +0 -17
package/README.md
CHANGED
|
@@ -16,8 +16,11 @@ ClawPort is an open-source dashboard for managing, monitoring, and talking direc
|
|
|
16
16
|
|
|
17
17
|
### Quick Start (npm)
|
|
18
18
|
|
|
19
|
+
> **Note:** The npm package is `clawport-ui`. The CLI command is `clawport`.
|
|
20
|
+
> Do not install the unrelated `clawport` package.
|
|
21
|
+
|
|
19
22
|
```bash
|
|
20
|
-
# Install globally
|
|
23
|
+
# Install globally (package: clawport-ui, command: clawport)
|
|
21
24
|
npm install -g clawport-ui
|
|
22
25
|
|
|
23
26
|
# Auto-detect your OpenClaw config
|
|
@@ -225,7 +228,7 @@ Five built-in themes, toggled via the sidebar button:
|
|
|
225
228
|
|
|
226
229
|
| Theme | Description |
|
|
227
230
|
|-------|-------------|
|
|
228
|
-
| **Dark** | Apple Dark Mode with warm blacks,
|
|
231
|
+
| **Dark** | Apple Dark Mode with warm blacks, red accent |
|
|
229
232
|
| **Glass** | Frosted translucent panels on deep blue-black |
|
|
230
233
|
| **Color** | Vibrant purple-indigo gradients |
|
|
231
234
|
| **Light** | Apple Light Mode, clean whites |
|
|
@@ -274,7 +277,7 @@ npm install -g clawport-ui
|
|
|
274
277
|
clawport help
|
|
275
278
|
```
|
|
276
279
|
|
|
277
|
-
Published as [`clawport-ui`](https://www.npmjs.com/package/clawport-ui) on npm.
|
|
280
|
+
Published as [`clawport-ui`](https://www.npmjs.com/package/clawport-ui) on npm. The CLI command is `clawport` (not `clawport-ui`). The separate `clawport` npm package is unrelated and not affiliated with this project.
|
|
278
281
|
|
|
279
282
|
### CLI Commands
|
|
280
283
|
|
package/app/globals.css
CHANGED
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
--text-secondary: rgba(235,235,245,0.60);
|
|
81
81
|
--text-tertiary: rgba(235,235,245,0.30);
|
|
82
82
|
--text-quaternary: rgba(235,235,245,0.18);
|
|
83
|
-
--accent: #
|
|
84
|
-
--accent-fill: rgba(
|
|
85
|
-
--accent-contrast: #
|
|
83
|
+
--accent: #EF4444;
|
|
84
|
+
--accent-fill: rgba(239,68,68,0.15);
|
|
85
|
+
--accent-contrast: #fff;
|
|
86
86
|
--system-blue: #0A84FF;
|
|
87
87
|
--system-green: #30D158;
|
|
88
88
|
--system-red: #FF453A;
|
|
@@ -128,9 +128,9 @@
|
|
|
128
128
|
--text-secondary: rgba(255,255,255,0.60);
|
|
129
129
|
--text-tertiary: rgba(255,255,255,0.30);
|
|
130
130
|
--text-quaternary: rgba(255,255,255,0.18);
|
|
131
|
-
--accent: #
|
|
132
|
-
--accent-fill: rgba(
|
|
133
|
-
--accent-contrast: #
|
|
131
|
+
--accent: #EF4444;
|
|
132
|
+
--accent-fill: rgba(239,68,68,0.18);
|
|
133
|
+
--accent-contrast: #fff;
|
|
134
134
|
--system-blue: #3B9EFF;
|
|
135
135
|
--system-green: #34D058;
|
|
136
136
|
--system-red: #FF5C57;
|
|
@@ -176,9 +176,9 @@
|
|
|
176
176
|
--text-secondary: rgba(220,210,255,0.70);
|
|
177
177
|
--text-tertiary: rgba(220,210,255,0.35);
|
|
178
178
|
--text-quaternary: rgba(220,210,255,0.20);
|
|
179
|
-
--accent: #
|
|
180
|
-
--accent-fill: rgba(
|
|
181
|
-
--accent-contrast: #
|
|
179
|
+
--accent: #EF4444;
|
|
180
|
+
--accent-fill: rgba(239,68,68,0.20);
|
|
181
|
+
--accent-contrast: #fff;
|
|
182
182
|
--system-blue: #60A5FA;
|
|
183
183
|
--system-green: #34D399;
|
|
184
184
|
--system-red: #F87171;
|
|
@@ -224,8 +224,8 @@
|
|
|
224
224
|
--text-secondary: rgba(60,60,67,0.60);
|
|
225
225
|
--text-tertiary: rgba(60,60,67,0.44);
|
|
226
226
|
--text-quaternary: rgba(60,60,67,0.30);
|
|
227
|
-
--accent: #
|
|
228
|
-
--accent-fill: rgba(
|
|
227
|
+
--accent: #DC2626;
|
|
228
|
+
--accent-fill: rgba(220,38,38,0.12);
|
|
229
229
|
--accent-contrast: #fff;
|
|
230
230
|
--system-blue: #007AFF;
|
|
231
231
|
--system-green: #28CD41;
|
package/app/settings/page.tsx
CHANGED
|
@@ -12,10 +12,10 @@ import { OnboardingWizard } from '@/components/OnboardingWizard'
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
14
14
|
const ACCENT_PRESETS = [
|
|
15
|
+
{ label: 'Red', value: '#EF4444' },
|
|
15
16
|
{ label: 'Gold', value: '#F5C518' },
|
|
16
17
|
{ label: 'Blue', value: '#3B82F6' },
|
|
17
18
|
{ label: 'Green', value: '#22C55E' },
|
|
18
|
-
{ label: 'Red', value: '#EF4444' },
|
|
19
19
|
{ label: 'Orange', value: '#F97316' },
|
|
20
20
|
{ label: 'Purple', value: '#A855F7' },
|
|
21
21
|
{ label: 'Pink', value: '#EC4899' },
|
|
@@ -368,7 +368,7 @@ export default function SettingsPage() {
|
|
|
368
368
|
? 'transparent'
|
|
369
369
|
: settings.accentColor
|
|
370
370
|
? `linear-gradient(135deg, ${settings.accentColor}, ${settings.accentColor}dd)`
|
|
371
|
-
: '
|
|
371
|
+
: 'transparent',
|
|
372
372
|
boxShadow: settings.iconBgHidden ? 'none' : 'var(--shadow-card)',
|
|
373
373
|
display: 'flex',
|
|
374
374
|
alignItems: 'center',
|
package/bin/clawport.mjs
CHANGED
|
@@ -3,8 +3,21 @@
|
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
import { dirname, resolve } from 'node:path'
|
|
5
5
|
import { spawn } from 'node:child_process'
|
|
6
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
6
|
+
import { existsSync, readFileSync, accessSync, constants } from 'node:fs'
|
|
7
7
|
import { execSync } from 'node:child_process'
|
|
8
|
+
import { createServer } from 'node:net'
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Node version gate (must be 22+ for native fetch / AbortSignal.timeout)
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const [major] = process.versions.node.split('.').map(Number)
|
|
15
|
+
if (major < 22) {
|
|
16
|
+
console.error(
|
|
17
|
+
`\x1b[31mError:\x1b[0m Node.js 22+ required (found ${process.versions.node})`
|
|
18
|
+
)
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
8
21
|
|
|
9
22
|
// ---------------------------------------------------------------------------
|
|
10
23
|
// Resolve package root (where app/, lib/, etc. live)
|
|
@@ -25,6 +38,8 @@ const red = (s) => `\x1b[31m${s}\x1b[0m`
|
|
|
25
38
|
const dim = (s) => `\x1b[2m${s}\x1b[0m`
|
|
26
39
|
const bold = (s) => `\x1b[1m${s}\x1b[0m`
|
|
27
40
|
|
|
41
|
+
const extraArgs = process.argv.slice(3)
|
|
42
|
+
|
|
28
43
|
function run(cmd, args = []) {
|
|
29
44
|
const child = spawn(cmd, args, {
|
|
30
45
|
cwd: PKG_ROOT,
|
|
@@ -34,6 +49,40 @@ function run(cmd, args = []) {
|
|
|
34
49
|
child.on('close', (code) => process.exit(code ?? 0))
|
|
35
50
|
}
|
|
36
51
|
|
|
52
|
+
async function checkGateway() {
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch('http://127.0.0.1:18789/', {
|
|
55
|
+
signal: AbortSignal.timeout(3000),
|
|
56
|
+
})
|
|
57
|
+
return res.ok || res.status > 0
|
|
58
|
+
} catch {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function findBinary(name) {
|
|
64
|
+
const cmd = process.platform === 'win32' ? 'where' : 'which'
|
|
65
|
+
try {
|
|
66
|
+
return execSync(`${cmd} ${name}`, {
|
|
67
|
+
encoding: 'utf-8',
|
|
68
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
69
|
+
}).trim()
|
|
70
|
+
} catch {
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function checkPort(port) {
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
const server = createServer()
|
|
78
|
+
server.once('error', () => resolve(false))
|
|
79
|
+
server.once('listening', () => {
|
|
80
|
+
server.close(() => resolve(true))
|
|
81
|
+
})
|
|
82
|
+
server.listen(port, '127.0.0.1')
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
37
86
|
// ---------------------------------------------------------------------------
|
|
38
87
|
// Commands
|
|
39
88
|
// ---------------------------------------------------------------------------
|
|
@@ -42,19 +91,25 @@ function showHelp() {
|
|
|
42
91
|
console.log(`
|
|
43
92
|
${bold('ClawPort')} -- AI Agent Dashboard
|
|
44
93
|
|
|
45
|
-
${bold('Usage:')} clawport <command>
|
|
94
|
+
${bold('Usage:')} clawport <command> [options]
|
|
46
95
|
|
|
47
96
|
${bold('Commands:')}
|
|
48
97
|
${green('dev')} Start the development server (next dev)
|
|
49
98
|
${green('start')} Build and start the production server
|
|
50
99
|
${green('setup')} Run the setup wizard (auto-detect OpenClaw config)
|
|
51
100
|
${green('status')} Check gateway reachability and current config
|
|
101
|
+
${green('doctor')} Run full environment health check
|
|
52
102
|
${green('help')} Show this help message
|
|
53
103
|
|
|
104
|
+
${bold('Options:')}
|
|
105
|
+
${dim('--port <n>')} Port for dev/start (passed through to Next.js)
|
|
106
|
+
|
|
54
107
|
${bold('Examples:')}
|
|
55
|
-
${dim('$ clawport setup
|
|
56
|
-
${dim('$ clawport dev
|
|
57
|
-
${dim('$ clawport
|
|
108
|
+
${dim('$ clawport setup # Configure your OpenClaw connection')}
|
|
109
|
+
${dim('$ clawport dev # Start dev server on localhost:3000')}
|
|
110
|
+
${dim('$ clawport dev --port 3005 # Start dev server on port 3005')}
|
|
111
|
+
${dim('$ clawport status # Check if gateway is reachable')}
|
|
112
|
+
${dim('$ clawport doctor # Diagnose environment issues')}
|
|
58
113
|
|
|
59
114
|
${dim(`Package root: ${PKG_ROOT}`)}
|
|
60
115
|
`)
|
|
@@ -62,12 +117,20 @@ ${dim(`Package root: ${PKG_ROOT}`)}
|
|
|
62
117
|
|
|
63
118
|
function cmdDev() {
|
|
64
119
|
console.log(`\n ${bold('Starting ClawPort dev server...')}\n`)
|
|
65
|
-
run(NEXT_BIN, ['dev'])
|
|
120
|
+
run(NEXT_BIN, ['dev', ...extraArgs])
|
|
66
121
|
}
|
|
67
122
|
|
|
68
123
|
function cmdStart() {
|
|
69
124
|
console.log(`\n ${bold('Building and starting ClawPort...')}\n`)
|
|
70
|
-
|
|
125
|
+
const build = spawn(NEXT_BIN, ['build'], {
|
|
126
|
+
cwd: PKG_ROOT,
|
|
127
|
+
stdio: 'inherit',
|
|
128
|
+
shell: true,
|
|
129
|
+
})
|
|
130
|
+
build.on('close', (code) => {
|
|
131
|
+
if (code !== 0) process.exit(code)
|
|
132
|
+
run(NEXT_BIN, ['start', ...extraArgs])
|
|
133
|
+
})
|
|
71
134
|
}
|
|
72
135
|
|
|
73
136
|
function cmdSetup() {
|
|
@@ -75,22 +138,13 @@ function cmdSetup() {
|
|
|
75
138
|
run('node', [resolve(PKG_ROOT, 'scripts/setup.mjs'), `--cwd=${PKG_ROOT}`])
|
|
76
139
|
}
|
|
77
140
|
|
|
78
|
-
function cmdStatus() {
|
|
141
|
+
async function cmdStatus() {
|
|
79
142
|
console.log()
|
|
80
143
|
console.log(bold(' ClawPort Status'))
|
|
81
144
|
console.log()
|
|
82
145
|
|
|
83
146
|
// Check gateway
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
const result = execSync(
|
|
87
|
-
'curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/ 2>/dev/null',
|
|
88
|
-
{ encoding: 'utf-8', timeout: 5000 }
|
|
89
|
-
).trim()
|
|
90
|
-
gatewayUp = result && result !== '000'
|
|
91
|
-
} catch {
|
|
92
|
-
// gateway not reachable
|
|
93
|
-
}
|
|
147
|
+
const gatewayUp = await checkGateway()
|
|
94
148
|
|
|
95
149
|
if (gatewayUp) {
|
|
96
150
|
console.log(` ${green('+')} Gateway reachable at ${dim('localhost:18789')}`)
|
|
@@ -125,6 +179,89 @@ function cmdStatus() {
|
|
|
125
179
|
console.log()
|
|
126
180
|
}
|
|
127
181
|
|
|
182
|
+
async function cmdDoctor() {
|
|
183
|
+
console.log()
|
|
184
|
+
console.log(bold(' ClawPort Doctor'))
|
|
185
|
+
console.log()
|
|
186
|
+
|
|
187
|
+
let passed = 0
|
|
188
|
+
let total = 0
|
|
189
|
+
|
|
190
|
+
function check(ok, label, fix) {
|
|
191
|
+
total++
|
|
192
|
+
if (ok) {
|
|
193
|
+
passed++
|
|
194
|
+
console.log(` ${green('+')} ${label}`)
|
|
195
|
+
} else {
|
|
196
|
+
console.log(` ${red('x')} ${label}`)
|
|
197
|
+
if (fix) console.log(` ${dim(fix)}`)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 1. Node.js version
|
|
202
|
+
check(major >= 22, `Node.js ${process.versions.node}`, 'Upgrade to Node.js 22 or later')
|
|
203
|
+
|
|
204
|
+
// 2. Package integrity -- next binary exists
|
|
205
|
+
check(existsSync(NEXT_BIN), 'Package integrity (node_modules/.bin/next)', 'Run: npm install')
|
|
206
|
+
|
|
207
|
+
// 3. OpenClaw binary
|
|
208
|
+
const openclawPath = findBinary('openclaw')
|
|
209
|
+
check(!!openclawPath, openclawPath ? `OpenClaw binary (${openclawPath})` : 'OpenClaw binary', 'Install OpenClaw: https://docs.openclaw.dev/install')
|
|
210
|
+
|
|
211
|
+
// 4. Gateway reachable
|
|
212
|
+
const gatewayUp = await checkGateway()
|
|
213
|
+
check(gatewayUp, 'Gateway reachable at localhost:18789', 'Start it with: openclaw gateway run')
|
|
214
|
+
|
|
215
|
+
// 5. Configuration -- .env.local with required vars
|
|
216
|
+
const envPath = resolve(PKG_ROOT, '.env.local')
|
|
217
|
+
const requiredVars = ['WORKSPACE_PATH', 'OPENCLAW_BIN', 'OPENCLAW_GATEWAY_TOKEN']
|
|
218
|
+
let envOk = false
|
|
219
|
+
let envFix = 'Run: clawport setup'
|
|
220
|
+
if (existsSync(envPath)) {
|
|
221
|
+
const content = readFileSync(envPath, 'utf-8')
|
|
222
|
+
const missing = requiredVars.filter((v) => !content.includes(`${v}=`))
|
|
223
|
+
if (missing.length === 0) {
|
|
224
|
+
envOk = true
|
|
225
|
+
} else {
|
|
226
|
+
envFix = `Missing in .env.local: ${missing.join(', ')}`
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
check(envOk, '.env.local with required variables', envFix)
|
|
230
|
+
|
|
231
|
+
// 6. Workspace structure
|
|
232
|
+
let workspaceOk = false
|
|
233
|
+
let workspaceFix = 'Set WORKSPACE_PATH in .env.local via: clawport setup'
|
|
234
|
+
if (envOk) {
|
|
235
|
+
const content = readFileSync(envPath, 'utf-8')
|
|
236
|
+
const match = content.match(/^WORKSPACE_PATH=(.+)$/m)
|
|
237
|
+
if (match) {
|
|
238
|
+
const wsPath = match[1].trim()
|
|
239
|
+
const hasSoul = existsSync(resolve(wsPath, 'SOUL.md'))
|
|
240
|
+
const hasAgents = existsSync(resolve(wsPath, 'agents'))
|
|
241
|
+
const hasMemory = existsSync(resolve(wsPath, 'memory'))
|
|
242
|
+
if (hasSoul || hasAgents || hasMemory) {
|
|
243
|
+
workspaceOk = true
|
|
244
|
+
} else {
|
|
245
|
+
workspaceFix = `Workspace at ${wsPath} missing expected files (SOUL.md, agents/, memory/)`
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
check(workspaceOk, 'Workspace structure', workspaceFix)
|
|
250
|
+
|
|
251
|
+
// 7. Port 3000 available
|
|
252
|
+
const portFree = await checkPort(3000)
|
|
253
|
+
check(portFree, 'Port 3000 available', 'Port 3000 is in use. Use: clawport dev --port 3001')
|
|
254
|
+
|
|
255
|
+
// Summary
|
|
256
|
+
console.log()
|
|
257
|
+
if (passed === total) {
|
|
258
|
+
console.log(` ${green(`${passed}/${total} checks passed`)}`)
|
|
259
|
+
} else {
|
|
260
|
+
console.log(` ${yellow(`${passed}/${total} checks passed`)} -- ${total - passed} issue${total - passed === 1 ? '' : 's'} found`)
|
|
261
|
+
}
|
|
262
|
+
console.log()
|
|
263
|
+
}
|
|
264
|
+
|
|
128
265
|
// ---------------------------------------------------------------------------
|
|
129
266
|
// Main
|
|
130
267
|
// ---------------------------------------------------------------------------
|
|
@@ -144,6 +281,9 @@ switch (command) {
|
|
|
144
281
|
case 'status':
|
|
145
282
|
cmdStatus()
|
|
146
283
|
break
|
|
284
|
+
case 'doctor':
|
|
285
|
+
cmdDoctor()
|
|
286
|
+
break
|
|
147
287
|
case 'help':
|
|
148
288
|
default:
|
|
149
289
|
showHelp()
|
|
@@ -116,7 +116,7 @@ export function MobileSidebar({
|
|
|
116
116
|
borderRadius: '6px',
|
|
117
117
|
background: settings.accentColor
|
|
118
118
|
? `linear-gradient(135deg, ${settings.accentColor}, ${settings.accentColor}dd)`
|
|
119
|
-
: '
|
|
119
|
+
: 'transparent',
|
|
120
120
|
display: 'flex',
|
|
121
121
|
alignItems: 'center',
|
|
122
122
|
justifyContent: 'center',
|
|
@@ -202,7 +202,7 @@ export function MobileSidebar({
|
|
|
202
202
|
borderRadius: '10px',
|
|
203
203
|
background: settings.accentColor
|
|
204
204
|
? `linear-gradient(135deg, ${settings.accentColor}, ${settings.accentColor}dd)`
|
|
205
|
-
: '
|
|
205
|
+
: 'transparent',
|
|
206
206
|
boxShadow: 'var(--shadow-card)',
|
|
207
207
|
display: 'flex',
|
|
208
208
|
alignItems: 'center',
|
|
@@ -12,10 +12,10 @@ import type { ThemeId } from '@/lib/themes'
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
14
14
|
const ACCENT_PRESETS = [
|
|
15
|
+
{ label: 'Red', value: '#EF4444' },
|
|
15
16
|
{ label: 'Gold', value: '#F5C518' },
|
|
16
17
|
{ label: 'Blue', value: '#3B82F6' },
|
|
17
18
|
{ label: 'Green', value: '#22C55E' },
|
|
18
|
-
{ label: 'Red', value: '#EF4444' },
|
|
19
19
|
{ label: 'Orange', value: '#F97316' },
|
|
20
20
|
{ label: 'Purple', value: '#A855F7' },
|
|
21
21
|
{ label: 'Pink', value: '#EC4899' },
|
|
@@ -508,7 +508,7 @@ export function OnboardingWizard({ forceOpen, onClose }: OnboardingWizardProps)
|
|
|
508
508
|
padding: '1px 4px',
|
|
509
509
|
borderRadius: 3,
|
|
510
510
|
color: 'var(--code-text)',
|
|
511
|
-
}}>
|
|
511
|
+
}}>clawport setup</code> in your terminal to auto-detect and configure your environment.
|
|
512
512
|
You can continue setup and fix this later.
|
|
513
513
|
</div>
|
|
514
514
|
</div>
|
|
@@ -657,7 +657,7 @@ export function OnboardingWizard({ forceOpen, onClose }: OnboardingWizardProps)
|
|
|
657
657
|
borderRadius: 8,
|
|
658
658
|
background: settings.accentColor
|
|
659
659
|
? `linear-gradient(135deg, ${settings.accentColor}, ${settings.accentColor}dd)`
|
|
660
|
-
: '
|
|
660
|
+
: 'transparent',
|
|
661
661
|
display: 'flex',
|
|
662
662
|
alignItems: 'center',
|
|
663
663
|
justifyContent: 'center',
|
package/components/Sidebar.tsx
CHANGED
|
@@ -60,7 +60,7 @@ export function Sidebar() {
|
|
|
60
60
|
? 'transparent'
|
|
61
61
|
: settings.accentColor
|
|
62
62
|
? `linear-gradient(135deg, ${settings.accentColor}, ${settings.accentColor}dd)`
|
|
63
|
-
: '
|
|
63
|
+
: 'transparent',
|
|
64
64
|
boxShadow: settings.iconBgHidden ? 'none' : 'var(--shadow-card)',
|
|
65
65
|
display: 'flex',
|
|
66
66
|
alignItems: 'center',
|
|
@@ -42,8 +42,13 @@ export function GettingStartedSection() {
|
|
|
42
42
|
/>
|
|
43
43
|
|
|
44
44
|
<SubHeading>Quick Start (npm)</SubHeading>
|
|
45
|
+
<Callout type="note">
|
|
46
|
+
The npm package is <InlineCode>clawport-ui</InlineCode>. The CLI command
|
|
47
|
+
is <InlineCode>clawport</InlineCode>. Do not install the unrelated{" "}
|
|
48
|
+
<InlineCode>clawport</InlineCode> package.
|
|
49
|
+
</Callout>
|
|
45
50
|
<CodeBlock title="terminal">
|
|
46
|
-
{`# Install globally
|
|
51
|
+
{`# Install globally (package: clawport-ui, command: clawport)
|
|
47
52
|
npm install -g clawport-ui
|
|
48
53
|
|
|
49
54
|
# Run the setup wizard (auto-detects your OpenClaw config)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawport-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Open-source dashboard for managing, monitoring, and chatting with your OpenClaw AI agents.",
|
|
5
5
|
"homepage": "https://clawport.dev",
|
|
6
6
|
"repository": {
|
|
@@ -19,6 +19,22 @@
|
|
|
19
19
|
"next.js"
|
|
20
20
|
],
|
|
21
21
|
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"app/",
|
|
27
|
+
"bin/",
|
|
28
|
+
"components/",
|
|
29
|
+
"docs/",
|
|
30
|
+
"lib/",
|
|
31
|
+
"public/",
|
|
32
|
+
"scripts/",
|
|
33
|
+
"next.config.mjs",
|
|
34
|
+
"postcss.config.mjs",
|
|
35
|
+
"tsconfig.json",
|
|
36
|
+
".env.example"
|
|
37
|
+
],
|
|
22
38
|
"bin": {
|
|
23
39
|
"clawport": "./bin/clawport.mjs"
|
|
24
40
|
},
|
package/scripts/setup.mjs
CHANGED
|
@@ -48,7 +48,8 @@ function detectWorkspacePath() {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function detectOpenClawBin() {
|
|
51
|
-
|
|
51
|
+
const cmd = process.platform === 'win32' ? 'where' : 'which'
|
|
52
|
+
return exec(`${cmd} openclaw`)
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
function detectGatewayToken() {
|
|
@@ -63,9 +64,15 @@ function detectGatewayToken() {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
function checkGatewayRunning() {
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
async function checkGatewayRunning() {
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch('http://127.0.0.1:18789/', {
|
|
70
|
+
signal: AbortSignal.timeout(3000),
|
|
71
|
+
})
|
|
72
|
+
return res.ok || res.status > 0
|
|
73
|
+
} catch {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
// ---------------------------------------------------------------------------
|
|
@@ -84,7 +91,7 @@ async function main() {
|
|
|
84
91
|
OPENCLAW_GATEWAY_TOKEN: detectGatewayToken(),
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
const gatewayUp = checkGatewayRunning()
|
|
94
|
+
const gatewayUp = await checkGatewayRunning()
|
|
88
95
|
|
|
89
96
|
// Report findings
|
|
90
97
|
const entries = [
|
|
@@ -203,12 +210,13 @@ async function main() {
|
|
|
203
210
|
console.log()
|
|
204
211
|
console.log(` ${green('Done!')} .env.local written.`)
|
|
205
212
|
console.log()
|
|
213
|
+
const startCmd = cwdFlag ? 'clawport dev' : 'npm run dev'
|
|
206
214
|
console.log(` Next steps:`)
|
|
207
215
|
if (!gatewayUp) {
|
|
208
216
|
console.log(` 1. Start the gateway: ${dim('openclaw gateway run')}`)
|
|
209
|
-
console.log(` 2. Start ClawPort:
|
|
217
|
+
console.log(` 2. Start ClawPort: ${dim(startCmd)}`)
|
|
210
218
|
} else {
|
|
211
|
-
console.log(` ${dim(
|
|
219
|
+
console.log(` ${dim(startCmd)}`)
|
|
212
220
|
}
|
|
213
221
|
console.log()
|
|
214
222
|
}
|
package/BRANDING.md
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
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/OrgMap.tsx`, `app/page.tsx`, `docs/COMPONENTS.md` | React Flow org chart component. |
|
|
46
|
-
| `OrgMapProps` (interface) | `components/OrgMap.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-ui` |
|
|
81
|
-
| `package-lock.json` `name` | `clawport-ui` |
|
|
82
|
-
| npm package | [`clawport-ui`](https://www.npmjs.com/package/clawport-ui) |
|
|
83
|
-
| Git clone URLs in docs | `https://github.com/openclaw/clawport.git` |
|
|
84
|
-
|
|
85
|
-
## 7. Workspace Paths
|
|
86
|
-
|
|
87
|
-
The user's agent registry override lives at `$WORKSPACE_PATH/clawport/agents.json`. This path is referenced in:
|
|
88
|
-
|
|
89
|
-
| File | What |
|
|
90
|
-
|------|------|
|
|
91
|
-
| `lib/agents-registry.ts` | `join(workspacePath, 'clawport', 'agents.json')` |
|
|
92
|
-
| Multiple test files | Mock paths like `/tmp/test-workspace/clawport/agents.json` |
|
|
93
|
-
| Documentation | Setup instructions referencing `$WORKSPACE_PATH/clawport/` |
|
|
94
|
-
|
|
95
|
-
## 8. Documentation Files
|
|
96
|
-
|
|
97
|
-
Every `.md` file contains brand references. Full list:
|
|
98
|
-
|
|
99
|
-
| File | Approximate Occurrences |
|
|
100
|
-
|------|------------------------|
|
|
101
|
-
| `README.md` | ~20 |
|
|
102
|
-
| `SETUP.md` | ~25 |
|
|
103
|
-
| `CLAUDE.md` | ~20 |
|
|
104
|
-
| `docs/API.md` | ~5 |
|
|
105
|
-
| `docs/THEMING.md` | ~30 |
|
|
106
|
-
| `docs/COMPONENTS.md` | ~35 |
|
|
107
|
-
| `.env.example` | 1 |
|
|
108
|
-
|
|
109
|
-
## 9. Test Files
|
|
110
|
-
|
|
111
|
-
Tests reference brand strings in mock data and localStorage keys:
|
|
112
|
-
|
|
113
|
-
| File | What |
|
|
114
|
-
|------|------|
|
|
115
|
-
| `lib/settings.test.ts` | `clawport-settings` key, `portalName`/`portalSubtitle`/`portalEmoji`/`portalIcon` fields |
|
|
116
|
-
| `lib/agents.test.ts` | `clawport/agents.json` paths, "ClawPort Orchestrator" in mock data |
|
|
117
|
-
| `lib/conversations.test.ts` | `clawport-conversations` key |
|
|
118
|
-
| `lib/kanban/store.test.ts` | `clawport-kanban` key |
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Rebrand Checklist
|
|
123
|
-
|
|
124
|
-
1. **User-facing text** (Section 1) -- find-and-replace the display name
|
|
125
|
-
2. **Documentation** (Section 8) -- update all .md files
|
|
126
|
-
3. **Package name** (Section 6) -- update package.json, re-run npm install
|
|
127
|
-
4. **Internal identifiers** (Section 2) -- rename interfaces, components, functions, fields
|
|
128
|
-
5. **localStorage keys** (Section 3) -- add migration in `loadSettings()` to read old keys
|
|
129
|
-
6. **Custom events** (Section 4) -- rename event strings
|
|
130
|
-
7. **API keys** (Section 5) -- update session key and idempotency prefix
|
|
131
|
-
8. **Workspace paths** (Section 7) -- update `agents-registry.ts` path, support both old/new
|
|
132
|
-
9. **Test files** (Section 9) -- update all mock data and key references
|
package/CLAUDE.md
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
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
|
-
### CLI (global install)
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install -g clawport-ui
|
|
17
|
-
clawport setup # Auto-detect config, write .env.local into package dir
|
|
18
|
-
clawport dev # Start dev server
|
|
19
|
-
clawport start # Build + start production server
|
|
20
|
-
clawport status # Check gateway reachability + env config
|
|
21
|
-
clawport help # Show usage
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The CLI resolves its own package root via `import.meta.url`, so all commands work regardless of the user's current working directory. Entry point: `bin/clawport.mjs`.
|
|
25
|
-
|
|
26
|
-
## Project Overview
|
|
27
|
-
|
|
28
|
-
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.
|
|
29
|
-
|
|
30
|
-
## Tech Stack
|
|
31
|
-
|
|
32
|
-
- Next.js 16.1.6 (App Router, Turbopack)
|
|
33
|
-
- React 19.2.3, TypeScript 5
|
|
34
|
-
- Tailwind CSS 4 with CSS custom properties for theming
|
|
35
|
-
- Vitest 4 with jsdom environment
|
|
36
|
-
- OpenAI SDK (routed to Claude via OpenClaw gateway at localhost:18789)
|
|
37
|
-
- React Flow (@xyflow/react) for org chart
|
|
38
|
-
|
|
39
|
-
## Environment Variables
|
|
40
|
-
|
|
41
|
-
```env
|
|
42
|
-
WORKSPACE_PATH # Required -- path to .openclaw/workspace
|
|
43
|
-
OPENCLAW_BIN # Required -- path to openclaw binary
|
|
44
|
-
OPENCLAW_GATEWAY_TOKEN # Required -- gateway auth token
|
|
45
|
-
ELEVENLABS_API_KEY # Optional -- voice indicators
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Run `npm run setup` to auto-detect all required values from your local OpenClaw installation.
|
|
49
|
-
|
|
50
|
-
## Architecture
|
|
51
|
-
|
|
52
|
-
### Agent Registry Resolution
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
loadRegistry() checks:
|
|
56
|
-
1. $WORKSPACE_PATH/clawport/agents.json (user override)
|
|
57
|
-
2. Bundled lib/agents.json (default)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
`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.
|
|
61
|
-
|
|
62
|
-
### operatorName Flow
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
OnboardingWizard / Settings page
|
|
66
|
-
-> ClawPortSettings.operatorName (localStorage)
|
|
67
|
-
-> settings-provider.tsx (React context)
|
|
68
|
-
-> NavLinks.tsx (dynamic initials + display name)
|
|
69
|
-
-> ConversationView.tsx (sends operatorName in POST body)
|
|
70
|
-
-> /api/chat/[id] route (injects into system prompt: "You are speaking with {operatorName}")
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
No hardcoded operator names anywhere. Falls back to "Operator" / "??" when unset.
|
|
74
|
-
|
|
75
|
-
### Chat Pipeline (Text)
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
Client -> POST /api/chat/[id] -> OpenAI SDK -> localhost:18789/v1/chat/completions -> Claude
|
|
79
|
-
(streaming SSE response)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Chat Pipeline (Images/Vision)
|
|
83
|
-
|
|
84
|
-
The gateway's HTTP endpoint strips image_url content. Vision uses the CLI agent pipeline:
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
Client resizes image to 1200px max (Canvas API)
|
|
88
|
-
-> base64 data URL in message
|
|
89
|
-
-> POST /api/chat/[id]
|
|
90
|
-
-> Detects image in LATEST user message only (not history)
|
|
91
|
-
-> execFile: openclaw gateway call chat.send --params <json> --token <token>
|
|
92
|
-
-> Polls: openclaw gateway call chat.history every 2s
|
|
93
|
-
-> Matches response by timestamp >= sendTs
|
|
94
|
-
-> Returns assistant text via SSE
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Key files: `lib/anthropic.ts` (send + poll logic), `app/api/chat/[id]/route.ts` (routing)
|
|
98
|
-
|
|
99
|
-
**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.
|
|
100
|
-
|
|
101
|
-
**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.
|
|
102
|
-
|
|
103
|
-
**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.
|
|
104
|
-
|
|
105
|
-
### Voice Message Pipeline
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
Browser MediaRecorder (webm/opus or mp4)
|
|
109
|
-
-> AudioContext AnalyserNode captures waveform (40-60 samples)
|
|
110
|
-
-> Stop -> audioBlob + waveform data
|
|
111
|
-
-> POST /api/transcribe (Whisper via gateway)
|
|
112
|
-
-> Transcription text sent as message content
|
|
113
|
-
-> Audio data URL + waveform stored in message for playback
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Key files: `lib/audio-recorder.ts`, `lib/transcribe.ts`, `components/chat/VoiceMessage.tsx`
|
|
117
|
-
|
|
118
|
-
### Conversation Persistence
|
|
119
|
-
|
|
120
|
-
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()`.
|
|
121
|
-
|
|
122
|
-
### Theming
|
|
123
|
-
|
|
124
|
-
Five themes defined via CSS custom properties in `app/globals.css`:
|
|
125
|
-
- Dark (default), Glass, Color, Light, System
|
|
126
|
-
- Components use semantic tokens: `--bg`, `--text-primary`, `--accent`, `--separator`, etc.
|
|
127
|
-
- Theme state managed by `app/providers.tsx` ThemeProvider (localStorage)
|
|
128
|
-
|
|
129
|
-
## Onboarding
|
|
130
|
-
|
|
131
|
-
`components/OnboardingWizard.tsx` -- 5-step first-run setup wizard:
|
|
132
|
-
|
|
133
|
-
1. **Welcome** -- portal name, subtitle, operator name (with live sidebar preview)
|
|
134
|
-
2. **Theme** -- pick from available themes (applies live)
|
|
135
|
-
3. **Accent Color** -- color preset grid
|
|
136
|
-
4. **Voice Chat** -- microphone permission test (optional)
|
|
137
|
-
5. **Overview** -- feature summary (Agent Map, Chat, Kanban, Crons, Memory)
|
|
138
|
-
|
|
139
|
-
**First-run detection:** checks `localStorage('clawport-onboarded')`. If absent, wizard shows automatically.
|
|
140
|
-
|
|
141
|
-
**Mounting:** `OnboardingWizard` is rendered in `app/layout.tsx` (always present, self-hides when not needed).
|
|
142
|
-
|
|
143
|
-
**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.
|
|
144
|
-
|
|
145
|
-
## Environment Safety
|
|
146
|
-
|
|
147
|
-
`lib/env.ts` exports `requireEnv(name)` -- throws a clear error with the missing variable name and a pointer to `.env.example`.
|
|
148
|
-
|
|
149
|
-
**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.
|
|
150
|
-
|
|
151
|
-
Used by: `lib/memory.ts`, `lib/cron-runs.ts`, `lib/kanban/chat-store.ts`, `lib/crons.ts`
|
|
152
|
-
|
|
153
|
-
## File Map
|
|
154
|
-
|
|
155
|
-
### API Routes
|
|
156
|
-
|
|
157
|
-
| Route | Method | Purpose |
|
|
158
|
-
|-------|--------|---------|
|
|
159
|
-
| `/api/agents` | GET | All agents from registry + SOUL.md |
|
|
160
|
-
| `/api/chat/[id]` | POST | Agent chat -- text (streaming) or vision (send+poll) |
|
|
161
|
-
| `/api/crons` | GET | Cron jobs via `openclaw cron list --json` |
|
|
162
|
-
| `/api/memory` | GET | Memory files from workspace |
|
|
163
|
-
| `/api/tts` | POST | Text-to-speech via OpenClaw |
|
|
164
|
-
| `/api/transcribe` | POST | Audio transcription via Whisper |
|
|
165
|
-
|
|
166
|
-
### Core Libraries
|
|
167
|
-
|
|
168
|
-
| File | Purpose |
|
|
169
|
-
|------|---------|
|
|
170
|
-
| `lib/agents.ts` | Agent list builder -- calls `loadRegistry()`, merges SOUL.md |
|
|
171
|
-
| `lib/agents-registry.ts` | `loadRegistry()` -- workspace override -> bundled fallback |
|
|
172
|
-
| `lib/agents.json` | Bundled default agent registry |
|
|
173
|
-
| `lib/anthropic.ts` | Vision pipeline: `hasImageContent`, `extractImageAttachments`, `buildTextPrompt`, `sendViaOpenClaw` (send + poll), `execCli` |
|
|
174
|
-
| `lib/audio-recorder.ts` | `createAudioRecorder()` -- MediaRecorder + waveform via AnalyserNode |
|
|
175
|
-
| `lib/conversations.ts` | Conversation store with localStorage persistence |
|
|
176
|
-
| `lib/crons.ts` | Cron data fetching via CLI |
|
|
177
|
-
| `lib/env.ts` | `requireEnv(name)` -- safe env var access with clear errors |
|
|
178
|
-
| `lib/multimodal.ts` | `buildApiContent()` -- converts Message+Media to OpenAI API format |
|
|
179
|
-
| `lib/settings.ts` | `ClawPortSettings` type, `loadSettings()`, `saveSettings()` (localStorage) |
|
|
180
|
-
| `lib/transcribe.ts` | `transcribe(audioBlob)` -- Whisper API with graceful fallback |
|
|
181
|
-
| `lib/validation.ts` | `validateChatMessages()` -- validates text + multimodal content arrays |
|
|
182
|
-
|
|
183
|
-
### Chat Components
|
|
184
|
-
|
|
185
|
-
| Component | Purpose |
|
|
186
|
-
|-----------|---------|
|
|
187
|
-
| `ConversationView.tsx` | Main chat: messages, input, recording, paste/drop, file staging. Sends `operatorName` in POST body. |
|
|
188
|
-
| `VoiceMessage.tsx` | Waveform playback: play/pause + animated bar visualization |
|
|
189
|
-
| `FileAttachment.tsx` | File bubble: icon by type + name + size + download |
|
|
190
|
-
| `MediaPreview.tsx` | Pre-send strip of staged attachments with remove buttons |
|
|
191
|
-
| `AgentList.tsx` | Desktop agent sidebar with unread badges |
|
|
192
|
-
|
|
193
|
-
### Other Components
|
|
194
|
-
|
|
195
|
-
| Component | Purpose |
|
|
196
|
-
|-----------|---------|
|
|
197
|
-
| `OnboardingWizard.tsx` | 5-step first-run setup wizard (name, theme, accent, mic, overview) |
|
|
198
|
-
| `NavLinks.tsx` | Sidebar nav with dynamic operator initials + name from settings |
|
|
199
|
-
| `Sidebar.tsx` | Sidebar layout shell |
|
|
200
|
-
| `AgentAvatar.tsx` | Agent emoji/image avatar with optional background |
|
|
201
|
-
| `DynamicFavicon.tsx` | Updates favicon based on portal emoji/icon settings |
|
|
202
|
-
|
|
203
|
-
### Scripts & CLI
|
|
204
|
-
|
|
205
|
-
| File | Purpose |
|
|
206
|
-
|------|---------|
|
|
207
|
-
| `bin/clawport.mjs` | CLI entry point -- `clawport dev`, `clawport setup`, `clawport status`, etc. Resolves package root via `import.meta.url` |
|
|
208
|
-
| `scripts/setup.mjs` | `npm run setup` / `clawport setup` -- auto-detects WORKSPACE_PATH, OPENCLAW_BIN, gateway token; writes `.env.local`. Accepts `--cwd=<path>` flag for CLI usage |
|
|
209
|
-
|
|
210
|
-
## Testing
|
|
211
|
-
|
|
212
|
-
17 test suites, 288 tests total. All in `lib/` directory.
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
npx vitest run # All tests
|
|
216
|
-
npx vitest run lib/anthropic.test.ts # Single suite
|
|
217
|
-
npx vitest --watch # Watch mode
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Key test patterns:
|
|
221
|
-
- `vi.mock('child_process')` for CLI tests (anthropic.ts)
|
|
222
|
-
- `vi.useFakeTimers({ shouldAdvanceTime: true })` for polling tests
|
|
223
|
-
- `vi.stubEnv()` for environment variable tests
|
|
224
|
-
- jsdom environment for DOM-dependent tests
|
|
225
|
-
|
|
226
|
-
## Conventions
|
|
227
|
-
|
|
228
|
-
- No external charting/media libraries -- native Web APIs (Canvas, MediaRecorder, AudioContext)
|
|
229
|
-
- Base64 data URLs for all persisted media (not blob URLs)
|
|
230
|
-
- CSS custom properties for theming -- no Tailwind color classes directly
|
|
231
|
-
- Inline styles referencing CSS vars (e.g., `style={{ color: 'var(--text-primary)' }}`)
|
|
232
|
-
- Tests colocated with source: `lib/foo.ts` + `lib/foo.test.ts`
|
|
233
|
-
- Agent chat uses `claude-sonnet-4-6` model via OpenClaw gateway
|
|
234
|
-
- No em dashes in agent responses (enforced via system prompt)
|
|
235
|
-
- Call `requireEnv()` inside functions, not at module top level
|
|
236
|
-
- No hardcoded operator names -- use `operatorName` from settings context
|
|
237
|
-
|
|
238
|
-
## Common Tasks
|
|
239
|
-
|
|
240
|
-
### Add a new agent
|
|
241
|
-
Edit `lib/agents.json` (or drop a custom `agents.json` into `$WORKSPACE_PATH/clawport/`). Auto-appears in map, chat, and detail pages.
|
|
242
|
-
|
|
243
|
-
### Customize agents for your workspace
|
|
244
|
-
Create `$WORKSPACE_PATH/clawport/agents.json` with your own agent entries. ClawPort loads this instead of the bundled default. Format matches `lib/agents.json`.
|
|
245
|
-
|
|
246
|
-
### Re-run onboarding wizard
|
|
247
|
-
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.
|
|
248
|
-
|
|
249
|
-
### Add a new setting field
|
|
250
|
-
1. Add the field to `ClawPortSettings` interface in `lib/settings.ts`
|
|
251
|
-
2. Add a default value in `DEFAULTS`
|
|
252
|
-
3. Add parsing logic in `loadSettings()`
|
|
253
|
-
4. Add a setter method in `app/settings-provider.tsx`
|
|
254
|
-
5. Consume via `useSettings()` hook in components
|
|
255
|
-
|
|
256
|
-
### Change the chat model
|
|
257
|
-
Edit `app/api/chat/[id]/route.ts` -- change the `model` field in `openai.chat.completions.create()`.
|
|
258
|
-
|
|
259
|
-
### Add a new theme
|
|
260
|
-
Add a `[data-theme="name"]` block in `app/globals.css` with all CSS custom properties. Add the theme ID to `lib/themes.ts`.
|
|
261
|
-
|
|
262
|
-
### Debug image pipeline
|
|
263
|
-
1. Check server console for `sendViaOpenClaw execFile error:` or `sendViaOpenClaw: timed out`
|
|
264
|
-
2. Test CLI directly: `openclaw gateway call chat.send --params '{"sessionKey":"agent:main:clawport","idempotencyKey":"test","message":"describe","attachments":[]}' --token <token> --json`
|
|
265
|
-
3. Check history: `openclaw gateway call chat.history --params '{"sessionKey":"agent:main:clawport"}' --token <token> --json`
|
|
266
|
-
4. Verify gateway is running: `openclaw gateway call health --token <token>`
|
package/SETUP.md
DELETED
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
# ClawPort -- Setup Guide
|
|
2
|
-
|
|
3
|
-
This guide walks you through getting ClawPort running against your own OpenClaw instance. If you just want the quick version, see the [README](README.md).
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Prerequisites
|
|
8
|
-
|
|
9
|
-
1. **Node.js 22+** -- [Download](https://nodejs.org). Verify with `node -v`.
|
|
10
|
-
2. **OpenClaw** -- [Install OpenClaw](https://openclaw.ai) and make sure the CLI works: `openclaw --version`.
|
|
11
|
-
3. **OpenClaw gateway running** -- ClawPort talks to the gateway at `localhost:18789`. Start it before launching the UI.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 1. Install ClawPort
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# Install globally from npm
|
|
19
|
-
npm install -g clawport-ui
|
|
20
|
-
|
|
21
|
-
# Or clone the repo
|
|
22
|
-
git clone https://github.com/JohnRiceML/clawport-ui.git
|
|
23
|
-
cd clawport-ui
|
|
24
|
-
npm install
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 2. Configure Environment
|
|
30
|
-
|
|
31
|
-
The fastest way is the auto-setup script:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# If installed globally via npm
|
|
35
|
-
clawport setup
|
|
36
|
-
|
|
37
|
-
# Or if running from source
|
|
38
|
-
npm run setup
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
This auto-detects your `WORKSPACE_PATH`, `OPENCLAW_BIN`, and gateway token from your local OpenClaw installation, shows you what it found, and writes `.env.local` after you confirm.
|
|
42
|
-
|
|
43
|
-
If you prefer to configure manually, copy the template and edit:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
cp .env.example .env.local
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Open `.env.local` in your editor and set the three required variables.
|
|
50
|
-
|
|
51
|
-
### WORKSPACE_PATH
|
|
52
|
-
|
|
53
|
-
The path to your OpenClaw workspace directory. This is where OpenClaw stores agent SOUL files, memory, and other data.
|
|
54
|
-
|
|
55
|
-
**Default location:** `~/.openclaw/workspace`
|
|
56
|
-
|
|
57
|
-
To verify:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
ls ~/.openclaw/workspace
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
You should see files like `SOUL.md`, an `agents/` directory, and a `memory/` directory. Use the full absolute path in your `.env.local`:
|
|
64
|
-
|
|
65
|
-
```env
|
|
66
|
-
WORKSPACE_PATH=/Users/yourname/.openclaw/workspace
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### OPENCLAW_BIN
|
|
70
|
-
|
|
71
|
-
The absolute path to the `openclaw` CLI binary. ClawPort calls this binary for vision messages, cron listing, and other CLI operations.
|
|
72
|
-
|
|
73
|
-
To find it:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
which openclaw
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Use whatever that returns:
|
|
80
|
-
|
|
81
|
-
```env
|
|
82
|
-
OPENCLAW_BIN=/usr/local/bin/openclaw
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
If you installed via nvm or a version manager, the path might be something like `/Users/yourname/.nvm/versions/node/v22.14.0/bin/openclaw`. That's fine -- just use the full path.
|
|
86
|
-
|
|
87
|
-
### OPENCLAW_GATEWAY_TOKEN
|
|
88
|
-
|
|
89
|
-
The token that authenticates all API calls to the OpenClaw gateway. Every request ClawPort makes (chat, vision, TTS, transcription) includes this token.
|
|
90
|
-
|
|
91
|
-
To find it:
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
openclaw gateway status
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This should display your gateway configuration including the token. Copy it into your `.env.local`:
|
|
98
|
-
|
|
99
|
-
```env
|
|
100
|
-
OPENCLAW_GATEWAY_TOKEN=your-token-here
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### ELEVENLABS_API_KEY (optional)
|
|
104
|
-
|
|
105
|
-
If you want voice indicators on agent profiles, add your ElevenLabs API key. Get one at [elevenlabs.io](https://elevenlabs.io).
|
|
106
|
-
|
|
107
|
-
```env
|
|
108
|
-
ELEVENLABS_API_KEY=sk_your-key-here
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
If you skip this, everything works normally. Voice indicators just won't appear.
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## 3. Start the Gateway
|
|
116
|
-
|
|
117
|
-
ClawPort expects the OpenClaw gateway to be running at `localhost:18789`. Start it in a separate terminal:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
openclaw gateway run
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Leave this running while you use ClawPort. If the gateway isn't running, chat and all AI features will fail with connection errors.
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## 4. Run ClawPort
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
# If installed globally via npm
|
|
131
|
-
clawport dev
|
|
132
|
-
|
|
133
|
-
# Or if running from source
|
|
134
|
-
npm run dev
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Open [http://localhost:3000](http://localhost:3000).
|
|
138
|
-
|
|
139
|
-
### First-Run Onboarding
|
|
140
|
-
|
|
141
|
-
On your first visit, ClawPort launches the **onboarding wizard**. This walks you through:
|
|
142
|
-
|
|
143
|
-
- **Naming your portal** -- give your command centre a custom name and subtitle
|
|
144
|
-
- **Choosing a theme** -- pick from Dark, Glass, Color, Light, or System
|
|
145
|
-
- **Setting an accent color** -- personalize the UI highlight color
|
|
146
|
-
- **Customizing your logo** -- upload an icon or choose an emoji
|
|
147
|
-
- **Entering your name** -- so the UI knows who the operator is
|
|
148
|
-
|
|
149
|
-
All of these can be changed later in the Settings page. The wizard just gets you started quickly.
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## 5. Agent Customization
|
|
154
|
-
|
|
155
|
-
### Using the Bundled Registry
|
|
156
|
-
|
|
157
|
-
ClawPort ships with a default agent registry at `lib/agents.json`. This is a working example showing a full team hierarchy. It works out of the box if your OpenClaw workspace has matching agent SOUL files.
|
|
158
|
-
|
|
159
|
-
### Using Your Own Agents
|
|
160
|
-
|
|
161
|
-
To define your own agent team, create a file at:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
$WORKSPACE_PATH/clawport/agents.json
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
For example, if your `WORKSPACE_PATH` is `/Users/yourname/.openclaw/workspace`:
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
mkdir -p /Users/yourname/.openclaw/workspace/clawport
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Then create `agents.json` in that directory. ClawPort checks for this file on every request. If it exists, it replaces the bundled registry entirely. If it's missing or contains invalid JSON, the bundled default is used as a fallback.
|
|
174
|
-
|
|
175
|
-
### Agent Entry Format
|
|
176
|
-
|
|
177
|
-
Your `agents.json` should be an array of agent objects. Here's the minimal required shape:
|
|
178
|
-
|
|
179
|
-
```json
|
|
180
|
-
[
|
|
181
|
-
{
|
|
182
|
-
"id": "my-agent",
|
|
183
|
-
"name": "My Agent",
|
|
184
|
-
"title": "What this agent does",
|
|
185
|
-
"reportsTo": null,
|
|
186
|
-
"directReports": [],
|
|
187
|
-
"soulPath": "agents/my-agent/SOUL.md",
|
|
188
|
-
"voiceId": null,
|
|
189
|
-
"color": "#06b6d4",
|
|
190
|
-
"emoji": "🤖",
|
|
191
|
-
"tools": ["read", "write"],
|
|
192
|
-
"memoryPath": null,
|
|
193
|
-
"description": "One-liner about this agent."
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Field Reference
|
|
199
|
-
|
|
200
|
-
| Field | Type | Description |
|
|
201
|
-
|-------|------|-------------|
|
|
202
|
-
| `id` | string | Unique slug for the agent (e.g., `"vera"`) |
|
|
203
|
-
| `name` | string | Display name (e.g., `"VERA"`) |
|
|
204
|
-
| `title` | string | Role title (e.g., `"Chief Strategy Officer"`) |
|
|
205
|
-
| `reportsTo` | string or null | Parent agent `id` for the org chart. `null` for the root. |
|
|
206
|
-
| `directReports` | string[] | Array of child agent `id`s |
|
|
207
|
-
| `soulPath` | string or null | Path to the agent's SOUL.md, relative to `WORKSPACE_PATH` |
|
|
208
|
-
| `voiceId` | string or null | ElevenLabs voice ID (requires `ELEVENLABS_API_KEY`) |
|
|
209
|
-
| `color` | string | Hex color for the agent's node in the Org Map |
|
|
210
|
-
| `emoji` | string | Emoji shown as the agent's avatar |
|
|
211
|
-
| `tools` | string[] | List of tools this agent has access to |
|
|
212
|
-
| `memoryPath` | string or null | Path to agent-specific memory (relative to `WORKSPACE_PATH`) |
|
|
213
|
-
| `description` | string | One-line description shown in the UI |
|
|
214
|
-
|
|
215
|
-
### Hierarchy Rules
|
|
216
|
-
|
|
217
|
-
- Exactly one agent should have `"reportsTo": null` -- this is your root/orchestrator node.
|
|
218
|
-
- `directReports` should be consistent with `reportsTo`. If agent B reports to agent A, then A's `directReports` should include B's `id`.
|
|
219
|
-
- The Org Map uses these relationships to build the org chart automatically.
|
|
220
|
-
|
|
221
|
-
### Example: Minimal Two-Agent Setup
|
|
222
|
-
|
|
223
|
-
```json
|
|
224
|
-
[
|
|
225
|
-
{
|
|
226
|
-
"id": "boss",
|
|
227
|
-
"name": "Boss",
|
|
228
|
-
"title": "Orchestrator",
|
|
229
|
-
"reportsTo": null,
|
|
230
|
-
"directReports": ["worker"],
|
|
231
|
-
"soulPath": "SOUL.md",
|
|
232
|
-
"voiceId": null,
|
|
233
|
-
"color": "#f5c518",
|
|
234
|
-
"emoji": "👑",
|
|
235
|
-
"tools": ["read", "write", "exec", "message"],
|
|
236
|
-
"memoryPath": null,
|
|
237
|
-
"description": "Top-level orchestrator."
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
"id": "worker",
|
|
241
|
-
"name": "Worker",
|
|
242
|
-
"title": "Task Runner",
|
|
243
|
-
"reportsTo": "boss",
|
|
244
|
-
"directReports": [],
|
|
245
|
-
"soulPath": "agents/worker/SOUL.md",
|
|
246
|
-
"voiceId": null,
|
|
247
|
-
"color": "#22c55e",
|
|
248
|
-
"emoji": "⚙️",
|
|
249
|
-
"tools": ["read", "write"],
|
|
250
|
-
"memoryPath": null,
|
|
251
|
-
"description": "Handles assigned tasks."
|
|
252
|
-
}
|
|
253
|
-
]
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
---
|
|
257
|
-
|
|
258
|
-
## 6. Production Build
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
# If installed globally via npm
|
|
262
|
-
clawport start
|
|
263
|
-
|
|
264
|
-
# Or if running from source
|
|
265
|
-
npx next build
|
|
266
|
-
npm start
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
The production server runs on port 3000 by default. The gateway still needs to be running at `localhost:18789`.
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
## Troubleshooting
|
|
274
|
-
|
|
275
|
-
### "Missing required environment variable: WORKSPACE_PATH"
|
|
276
|
-
|
|
277
|
-
Your `.env.local` is missing or the variable isn't set. Make sure you copied `.env.example`:
|
|
278
|
-
|
|
279
|
-
```bash
|
|
280
|
-
cp .env.example .env.local
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Then fill in the values. Restart the dev server after changing `.env.local`.
|
|
284
|
-
|
|
285
|
-
### Gateway connection refused / chat not working
|
|
286
|
-
|
|
287
|
-
The OpenClaw gateway isn't running. Start it:
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
openclaw gateway run
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Verify it's reachable:
|
|
294
|
-
|
|
295
|
-
```bash
|
|
296
|
-
curl http://localhost:18789/v1/models
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
You should get a JSON response. If not, check that nothing else is using port 18789.
|
|
300
|
-
|
|
301
|
-
### No agents showing up
|
|
302
|
-
|
|
303
|
-
1. **Check `WORKSPACE_PATH`** -- make sure it points to a valid OpenClaw workspace directory.
|
|
304
|
-
2. **Check your agents.json** -- if you placed a custom `agents.json` at `$WORKSPACE_PATH/clawport/agents.json`, make sure it's valid JSON. A syntax error will cause a silent fallback to the bundled registry. Test with:
|
|
305
|
-
```bash
|
|
306
|
-
cat $WORKSPACE_PATH/clawport/agents.json | python3 -m json.tool
|
|
307
|
-
```
|
|
308
|
-
3. **Check the server console** -- ClawPort logs errors to the terminal where `npm run dev` is running.
|
|
309
|
-
|
|
310
|
-
### Agent SOUL.md not loading
|
|
311
|
-
|
|
312
|
-
The `soulPath` in your agents.json is relative to `WORKSPACE_PATH`. If your workspace is at `/Users/you/.openclaw/workspace` and `soulPath` is `"agents/vera/SOUL.md"`, ClawPort will look for `/Users/you/.openclaw/workspace/agents/vera/SOUL.md`.
|
|
313
|
-
|
|
314
|
-
Make sure the file exists at that path.
|
|
315
|
-
|
|
316
|
-
### Images not working in chat
|
|
317
|
-
|
|
318
|
-
Image messages use the CLI pipeline (`openclaw gateway call chat.send`). Common issues:
|
|
319
|
-
|
|
320
|
-
1. **`OPENCLAW_BIN` path is wrong** -- run `which openclaw` and update `.env.local`.
|
|
321
|
-
2. **Gateway token is wrong** -- verify with `openclaw gateway status`.
|
|
322
|
-
3. **Image too large** -- ClawPort resizes to 1200px max, but extremely large images may still hit limits. Try a smaller image.
|
|
323
|
-
|
|
324
|
-
Check the server console for errors like `sendViaOpenClaw execFile error:` or `E2BIG`.
|
|
325
|
-
|
|
326
|
-
### Voice/TTS features not working
|
|
327
|
-
|
|
328
|
-
Voice features require `ELEVENLABS_API_KEY` in your `.env.local`. Without it, voice indicators won't appear on agent profiles.
|
|
329
|
-
|
|
330
|
-
Audio transcription (speech-to-text) uses Whisper through the OpenClaw gateway and does not require a separate key.
|
|
331
|
-
|
|
332
|
-
### Port 3000 already in use
|
|
333
|
-
|
|
334
|
-
Another process is using port 3000. Either stop it or run ClawPort on a different port:
|
|
335
|
-
|
|
336
|
-
```bash
|
|
337
|
-
npm run dev -- -p 3001
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
## Running Tests
|
|
343
|
-
|
|
344
|
-
```bash
|
|
345
|
-
npm test # Run all tests via Vitest
|
|
346
|
-
npx tsc --noEmit # Type-check (expect 0 errors)
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
---
|
|
350
|
-
|
|
351
|
-
## Developer Guide
|
|
352
|
-
|
|
353
|
-
For architecture deep-dives, test patterns, and contribution conventions, see [CLAUDE.md](CLAUDE.md).
|
package/components.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
-
"style": "new-york",
|
|
4
|
-
"rsc": true,
|
|
5
|
-
"tsx": true,
|
|
6
|
-
"tailwind": {
|
|
7
|
-
"config": "",
|
|
8
|
-
"css": "app/globals.css",
|
|
9
|
-
"baseColor": "neutral",
|
|
10
|
-
"cssVariables": true,
|
|
11
|
-
"prefix": ""
|
|
12
|
-
},
|
|
13
|
-
"iconLibrary": "lucide",
|
|
14
|
-
"rtl": false,
|
|
15
|
-
"aliases": {
|
|
16
|
-
"components": "@/components",
|
|
17
|
-
"utils": "@/lib/utils",
|
|
18
|
-
"ui": "@/components/ui",
|
|
19
|
-
"lib": "@/lib",
|
|
20
|
-
"hooks": "@/hooks"
|
|
21
|
-
},
|
|
22
|
-
"registries": {}
|
|
23
|
-
}
|
package/vitest.config.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
})
|