fix: prevent pcbnew stdout noise from causing sync_schematic_to_board timeouts

The TS<->Python communication channel uses stdout for JSON responses.
pcbnew's C++ SWIG layer can write warnings and diagnostics directly to
C-level stdout (fd 1), corrupting the JSON framing. The TS parser then
never sees valid JSON and the command times out after 30 seconds.

Three changes fix this:

1. Python stdout redirect: In main(), save the original stdout fd for
   exclusive JSON response use, then redirect fd 1 to stderr so all
   pcbnew C++ output goes to logs instead of the response pipe.

2. Robust TS JSON parser: tryParseResponse() now uses newline-delimited
   parsing as a fallback. The Python side writes single-line JSON
   terminated by \n; the parser uses this as the completion signal
   instead of brace-matching, which prevents premature resolution of
   truncated chunked responses. Non-JSON preamble lines are logged
   and stripped.

3. Fix stray print() calls: Converted print() to logger in
   component_schematic.py and library_schematic.py so they don't
   leak to stdout during normal operations.

Also adds sync_schematic_to_board to the longRunningCommands list for
an appropriate timeout value.
This commit is contained in:
William Viana
2026-04-03 11:24:42 -07:00
parent f79a3d6435
commit 0bc00b1451
4 changed files with 137 additions and 50 deletions

View File

@@ -4024,8 +4024,29 @@ print("ok")
}
def _write_response(response_fd, response):
"""Write a JSON response to the original stdout fd.
All response output goes through this function so that stray C-level
writes from pcbnew (warnings, diagnostics) never corrupt the JSON
framing seen by the TypeScript host.
"""
payload = json.dumps(response) + "\n"
os.write(response_fd, payload.encode("utf-8"))
def main():
"""Main entry point"""
# --- Redirect stdout so pcbnew C++ noise never reaches the TS host ---
# Save the real stdout fd for our exclusive JSON response channel.
_response_fd = os.dup(1)
# Point fd 1 (C-level stdout) at stderr so that any printf / std::cout
# output from pcbnew or other C extensions is visible in logs but does
# NOT corrupt the JSON stream the TypeScript side is parsing.
os.dup2(2, 1)
# Also redirect Python-level stdout to stderr for the same reason.
sys.stdout = sys.stderr
logger.info("Starting KiCAD interface...")
interface = KiCADInterface()
@@ -4167,10 +4188,9 @@ def main():
# Handle command
response = interface.handle_command(command, params)
# Send response
# Send response via the clean fd (immune to pcbnew stdout noise)
logger.debug(f"Sending response: {response}")
print(json.dumps(response))
sys.stdout.flush()
_write_response(_response_fd, response)
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON input: {str(e)}")
@@ -4179,8 +4199,7 @@ def main():
"message": "Invalid JSON input",
"errorDetails": str(e),
}
print(json.dumps(response))
sys.stdout.flush()
_write_response(_response_fd, response)
except KeyboardInterrupt:
logger.info("KiCAD interface stopped")