fix(drone): --json pass-through uses sys.stdout.write, no Rich mid-string wrap (td-49)
--json was routed through Rich console.print(), which defaults to width 80 on a non-TTY and hard-wraps mid-string, producing invalid JSON (e.g. 'Security \nScan'). Write raw JSON with sys.stdout.write() in the pass-through paths (drone.py + router.py); keep Rich for drone's own human UI. Verified live. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EccxENcB3KtyT9XuT4ybPz
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
61f958c17e
commit
2a5a370185
@@ -30,6 +30,22 @@ PyPI version — not the changelog header.
|
||||
to it). Hooks tests 66 green (presence_gate / cc_sessions / session_boot),
|
||||
telegram presence_pointer 42 green. (DPLAN-0226 P1/P2, FPLAN-0290/0291/0292)
|
||||
|
||||
- **Seedgo stale-template audit checker (`template_check`)** — a new advisory
|
||||
standard that flags branches still carrying unrendered template markers in
|
||||
their local prompts / config, so a citizen that never customized its scaffold
|
||||
no longer fails silently. Auto-discovered like every other checker; advisory
|
||||
(warns, never blocks). Ships with `template_content.py` and a `template.md`
|
||||
standard doc, covered by `test_template_check.py`. (built by @seedgo, DPLAN-0228)
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Drone `--json` output no longer corrupts machine JSON** — `--json`
|
||||
pass-through was routed through Rich's `console.print()`, which defaults to
|
||||
width 80 on a non-TTY and hard-wraps mid-string, producing invalid JSON
|
||||
(e.g. `"Security \nScan"`). Fixed by writing raw JSON with `sys.stdout.write()`
|
||||
in the pass-through paths (`drone.py` + `router.py`) while keeping Rich for
|
||||
drone's own human UI. Verified live end-to-end. (fixed by @drone, td-49)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Presence gate re-sourced to CC-native session files (presence_gate v2)** —
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
{
|
||||
"file": "apps/drone.py",
|
||||
"standard": "cli",
|
||||
"lines": [
|
||||
166,
|
||||
168
|
||||
],
|
||||
"reason": "Raw passthrough of module subprocess stdout/stderr — console.print() breaks routed output"
|
||||
"lines": [244, 246, 360, 362, 479, 481, 585, 587],
|
||||
"reason": "Raw passthrough of routed command stdout/stderr — console.print() wraps at 80 cols when piped, corrupting JSON and machine output"
|
||||
},
|
||||
{
|
||||
"file": "apps/modules/router.py",
|
||||
"standard": "cli",
|
||||
"lines": [62],
|
||||
"reason": "Raw passthrough of routed command stdout — console.print() wraps at 80 cols when piped, corrupting JSON and machine output"
|
||||
},
|
||||
{
|
||||
"file": "apps/handlers/scanning/formatters.py",
|
||||
|
||||
@@ -241,9 +241,9 @@ def _handle_module(name: str, args: List[str]) -> int:
|
||||
return 1
|
||||
|
||||
if result.get("stdout"):
|
||||
console.print(result["stdout"], end="", highlight=False, markup=False)
|
||||
sys.stdout.write(result["stdout"])
|
||||
if result.get("stderr"):
|
||||
err_console.print(result["stderr"], end="", highlight=False, markup=False)
|
||||
sys.stderr.write(result["stderr"])
|
||||
return result.get("exit_code", 0)
|
||||
|
||||
|
||||
@@ -357,9 +357,9 @@ def _handle_custom_command(args: list[str]) -> int:
|
||||
return 1
|
||||
|
||||
if result.stdout:
|
||||
console.print(result.stdout, end="", highlight=False)
|
||||
sys.stdout.write(result.stdout)
|
||||
if result.stderr:
|
||||
err_console.print(result.stderr, end="", highlight=False)
|
||||
sys.stderr.write(result.stderr)
|
||||
return result.exit_code
|
||||
|
||||
|
||||
@@ -476,9 +476,9 @@ def _handle_target(args: List[str]) -> int:
|
||||
return 1
|
||||
|
||||
if result.stdout:
|
||||
console.print(result.stdout, end="", highlight=False)
|
||||
sys.stdout.write(result.stdout)
|
||||
if result.stderr:
|
||||
err_console.print(result.stderr, end="", highlight=False)
|
||||
sys.stderr.write(result.stderr)
|
||||
return result.exit_code
|
||||
|
||||
|
||||
@@ -582,9 +582,9 @@ def main() -> int:
|
||||
return 1
|
||||
if isinstance(result, dict):
|
||||
if result.get("stdout"):
|
||||
console.print(result["stdout"], end="", highlight=False)
|
||||
sys.stdout.write(result["stdout"])
|
||||
if result.get("stderr"):
|
||||
err_console.print(result["stderr"], end="", highlight=False)
|
||||
sys.stderr.write(result["stderr"])
|
||||
return result.get("exit_code", 0)
|
||||
return 0 if result else 1
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ to the handler layer.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
@@ -58,7 +59,7 @@ def handle_command(command: Optional[str] = None, args: Optional[List[str]] = No
|
||||
cmd_args = args[2:] if len(args) > 2 else None
|
||||
result = route_command(target, cmd, args=cmd_args)
|
||||
if result.stdout:
|
||||
console.print(result.stdout, highlight=False)
|
||||
sys.stdout.write(result.stdout)
|
||||
return result.exit_code == 0
|
||||
if command == "route_all":
|
||||
if not args:
|
||||
@@ -132,7 +133,8 @@ def print_introspection():
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print(" [cyan]handlers/[/cyan]")
|
||||
console.print(
|
||||
" - [cyan]router_handler.py[/cyan] [dim](execute_branch_command — resolves and executes branch commands)[/dim]"
|
||||
" - [cyan]router_handler.py[/cyan] "
|
||||
"[dim](execute_branch_command — resolves and executes branch commands)[/dim]"
|
||||
)
|
||||
console.print(" - [cyan]executor.py[/cyan] [dim](CommandResult — subprocess execution result dataclass)[/dim]")
|
||||
console.print()
|
||||
|
||||
Reference in New Issue
Block a user