chore: import upstream snapshot with attribution
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:10:45 +08:00
commit 4b6817381b
3933 changed files with 525247 additions and 0 deletions
@@ -0,0 +1,30 @@
---
name: github-workflow
description: Use GitHub workflow tools to read work status, draft reports, summarize follow-ups, and execute only approved issue mutations.
tools:
- list_github_work_items
- summarize_github_pr_status
- list_github_security_alerts
- generate_work_status_report
- summarize_community_followups
- propose_github_issue_mutation_from_slack
- execute_github_issue_mutation
---
# GitHub Workflow
Use this workflow when the user asks about GitHub engineering status, PR readiness,
community follow-ups, or turning an explicit Slack request into a GitHub issue.
1. Read before reporting. Use the read-only GitHub tools first, and treat missing
or failed reads as incomplete status rather than proof that there are no
blockers.
2. Report or summarize from known data. Use `generate_work_status_report` for
Slack-ready status and `summarize_community_followups` for unanswered
contributor questions or agenda items.
3. Propose mutations before execution. Use
`propose_github_issue_mutation_from_slack` only for explicit Slack-sourced
create, update, or close requests.
4. Execute only through approval. `execute_github_issue_mutation` is the only
mutating GitHub workflow tool. It is never an investigation action and must
remain chat-only, approval-gated, and proposal-driven.
@@ -0,0 +1,44 @@
"""Semantic helpers for GitHub workflow tools."""
from __future__ import annotations
from integrations.github.client import GitHubApiError, GitHubRestClient
from integrations.github.tools.workflow.followup import (
issue_number_from_url,
normalize_community_comment,
summarize_community_followups_from_comments,
)
from integrations.github.tools.workflow.models import (
CommunityFollowup,
GitHubIssueMutationProposal,
GitHubReadSnapshot,
IssueMutationOperation,
PullRequestStatus,
SecurityAlert,
WorkItem,
WorkStatusReport,
)
from integrations.github.tools.workflow.mutation import (
build_issue_mutation_proposal,
title_from_slack_text,
)
from integrations.github.tools.workflow.report import build_work_status_report
__all__ = [
"CommunityFollowup",
"GitHubApiError",
"GitHubIssueMutationProposal",
"GitHubReadSnapshot",
"GitHubRestClient",
"IssueMutationOperation",
"PullRequestStatus",
"SecurityAlert",
"WorkItem",
"WorkStatusReport",
"build_issue_mutation_proposal",
"build_work_status_report",
"issue_number_from_url",
"normalize_community_comment",
"summarize_community_followups_from_comments",
"title_from_slack_text",
]
@@ -0,0 +1,102 @@
"""Community follow-up summarization for GitHub workflow tools."""
from __future__ import annotations
import re
from typing import Any
from integrations.github.tools.workflow.models import CommunityFollowup
_ISSUE_NUMBER_RE = re.compile(r"/issues/(?P<number>\d+)(?:$|[#?])")
def issue_number_from_url(url: str) -> int | None:
match = _ISSUE_NUMBER_RE.search(url)
if match is None:
return None
return int(match.group("number"))
def normalize_community_comment(raw: dict[str, Any]) -> CommunityFollowup:
"""Normalize GitHub repository issue-comment payloads."""
issue_number = raw.get("issue_number")
if not isinstance(issue_number, int):
issue_url = str(raw.get("issue_url") or raw.get("html_url") or "")
issue_number = issue_number_from_url(issue_url)
return CommunityFollowup(
issue_number=issue_number,
issue_title=str(raw.get("issue_title", "")),
author=str(raw.get("author") or (raw.get("user") or {}).get("login", "")),
body=str(raw.get("body", "")),
created_at=str(raw.get("created_at", "")),
url=str(raw.get("url") or raw.get("html_url") or ""),
)
def _is_question(text: str) -> bool:
lowered = text.lower()
return "?" in text or lowered.startswith(
("when ", "what ", "who ", "how ", "where ", "can ", "could ")
)
def _is_agenda_item(text: str) -> bool:
lowered = text.lower()
return any(term in lowered for term in ("agenda", "standup"))
def _question_answered_later(
question: CommunityFollowup,
comments: list[CommunityFollowup],
maintainers: set[str],
) -> bool:
for comment in comments:
if comment.issue_number != question.issue_number:
continue
if comment.created_at <= question.created_at:
continue
if comment.author.lower() in maintainers:
return True
return False
def _suggest_reply(question: CommunityFollowup) -> dict[str, Any]:
return {
"issue_number": question.issue_number,
"issue_title": question.issue_title,
"context": question.body,
"suggested_reply": (
"Thanks for the question — we should confirm the current owner/status "
"and reply in this thread with the next concrete step."
),
"url": question.url,
}
def summarize_community_followups_from_comments(
*,
comments: list[dict[str, Any]],
maintainer_logins: list[str] | None = None,
) -> dict[str, Any]:
normalized_comments = [normalize_community_comment(comment) for comment in comments]
maintainers = {login.lower() for login in (maintainer_logins or [])}
questions = [comment for comment in normalized_comments if _is_question(comment.body)]
unanswered = [
question
for question in questions
if question.author.lower() not in maintainers
and not _question_answered_later(question, normalized_comments, maintainers)
]
agenda_items = [comment for comment in normalized_comments if _is_agenda_item(comment.body)]
return {
"unanswered_questions": [question.to_dict() for question in unanswered],
"agenda_items": [item.to_dict() for item in agenda_items],
"suggested_replies": [_suggest_reply(question) for question in unanswered],
"counts": {
"comments": len(normalized_comments),
"unanswered_questions": len(unanswered),
"agenda_items": len(agenda_items),
},
"side_effects": [],
}
@@ -0,0 +1,166 @@
"""Semantic GitHub workflow models."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Literal
IssueMutationOperation = Literal["create", "update", "close"]
@dataclass(frozen=True)
class WorkItem:
number: int | None
title: str
state: str
url: str
author: str
labels: list[str]
assignees: list[str]
updated_at: str
work_status: Literal["taken", "up_for_grabs", "unassigned"]
def to_dict(self) -> dict[str, Any]:
return {
"number": self.number,
"title": self.title,
"state": self.state,
"url": self.url,
"author": self.author,
"labels": self.labels,
"assignees": self.assignees,
"updated_at": self.updated_at,
"work_status": self.work_status,
}
@dataclass(frozen=True)
class PullRequestStatus:
number: int | None
title: str
url: str
author: str
head_ref: str
head_sha: str
draft: bool
mergeable: bool | None
mergeable_state: str
check_status: str
status: Literal["mergeable", "blocked", "unknown"]
mergeability: Literal["mergeable", "blocked", "unknown"]
blocking_reasons: list[str]
updated_at: str
def to_dict(self) -> dict[str, Any]:
return {
"number": self.number,
"title": self.title,
"url": self.url,
"author": self.author,
"head_ref": self.head_ref,
"head_sha": self.head_sha,
"draft": self.draft,
"mergeable": self.mergeable,
"mergeable_state": self.mergeable_state,
"check_status": self.check_status,
"status": self.status,
"mergeability": self.mergeability,
"blocking_reasons": self.blocking_reasons,
"updated_at": self.updated_at,
}
@dataclass(frozen=True)
class SecurityAlert:
type: str
number: Any
state: str
summary: str
url: str
def to_dict(self) -> dict[str, Any]:
return {
"type": self.type,
"number": self.number,
"state": self.state,
"summary": self.summary,
"url": self.url,
}
@dataclass(frozen=True)
class CommunityFollowup:
issue_number: int | None
issue_title: str
author: str
body: str
created_at: str
url: str
def to_dict(self) -> dict[str, Any]:
return {
"issue_number": self.issue_number,
"issue_title": self.issue_title,
"author": self.author,
"body": self.body,
"created_at": self.created_at,
"url": self.url,
}
@dataclass(frozen=True)
class GitHubReadSnapshot:
owner: str
repo: str
work_items: list[WorkItem] = field(default_factory=list)
pull_requests: list[PullRequestStatus] = field(default_factory=list)
security_alerts: list[SecurityAlert] = field(default_factory=list)
errors: list[str] = field(default_factory=list)
@property
def incomplete(self) -> bool:
return bool(self.errors)
@dataclass(frozen=True)
class WorkStatusReport:
counts: dict[str, int]
slack_markdown: str
available: bool
incomplete: bool
errors: list[str]
side_effects: list[str] = field(default_factory=list)
def to_dict(self) -> dict[str, Any]:
return {
"counts": self.counts,
"slack_markdown": self.slack_markdown,
"available": self.available,
"incomplete": self.incomplete,
"errors": self.errors,
"side_effects": self.side_effects,
}
@dataclass(frozen=True)
class GitHubIssueMutationProposal:
proposal_id: str
operation: IssueMutationOperation
owner: str
repo: str
target: dict[str, Any]
payload: dict[str, Any]
slack_url: str
idempotency_marker: str
def to_dict(self) -> dict[str, Any]:
return {
"proposal_id": self.proposal_id,
"operation": self.operation,
"owner": self.owner,
"repo": self.repo,
"target": self.target,
"payload": self.payload,
"slack_url": self.slack_url,
"idempotency_marker": self.idempotency_marker,
}
@@ -0,0 +1,103 @@
"""Mutation proposal helpers for GitHub issue workflow tools."""
from __future__ import annotations
import hashlib
import json
from typing import Any
from integrations.github.tools.workflow.models import (
GitHubIssueMutationProposal,
IssueMutationOperation,
)
def _proposal_digest(data: dict[str, Any]) -> str:
raw = json.dumps(data, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]
def _issue_body(slack_text: str, slack_url: str, marker: str) -> str:
body = ["## Slack request", "", slack_text.strip() or "(No Slack text provided.)"]
if slack_url.strip():
body.extend(["", f"Source: {slack_url.strip()}"])
body.extend(["", f"<!-- {marker} -->"])
return "\n".join(body)
def _comment_body(slack_text: str, slack_url: str, marker: str) -> str:
body = ["Slack follow-up:", "", slack_text.strip() or "(No Slack text provided.)"]
if slack_url.strip():
body.extend(["", f"Source: {slack_url.strip()}"])
body.extend(["", f"<!-- {marker} -->"])
return "\n".join(body)
def title_from_slack_text(slack_text: str) -> str:
cleaned = " ".join(slack_text.strip().split())
if not cleaned:
return "Task from Slack"
return cleaned[:80].rstrip(" .")
def build_issue_mutation_proposal(
*,
owner: str,
repo: str,
operation: IssueMutationOperation,
slack_text: str,
slack_url: str = "",
issue_number: int | None = None,
title: str = "",
labels: list[str] | None = None,
assignees: list[str] | None = None,
) -> GitHubIssueMutationProposal:
seed = {
"owner": owner,
"repo": repo,
"operation": operation,
"issue_number": issue_number,
"slack_text": " ".join(slack_text.split()),
"slack_url": slack_url.strip(),
"title": title.strip(),
"labels": labels or [],
"assignees": assignees or [],
}
proposal_id = f"ghslack-{_proposal_digest(seed)}"
marker = f"opensre-slack-proposal:{proposal_id}"
target = {"issue_number": issue_number} if issue_number is not None else {}
if operation == "create":
payload: dict[str, Any] = {
"title": title.strip() or title_from_slack_text(slack_text),
"body": _issue_body(slack_text, slack_url, marker),
}
if labels is not None:
payload["labels"] = labels
if assignees is not None:
payload["assignees"] = assignees
elif operation == "update":
payload = {"comment_body": _comment_body(slack_text, slack_url, marker)}
if title.strip():
payload["title"] = title.strip()
if labels is not None:
payload["labels"] = labels
if assignees is not None:
payload["assignees"] = assignees
else:
payload = {
"comment_body": _comment_body(slack_text, slack_url, marker),
"state": "closed",
"state_reason": "completed",
}
return GitHubIssueMutationProposal(
proposal_id=proposal_id,
operation=operation,
owner=owner,
repo=repo,
target=target,
payload=payload,
slack_url=slack_url.strip(),
idempotency_marker=marker,
)
@@ -0,0 +1,117 @@
"""Report composition helpers for GitHub workflow tools."""
from __future__ import annotations
from collections.abc import Sequence
from typing import Any
from integrations.github.tools.workflow.models import PullRequestStatus, WorkItem, WorkStatusReport
def _as_dict(item: WorkItem | PullRequestStatus | dict[str, Any]) -> dict[str, Any]:
if isinstance(item, WorkItem | PullRequestStatus):
return item.to_dict()
return item
def _item_line(item: dict[str, Any]) -> str:
assignees = item.get("assignees") or []
owner = f" — @{', @'.join(assignees)}" if assignees else ""
return f"• #{item.get('number', '?')} {item.get('title', '')}{owner}"
def _pr_line(pr: dict[str, Any]) -> str:
reasons = pr.get("blocking_reasons") or []
reason_text = f"{', '.join(str(reason) for reason in reasons)}" if reasons else ""
return f"• PR #{pr.get('number', '?')} {pr.get('title', '')}{reason_text}"
def _recommended_actions(
*,
up_for_grabs: list[dict[str, Any]],
unassigned: list[dict[str, Any]],
blocked_prs: list[dict[str, Any]],
mergeable_prs: list[dict[str, Any]],
errors: list[str],
) -> list[str]:
actions: list[str] = []
if errors:
actions.append("• Re-run failed GitHub reads before trusting this status report.")
if blocked_prs:
actions.append(f"• Unblock {len(blocked_prs)} PR(s) before starting new work.")
if mergeable_prs:
actions.append(f"• Review or merge {len(mergeable_prs)} ready PR(s).")
if up_for_grabs:
actions.append(f"• Assign {len(up_for_grabs)} up-for-grabs task(s).")
if unassigned:
actions.append(f"• Triage {len(unassigned)} unassigned issue(s).")
if not actions:
actions.append("• No obvious blockers from the supplied data.")
return actions
def build_work_status_report(
*,
work_items: Sequence[WorkItem | dict[str, Any]],
pull_requests: Sequence[PullRequestStatus | dict[str, Any]],
context: str = "today",
errors: list[str] | None = None,
) -> WorkStatusReport:
"""Build a Slack-ready report from an already-read GitHub snapshot."""
errors = list(errors or [])
item_dicts = [_as_dict(item) for item in work_items]
pr_dicts = [_as_dict(pr) for pr in pull_requests]
up_for_grabs = [item for item in item_dicts if item.get("work_status") == "up_for_grabs"]
unassigned = [item for item in item_dicts if item.get("work_status") == "unassigned"]
taken = [item for item in item_dicts if item.get("work_status") == "taken"]
blocked_prs = [pr for pr in pr_dicts if pr.get("status") == "blocked"]
mergeable_prs = [pr for pr in pr_dicts if pr.get("status") == "mergeable"]
unknown_prs = [pr for pr in pr_dicts if pr.get("status") == "unknown"]
sections = [f"*Engineering status — {context}*", ""]
if errors:
sections.extend(["*Incomplete report:*", *[f"{error}" for error in errors], ""])
sections.append(
f"*Open work:* {len(item_dicts)} total ({len(taken)} taken, "
f"{len(up_for_grabs)} up for grabs, {len(unassigned)} unassigned)"
)
if up_for_grabs:
sections.extend(["", "*Up for grabs:*", *[_item_line(item) for item in up_for_grabs[:10]]])
if unassigned:
sections.extend(["", "*Unassigned:*", *[_item_line(item) for item in unassigned[:10]]])
if blocked_prs:
sections.extend(["", "*Blocked PRs:*", *[_pr_line(pr) for pr in blocked_prs[:10]]])
if unknown_prs:
sections.extend(["", "*Unknown PR status:*", *[_pr_line(pr) for pr in unknown_prs[:10]]])
if mergeable_prs:
sections.extend(["", "*Ready to merge:*", *[_pr_line(pr) for pr in mergeable_prs[:10]]])
sections.extend(
[
"",
"*Recommended next actions:*",
*_recommended_actions(
up_for_grabs=up_for_grabs,
unassigned=unassigned,
blocked_prs=blocked_prs,
mergeable_prs=mergeable_prs,
errors=errors,
),
]
)
return WorkStatusReport(
counts={
"open_work": len(item_dicts),
"taken": len(taken),
"up_for_grabs": len(up_for_grabs),
"unassigned": len(unassigned),
"blocked_prs": len(blocked_prs),
"mergeable_prs": len(mergeable_prs),
"unknown_prs": len(unknown_prs),
},
slack_markdown="\n".join(sections).strip(),
available=not errors,
incomplete=bool(errors),
errors=errors,
)