oh-my-opencode 4.3.1 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/command/get-unpublished-changes.md +148 -0
- package/.agents/command/omomomo.md +37 -0
- package/.agents/command/publish.md +376 -0
- package/.agents/command/remove-deadcode.md +221 -0
- package/.agents/command/security-research.md +16 -0
- package/.agents/skills/get-unpublished-changes/SKILL.md +24 -0
- package/.agents/skills/github-triage/SKILL.md +587 -0
- package/.agents/skills/github-triage/scripts/gh_fetch.py +398 -0
- package/.agents/skills/hyperplan/SKILL.md +450 -0
- package/.agents/skills/omomomo/SKILL.md +36 -0
- package/.agents/skills/pre-publish-review/SKILL.md +407 -0
- package/.agents/skills/publish/SKILL.md +428 -0
- package/.agents/skills/remove-deadcode/SKILL.md +216 -0
- package/.agents/skills/security-research/SKILL.md +204 -0
- package/.agents/skills/work-with-pr/SKILL.md +360 -0
- package/.agents/skills/work-with-pr-workspace/evals/evals.json +76 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
- package/.opencode/command/get-unpublished-changes.md +148 -0
- package/.opencode/command/omomomo.md +37 -0
- package/.opencode/command/publish.md +376 -0
- package/.opencode/command/remove-deadcode.md +221 -0
- package/.opencode/command/security-research.md +16 -0
- package/.opencode/skills/github-triage/SKILL.md +587 -0
- package/.opencode/skills/github-triage/scripts/gh_fetch.py +398 -0
- package/.opencode/skills/hyperplan/SKILL.md +450 -0
- package/.opencode/skills/pre-publish-review/SKILL.md +407 -0
- package/.opencode/skills/work-with-pr/SKILL.md +360 -0
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +76 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh-cn.md +1 -1
- package/dist/agents/atlas/agent.d.ts +6 -6
- package/dist/agents/prometheus/gemini.d.ts +0 -11
- package/dist/agents/prometheus/gpt.d.ts +0 -10
- package/dist/agents/prometheus/system-prompt.d.ts +2 -20
- package/dist/agents/types.d.ts +1 -16
- package/dist/cli/index.js +60 -20
- package/dist/config/schema/agent-names.d.ts +3 -3
- package/dist/config/schema/agent-overrides.d.ts +208 -208
- package/dist/config/schema/categories.d.ts +28 -28
- package/dist/config/schema/fallback-models.d.ts +20 -20
- package/dist/config/schema/oh-my-opencode-config.d.ts +208 -208
- package/dist/features/background-agent/parent-wake-dedupe.d.ts +19 -0
- package/dist/features/background-agent/parent-wake-notifier.d.ts +8 -19
- package/dist/help/schema/acp.d.ts +95 -0
- package/dist/help/schema/doctor.d.ts +147 -0
- package/dist/help/schema/sandbox.d.ts +74 -0
- package/dist/help/schema/status.d.ts +139 -0
- package/dist/hooks/keyword-detector/analyze/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/hyperplan/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/search/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/team/default.d.ts +2 -7
- package/dist/hooks/keyword-detector/ultrawork/default.d.ts +1 -9
- package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +1 -16
- package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts +1 -10
- package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -5
- package/dist/hooks/ralph-loop/no-progress-turn-detector.d.ts +7 -0
- package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +1 -0
- package/dist/hooks/ralph-loop/types.d.ts +1 -0
- package/dist/hooks/runtime-fallback/error-classifier.d.ts +1 -0
- package/dist/hooks/tool-pair-validator/hook.d.ts +6 -1
- package/dist/index.js +51976 -50299
- package/dist/plugin-handlers/provider-config-handler.d.ts +1 -0
- package/dist/shared/migration/model-versions.d.ts +6 -0
- package/dist/shared/prompt-async-gate/pending-tool-turn.d.ts +1 -0
- package/dist/shared/prompt-async-gate/types.d.ts +4 -3
- package/package.json +19 -13
- package/dist/agents/atlas/default-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/default.d.ts +0 -2
- package/dist/agents/atlas/gemini-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/gemini.d.ts +0 -2
- package/dist/agents/atlas/gpt-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/gpt.d.ts +0 -2
- package/dist/agents/atlas/kimi-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/kimi.d.ts +0 -2
- package/dist/agents/atlas/opus-4-7-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/opus-4-7.d.ts +0 -2
- package/dist/agents/atlas/shared-prompt.d.ts +0 -9
- package/dist/agents/prometheus/behavioral-summary.d.ts +0 -6
- package/dist/agents/prometheus/high-accuracy-mode.d.ts +0 -6
- package/dist/agents/prometheus/identity-constraints.d.ts +0 -7
- package/dist/agents/prometheus/interview-mode.d.ts +0 -7
- package/dist/agents/prometheus/plan-generation.d.ts +0 -7
- package/dist/agents/prometheus/plan-template.d.ts +0 -7
- package/dist/agents/prometheus/spec-driven-mode.d.ts +0 -7
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#!/usr/bin/env -S uv run --script
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.11"
|
|
4
|
+
# dependencies = [
|
|
5
|
+
# "typer>=0.12.0",
|
|
6
|
+
# "rich>=13.0.0",
|
|
7
|
+
# ]
|
|
8
|
+
# ///
|
|
9
|
+
"""
|
|
10
|
+
GitHub Issues/PRs Fetcher with Exhaustive Pagination.
|
|
11
|
+
|
|
12
|
+
Fetches ALL issues and/or PRs from a GitHub repository using gh CLI.
|
|
13
|
+
Implements proper pagination to ensure no items are missed.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
./gh_fetch.py issues # Fetch all issues
|
|
17
|
+
./gh_fetch.py prs # Fetch all PRs
|
|
18
|
+
./gh_fetch.py all # Fetch both issues and PRs
|
|
19
|
+
./gh_fetch.py issues --hours 48 # Issues from last 48 hours
|
|
20
|
+
./gh_fetch.py prs --state open # Only open PRs
|
|
21
|
+
./gh_fetch.py all --repo owner/repo # Specify repository
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import asyncio
|
|
25
|
+
import json
|
|
26
|
+
from datetime import UTC, datetime, timedelta
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from typing import Annotated
|
|
29
|
+
|
|
30
|
+
import typer
|
|
31
|
+
from rich.console import Console
|
|
32
|
+
from rich.panel import Panel
|
|
33
|
+
from rich.progress import Progress, TaskID
|
|
34
|
+
from rich.table import Table
|
|
35
|
+
|
|
36
|
+
app = typer.Typer(
|
|
37
|
+
name="gh_fetch",
|
|
38
|
+
help="Fetch GitHub issues/PRs with exhaustive pagination.",
|
|
39
|
+
no_args_is_help=True,
|
|
40
|
+
)
|
|
41
|
+
console = Console()
|
|
42
|
+
|
|
43
|
+
BATCH_SIZE = 500 # Maximum allowed by GitHub API
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ItemState(str, Enum):
|
|
47
|
+
ALL = "all"
|
|
48
|
+
OPEN = "open"
|
|
49
|
+
CLOSED = "closed"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class OutputFormat(str, Enum):
|
|
53
|
+
JSON = "json"
|
|
54
|
+
TABLE = "table"
|
|
55
|
+
COUNT = "count"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def run_gh_command(args: list[str]) -> tuple[str, str, int]:
|
|
59
|
+
"""Run gh CLI command asynchronously."""
|
|
60
|
+
proc = await asyncio.create_subprocess_exec(
|
|
61
|
+
"gh",
|
|
62
|
+
*args,
|
|
63
|
+
stdout=asyncio.subprocess.PIPE,
|
|
64
|
+
stderr=asyncio.subprocess.PIPE,
|
|
65
|
+
)
|
|
66
|
+
stdout, stderr = await proc.communicate()
|
|
67
|
+
return stdout.decode(), stderr.decode(), proc.returncode or 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def get_current_repo() -> str:
|
|
71
|
+
"""Get the current repository from gh CLI."""
|
|
72
|
+
stdout, stderr, code = await run_gh_command(
|
|
73
|
+
["repo", "view", "--json", "nameWithOwner", "-q", ".nameWithOwner"]
|
|
74
|
+
)
|
|
75
|
+
if code != 0:
|
|
76
|
+
console.print(f"[red]Error getting current repo: {stderr}[/red]")
|
|
77
|
+
raise typer.Exit(1)
|
|
78
|
+
return stdout.strip()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def fetch_items_page(
|
|
82
|
+
repo: str,
|
|
83
|
+
item_type: str, # "issue" or "pr"
|
|
84
|
+
state: str,
|
|
85
|
+
limit: int,
|
|
86
|
+
search_filter: str = "",
|
|
87
|
+
) -> list[dict]:
|
|
88
|
+
"""Fetch a single page of issues or PRs."""
|
|
89
|
+
cmd = [
|
|
90
|
+
item_type,
|
|
91
|
+
"list",
|
|
92
|
+
"--repo",
|
|
93
|
+
repo,
|
|
94
|
+
"--state",
|
|
95
|
+
state,
|
|
96
|
+
"--limit",
|
|
97
|
+
str(limit),
|
|
98
|
+
"--json",
|
|
99
|
+
"number,title,state,createdAt,updatedAt,labels,author,body",
|
|
100
|
+
]
|
|
101
|
+
if search_filter:
|
|
102
|
+
cmd.extend(["--search", search_filter])
|
|
103
|
+
|
|
104
|
+
stdout, stderr, code = await run_gh_command(cmd)
|
|
105
|
+
if code != 0:
|
|
106
|
+
console.print(f"[red]Error fetching {item_type}s: {stderr}[/red]")
|
|
107
|
+
return []
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
return json.loads(stdout) if stdout.strip() else []
|
|
111
|
+
except json.JSONDecodeError:
|
|
112
|
+
console.print(f"[red]Error parsing {item_type} response[/red]")
|
|
113
|
+
return []
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
async def fetch_all_items(
|
|
117
|
+
repo: str,
|
|
118
|
+
item_type: str,
|
|
119
|
+
state: str,
|
|
120
|
+
hours: int | None,
|
|
121
|
+
progress: Progress,
|
|
122
|
+
task_id: TaskID,
|
|
123
|
+
) -> list[dict]:
|
|
124
|
+
"""Fetch ALL items with exhaustive pagination."""
|
|
125
|
+
all_items: list[dict] = []
|
|
126
|
+
page = 1
|
|
127
|
+
|
|
128
|
+
progress.update(task_id, description=f"[cyan]Fetching {item_type}s page {page}...")
|
|
129
|
+
items = await fetch_items_page(repo, item_type, state, BATCH_SIZE)
|
|
130
|
+
fetched_count = len(items)
|
|
131
|
+
all_items.extend(items)
|
|
132
|
+
|
|
133
|
+
console.print(f"[dim]Page {page}: fetched {fetched_count} {item_type}s[/dim]")
|
|
134
|
+
|
|
135
|
+
while fetched_count == BATCH_SIZE:
|
|
136
|
+
page += 1
|
|
137
|
+
progress.update(
|
|
138
|
+
task_id, description=f"[cyan]Fetching {item_type}s page {page}..."
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
last_created = all_items[-1].get("createdAt", "")
|
|
142
|
+
if not last_created:
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
search_filter = f"created:<{last_created}"
|
|
146
|
+
items = await fetch_items_page(
|
|
147
|
+
repo, item_type, state, BATCH_SIZE, search_filter
|
|
148
|
+
)
|
|
149
|
+
fetched_count = len(items)
|
|
150
|
+
|
|
151
|
+
if fetched_count == 0:
|
|
152
|
+
break
|
|
153
|
+
|
|
154
|
+
existing_numbers = {item["number"] for item in all_items}
|
|
155
|
+
new_items = [item for item in items if item["number"] not in existing_numbers]
|
|
156
|
+
all_items.extend(new_items)
|
|
157
|
+
|
|
158
|
+
console.print(
|
|
159
|
+
f"[dim]Page {page}: fetched {fetched_count}, added {len(new_items)} new (total: {len(all_items)})[/dim]"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if page > 20:
|
|
163
|
+
console.print("[yellow]Safety limit reached (20 pages)[/yellow]")
|
|
164
|
+
break
|
|
165
|
+
|
|
166
|
+
if hours is not None:
|
|
167
|
+
cutoff = datetime.now(UTC) - timedelta(hours=hours)
|
|
168
|
+
cutoff_str = cutoff.isoformat()
|
|
169
|
+
|
|
170
|
+
original_count = len(all_items)
|
|
171
|
+
all_items = [
|
|
172
|
+
item
|
|
173
|
+
for item in all_items
|
|
174
|
+
if item.get("createdAt", "") >= cutoff_str
|
|
175
|
+
or item.get("updatedAt", "") >= cutoff_str
|
|
176
|
+
]
|
|
177
|
+
filtered_count = original_count - len(all_items)
|
|
178
|
+
if filtered_count > 0:
|
|
179
|
+
console.print(
|
|
180
|
+
f"[dim]Filtered out {filtered_count} items older than {hours} hours[/dim]"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return all_items
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def display_table(items: list[dict], item_type: str) -> None:
|
|
187
|
+
"""Display items in a Rich table."""
|
|
188
|
+
table = Table(title=f"{item_type.upper()}s ({len(items)} total)")
|
|
189
|
+
table.add_column("#", style="cyan", width=6)
|
|
190
|
+
table.add_column("Title", style="white", max_width=50)
|
|
191
|
+
table.add_column("State", style="green", width=8)
|
|
192
|
+
table.add_column("Author", style="yellow", width=15)
|
|
193
|
+
table.add_column("Labels", style="magenta", max_width=30)
|
|
194
|
+
table.add_column("Updated", style="dim", width=12)
|
|
195
|
+
|
|
196
|
+
for item in items[:50]:
|
|
197
|
+
labels = ", ".join(label.get("name", "") for label in item.get("labels", []))
|
|
198
|
+
updated = item.get("updatedAt", "")[:10]
|
|
199
|
+
author = item.get("author", {}).get("login", "unknown")
|
|
200
|
+
|
|
201
|
+
table.add_row(
|
|
202
|
+
str(item.get("number", "")),
|
|
203
|
+
(item.get("title", "")[:47] + "...")
|
|
204
|
+
if len(item.get("title", "")) > 50
|
|
205
|
+
else item.get("title", ""),
|
|
206
|
+
item.get("state", ""),
|
|
207
|
+
author,
|
|
208
|
+
(labels[:27] + "...") if len(labels) > 30 else labels,
|
|
209
|
+
updated,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
console.print(table)
|
|
213
|
+
if len(items) > 50:
|
|
214
|
+
console.print(f"[dim]... and {len(items) - 50} more items[/dim]")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@app.command()
|
|
218
|
+
def issues(
|
|
219
|
+
repo: Annotated[
|
|
220
|
+
str | None, typer.Option("--repo", "-r", help="Repository (owner/repo)")
|
|
221
|
+
] = None,
|
|
222
|
+
state: Annotated[
|
|
223
|
+
ItemState, typer.Option("--state", "-s", help="Issue state filter")
|
|
224
|
+
] = ItemState.ALL,
|
|
225
|
+
hours: Annotated[
|
|
226
|
+
int | None,
|
|
227
|
+
typer.Option(
|
|
228
|
+
"--hours", "-h", help="Only issues from last N hours (created or updated)"
|
|
229
|
+
),
|
|
230
|
+
] = None,
|
|
231
|
+
output: Annotated[
|
|
232
|
+
OutputFormat, typer.Option("--output", "-o", help="Output format")
|
|
233
|
+
] = OutputFormat.TABLE,
|
|
234
|
+
) -> None:
|
|
235
|
+
"""Fetch all issues with exhaustive pagination."""
|
|
236
|
+
|
|
237
|
+
async def async_main() -> None:
|
|
238
|
+
target_repo = repo or await get_current_repo()
|
|
239
|
+
|
|
240
|
+
console.print(f"""
|
|
241
|
+
[cyan]Repository:[/cyan] {target_repo}
|
|
242
|
+
[cyan]State:[/cyan] {state.value}
|
|
243
|
+
[cyan]Time filter:[/cyan] {f"Last {hours} hours" if hours else "All time"}
|
|
244
|
+
""")
|
|
245
|
+
|
|
246
|
+
with Progress(console=console) as progress:
|
|
247
|
+
task: TaskID = progress.add_task("[cyan]Fetching issues...", total=None)
|
|
248
|
+
items = await fetch_all_items(
|
|
249
|
+
target_repo, "issue", state.value, hours, progress, task
|
|
250
|
+
)
|
|
251
|
+
progress.update(
|
|
252
|
+
task, description="[green]Complete!", completed=100, total=100
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
console.print(
|
|
256
|
+
Panel(f"[green]Found {len(items)} issues[/green]", border_style="green")
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if output == OutputFormat.JSON:
|
|
260
|
+
console.print(json.dumps(items, indent=2, ensure_ascii=False))
|
|
261
|
+
elif output == OutputFormat.TABLE:
|
|
262
|
+
display_table(items, "issue")
|
|
263
|
+
else:
|
|
264
|
+
console.print(f"Total issues: {len(items)}")
|
|
265
|
+
|
|
266
|
+
asyncio.run(async_main())
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@app.command()
|
|
270
|
+
def prs(
|
|
271
|
+
repo: Annotated[
|
|
272
|
+
str | None, typer.Option("--repo", "-r", help="Repository (owner/repo)")
|
|
273
|
+
] = None,
|
|
274
|
+
state: Annotated[
|
|
275
|
+
ItemState, typer.Option("--state", "-s", help="PR state filter")
|
|
276
|
+
] = ItemState.OPEN,
|
|
277
|
+
hours: Annotated[
|
|
278
|
+
int | None,
|
|
279
|
+
typer.Option(
|
|
280
|
+
"--hours", "-h", help="Only PRs from last N hours (created or updated)"
|
|
281
|
+
),
|
|
282
|
+
] = None,
|
|
283
|
+
output: Annotated[
|
|
284
|
+
OutputFormat, typer.Option("--output", "-o", help="Output format")
|
|
285
|
+
] = OutputFormat.TABLE,
|
|
286
|
+
) -> None:
|
|
287
|
+
"""Fetch all PRs with exhaustive pagination."""
|
|
288
|
+
|
|
289
|
+
async def async_main() -> None:
|
|
290
|
+
target_repo = repo or await get_current_repo()
|
|
291
|
+
|
|
292
|
+
console.print(f"""
|
|
293
|
+
[cyan]Repository:[/cyan] {target_repo}
|
|
294
|
+
[cyan]State:[/cyan] {state.value}
|
|
295
|
+
[cyan]Time filter:[/cyan] {f"Last {hours} hours" if hours else "All time"}
|
|
296
|
+
""")
|
|
297
|
+
|
|
298
|
+
with Progress(console=console) as progress:
|
|
299
|
+
task: TaskID = progress.add_task("[cyan]Fetching PRs...", total=None)
|
|
300
|
+
items = await fetch_all_items(
|
|
301
|
+
target_repo, "pr", state.value, hours, progress, task
|
|
302
|
+
)
|
|
303
|
+
progress.update(
|
|
304
|
+
task, description="[green]Complete!", completed=100, total=100
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
console.print(
|
|
308
|
+
Panel(f"[green]Found {len(items)} PRs[/green]", border_style="green")
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
if output == OutputFormat.JSON:
|
|
312
|
+
console.print(json.dumps(items, indent=2, ensure_ascii=False))
|
|
313
|
+
elif output == OutputFormat.TABLE:
|
|
314
|
+
display_table(items, "pr")
|
|
315
|
+
else:
|
|
316
|
+
console.print(f"Total PRs: {len(items)}")
|
|
317
|
+
|
|
318
|
+
asyncio.run(async_main())
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@app.command(name="all")
|
|
322
|
+
def fetch_all(
|
|
323
|
+
repo: Annotated[
|
|
324
|
+
str | None, typer.Option("--repo", "-r", help="Repository (owner/repo)")
|
|
325
|
+
] = None,
|
|
326
|
+
state: Annotated[
|
|
327
|
+
ItemState, typer.Option("--state", "-s", help="State filter")
|
|
328
|
+
] = ItemState.ALL,
|
|
329
|
+
hours: Annotated[
|
|
330
|
+
int | None,
|
|
331
|
+
typer.Option(
|
|
332
|
+
"--hours", "-h", help="Only items from last N hours (created or updated)"
|
|
333
|
+
),
|
|
334
|
+
] = None,
|
|
335
|
+
output: Annotated[
|
|
336
|
+
OutputFormat, typer.Option("--output", "-o", help="Output format")
|
|
337
|
+
] = OutputFormat.TABLE,
|
|
338
|
+
) -> None:
|
|
339
|
+
"""Fetch all issues AND PRs with exhaustive pagination."""
|
|
340
|
+
|
|
341
|
+
async def async_main() -> None:
|
|
342
|
+
target_repo = repo or await get_current_repo()
|
|
343
|
+
|
|
344
|
+
console.print(f"""
|
|
345
|
+
[cyan]Repository:[/cyan] {target_repo}
|
|
346
|
+
[cyan]State:[/cyan] {state.value}
|
|
347
|
+
[cyan]Time filter:[/cyan] {f"Last {hours} hours" if hours else "All time"}
|
|
348
|
+
[cyan]Fetching:[/cyan] Issues AND PRs
|
|
349
|
+
""")
|
|
350
|
+
|
|
351
|
+
with Progress(console=console) as progress:
|
|
352
|
+
issues_task: TaskID = progress.add_task(
|
|
353
|
+
"[cyan]Fetching issues...", total=None
|
|
354
|
+
)
|
|
355
|
+
prs_task: TaskID = progress.add_task("[cyan]Fetching PRs...", total=None)
|
|
356
|
+
|
|
357
|
+
issues_items, prs_items = await asyncio.gather(
|
|
358
|
+
fetch_all_items(
|
|
359
|
+
target_repo, "issue", state.value, hours, progress, issues_task
|
|
360
|
+
),
|
|
361
|
+
fetch_all_items(
|
|
362
|
+
target_repo, "pr", state.value, hours, progress, prs_task
|
|
363
|
+
),
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
progress.update(
|
|
367
|
+
issues_task,
|
|
368
|
+
description="[green]Issues complete!",
|
|
369
|
+
completed=100,
|
|
370
|
+
total=100,
|
|
371
|
+
)
|
|
372
|
+
progress.update(
|
|
373
|
+
prs_task, description="[green]PRs complete!", completed=100, total=100
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
console.print(
|
|
377
|
+
Panel(
|
|
378
|
+
f"[green]Found {len(issues_items)} issues and {len(prs_items)} PRs[/green]",
|
|
379
|
+
border_style="green",
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
if output == OutputFormat.JSON:
|
|
384
|
+
result = {"issues": issues_items, "prs": prs_items}
|
|
385
|
+
console.print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
386
|
+
elif output == OutputFormat.TABLE:
|
|
387
|
+
display_table(issues_items, "issue")
|
|
388
|
+
console.print("")
|
|
389
|
+
display_table(prs_items, "pr")
|
|
390
|
+
else:
|
|
391
|
+
console.print(f"Total issues: {len(issues_items)}")
|
|
392
|
+
console.print(f"Total PRs: {len(prs_items)}")
|
|
393
|
+
|
|
394
|
+
asyncio.run(async_main())
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
if __name__ == "__main__":
|
|
398
|
+
app()
|