docs: tools,github,packages (8 files)

This commit is contained in:
Richard Ward
2025-12-30 13:06:04 +00:00
parent 73913a6161
commit 1232982184
8 changed files with 568 additions and 509 deletions

View File

@@ -81,11 +81,26 @@ Phase 6: Cleanup (Week 8+) ⏳ Pending
- moderation.cases.json with test data
- **Total fakemui icons now: 80+** (up from 70+)
**✅ Additional Progress (Session 3 - 2025-12-31):**
- **@mui/icons-material completely eliminated from source code!**
- Migrated 40+ component files to fakemui icons
- Created 50+ new fakemui icons including:
- Component icons: Article, Checkbox, CropFree, CropPortrait, GridView, etc.
- Navigation: FirstPage, LastPage, ViewColumn, ViewStream
- Interaction: ToggleOn, TouchApp, FormatAlignLeft
- Display: AccountCircle, Verified, LocalOffer, LooksOne, TextFields, TableChart, Minus
- Updated atoms/display/Icon.tsx to use fakemui icons dynamically
- Migrated get-component-icon.tsx to fakemui
- Updated all test files (NavLink.test.tsx, NavItem.test.tsx, NavGroup.test.tsx)
- **Total fakemui icons now: 130+** (up from 80+)
- Icon mappings complete for all common MUI icon names
**📋 Ready to Execute:**
- ✅ Icon strategy: Full fakemui custom icons (no Phosphor) - 80+ icons!
- ✅ Icon strategy: Full fakemui custom icons (no Phosphor) - 130+ icons!
- ✅ Phase 1: Complete - all foundation components ready
- ✅ Phase 2: ButtonGroup, FormControl, RadioGroup, NativeSelect added
- Phase 3: Continue icon expansion as needed
- @mui/icons-material: ELIMINATED from source code
- Phase 3: Continue MUI core component elimination
---

View File

