From 10957a1fa26463b0d6a9c810700682e3ea7b6bc5 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Sat, 3 Jan 2026 15:06:30 +0100 Subject: [PATCH] fix: Use full brace-matching for .contacts JSON extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: - Previous fix only skipped prompt at start - stdout also has prompt at end: '{...}\nMarWoj|* ' - json.loads() failed with 'Extra data: line 302 column 2' Solution: - Use complete brace-matching (count depth, find matching braces) - Extract only JSON object between first '{' and matching '}' - Same technique as bridge uses for .pending_contacts - Ignores prompts both before and after JSON 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- app/meshcore/cli.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/app/meshcore/cli.py b/app/meshcore/cli.py index d7bb7da..10cad21 100644 --- a/app/meshcore/cli.py +++ b/app/meshcore/cli.py @@ -663,18 +663,32 @@ def get_contacts_json() -> Tuple[bool, Dict[str, Dict], str]: logger.error(f".contacts returned empty output (success={success})") return False, {}, '.contacts command returned empty output' - # Parse JSON output - use brace-matching to skip prompt line - # stdout format: "MarWoj|* .contacts\n{...}" - # We need to find the first '{' and parse from there + # Parse JSON output - use brace-matching to extract complete JSON object + # stdout format: "MarWoj|* .contacts\n{...}\nMarWoj|* " + # We need to find matching braces and parse only the JSON object try: - # Find first opening brace (skips prompt and command echo) - json_start = stdout.find('{') - if json_start == -1: - logger.error(f".contacts output has no JSON object (no opening brace found)") - return False, {}, 'No JSON object found in .contacts output' + # Use brace-matching to extract complete JSON object (same as bridge does) + depth = 0 + start_idx = None + end_idx = None - # Extract JSON string from first brace to end - json_str = stdout[json_start:] + for i, char in enumerate(stdout): + if char == '{': + if depth == 0: + start_idx = i + depth += 1 + elif char == '}': + depth -= 1 + if depth == 0 and start_idx is not None: + end_idx = i + 1 + break # Found complete JSON object + + if start_idx is None or end_idx is None: + logger.error(f".contacts output has no complete JSON object") + return False, {}, 'No complete JSON object found in .contacts output' + + # Extract only the JSON object (ignoring prompts before and after) + json_str = stdout[start_idx:end_idx] # Parse JSON contacts_dict = json.loads(json_str)