diff --git a/components/OnboardingWizard.tsx b/components/OnboardingWizard.tsx index 567c8c7..a12f91e 100644 --- a/components/OnboardingWizard.tsx +++ b/components/OnboardingWizard.tsx @@ -164,15 +164,24 @@ export function OnboardingWizard({ forceOpen, onClose }: OnboardingWizardProps) // Check crons (validates gateway + openclaw binary) fetch('/api/crons') - .then(r => { - if (!r.ok) throw new Error(`HTTP ${r.status}`) + .then(async r => { + if (!r.ok) { + const body = await r.json().catch(() => null) + const serverMsg = body?.error + throw new Error(serverMsg || `HTTP ${r.status}`) + } return r.json() }) .then(() => { setCronsStatus('ok') }) - .catch(() => { - setCronsError('Could not reach OpenClaw gateway. Run: openclaw gateway run') + .catch((err: Error) => { + const msg = err.message || '' + if (msg.includes('Failed to fetch cron') || msg.includes('JSON') || msg.includes('Unexpected token')) { + setCronsError('Cron list failed -- OpenClaw CLI may be printing log output before JSON. Try: OPENCLAW_LOG_LEVEL=error clawport dev') + } else { + setCronsError('Could not reach OpenClaw gateway. Run: openclaw gateway run') + } setCronsStatus('error') }) } diff --git a/lib/cli-utils.test.ts b/lib/cli-utils.test.ts index a0843da..b183075 100644 --- a/lib/cli-utils.test.ts +++ b/lib/cli-utils.test.ts @@ -41,4 +41,20 @@ hooks: Unrecognized key: "allowedAgentIds" it('throws on empty string', () => { expect(() => extractJson('')).toThrow() }) + + it('skips bracketed log lines like [plugins] before real JSON', () => { + const raw = `[plugins] [debug] Database schema initialized +[plugins] [debug] Loading context engine +{"jobs":[{"name":"daily-report","schedule":"0 8 * * *"}]}` + const result = extractJson(raw) as Record + expect(result.jobs).toEqual([{ name: 'daily-report', schedule: '0 8 * * *' }]) + }) + + it('skips bracketed log lines before JSON array', () => { + const raw = `[plugins] [debug] Database schema initialized +[plugins] [info] Ready +[{"id":"pulse","name":"daily-pulse"}]` + const result = extractJson(raw) + expect(result).toEqual([{ id: 'pulse', name: 'daily-pulse' }]) + }) }) diff --git a/lib/cli-utils.ts b/lib/cli-utils.ts index c32b133..e4b916e 100644 --- a/lib/cli-utils.ts +++ b/lib/cli-utils.ts @@ -1,25 +1,38 @@ /** * Extract a JSON value from CLI output that may contain non-JSON preamble. * - * Some OpenClaw versions print validation warnings (e.g. "Unrecognized key") - * to stdout before the JSON payload. This function finds the first `[` or `{` - * and parses from there, so ClawPort doesn't break on noisy CLI output. + * Some OpenClaw versions print validation warnings or debug log lines + * (e.g. "[plugins] [debug] ...") to stdout before the JSON payload. + * This function finds the actual JSON structure by trying each `[` or `{` + * position until one parses successfully. */ export function extractJson(raw: string): unknown { // Fast path: raw is already valid JSON const trimmed = raw.trim() if (trimmed.startsWith('[') || trimmed.startsWith('{')) { - return JSON.parse(trimmed) + try { + return JSON.parse(trimmed) + } catch { + // May start with [ but be a log line like "[plugins] ..." -- fall through + } } - // Find the first JSON structure in the output - const arrStart = raw.indexOf('[') - const objStart = raw.indexOf('{') - const starts = [arrStart, objStart].filter(i => i >= 0) - if (starts.length === 0) { - throw new SyntaxError('No JSON found in CLI output') + // Try each potential JSON start position + let pos = 0 + while (pos < raw.length) { + const arrStart = raw.indexOf('[', pos) + const objStart = raw.indexOf('{', pos) + const candidates = [arrStart, objStart].filter(i => i >= 0) + if (candidates.length === 0) break + + const start = Math.min(...candidates) + try { + return JSON.parse(raw.slice(start)) + } catch { + // This wasn't the real JSON start -- advance past it + pos = start + 1 + } } - const start = Math.min(...starts) - return JSON.parse(raw.slice(start)) + throw new SyntaxError('No JSON found in CLI output') } diff --git a/package-lock.json b/package-lock.json index f11c60d..e0dee6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "clawport-ui", - "version": "0.8.5", + "version": "0.8.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "clawport-ui", - "version": "0.8.5", + "version": "0.8.6", "license": "MIT", "dependencies": { "@dagrejs/dagre": "^2.0.4", diff --git a/package.json b/package.json index 942a209..bed8545 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clawport-ui", - "version": "0.8.5", + "version": "0.8.6", "description": "Open-source dashboard for managing, monitoring, and chatting with your OpenClaw AI agents.", "homepage": "https://clawport.dev", "repository": {