@@ -1,100 +1,100 @@
-- Analyze workflow run statistics
---@class AnalyzeModule
local M = {}
---Calculate statistics from a list of runs
---@param runs WorkflowRun[] Array of workflow runs
---@return RunStats
function M.calculateStats(runs)
local total = #runs
local success = 0
local failure = 0
local pending = 0
local total_duration = 0
local completed_runs = 0
for _, run in ipairs(runs) do
if run.conclusion == "success" then
success = success + 1
elseif run.conclusion == "failure" then
failure = failure + 1
elseif run.status == "pending" or run.status == "in_progress" then
pending = pending + 1
end
-- Calculate duration if completed
if run.created_at and run.updated_at then
-- Duration calculation would parse ISO dates
-- Placeholder for now
completed_runs = completed_runs + 1
end
end
local success_rate = 0
if total > 0 then
success_rate = (success / total) * 100
end
local avg_duration = 0
if completed_runs > 0 then
avg_duration = total_duration / completed_runs
end
return {
total = total,
success = success,
failure = failure,
pending = pending,
success_rate = math.floor(success_rate * 10) / 10,
avg_duration = avg_duration
}
end
---Get trend data for success rate over time
---@param runs WorkflowRun[] Array of workflow runs
---@param buckets number Number of time buckets (default 7)
---@return table[] Array of {date, success_rate} pairs
function M.getSuccessTrend(runs, buckets)
buckets = buckets or 7
local trend = {}
-- Group runs by date and calculate daily success rate
-- Placeholder implementation
for i = 1, buckets do
table.insert(trend, {
date = "Day " .. i,
success_rate = 0
})
end
return trend
end
---Get failure breakdown by type
---@param runs WorkflowRun[] Array of workflow runs
---@return table<string, number> Map of failure type to count
function M.getFailureBreakdown(runs)
local breakdown = {
build_failure = 0,
test_failure = 0,
timeout = 0,
cancelled = 0,
other = 0
}
for _, run in ipairs(runs) do
if run.conclusion == "failure" then
-- Would analyze job names to categorize
breakdown.other = breakdown.other + 1
elseif run.conclusion == "timed_out" then
breakdown.timeout = breakdown.timeout + 1
elseif run.conclusion == "cancelled" then
breakdown.cancelled = breakdown.cancelled + 1
end
end
return breakdown
end
return M
-- Analyze workflow run statistics
---@class AnalyzeModule
local M = {}
---Calculate statistics from a list of runs
---@param runs WorkflowRun[] Array of workflow runs
---@return RunStats
function M.calculateStats(runs)
local total = #runs
local success = 0
local failure = 0
local pending = 0
local total_duration = 0
local completed_runs = 0
for _, run in ipairs(runs) do
if run.conclusion == "success" then
success = success + 1
elseif run.conclusion == "failure" then
failure = failure + 1
elseif run.status == "pending" or run.status == "in_progress" then
pending = pending + 1
end
-- Calculate duration if completed
if run.created_at and run.updated_at then
-- Duration calculation would parse ISO dates
-- Placeholder for now
completed_runs = completed_runs + 1
end
end
local success_rate = 0
if total > 0 then
success_rate = (success / total) * 100
end
local avg_duration = 0
if completed_runs > 0 then
avg_duration = total_duration / completed_runs
end
return {
total = total,
success = success,
failure = failure,
pending = pending,
success_rate = math.floor(success_rate * 10) / 10,
avg_duration = avg_duration
}
end
---Get trend data for success rate over time
---@param runs WorkflowRun[] Array of workflow runs
---@param buckets number Number of time buckets (default 7)
---@return table[] Array of {date, success_rate} pairs
function M.getSuccessTrend(runs, buckets)
buckets = buckets or 7
local trend = {}
-- Group runs by date and calculate daily success rate
-- Placeholder implementation
for i = 1, buckets do
table.insert(trend, {
date = "Day " .. i,
success_rate = 0
})
end
return trend
end
---Get failure breakdown by type
---@param runs WorkflowRun[] Array of workflow runs
---@return table<string, number> Map of failure type to count
function M.getFailureBreakdown(runs)
local breakdown = {
build_failure = 0,
test_failure = 0,
timeout = 0,
cancelled = 0,
other = 0
}
for _, run in ipairs(runs) do
if run.conclusion == "failure" then
-- Would analyze job names to categorize
breakdown.other = breakdown.other + 1
elseif run.conclusion == "timed_out" then
breakdown.timeout = breakdown.timeout + 1
elseif run.conclusion == "cancelled" then
breakdown.cancelled = breakdown.cancelled + 1
end
end
return breakdown
end
return M

View File

