clawport-ui 0.8.5 → 0.8.6

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.
@@ -164,15 +164,24 @@ export function OnboardingWizard({ forceOpen, onClose }: OnboardingWizardProps)
164
164
 
165
165
  // Check crons (validates gateway + openclaw binary)
166
166
  fetch('/api/crons')
167
- .then(r => {
168
- if (!r.ok) throw new Error(`HTTP ${r.status}`)
167
+ .then(async r => {
168
+ if (!r.ok) {
169
+ const body = await r.json().catch(() => null)
170
+ const serverMsg = body?.error
171
+ throw new Error(serverMsg || `HTTP ${r.status}`)
172
+ }
169
173
  return r.json()
170
174
  })
171
175
  .then(() => {
172
176
  setCronsStatus('ok')
173
177
  })
174
- .catch(() => {
175
- setCronsError('Could not reach OpenClaw gateway. Run: openclaw gateway run')
178
+ .catch((err: Error) => {
179
+ const msg = err.message || ''
180
+ if (msg.includes('Failed to fetch cron') || msg.includes('JSON') || msg.includes('Unexpected token')) {
181
+ setCronsError('Cron list failed -- OpenClaw CLI may be printing log output before JSON. Try: OPENCLAW_LOG_LEVEL=error clawport dev')
182
+ } else {
183
+ setCronsError('Could not reach OpenClaw gateway. Run: openclaw gateway run')
184
+ }
176
185
  setCronsStatus('error')
177
186
  })
178
187
  }
@@ -41,4 +41,20 @@ hooks: Unrecognized key: "allowedAgentIds"
41
41
  it('throws on empty string', () => {
42
42
  expect(() => extractJson('')).toThrow()
43
43
  })
44
+
45
+ it('skips bracketed log lines like [plugins] before real JSON', () => {
46
+ const raw = `[plugins] [debug] Database schema initialized
47
+ [plugins] [debug] Loading context engine
48
+ {"jobs":[{"name":"daily-report","schedule":"0 8 * * *"}]}`
49
+ const result = extractJson(raw) as Record<string, unknown>
50
+ expect(result.jobs).toEqual([{ name: 'daily-report', schedule: '0 8 * * *' }])
51
+ })
52
+
53
+ it('skips bracketed log lines before JSON array', () => {
54
+ const raw = `[plugins] [debug] Database schema initialized
55
+ [plugins] [info] Ready
56
+ [{"id":"pulse","name":"daily-pulse"}]`
57
+ const result = extractJson(raw)
58
+ expect(result).toEqual([{ id: 'pulse', name: 'daily-pulse' }])
59
+ })
44
60
  })
package/lib/cli-utils.ts CHANGED
@@ -1,25 +1,38 @@
1
1
  /**
2
2
  * Extract a JSON value from CLI output that may contain non-JSON preamble.
3
3
  *
4
- * Some OpenClaw versions print validation warnings (e.g. "Unrecognized key")
5
- * to stdout before the JSON payload. This function finds the first `[` or `{`
6
- * and parses from there, so ClawPort doesn't break on noisy CLI output.
4
+ * Some OpenClaw versions print validation warnings or debug log lines
5
+ * (e.g. "[plugins] [debug] ...") to stdout before the JSON payload.
6
+ * This function finds the actual JSON structure by trying each `[` or `{`
7
+ * position until one parses successfully.
7
8
  */
8
9
  export function extractJson(raw: string): unknown {
9
10
  // Fast path: raw is already valid JSON
10
11
  const trimmed = raw.trim()
11
12
  if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
12
- return JSON.parse(trimmed)
13
+ try {
14
+ return JSON.parse(trimmed)
15
+ } catch {
16
+ // May start with [ but be a log line like "[plugins] ..." -- fall through
17
+ }
13
18
  }
14
19
 
15
- // Find the first JSON structure in the output
16
- const arrStart = raw.indexOf('[')
17
- const objStart = raw.indexOf('{')
18
- const starts = [arrStart, objStart].filter(i => i >= 0)
19
- if (starts.length === 0) {
20
- throw new SyntaxError('No JSON found in CLI output')
20
+ // Try each potential JSON start position
21
+ let pos = 0
22
+ while (pos < raw.length) {
23
+ const arrStart = raw.indexOf('[', pos)
24
+ const objStart = raw.indexOf('{', pos)
25
+ const candidates = [arrStart, objStart].filter(i => i >= 0)
26
+ if (candidates.length === 0) break
27
+
28
+ const start = Math.min(...candidates)
29
+ try {
30
+ return JSON.parse(raw.slice(start))
31
+ } catch {
32
+ // This wasn't the real JSON start -- advance past it
33
+ pos = start + 1
34
+ }
21
35
  }
22
36
 
23
- const start = Math.min(...starts)
24
- return JSON.parse(raw.slice(start))
37
+ throw new SyntaxError('No JSON found in CLI output')
25
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawport-ui",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
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": {