Preserve clean mode for last run state
This commit is contained in:
committed by
Trevin Chow
parent
5ab8c3ba76
commit
dd7e6a1562
@@ -63,14 +63,52 @@ fi
|
||||
# Check SETUP_COMPLETE (from file or env)
|
||||
SETUP_COMPLETE="${ENV_SETUP_COMPLETE:-${SETUP_COMPLETE:-}}"
|
||||
|
||||
# Compute last-run summary line (if last-run.json exists)
|
||||
if [[ "${LAST30DAYS_CONFIG_DIR+x}" == "x" ]]; then
|
||||
if [[ -n "$LAST30DAYS_CONFIG_DIR" ]]; then
|
||||
LAST_RUN_FILE="$LAST30DAYS_CONFIG_DIR/last-run.json"
|
||||
else
|
||||
LAST_RUN_FILE=""
|
||||
fi
|
||||
else
|
||||
LAST_RUN_FILE="$HOME/.config/last30days/last-run.json"
|
||||
fi
|
||||
LAST_RUN_LINE=""
|
||||
if [[ -n "$LAST_RUN_FILE" && -f "$LAST_RUN_FILE" ]]; then
|
||||
LAST_RUN_LINE=$(LAST_RUN_FILE="$LAST_RUN_FILE" python3 - <<'PY' 2>/dev/null
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
path = os.environ["LAST_RUN_FILE"]
|
||||
try:
|
||||
d = json.load(open(path))
|
||||
topic = (d.get("topic") or "?")[:60]
|
||||
ts = d.get("timestamp", "")
|
||||
dt = datetime.datetime.fromisoformat(ts.replace("Z", "+00:00"))
|
||||
delta = (datetime.datetime.now(datetime.timezone.utc) - dt).total_seconds()
|
||||
if delta < 60: ago = f"{int(delta)}s ago"
|
||||
elif delta < 3600: ago = f"{int(delta//60)}m ago"
|
||||
elif delta < 86400: ago = f"{int(delta//3600)}h ago"
|
||||
else: ago = f"{int(delta//86400)}d ago"
|
||||
total = d.get("total", 0)
|
||||
print(f" Last run: \"{topic}\" · {ago} · {total} results")
|
||||
except Exception:
|
||||
pass
|
||||
PY
|
||||
)
|
||||
fi
|
||||
|
||||
# If setup has never been run, show welcome message for new users
|
||||
if [[ -z "$SETUP_COMPLETE" && -z "$CONFIG_FILE" && -z "${OPENAI_API_KEY:-}" && -z "${SCRAPECREATORS_API_KEY:-}" && -z "${AUTH_TOKEN:-}" && -z "${XAI_API_KEY:-}" ]]; then
|
||||
cat <<'EOF'
|
||||
/last30days: Ready to use. Run /last30days to get started — setup takes 30 seconds.
|
||||
Research any topic across Reddit, HN, X, YouTube, Polymarket (last 30 days).
|
||||
|
||||
Reddit, Hacker News, and Polymarket work out of the box.
|
||||
The setup wizard can unlock X/Twitter, YouTube, and more.
|
||||
EOF
|
||||
[[ -n "$LAST_RUN_LINE" ]] && echo "$LAST_RUN_LINE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -121,9 +159,13 @@ fi
|
||||
if [[ -n "$HAS_SCRAPECREATORS" ]]; then
|
||||
# Fully configured — compact ready message
|
||||
echo "/last30days: Ready — ${SOURCE_COUNT} sources active."
|
||||
echo " Research any topic across social + market + web sources (last 30 days)."
|
||||
[[ -n "$LAST_RUN_LINE" ]] && echo "$LAST_RUN_LINE"
|
||||
else
|
||||
# Setup done but missing ScrapeCreators — recommend it
|
||||
echo "/last30days: Ready — ${SOURCE_COUNT} sources active."
|
||||
echo " Research any topic across social + market + web sources (last 30 days)."
|
||||
[[ -n "$LAST_RUN_LINE" ]] && echo "$LAST_RUN_LINE"
|
||||
echo " Tip: Add ScrapeCreators for Reddit comments + TikTok + Instagram."
|
||||
echo " 100 free credits, no credit card — scrapecreators.com"
|
||||
echo " last30days has no affiliation with any API provider."
|
||||
|
||||
@@ -531,6 +531,25 @@ def _show_runtime_ui(
|
||||
progress.show_promo(promo, diag=diag)
|
||||
|
||||
|
||||
def _write_last_run(topic: str, report: "schema.Report") -> None:
|
||||
try:
|
||||
import datetime
|
||||
if env.CONFIG_DIR is None:
|
||||
return
|
||||
target = env.CONFIG_DIR
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
counts = {source: len(items) for source, items in report.items_by_source.items()}
|
||||
payload = {
|
||||
"topic": topic,
|
||||
"timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
"sources": counts,
|
||||
"total": sum(counts.values()),
|
||||
}
|
||||
(target / "last-run.json").write_text(json.dumps(payload, indent=2))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = build_parser()
|
||||
# Use parse_known_args so setup sub-flags (--device-auth, --github,
|
||||
@@ -870,6 +889,7 @@ def main() -> int:
|
||||
report, progress, diag,
|
||||
suppress_web_promo=bool(external_plan or comp_plan),
|
||||
)
|
||||
_write_last_run(topic, report)
|
||||
if args.store:
|
||||
counts = persist_report(report)
|
||||
sys.stderr.write(
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
LAST30DAYS_SCRIPT = REPO_ROOT / "skills" / "last30days" / "scripts" / "last30days.py"
|
||||
|
||||
|
||||
def run_last30days(topic: str, env: dict[str, str]) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(LAST30DAYS_SCRIPT), topic, "--mock", "--emit=json"],
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
||||
class LastRunStateTests(unittest.TestCase):
|
||||
def test_empty_config_override_disables_last_run_write(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
home = Path(tmp) / "home"
|
||||
env = os.environ.copy()
|
||||
env["HOME"] = str(home)
|
||||
env["LAST30DAYS_CONFIG_DIR"] = ""
|
||||
|
||||
result = run_last30days("synthetic eval query", env)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertFalse((home / ".config" / "last30days" / "last-run.json").exists())
|
||||
|
||||
def test_custom_config_override_writes_last_run_to_custom_dir(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
config_dir = Path(tmp) / "custom-config"
|
||||
env = os.environ.copy()
|
||||
env["HOME"] = str(Path(tmp) / "home")
|
||||
env["LAST30DAYS_CONFIG_DIR"] = str(config_dir)
|
||||
|
||||
result = run_last30days("custom config query", env)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
payload = json.loads((config_dir / "last-run.json").read_text())
|
||||
self.assertEqual(payload["topic"], "custom config query")
|
||||
self.assertGreaterEqual(payload["total"], 0)
|
||||
|
||||
def test_hook_reads_last_run_from_custom_config_dir(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
config_dir = Path(tmp) / "custom-config"
|
||||
config_dir.mkdir()
|
||||
(config_dir / "last-run.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"topic": "custom hook query",
|
||||
"timestamp": "2026-04-30T00:00:00+00:00",
|
||||
"sources": {"reddit": 2},
|
||||
"total": 2,
|
||||
}
|
||||
)
|
||||
)
|
||||
env = os.environ.copy()
|
||||
env["HOME"] = str(Path(tmp) / "home")
|
||||
env["LAST30DAYS_CONFIG_DIR"] = str(config_dir)
|
||||
|
||||
result = subprocess.run(
|
||||
["bash", "hooks/scripts/check-config.sh"],
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertIn('Last run: "custom hook query"', result.stdout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user