@@ -1,96 +1,96 @@
-- Fetch workflow runs from GitHub API
---@class FetchRunsModule
local M = {}
---@class FetchOptions
---@field owner string Repository owner
---@field repo string Repository name
---@field workflow? string Workflow file name
---@field branch? string Filter by branch
---@field status? RunStatus Filter by status
---@field per_page? number Results per page (default 30)
---@field page? number Page number (default 1)
---@class FetchResult
---@field runs WorkflowRun[] Array of workflow runs
---@field total_count number Total number of runs
---@field page number Current page
---@field has_more boolean Whether more pages exist
---Build API URL for workflow runs
---@param opts FetchOptions
---@return string
local function buildUrl(opts)
local base = "https://api.github.com/repos/" .. opts.owner .. "/" .. opts.repo
if opts.workflow then
base = base .. "/actions/workflows/" .. opts.workflow .. "/runs"
else
base = base .. "/actions/runs"
end
local params = {}
if opts.branch then
table.insert(params, "branch=" .. opts.branch)
end
if opts.status then
table.insert(params, "status=" .. opts.status)
end
table.insert(params, "per_page=" .. (opts.per_page or 30))
table.insert(params, "page=" .. (opts.page or 1))
if #params > 0 then
base = base .. "?" .. table.concat(params, "&")
end
return base
end
---Fetch workflow runs from GitHub
---@param opts FetchOptions Fetch options
---@return FetchResult
function M.fetchRuns(opts)
local url = buildUrl(opts)
-- In production, this would make HTTP request
-- For now, return placeholder structure
log("Fetching runs from: " .. url)
return {
runs = {},
total_count = 0,
page = opts.page or 1,
has_more = false
}
end
---Fetch jobs for a specific run
---@param owner string Repository owner
---@param repo string Repository name
---@param run_id number Run ID
---@return WorkflowJob[]
function M.fetchJobs(owner, repo, run_id)
local url = "https://api.github.com/repos/" .. owner .. "/" .. repo
url = url .. "/actions/runs/" .. tostring(run_id) .. "/jobs"
log("Fetching jobs from: " .. url)
return {}
end
---Fetch logs for a job
---@param owner string Repository owner
---@param repo string Repository name
---@param job_id number Job ID
---@return string Log content
function M.fetchLogs(owner, repo, job_id)
local url = "https://api.github.com/repos/" .. owner .. "/" .. repo
url = url .. "/actions/jobs/" .. tostring(job_id) .. "/logs"
log("Fetching logs from: " .. url)
return ""
end
return M
-- Fetch workflow runs from GitHub API
---@class FetchRunsModule
local M = {}
---@class FetchOptions
---@field owner string Repository owner
---@field repo string Repository name
---@field workflow? string Workflow file name
---@field branch? string Filter by branch
---@field status? RunStatus Filter by status
---@field per_page? number Results per page (default 30)
---@field page? number Page number (default 1)
---@class FetchResult
---@field runs WorkflowRun[] Array of workflow runs
---@field total_count number Total number of runs
---@field page number Current page
---@field has_more boolean Whether more pages exist
---Build API URL for workflow runs
---@param opts FetchOptions
---@return string
local function buildUrl(opts)
local base = "https://api.github.com/repos/" .. opts.owner .. "/" .. opts.repo
if opts.workflow then
base = base .. "/actions/workflows/" .. opts.workflow .. "/runs"
else
base = base .. "/actions/runs"
end
local params = {}
if opts.branch then
table.insert(params, "branch=" .. opts.branch)
end
if opts.status then
table.insert(params, "status=" .. opts.status)
end
table.insert(params, "per_page=" .. (opts.per_page or 30))
table.insert(params, "page=" .. (opts.page or 1))
if #params > 0 then
base = base .. "?" .. table.concat(params, "&")
end
return base
end
---Fetch workflow runs from GitHub
---@param opts FetchOptions Fetch options
---@return FetchResult
function M.fetchRuns(opts)
local url = buildUrl(opts)
-- In production, this would make HTTP request
-- For now, return placeholder structure
log("Fetching runs from: " .. url)
return {
runs = {},
total_count = 0,
page = opts.page or 1,
has_more = false
}
end
---Fetch jobs for a specific run
---@param owner string Repository owner
---@param repo string Repository name
---@param run_id number Run ID
---@return WorkflowJob[]
function M.fetchJobs(owner, repo, run_id)
local url = "https://api.github.com/repos/" .. owner .. "/" .. repo
url = url .. "/actions/runs/" .. tostring(run_id) .. "/jobs"
log("Fetching jobs from: " .. url)
return {}
end
---Fetch logs for a job
---@param owner string Repository owner
---@param repo string Repository name
---@param job_id number Job ID
---@return string Log content
function M.fetchLogs(owner, repo, job_id)
local url = "https://api.github.com/repos/" .. owner .. "/" .. repo
url = url .. "/actions/jobs/" .. tostring(job_id) .. "/logs"
log("Fetching logs from: " .. url)
return ""
end
return M

View File

