Skip to content

Project Info Panel v2 โ€” Grouped Sections with Rich Stats โ€‹

Date: 2026-03-29 Status: Approved Scope: VS Code extension (tooling/vscode-extension/) Builds on: 2026-03-28-project-info-panel-design.md


Summary โ€‹

Enhance the Project Info panel from a flat list of 5 items into a grouped, collapsible tree with 7 sections: Milestone, Issues, Pull Requests, CI Status, Branches, Activity, and Review Requests. Each group shows a summary in the collapsed description and expands to reveal detailed sub-items.

Motivation โ€‹

The current panel shows milestone progress, branch, PR, and version. As the project grows, developers need visibility into issue/PR health, branch hygiene (stale and [gone] branches), and recent activity โ€” without leaving the editor or running CLI commands.

Design โ€‹

Panel Structure โ€‹

โ–ผ Milestone: Prototype                11% (14/132)
    Open: 118
    Closed: 14
โ–ผ Issues                              118 open, 14 closed
    Open: 118
    Closed: 14
    Unassigned: 96
โ–ผ Pull Requests                       13 open, 42 merged
    Open: 13
    Merged: 42
    Closed (unmerged): 3
    Draft: 2
    โ†’ Current: #302 โ€” Fix permission...
โ–ผ CI Status                           โœ“ passing
    Latest: โœ“ validate โ€” passed (2h ago)
    Latest: โœ“ deploy-preview โ€” passed (2h ago)
    Latest: โœ— test-e2e โ€” failed (1h ago)
โ–ผ Review Requests                     2 awaiting review
    #298 โ€” Add privacy policy          waiting 3 days
    #295 โ€” Refactor Discord bot        waiting 5 days
โ–ผ Branches                            24 local / 18 remote
    โ˜… Current: copilot/fix-permission...
    Local: 24
    Remote: 18
    โš  Gone (remote deleted): 5
    Stale (30+ days): 3
โ–ผ Activity                            47 this week, 1,204 total
    Commits (7d): 47
    Commits (all time): 1,204
    Contributors (7d): 3
    Last commit: 2 hours ago
  Version: 0.5.2
  Last refreshed: 2 min ago

Group Details โ€‹

Milestone (existing, now collapsible) โ€‹

Same data source as v1 (gh api repos/{owner}/{repo}/milestones). The group label shows Milestone: {title} with {percent}% ({closed}/{total}) as the description. Expands to show open and closed counts. Clicking the group opens the milestone URL in the browser.

Issues โ€‹

Summary description: {open} open, {closed} closed. Sub-items:

  • Open โ€” count of open issues
  • Closed โ€” count of closed issues
  • Unassigned โ€” count of open issues with no assignee

Data source: gh api repos/{owner}/{repo}/issues?state=open&per_page=1 with response header Link for total count, or use the search API for counts:

  • gh api search/issues?q=repo:{owner}/{repo}+type:issue+state:open โ€” total_count
  • gh api search/issues?q=repo:{owner}/{repo}+type:issue+state:closed โ€” total_count
  • gh api search/issues?q=repo:{owner}/{repo}+type:issue+state:open+no:assignee โ€” total_count

Clicking the group opens the repo's issues page in the browser.

Pull Requests โ€‹

Summary description: {open} open, {merged} merged. Sub-items:

  • Open โ€” count of open PRs
  • Merged โ€” count of merged PRs
  • Closed (unmerged) โ€” count of PRs closed without merging
  • Draft โ€” count of open draft PRs
  • Current branch PR โ€” if a PR exists for the current branch, show โ†’ #N โ€” title (clickable to open PR URL)

Data source: GitHub search API for counts:

  • gh api search/issues?q=repo:{owner}/{repo}+type:pr+state:open โ€” total_count
  • gh api search/issues?q=repo:{owner}/{repo}+type:pr+is:merged โ€” total_count
  • gh api search/issues?q=repo:{owner}/{repo}+type:pr+state:closed+-is:merged โ€” total_count
  • gh api search/issues?q=repo:{owner}/{repo}+type:pr+state:open+draft:true โ€” total_count
  • Current branch PR: existing fetchBranchPR() function

Clicking the group opens the repo's pull requests page in the browser.

CI Status โ€‹

Summary description: โœ“ passing, โœ— failing, or โ— running based on the overall status of the latest workflow runs for the current branch. Sub-items show each workflow run:

  • Per-workflow row โ€” โœ“ {name} โ€” passed ({time ago}) or โœ— {name} โ€” failed ({time ago})

Data source: GitHub CLI:

  • gh run list --branch {branch} --limit 10 --json name,status,conclusion,createdAt โ€” latest runs per workflow

The overall summary is derived from the runs: if any run has conclusion: failure, show โœ— failing; if any is status: in_progress, show โ— running; otherwise โœ“ passing.

Clicking a sub-item opens the run's URL in the browser. Clicking the group opens the repo's Actions page filtered to the current branch.

Review Requests โ€‹

