Files
2026-06-22 09:27:36 -05:00

48 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""echo_output.py — M4: machine-readable output + dry-run plumbing. [v1.0 SCAFFOLD — implemented]
The high-level ops (capture/recall/resolve/scope) print prose, forcing the agent to
re-parse free text to act on a result. This provides a single JSON envelope and a
small dry-run helper so every op can emit a structured result and preview writes.
INTEGRATION (merge step): thread a global `--json` / `--dry-run` flag through echo.py's
parser and have each cmd_* return its data dict; emit() it. In --dry-run, the write
verbs print the envelope with action="dry-run" and perform no network mutation.
"""
from __future__ import annotations
import json
import sys
def envelope(action: str, data: dict | None = None, ok: bool = True,
error: str | None = None) -> dict:
"""Canonical result shape for every high-level op."""
env = {"ok": ok, "action": action}
if data:
env.update(data)
if error:
env["error"] = error
return env
def emit(env: dict, as_json: bool) -> None:
"""Print either the JSON envelope (machine mode) or a one-line human summary."""
if as_json:
print(json.dumps(env, ensure_ascii=False))
return
if not env.get("ok"):
print(f"error: {env.get('error', 'failed')}", file=sys.stderr)
return
bits = [env.get("action", "ok")]
if env.get("path"):
bits.append(str(env["path"]))
if env.get("links_added"):
bits.append(f"+{env['links_added']} links")
print("ok: " + " ".join(bits))
def dry_run_envelope(action: str, data: dict | None = None) -> dict:
"""Result for a previewed-but-not-executed write."""
return envelope(f"dry-run:{action}", data, ok=True)