@@ -1,109 +1,109 @@
-- Filter workflow runs
---@class FilterModule
local M = {}
---Apply filters to a list of runs
---@param runs WorkflowRun[] Array of workflow runs
---@param filters RunFilters Filter criteria
---@return WorkflowRun[] Filtered runs
function M.filterRuns(runs, filters)
local result = {}
for _, run in ipairs(runs) do
local include = true
-- Filter by status
if filters.status and filters.status ~= "all" then
if run.status ~= filters.status and run.conclusion ~= filters.status then
include = false
end
end
-- Filter by branch
if include and filters.branch and filters.branch ~= "" then
if run.head_branch ~= filters.branch then
include = false
end
end
-- Filter by date range
if include and filters.dateRange then
local cutoff = M.getDateCutoff(filters.dateRange)
if cutoff and run.created_at < cutoff then
include = false
end
end
if include then
table.insert(result, run)
end
end
return result
end
---Get date cutoff for time range filter
---@param range string Time range (1d, 7d, 30d)
---@return string? ISO date string for cutoff
function M.getDateCutoff(range)
local days = 0
if range == "1d" then
days = 1
elseif range == "7d" then
days = 7
elseif range == "30d" then
days = 30
else
return nil
end
-- Calculate cutoff date (placeholder)
-- Would return ISO date string
return nil
end
---Apply filters from form data
---@param runs WorkflowRun[] Array of workflow runs
---@param formData table Form data with filter values
---@return WorkflowRun[]
function M.applyFilters(runs, formData)
local filters = {
status = formData.status,
branch = formData.branch,
dateRange = formData.dateRange
}
return M.filterRuns(runs, filters)
end
---Sort runs by field
---@param runs WorkflowRun[] Array of workflow runs
---@param field string Field to sort by
---@param ascending boolean Sort ascending if true
---@return WorkflowRun[] Sorted runs
function M.sortRuns(runs, field, ascending)
local sorted = {}
for _, run in ipairs(runs) do
table.insert(sorted, run)
end
table.sort(sorted, function(a, b)
local va = a[field]
local vb = b[field]
if va == nil then return false end
if vb == nil then return true end
if ascending then
return va < vb
else
return va > vb
end
end)
return sorted
end
return M
-- Filter workflow runs
---@class FilterModule
local M = {}
---Apply filters to a list of runs
---@param runs WorkflowRun[] Array of workflow runs
---@param filters RunFilters Filter criteria
---@return WorkflowRun[] Filtered runs
function M.filterRuns(runs, filters)
local result = {}
for _, run in ipairs(runs) do
local include = true
-- Filter by status
if filters.status and filters.status ~= "all" then
if run.status ~= filters.status and run.conclusion ~= filters.status then
include = false
end
end
-- Filter by branch
if include and filters.branch and filters.branch ~= "" then
if run.head_branch ~= filters.branch then
include = false
end
end
-- Filter by date range
if include and filters.dateRange then
local cutoff = M.getDateCutoff(filters.dateRange)
if cutoff and run.created_at < cutoff then
include = false
end
end
if include then
table.insert(result, run)
end
end
return result
end
---Get date cutoff for time range filter
---@param range string Time range (1d, 7d, 30d)
---@return string? ISO date string for cutoff
function M.getDateCutoff(range)
local days = 0
if range == "1d" then
days = 1
elseif range == "7d" then
days = 7
elseif range == "30d" then
days = 30
else
return nil
end
-- Calculate cutoff date (placeholder)
-- Would return ISO date string
return nil
end
---Apply filters from form data
---@param runs WorkflowRun[] Array of workflow runs
---@param formData table Form data with filter values
---@return WorkflowRun[]
function M.applyFilters(runs, formData)
local filters = {
status = formData.status,
branch = formData.branch,
dateRange = formData.dateRange
}
return M.filterRuns(runs, filters)
end
---Sort runs by field
---@param runs WorkflowRun[] Array of workflow runs
---@param field string Field to sort by
---@param ascending boolean Sort ascending if true
---@return WorkflowRun[] Sorted runs
function M.sortRuns(runs, field, ascending)
local sorted = {}
for _, run in ipairs(runs) do
table.insert(sorted, run)
end
table.sort(sorted, function(a, b)
local va = a[field]
local vb = b[field]
if va == nil then return false end
if vb == nil then return true end
if ascending then
return va < vb
else
return va > vb
end
end)
return sorted
end
return M

