#!/usr/bin/env bash # countdown-milestone-refresh.sh — 把「主線 milestone 的期限」寫進倒數用的快取 # (inkstone/ISEP#63 的第二個基準) # # 為什麼是一支獨立腳本、而不是寫在 hook 裡: # 倒數那一行走在 **UserPromptSubmit** 上,也就是每一則訊息的關鍵路徑。 # 在那裡打 HTTP = leo 每講一句話都先等一次網路。 # ⇒ hook 只讀快取(`hooks/lib/countdown.py` 從不打網路), # 快取由本支在 **SessionStart** 更新一次。不是輪詢、不掛排程(守 D14 紅線)。 # # 寫出來的檔:`$ISEP_COUNTDOWN_STATE_DIR/milestone-due`,一行 `YYYY-MM-DD|<名稱>`。 # 拿不到 token/拿不到期限 ⇒ **不寫、不報錯、不留舊資料以外的東西**: # 倒數那一行寧可少一段,也不要顯示一個編出來的日期。 set -uo pipefail HOST="${TICKET_HOST:-https://git.uncle6.me}" TOKEN="${GITEA_TOKEN_CLAUDE_CODE:-${GITEA_TOKEN:-}}" REPOS="${ISEP_COUNTDOWN_REPOS:-inkstone/InkStoneCo inkstone/ISEP}" DIR="${ISEP_COUNTDOWN_STATE_DIR:-$HOME/.claude/isep-countdown}" mkdir -p "$DIR" 2>/dev/null || exit 0 OUT="$DIR/milestone-due" [ -n "$TOKEN" ] || exit 0 RAW="" for repo in $REPOS; do body=$(curl -s --max-time 4 -H "Authorization: token $TOKEN" \ "$HOST/api/v1/repos/$repo/milestones?state=open" 2>/dev/null) || continue RAW="$RAW$body"$'\n' done printf '%s' "$RAW" | ISEP_OUT="$OUT" python3 -c ' import json, os, sys from datetime import datetime, timezone best = None for chunk in sys.stdin.read().split("\n"): chunk = chunk.strip() if not chunk: continue try: rows = json.loads(chunk) except Exception: continue if not isinstance(rows, list): continue for m in rows: due = (m or {}).get("due_on") or "" if not due: continue # 沒設期限的 milestone 不是節拍器 try: dt = datetime.fromisoformat(due.replace("Z", "+00:00")) except Exception: continue if dt.tzinfo is None: dt = dt.replace(tzinfo=timezone.utc) # 最近的那一個=現在真的在追的那一個 if best is None or dt < best[0]: best = (dt, (m or {}).get("title") or "主線") if best is None: raise SystemExit(0) dt, title = best with open(os.environ["ISEP_OUT"], "w") as f: f.write("%s|%s\n" % (dt.astimezone().strftime("%Y-%m-%d"), title)) ' 2>/dev/null || true exit 0