feat: render briefing in pager (less) — starts at top, scroll down

Output now pipes through less -R so the calendar and summary
are always visible at the top. Scroll down for waiting tasks,
done, and commits. Press q to get to the interactive prompt.
On refresh (r), the pager opens again from the top.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 13:28:16 +02:00
parent 0b4e06eb04
commit a344a9032d

View File

@@ -7,7 +7,8 @@ Usage: briefing [7|30] [client]
briefing 7 OHS — 7-day, OHS only briefing 7 OHS — 7-day, OHS only
""" """
import json, sys, subprocess, re, readline, os import json, sys, subprocess, re, readline, os, io
from contextlib import redirect_stdout
from datetime import datetime, timezone, timedelta from datetime import datetime, timezone, timedelta
API_KEY = "b666180ef00fffd23b9a606a4bd8deddea274d2e69fab975583d3d966fbfafed" API_KEY = "b666180ef00fffd23b9a606a4bd8deddea274d2e69fab975583d3d966fbfafed"
@@ -449,16 +450,22 @@ def show_task_detail(nid):
print(f"\n {DIM}URL: https://teacup.nodie.co.za/?sn={node.get('nodesid')}{RESET}") print(f"\n {DIM}URL: https://teacup.nodie.co.za/?sn={node.get('nodesid')}{RESET}")
def show_in_pager(content):
"""Show content in less, starting at the top. User scrolls down, q to exit."""
try:
proc = subprocess.Popen(['less', '-R', '-S', '--mouse'], stdin=subprocess.PIPE)
proc.communicate(input=content.encode())
except (BrokenPipeError, FileNotFoundError):
# Fallback: just print if less isn't available
print(content)
def fetch_and_render(range_days, client): def fetch_and_render(range_days, client):
"""Fetch briefing data from API and render it. Returns tasks list.""" """Fetch briefing data from API, render to pager. Returns tasks list."""
url = f"{BASE_URL}/briefing?range={range_days}" url = f"{BASE_URL}/briefing?range={range_days}"
if client: if client:
url += f"&client={client}" url += f"&client={client}"
# Clear screen so briefing always starts at top
if sys.stdout.isatty():
print("\033[2J\033[H", end="", flush=True)
result = subprocess.run( result = subprocess.run(
["curl", "-s", "-H", f"Authorization: Bearer {API_KEY}", url], ["curl", "-s", "-H", f"Authorization: Bearer {API_KEY}", url],
capture_output=True, text=True capture_output=True, text=True
@@ -481,11 +488,20 @@ def fetch_and_render(range_days, client):
raw = data["data"] raw = data["data"]
# Render to buffer
buf = io.StringIO()
with redirect_stdout(buf):
render_summary(raw.get('summary', {}), int(range_days)) render_summary(raw.get('summary', {}), int(range_days))
render_calendar(raw.get('calendar', {})) render_calendar(raw.get('calendar', {}))
render_tasks(raw.get('tasks', [])) render_tasks(raw.get('tasks', []))
render_commits(raw.get('git_commits', {})) render_commits(raw.get('git_commits', {}))
# Show in pager (starts at top, scroll down for more)
if sys.stdout.isatty():
show_in_pager(buf.getvalue())
else:
print(buf.getvalue())
return raw.get('tasks', []) return raw.get('tasks', [])