View File

@@ -1,47 +1,47 @@
-- GitHub Tools initialization
-- Entry point for package setup
---@class InitModule
local M = {}
---@class InitContext
---@field config GitHubConfig GitHub configuration
---@field user table Current user info
---@class InitResult
---@field success boolean
---@field message string
---@field config GitHubConfig
---Initialize the GitHub Tools package
---@param ctx InitContext Initialization context
---@return InitResult
function M.initialize(ctx)
local config = ctx.config or {}
if not config.owner or config.owner == "" then
return {
success = false,
message = "Repository owner is required",
config = config
}
end
if not config.repo or config.repo == "" then
return {
success = false,
message = "Repository name is required",
config = config
}
end
log("GitHub Tools initialized for " .. config.owner .. "/" .. config.repo)
return {
success = true,
message = "GitHub Tools ready",
config = config
}
end
return M
-- GitHub Tools initialization
-- Entry point for package setup
---@class InitModule
local M = {}
---@class InitContext
---@field config GitHubConfig GitHub configuration
---@field user table Current user info
---@class InitResult
---@field success boolean
---@field message string
---@field config GitHubConfig
---Initialize the GitHub Tools package
---@param ctx InitContext Initialization context
---@return InitResult
function M.initialize(ctx)
local config = ctx.config or {}
if not config.owner or config.owner == "" then
return {
success = false,
message = "Repository owner is required",
config = config
}
end
if not config.repo or config.repo == "" then
return {
success = false,
message = "Repository name is required",
config = config
}
end
log("GitHub Tools initialized for " .. config.owner .. "/" .. config.repo)
return {
success = true,
message = "GitHub Tools ready",
config = config
}
end
return M

View File

