feat: add refresh command to interactive mode

Type 'r' in the interactive prompt to re-fetch and re-render
the full briefing without exiting. Refactored main() to
separate fetch/render from the interactive loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 13:23:46 +02:00
parent 9189896d4a
commit 182644976c

View File

@@ -449,15 +449,46 @@ 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 interactive_mode(tasks): def fetch_and_render(range_days, client):
"""Interactive prompt — type a task number to see details.""" """Fetch briefing data from API and render it. Returns tasks list."""
# Build lookup url = f"{BASE_URL}/briefing?range={range_days}"
task_ids = set() if client:
for t in tasks: url += f"&client={client}"
task_ids.add(str(t['nodesid']))
result = subprocess.run(
["curl", "-s", "-H", f"Authorization: Bearer {API_KEY}", url],
capture_output=True, text=True
)
if not result.stdout.strip():
print(f"{RED}Empty response from API{RESET}")
return []
try:
data = json.loads(result.stdout)
except json.JSONDecodeError:
print(f"{RED}Invalid JSON response{RESET}")
print(result.stdout[:500])
return []
if not data.get("success"):
print(f"{RED}API error: {data.get('message', 'Unknown')}{RESET}")
return []
raw = data["data"]
render_summary(raw.get('summary', {}), int(range_days))
render_calendar(raw.get('calendar', {}))
render_tasks(raw.get('tasks', []))
render_commits(raw.get('git_commits', {}))
return raw.get('tasks', [])
def interactive_mode(tasks, range_days, client):
"""Interactive prompt — type a task number for details, 'r' to refresh."""
print(f"\n{BOLD}{CYAN}{'─' * 60}{RESET}") print(f"\n{BOLD}{CYAN}{'─' * 60}{RESET}")
print(f"{DIM}Type a task number for details, or 'q' to quit{RESET}") print(f"{DIM}Commands: task number | r = refresh | q = quit{RESET}")
print(f"{BOLD}{CYAN}{'─' * 60}{RESET}") print(f"{BOLD}{CYAN}{'─' * 60}{RESET}")
while True: while True:
@@ -470,13 +501,22 @@ def interactive_mode(tasks):
if not inp or inp.lower() in ('q', 'quit', 'exit'): if not inp or inp.lower() in ('q', 'quit', 'exit'):
break break
# Refresh
if inp.lower() in ('r', 'refresh'):
print(f"\n{DIM}Refreshing...{RESET}\n")
tasks = fetch_and_render(range_days, client)
print(f"\n{BOLD}{CYAN}{'─' * 60}{RESET}")
print(f"{DIM}Commands: task number | r = refresh | q = quit{RESET}")
print(f"{BOLD}{CYAN}{'─' * 60}{RESET}")
continue
# Strip # prefix if present # Strip # prefix if present
inp = inp.lstrip('#') inp = inp.lstrip('#')
if inp.isdigit(): if inp.isdigit():
show_task_detail(int(inp)) show_task_detail(int(inp))
else: else:
print(f" {DIM}Enter a task number (e.g. 3047) or 'q' to quit{RESET}") print(f" {DIM}Commands: task number | r = refresh | q = quit{RESET}")
def main(): def main():
@@ -489,42 +529,11 @@ def main():
if args: if args:
client = args[0] client = args[0]
url = f"{BASE_URL}/briefing?range={range_days}" tasks = fetch_and_render(range_days, client)
if client:
url += f"&client={client}"
result = subprocess.run(
["curl", "-s", "-H", f"Authorization: Bearer {API_KEY}", url],
capture_output=True, text=True
)
if not result.stdout.strip():
print(f"{RED}Empty response from API{RESET}")
sys.exit(1)
try:
data = json.loads(result.stdout)
except json.JSONDecodeError:
print(f"{RED}Invalid JSON response{RESET}")
print(result.stdout[:500])
sys.exit(1)
if not data.get("success"):
print(f"{RED}API error: {data.get('message', 'Unknown')}{RESET}")
sys.exit(1)
raw = data["data"]
# Render from raw JSON data
render_summary(raw.get('summary', {}), int(range_days))
render_calendar(raw.get('calendar', {}))
render_tasks(raw.get('tasks', []))
render_commits(raw.get('git_commits', {}))
# Interactive mode # Interactive mode
tasks = raw.get('tasks', []) if sys.stdin.isatty():
if tasks and sys.stdin.isatty(): interactive_mode(tasks, range_days, client)
interactive_mode(tasks)
if __name__ == "__main__": if __name__ == "__main__":