Summary description: {count} awaiting review. Sub-items list each PR requesting your review:

  • Per-PR row โ€” #{number} โ€” {title} with waiting {N} days as description

Data source: GitHub Search API:

  • gh api search/issues?q=repo:{owner}/{repo}+type:pr+state:open+review-requested:@me โ€” returns PRs awaiting your review

Clicking a sub-item opens the PR URL in the browser. Clicking the group opens GitHub's review-requested filter page.

If the authenticated user has no pending reviews, the group shows 0 awaiting review with no sub-items.

Branches โ€‹

Summary description: {local} local / {remote} remote. Sub-items:

  • Current โ€” current branch name (from existing getCurrentBranch())
  • Local โ€” total local branch count
  • Remote โ€” total remote tracking branch count
  • Gone (remote deleted) โ€” branches where upstream is [gone] (candidates for clean_gone)
  • Stale (30+ days) โ€” local branches with no commits in last 30 days

Data source: All local git commands (no API calls):

  • git branch --list โ€” local count
  • git branch -r --list โ€” remote count
  • git branch -vv and filter for [gone] โ€” gone count
  • git for-each-ref --sort=-committerdate --format='%(refname:short) %(committerdate:unix)' refs/heads/ โ€” stale detection

No click action on the group (no single URL to open).

Activity (7 days) โ€‹

Summary description: {weekCommits} this week, {totalCommits} total. Sub-items:

  • Commits (7d) โ€” commits in last 7 days across all branches
  • Commits (all time) โ€” total commit count
  • Contributors (7d) โ€” unique authors in last 7 days
  • Last commit โ€” relative time since most recent commit

Data source: Local git commands:

  • git rev-list --count --since='7 days ago' --all โ€” 7-day commit count
  • git rev-list --count --all โ€” total commit count
  • git log --format='%ae' --since='7 days ago' --all | sort -u โ€” contributor count
  • git log -1 --format='%ci' โ€” last commit timestamp

No click action on the group.

Flat Items (bottom) โ€‹

  • Version โ€” from readPackageJson() (unchanged)
  • Last refreshed โ€” relative timestamp (unchanged)

Tree Item Architecture โ€‹

Replace the single InfoItem class with:

  • InfoGroup โ€” collapsible parent item (TreeItemCollapsibleState.Collapsed). Has label, description (summary), iconPath, optional command (open URL), and stores its children.
  • InfoItem โ€” leaf item (TreeItemCollapsibleState.None). Unchanged from current implementation.

The provider's getChildren(element) method:

  • When element is undefined โ€” return the top-level groups + flat items
  • When element is an InfoGroup โ€” return that group's children

Data Fetching โ€‹

Split githubData.js into focused fetch functions:

FunctionReturnsSource
fetchActiveMilestone(cwd)milestone objectGitHub API (existing)
fetchIssueCounts(cwd){ open, closed, unassigned }GitHub Search API
fetchPRCounts(cwd){ open, merged, closed, draft }GitHub Search API
fetchBranchPR(cwd, branch)PR object or nullGitHub CLI (existing)
fetchCIStatus(cwd, branch){ overall, runs: [{ name, status, conclusion, url, createdAt }] }GitHub CLI
fetchReviewRequests(cwd)[{ number, title, url, createdAt }]GitHub Search API
fetchBranchStats(cwd){ current, local, remote, gone, stale }Local git
fetchActivityStats(cwd){ weekCommits, totalCommits, contributors, lastCommit }Local git

All GitHub API calls use the existing execAsync wrapper with 10-second timeout. Failures return null and the group shows "unavailable".

Branch and activity stats use local git only โ€” no API calls, no auth required, always available.

Refresh Behavior โ€‹

Same as v1:

  • On activation: Full fetch of all data
  • On branch change: Full refresh (piggybacks on existing 10-second polling)
  • Manual: Refresh button in view title bar
  • No periodic auto-refresh for GitHub data

All fetch functions run in parallel (Promise.all) during refresh to minimize wait time.

Error Handling โ€‹

Same graceful degradation as v1. Each group independently handles fetch failures โ€” if issue counts fail but branch stats work, the Issues group shows "unavailable" while Branches works fine.

Files to Modify โ€‹

  • src/lib/githubData.js โ€” Add fetchIssueCounts(), fetchPRCounts(), fetchBranchStats(), fetchActivityStats()
  • src/providers/ProjectInfoProvider.js โ€” Add InfoGroup class, refactor getChildren() for parent/child tree, update refresh() to call all fetch functions

Files NOT Changed โ€‹

  • package.json โ€” No new views, commands, or configuration needed
  • src/extension.js โ€” No changes, already wires up the provider correctly

What This Does NOT Include โ€‹

  • No click-to-cleanup for gone branches (future: could invoke clean_gone skill)
  • No per-item refresh (whole panel refreshes together)
  • No configuration for time windows (7 days is fixed)
  • No milestone editing or switching

Built with VitePress