mirror of
https://github.com/hanzoai/code.git
synced 2026-09-30 20:53:35 +00:00
drop the issue-triage workflow: it has never once succeeded
100 of the last 100 runs failed. It fires every six hours, so it has been
producing four red runs a day for as long as the history goes back, and it is
the only workflow in this repo — so the repo's CI signal has been pure noise.
It cannot work here, for a reason that is not in the file. It needs
secrets.OPENAI_API_KEY and secrets.WIKI_TOKEN, and this org is on the GitHub Free
plan, where ORG-scoped secrets reach no repository at all — not even public ones.
The API accepts `gh secret set --org` and lists them as visibility ALL, so they
look present and arrive empty. Nothing errors; the step just gets "".
Two standing rules also say it should not exist in this shape:
- `runs-on: ubuntu-latest` puts the job on GitHub's builders. Ours run on the
git.hanzo.ai fleet.
- it pip-installs `openai` and calls that API. We have our own AI stack.
Deleting rather than repairing, because repairing means writing it twice: once
onto our runners and once onto our own models, which is not a fix to this file
but a new job. If issue triage is wanted, it belongs in .hanzo/workflows against
our stack, and it should be written as that.
The script goes with it; nothing else referenced it.
This commit is contained in:
@@ -1,164 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
from __future__ import annotations
|
|
||||||
import os, sys, json, datetime, pathlib, textwrap, requests
|
|
||||||
from openai import OpenAI
|
|
||||||
|
|
||||||
REPO = "voideditor/void"
|
|
||||||
CACHE_FILE = pathlib.Path(".github/triage_cache.json")
|
|
||||||
STAMP_FILE = pathlib.Path(".github/last_triage.txt")
|
|
||||||
|
|
||||||
THEMES_MD = textwrap.dedent("""\
|
|
||||||
1. 🔗 LLM Integration & Provider Support
|
|
||||||
2. 🖥 App Build & Platform Compatibility
|
|
||||||
3. 🎯 Prompt, Token, and Cost Management
|
|
||||||
4. 🧩 Editor UX & Interaction Design
|
|
||||||
5. 🤖 Agent & Automation Features
|
|
||||||
6. ⚙️ System Config & Environment Setup
|
|
||||||
7. 🗃 Meta: Feature Comparison, Structure, and Naming
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
|
|
||||||
headers = {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"}
|
|
||||||
|
|
||||||
|
|
||||||
# ───────── helpers ────────────────────────────────────────────────────────
|
|
||||||
def utc_iso_now() -> str:
|
|
||||||
return datetime.datetime.utcnow().replace(microsecond=0, tzinfo=datetime.timezone.utc).isoformat()
|
|
||||||
|
|
||||||
def read_stamp() -> str:
|
|
||||||
return STAMP_FILE.read_text().strip() if STAMP_FILE.exists() else "1970-01-01T00:00:00Z"
|
|
||||||
|
|
||||||
def save_stamp():
|
|
||||||
STAMP_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
STAMP_FILE.write_text(utc_iso_now())
|
|
||||||
|
|
||||||
def load_cache() -> dict[int, str]:
|
|
||||||
return json.loads(CACHE_FILE.read_text()) if CACHE_FILE.exists() else {}
|
|
||||||
|
|
||||||
def save_cache(d: dict[int, str]):
|
|
||||||
CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
CACHE_FILE.write_text(json.dumps(d, indent=2))
|
|
||||||
|
|
||||||
def fetch_open_issues(since_iso: str | None = None) -> list[dict]:
|
|
||||||
issues, page = [], 1
|
|
||||||
while True:
|
|
||||||
url = (
|
|
||||||
f"https://api.github.com/repos/{REPO}/issues"
|
|
||||||
f"?state=open&per_page=100&page={page}"
|
|
||||||
+ (f"&since={since_iso}" if since_iso else "")
|
|
||||||
)
|
|
||||||
chunk = requests.get(url, headers=headers).json()
|
|
||||||
if not chunk or (isinstance(chunk, dict) and chunk.get("message")):
|
|
||||||
break
|
|
||||||
issues.extend(i for i in chunk if "pull_request" not in i)
|
|
||||||
page += 1
|
|
||||||
return issues
|
|
||||||
|
|
||||||
|
|
||||||
# ───────── main ───────────────────────────────────────────────────────────
|
|
||||||
last_stamp = read_stamp()
|
|
||||||
changed = fetch_open_issues(since_iso=last_stamp)
|
|
||||||
|
|
||||||
# Fallback if **nothing** changed AND we have *no* existing output
|
|
||||||
if not changed:
|
|
||||||
cache_exists = CACHE_FILE.exists()
|
|
||||||
wiki_exists = pathlib.Path("wiki/Issue-Categories.md").exists()
|
|
||||||
if not cache_exists or not wiki_exists:
|
|
||||||
# first run or someone wiped the wiki → build from scratch
|
|
||||||
print("⏩ First run or empty wiki — fetching ALL open issues.", file=sys.stderr)
|
|
||||||
changed = fetch_open_issues() # full list
|
|
||||||
else:
|
|
||||||
print(f"✅ No issues updated since {last_stamp}. Nothing to classify.", file=sys.stderr)
|
|
||||||
save_stamp()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- prompt
|
|
||||||
issue_lines = "\n".join(f"- {i['title']} ({i['html_url']})" for i in changed)
|
|
||||||
prompt = textwrap.dedent(f"""\
|
|
||||||
You are an AI assistant helping triage GitHub issues into exactly 7 predefined themes.
|
|
||||||
|
|
||||||
Each issue must go into exactly one of the themes below:
|
|
||||||
|
|
||||||
{THEMES_MD}
|
|
||||||
|
|
||||||
Format your output in Markdown like:
|
|
||||||
## 🎯 Prompt, Token, and Cost Management
|
|
||||||
- [#123](https://github.com/org/repo/issues/123) – Title here
|
|
||||||
|
|
||||||
Classify these issues:
|
|
||||||
{issue_lines}
|
|
||||||
""")
|
|
||||||
|
|
||||||
resp = client.chat.completions.create(
|
|
||||||
model="gpt-4.1",
|
|
||||||
messages=[{"role": "user", "content": prompt}],
|
|
||||||
temperature=0.2,
|
|
||||||
)
|
|
||||||
|
|
||||||
md = resp.choices[0].message.content
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- parse GPT
|
|
||||||
new_map: dict[int, str] = {}
|
|
||||||
current = None
|
|
||||||
for ln in md.splitlines():
|
|
||||||
if ln.startswith("##"):
|
|
||||||
current = ln.lstrip("# ").strip()
|
|
||||||
elif ln.lstrip().startswith("- [#"):
|
|
||||||
try:
|
|
||||||
num = int(ln.split("[#")[1].split("]")[0])
|
|
||||||
new_map[num] = current
|
|
||||||
except Exception:
|
|
||||||
pass # ignore malformed lines
|
|
||||||
|
|
||||||
cache = load_cache()
|
|
||||||
cache.update(new_map)
|
|
||||||
save_cache(cache)
|
|
||||||
save_stamp()
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- rebuild wiki
|
|
||||||
order = [
|
|
||||||
"🔗 LLM Integration & Provider Support",
|
|
||||||
"🖥 App Build & Platform Compatibility",
|
|
||||||
"🎯 Prompt, Token, and Cost Management",
|
|
||||||
"🧩 Editor UX & Interaction Design",
|
|
||||||
"🤖 Agent & Automation Features",
|
|
||||||
"⚙️ System Config & Environment Setup",
|
|
||||||
"🗃 Meta: Feature Comparison, Structure, and Naming",
|
|
||||||
]
|
|
||||||
|
|
||||||
sections: dict[str, list[int]] = {t: [] for t in order}
|
|
||||||
|
|
||||||
# ── fetch ALL current open issues once (PRs filtered out) ────────────────
|
|
||||||
title_map: dict[int, tuple[str, str]] = {}
|
|
||||||
open_now: set[int] = set()
|
|
||||||
|
|
||||||
page = 1
|
|
||||||
while True:
|
|
||||||
batch = fetch_open_issues(since_iso=None) if page == 1 else []
|
|
||||||
if not batch:
|
|
||||||
break
|
|
||||||
for it in batch:
|
|
||||||
num = it["number"]
|
|
||||||
title_map[num] = (it["title"], it["html_url"])
|
|
||||||
open_now.add(num)
|
|
||||||
page += 1
|
|
||||||
|
|
||||||
# 🧹 drop any cached IDs that are no longer open issues (e.g., became a PR or were closed)
|
|
||||||
for stale in set(cache) - open_now:
|
|
||||||
del cache[stale]
|
|
||||||
save_cache(cache) # persist cleaned cache
|
|
||||||
|
|
||||||
# build sections from cleaned cache
|
|
||||||
for num, theme in cache.items():
|
|
||||||
if theme in sections: # extra safety
|
|
||||||
sections[theme].append(num)
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- print roadmap
|
|
||||||
for theme in order:
|
|
||||||
issues = sections[theme]
|
|
||||||
if issues:
|
|
||||||
print(f"## {theme}")
|
|
||||||
for n in sorted(issues):
|
|
||||||
title, url = title_map.get(n, ("(missing)", f"https://github.com/{REPO}/issues/{n}"))
|
|
||||||
print(f"- [#{n}]({url}) – {title}")
|
|
||||||
print()
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
name: Issue Triage to Wiki
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 */6 * * *' # every 6 hrs (UTC)
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
roadmap:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# 1️⃣ Check out code (so the script and cache files are present)
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 1 # shallow clone
|
|
||||||
|
|
||||||
# 2️⃣ Set up Python
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
|
|
||||||
# 3️⃣ Install dependencies
|
|
||||||
- name: Install Python dependencies
|
|
||||||
run: |
|
|
||||||
pip install openai requests
|
|
||||||
|
|
||||||
# 4️⃣ Clone your fork’s Wiki
|
|
||||||
- name: Clone your fork's Wiki
|
|
||||||
run: |
|
|
||||||
git clone https://x-access-token:${{ secrets.WIKI_TOKEN }}@github.com/${{ github.repository }}.wiki.git wiki
|
|
||||||
|
|
||||||
# 5️⃣ (Optional) Show repo tree for debugging
|
|
||||||
- name: Show repo tree (debug)
|
|
||||||
run: |
|
|
||||||
echo "PWD: $(pwd)"
|
|
||||||
ls -al
|
|
||||||
ls -al .github/scripts || true
|
|
||||||
ls -al void/.github/scripts || true
|
|
||||||
|
|
||||||
# 6️⃣ Generate roadmap and push only if it changed
|
|
||||||
- name: Generate roadmap directly into wiki
|
|
||||||
run: |
|
|
||||||
python .github/scripts/issue_triage.py > wiki/_new.md
|
|
||||||
if ! cmp -s wiki/_new.md wiki/Issue-Categories.md ; then
|
|
||||||
mv wiki/_new.md wiki/Issue-Categories.md
|
|
||||||
cd wiki
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
git add Issue-Categories.md
|
|
||||||
git commit -m "Auto-update Issue-Categories.md from GPT triage"
|
|
||||||
git push
|
|
||||||
else
|
|
||||||
echo "No content change – skipping wiki update"
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.WIKI_TOKEN }}
|
|
||||||
Reference in New Issue
Block a user