diff --git a/SKILL.md b/SKILL.md index 90ab1a1..166d75c 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: last30days description: Research a topic from the last 30 days on Reddit + X + Web, become an expert, and write copy-paste-ready prompts for the user's target tool. -argument-hint: '"[topic] for [tool]" or "[topic]"' +argument-hint: '"[topic]" or "[topic] --days=7"' allowed-tools: Bash, Read, Write, AskUserQuestion, WebSearch --- @@ -103,7 +103,8 @@ For ALL query types: - INCLUDE: blogs, tutorials, docs, news, GitHub repos - **DO NOT output "Sources:" list** - this is noise, we'll show stats at the end -**Depth options** (passed through from user's command): +**Options** (passed through from user's command): +- `--days=N` → Look back N days instead of 30 (e.g., `--days=7` for weekly roundup) - `--quick` → Faster, fewer sources (8-12 each) - (default) → Balanced (20-30 each) - `--deep` → Comprehensive (50-70 Reddit, 40-60 X) diff --git a/scripts/last30days.py b/scripts/last30days.py index edf8d0d..2066a79 100644 --- a/scripts/last30days.py +++ b/scripts/last30days.py @@ -323,8 +323,13 @@ def run_research( def main(): + # Fix Unicode output on Windows (cp1252 can't encode emoji) + if sys.platform == "win32": + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + parser = argparse.ArgumentParser( - description="Research a topic from the last 30 days on Reddit + X" + description="Research a topic from the last N days on Reddit + X" ) parser.add_argument("topic", nargs="?", help="Topic to research") parser.add_argument("--mock", action="store_true", help="Use fixtures") @@ -360,6 +365,14 @@ def main(): action="store_true", help="Include general web search alongside Reddit/X (lower weighted)", ) + parser.add_argument( + "--days", + type=int, + default=30, + choices=range(1, 31), + metavar="N", + help="Number of days to look back (1-30, default: 30)", + ) args = parser.parse_args() @@ -425,7 +438,7 @@ def main(): sys.exit(1) # Get date range - from_date, to_date = dates.get_date_range(30) + from_date, to_date = dates.get_date_range(args.days) # Check what keys are missing for promo messaging missing_keys = env.get_missing_keys(config) @@ -543,7 +556,7 @@ def main(): progress.show_complete(len(deduped_reddit), len(deduped_x)) # Output result - output_result(report, args.emit, web_needed, args.topic, from_date, to_date, missing_keys) + output_result(report, args.emit, web_needed, args.topic, from_date, to_date, missing_keys, args.days) def output_result( @@ -554,6 +567,7 @@ def output_result( from_date: str = "", to_date: str = "", missing_keys: str = "none", + days: int = 30, ): """Output the result based on emit mode.""" if emit_mode == "compact": @@ -577,7 +591,7 @@ def output_result( print("") print("Claude: Use your WebSearch tool to find 8-15 relevant web pages.") print("EXCLUDE: reddit.com, x.com, twitter.com (already covered above)") - print("INCLUDE: blogs, docs, news, tutorials from the last 30 days") + print(f"INCLUDE: blogs, docs, news, tutorials from the last {days} days") print("") print("After searching, synthesize WebSearch results WITH the Reddit/X") print("results above. WebSearch items should rank LOWER than comparable") diff --git a/scripts/lib/models.py b/scripts/lib/models.py index 78399c7..29e1223 100644 --- a/scripts/lib/models.py +++ b/scripts/lib/models.py @@ -7,7 +7,7 @@ from . import cache, http # OpenAI API OPENAI_MODELS_URL = "https://api.openai.com/v1/models" -OPENAI_FALLBACK_MODELS = ["gpt-5.2", "gpt-5.1", "gpt-5", "gpt-4o"] +OPENAI_FALLBACK_MODELS = ["gpt-5.2", "gpt-5.1", "gpt-5", "gpt-4.1", "gpt-4o"] # xAI API - Agent Tools API requires grok-4 family XAI_MODELS_URL = "https://api.x.ai/v1/models" @@ -35,8 +35,8 @@ def is_mainline_openai_model(model_id: str) -> bool: """Check if model is a mainline GPT model (not mini/nano/chat/codex/pro).""" model_lower = model_id.lower() - # Must be gpt-5 series - if not re.match(r'^gpt-5(\.\d+)*$', model_lower): + # Must be gpt-4o, gpt-4.1+, or gpt-5+ series (mainline, not mini/nano/etc) + if not re.match(r'^gpt-(?:4o|4\.1|5)(\.\d+)*$', model_lower): return False # Exclude variants diff --git a/scripts/lib/openai_reddit.py b/scripts/lib/openai_reddit.py index 68da853..8067a30 100644 --- a/scripts/lib/openai_reddit.py +++ b/scripts/lib/openai_reddit.py @@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional from . import http # Fallback models when the selected model isn't accessible (e.g., org not verified for GPT-5) -MODEL_FALLBACK_ORDER = ["gpt-4o", "gpt-4o-mini"] +MODEL_FALLBACK_ORDER = ["gpt-4.1", "gpt-4o", "gpt-4o-mini"] def _log_error(msg: str): @@ -25,7 +25,7 @@ def _log_info(msg: str): def _is_model_access_error(error: http.HTTPError) -> bool: """Check if error is due to model access/verification issues.""" - if error.status_code != 400: + if error.status_code not in (400, 403): return False if not error.body: return False