@@ -1,102 +1,102 @@
-- Status utilities for workflow runs
---@class StatusModule
local M = {}
---@alias StatusColor "success" | "error" | "warning" | "info" | "default"
---Get color for run status
---@param status RunStatus
---@return StatusColor
function M.getStatusColor(status)
if status == "success" then
return "success"
elseif status == "failure" then
return "error"
elseif status == "pending" or status == "in_progress" then
return "warning"
elseif status == "cancelled" or status == "skipped" then
return "default"
else
return "info"
end
end
---Get icon name for run status
---@param status RunStatus
---@return string Icon name from fakemui/icons
function M.getStatusIcon(status)
if status == "success" then
return "CheckCircle"
elseif status == "failure" then
return "XCircle"
elseif status == "pending" then
return "Clock"
elseif status == "in_progress" then
return "Loader"
elseif status == "cancelled" then
return "Cancel"
elseif status == "skipped" then
return "ArrowRight"
else
return "Info"
end
end
---Get human-readable status label
---@param status RunStatus
---@return string
function M.getStatusLabel(status)
local labels = {
success = "Success",
failure = "Failed",
pending = "Pending",
in_progress = "Running",
cancelled = "Cancelled",
skipped = "Skipped"
}
return labels[status] or status
end
---Render status badge component
---@param status RunStatus
---@return table UIComponent
function M.renderBadge(status)
return {
type = "Chip",
props = {
label = M.getStatusLabel(status),
color = M.getStatusColor(status),
size = "small",
icon = M.getStatusIcon(status)
}
}
end
---Format duration in human-readable form
---@param seconds number Duration in seconds
---@return string Formatted duration
function M.formatDuration(seconds)
if seconds < 60 then
return math.floor(seconds) .. "s"
elseif seconds < 3600 then
local mins = math.floor(seconds / 60)
local secs = math.floor(seconds % 60)
return mins .. "m " .. secs .. "s"
else
local hours = math.floor(seconds / 3600)
local mins = math.floor((seconds % 3600) / 60)
return hours .. "h " .. mins .. "m"
end
end
---Format timestamp as relative time
---@param timestamp string ISO timestamp
---@return string Relative time string
function M.formatRelativeTime(timestamp)
-- Placeholder - would calculate relative time
return timestamp
end
return M
-- Status utilities for workflow runs
---@class StatusModule
local M = {}
---@alias StatusColor "success" | "error" | "warning" | "info" | "default"
---Get color for run status
---@param status RunStatus
---@return StatusColor
function M.getStatusColor(status)
if status == "success" then
return "success"
elseif status == "failure" then
return "error"
elseif status == "pending" or status == "in_progress" then
return "warning"
elseif status == "cancelled" or status == "skipped" then
return "default"
else
return "info"
end
end
---Get icon name for run status
---@param status RunStatus
---@return string Icon name from fakemui/icons
function M.getStatusIcon(status)
if status == "success" then
return "CheckCircle"
elseif status == "failure" then
return "XCircle"
elseif status == "pending" then
return "Clock"
elseif status == "in_progress" then
return "Loader"
elseif status == "cancelled" then
return "Cancel"
elseif status == "skipped" then
return "ArrowRight"
else
return "Info"
end
end
---Get human-readable status label
---@param status RunStatus
---@return string
function M.getStatusLabel(status)
local labels = {
success = "Success",
failure = "Failed",
pending = "Pending",
in_progress = "Running",
cancelled = "Cancelled",
skipped = "Skipped"
}
return labels[status] or status
end
---Render status badge component
---@param status RunStatus
---@return table UIComponent
function M.renderBadge(status)
return {
type = "Chip",
props = {
label = M.getStatusLabel(status),
color = M.getStatusColor(status),
size = "small",
icon = M.getStatusIcon(status)
}
}
end
---Format duration in human-readable form
---@param seconds number Duration in seconds
---@return string Formatted duration
function M.formatDuration(seconds)
if seconds < 60 then
return math.floor(seconds) .. "s"
elseif seconds < 3600 then
local mins = math.floor(seconds / 60)
local secs = math.floor(seconds % 60)
return mins .. "m " .. secs .. "s"
else
local hours = math.floor(seconds / 3600)
local mins = math.floor((seconds % 3600) / 60)
return hours .. "h " .. mins .. "m"
end
end
---Format timestamp as relative time
---@param timestamp string ISO timestamp
---@return string Relative time string
function M.formatRelativeTime(timestamp)
-- Placeholder - would calculate relative time
return timestamp
end
return M

View File

@@ -0,0 +1,44 @@
{
"status": {
"colors": [
{ "status": "success", "expected_color": "success", "desc": "Success is green" },
{ "status": "failure", "expected_color": "error", "desc": "Failure is red" },
{ "status": "pending", "expected_color": "warning", "desc": "Pending is yellow" },
{ "status": "in_progress", "expected_color": "warning", "desc": "In progress is yellow" },
{ "status": "cancelled", "expected_color": "default", "desc": "Cancelled is gray" },
{ "status": "skipped", "expected_color": "default", "desc": "Skipped is gray" }
],
"icons": [
{ "status": "success", "expected_icon": "CheckCircle", "desc": "Success shows check" },
{ "status": "failure", "expected_icon": "XCircle", "desc": "Failure shows X" },
{ "status": "pending", "expected_icon": "Clock", "desc": "Pending shows clock" },
{ "status": "in_progress", "expected_icon": "Loader", "desc": "Running shows loader" }
],
"durations": [
{ "seconds": 30, "expected": "30s", "desc": "30 seconds" },
{ "seconds": 90, "expected": "1m 30s", "desc": "90 seconds to minutes" },
{ "seconds": 3660, "expected": "1h 1m", "desc": "3660 seconds to hours" },
{ "seconds": 7200, "expected": "2h 0m", "desc": "2 hours exact" }
]
},
"filter": {
"status_filters": [
{ "filter": "success", "runs": 10, "expected_count": 5, "desc": "Filter success only" },
{ "filter": "failure", "runs": 10, "expected_count": 3, "desc": "Filter failures only" },
{ "filter": "all", "runs": 10, "expected_count": 10, "desc": "No filter returns all" }
],
"date_ranges": [
{ "range": "1d", "expected_days": 1, "desc": "Last 24 hours" },
{ "range": "7d", "expected_days": 7, "desc": "Last 7 days" },
{ "range": "30d", "expected_days": 30, "desc": "Last 30 days" }
]
},
"analyze": {
"success_rates": [
{ "success": 8, "total": 10, "expected_rate": 80.0, "desc": "80% success rate" },
{ "success": 0, "total": 10, "expected_rate": 0.0, "desc": "0% success rate" },
{ "success": 10, "total": 10, "expected_rate": 100.0, "desc": "100% success rate" },
{ "success": 0, "total": 0, "expected_rate": 0.0, "desc": "Empty list" }
]
}
}

