Add morning-report and stock-lookup skills

Add comprehensive morning report skill with collectors for calendar, email, tasks,
infrastructure status, news, stocks, and weather. Add stock lookup skill for quote queries.
This commit is contained in:
OpenCode Test
2026-01-03 10:54:54 -08:00
parent ae958528a6
commit daa4de8832
13 changed files with 1590 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
#!/usr/bin/env python3
"""Stocks collector using stock-lookup skill."""
import json
import subprocess
import sys
from pathlib import Path
def get_quotes(symbols: list) -> list:
"""Fetch quotes using stock-lookup skill."""
script = Path.home() / ".claude/skills/stock-lookup/scripts/quote.py"
try:
result = subprocess.run(
[sys.executable, str(script), "--json"] + symbols,
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
return json.loads(result.stdout)
else:
return [{"symbol": s, "error": "fetch failed"} for s in symbols]
except Exception as e:
return [{"symbol": s, "error": str(e)} for s in symbols]
def format_stocks_with_haiku(quotes: list) -> str:
"""Use Haiku to format stock data nicely."""
# Build context
lines = []
for q in quotes:
if "error" in q:
lines.append(f"{q.get('symbol', '?')}: error - {q['error']}")
else:
price = q.get("price", 0)
prev = q.get("previous_close", price)
if prev and prev > 0:
change = ((price - prev) / prev) * 100
direction = "+" if change >= 0 else ""
lines.append(f"{q['symbol']}: ${price:.2f} ({direction}{change:.1f}%)")
else:
lines.append(f"{q['symbol']}: ${price:.2f}")
stock_data = "\n".join(lines)
prompt = f"""Format these stock quotes into a compact single line for a morning dashboard.
Use arrow indicators (▲▼) for direction. Keep it concise.
{stock_data}
Output ONLY the formatted stock line, nothing else."""
try:
result = subprocess.run(
["claude", "--print", "--model", "haiku", "-p", prompt],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
except Exception:
pass
# Fallback to basic format
parts = []
for q in quotes:
if "error" in q:
parts.append(f"{q.get('symbol', '?')} ⚠️")
else:
price = q.get("price", 0)
prev = q.get("previous_close", price)
if prev and prev > 0:
change = ((price - prev) / prev) * 100
arrow = "" if change >= 0 else ""
parts.append(f"{q['symbol']} ${price:.2f} {'+' if change >= 0 else ''}{change:.1f}% {arrow}")
else:
parts.append(f"{q['symbol']} ${price:.2f}")
return " ".join(parts)
def collect(config: dict) -> dict:
"""Main collector entry point."""
watchlist = config.get("stocks", {}).get("watchlist", ["NVDA", "AAPL", "MSFT"])
quotes = get_quotes(watchlist)
formatted = format_stocks_with_haiku(quotes)
errors = [q.get("error") for q in quotes if "error" in q]
return {
"section": "Stocks",
"icon": "📈",
"content": formatted,
"raw": quotes,
"error": errors[0] if errors else None
}
if __name__ == "__main__":
config = {"stocks": {"watchlist": ["CRWV", "NVDA", "MSFT"]}}
result = collect(config)
print(f"## {result['icon']} {result['section']}")
print(result["content"])