View File

@@ -1,53 +1,53 @@
-- GitHub Tools package types
---@meta
---@alias RunStatus "success" | "failure" | "pending" | "cancelled" | "skipped"
---@alias RunConclusion "success" | "failure" | "cancelled" | "skipped" | "timed_out" | "action_required"
---@class WorkflowRun
---@field id number Run ID
---@field name string Workflow name
---@field head_branch string Branch name
---@field head_sha string Commit SHA
---@field status RunStatus Run status
---@field conclusion? RunConclusion Run conclusion
---@field created_at string ISO timestamp
---@field updated_at string ISO timestamp
---@field run_number number Run number
---@field html_url string GitHub URL
---@class WorkflowJob
---@field id number Job ID
---@field name string Job name
---@field status RunStatus Job status
---@field conclusion? RunConclusion Job conclusion
---@field started_at? string ISO timestamp
---@field completed_at? string ISO timestamp
---@field steps JobStep[] Job steps
---@class JobStep
---@field name string Step name
---@field status RunStatus Step status
---@field conclusion? RunConclusion Step conclusion
---@field number number Step number
---@class RunFilters
---@field status? RunStatus Filter by status
---@field branch? string Filter by branch
---@field dateRange? string Time range (1d, 7d, 30d)
---@class RunStats
---@field total number Total runs
---@field success number Successful runs
---@field failure number Failed runs
---@field pending number Pending runs
---@field success_rate number Success percentage
---@field avg_duration number Average duration in seconds
---@class GitHubConfig
---@field owner string Repository owner
---@field repo string Repository name
---@field token? string GitHub token
---@field workflow? string Workflow file name
return {}
-- GitHub Tools package types
---@meta
---@alias RunStatus "success" | "failure" | "pending" | "cancelled" | "skipped"
---@alias RunConclusion "success" | "failure" | "cancelled" | "skipped" | "timed_out" | "action_required"
---@class WorkflowRun
---@field id number Run ID
---@field name string Workflow name
---@field head_branch string Branch name
---@field head_sha string Commit SHA
---@field status RunStatus Run status
---@field conclusion? RunConclusion Run conclusion
---@field created_at string ISO timestamp
---@field updated_at string ISO timestamp
---@field run_number number Run number
---@field html_url string GitHub URL
---@class WorkflowJob
---@field id number Job ID
---@field name string Job name
---@field status RunStatus Job status
---@field conclusion? RunConclusion Job conclusion
---@field started_at? string ISO timestamp
---@field completed_at? string ISO timestamp
---@field steps JobStep[] Job steps
---@class JobStep
---@field name string Step name
---@field status RunStatus Step status
---@field conclusion? RunConclusion Step conclusion
---@field number number Step number
---@class RunFilters
---@field status? RunStatus Filter by status
---@field branch? string Filter by branch
---@field dateRange? string Time range (1d, 7d, 30d)
---@class RunStats
---@field total number Total runs
---@field success number Successful runs
---@field failure number Failed runs
---@field pending number Pending runs
---@field success_rate number Success percentage
---@field avg_duration number Average duration in seconds
---@class GitHubConfig
---@field owner string Repository owner
---@field repo string Repository name
---@field token? string GitHub token
---@field workflow? string Workflow file name
return {}