positron-qa-verify
Generates clear, actionable verification guides for QA testing of Positron bug fixes and features
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install posit-dev-positron-positron-qa-verify
Repository
Skill path: .claude/skills/positron-qa-verify
Generates clear, actionable verification guides for QA testing of Positron bug fixes and features
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Testing.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: posit-dev.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install positron-qa-verify into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/posit-dev/positron before adding positron-qa-verify to shared team environments
- Use positron-qa-verify for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: positron-qa-verify
description: Generates clear, actionable verification guides for QA testing of Positron bug fixes and features
---
# Positron QA Verify
This skill analyzes GitHub issues and their associated PRs to generate comprehensive verification guides for manual QA testing. It extracts the essential information from issues, comments, linked PRs, and code changes to produce clear test scenarios.
## When to Use This Skill
Use this skill when:
- You're assigned a ticket from the QA verification board (https://github.com/orgs/posit-dev/projects/2/views/8)
- You need to understand what to test for a specific bug fix or feature
- You want to extract test scenarios from an issue and its related PRs
- You need to identify all edge cases and related scenarios mentioned in comments
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- Working in the Positron repository
- Access to the posit-dev/positron repository
## Execution Mode
**CRITICAL: This skill MUST run non-interactively without ANY prompts.**
- **NEVER use `AskUserQuestion`** - The skill always writes to a safe output directory (`.claude/skills/positron-qa-verify/output/`)
- **Version auto-detection is best-effort** - If it fails, silently use empty values. The user can fill them in manually.
- **All operations must complete quickly** - Fail fast if data cannot be retrieved within reasonable timeouts
- **No permission requests** - Reading issue data, writing markdown files, and running version detection do not require special permissions
**Performance requirements:**
- Version detection must complete in ≤4 seconds total (enforced by script timeouts)
- If version detection times out or fails, continue without error messages
- Never attempt interactive detection methods (no manual path prompts, no user input)
**Windows compatibility:**
- The `detect_versions.sh` script handles Windows paths via Git Bash/MSYS/PowerShell
- Falls back gracefully if Positron installation path cannot be found
- Uses multiple detection methods to maximize success rate across platforms
## Input
Provide an issue number or URL. Examples:
- `4567`
- `#4567`
- `https://github.com/posit-dev/positron/issues/4567`
## Workflow
I'll analyze the issue and generate a verification guide following these steps:
### Performance Optimization Strategy
**CRITICAL: Use parallel execution wherever possible to minimize latency.**
- **Step 1 & 2 run in parallel** - Issue details and PR search are independent
- **Step 3 fetches run in parallel** - Related PRs/issues are fetched concurrently
- **Step 4 checks size first** - Only fetch diff for small PRs (<500 lines)
Total time savings: ~40-50% faster than sequential execution (5-8s vs 10-15s typical)
### Step 1: Fetch Issue Details (Parallel with Step 2)
**MUST RUN IN PARALLEL** with Step 2 using a single message with multiple Bash tool calls.
Using `gh issue view`, I'll retrieve:
- Issue title and description
- Reporter's repro steps
- All comments (which often contain additional test scenarios)
- Labels and metadata
- Linked issues
### Step 2: Identify Related PR(s) (Parallel with Step 1)
**MUST RUN IN PARALLEL** with Step 1 using a single message with multiple Bash tool calls.
I'll automatically detect the PR that fixes this issue by:
1. Looking for PR references in issue comments (e.g., "Fixed in #1234")
2. Checking for timeline events linking PRs
3. Using `gh pr list` with issue filter if needed
If multiple PRs are found, I'll analyze all of them.
### Step 3: Analyze PR Context
**OPTIMIZATION:** Fetch primary PR details first, then fetch all related PRs/issues in parallel.
For the primary PR, I'll fetch:
- PR description and summary
- All PR comments (often contain testing notes)
- **Additions and deletions counts** (needed for Step 4 size check)
- Related PRs/issues mentioned in the body
Then, for all related PRs/issues referenced, I'll fetch them **in parallel using multiple Bash tool calls in a single message**.
### Step 4: Review Code Changes (Conditionally)
**OPTIMIZATION:** Check PR size from Step 3 data (additions + deletions) BEFORE fetching diff.
**For small PRs (< 500 lines changed):**
- I'll use `gh pr diff` to review actual code changes
- This helps identify:
- Edge cases to test
- Related functionality that might be affected
- Whether the fix is focused or touches multiple areas
**For large PRs (>= 500 lines):**
- I'll skip detailed code review (don't fetch diff at all)
- Focus on PR description and comments instead
- Saves 1-5 seconds by avoiding large diff download
### Step 5: Extract Linked Issues and Scenarios
I'll search comments for:
- References to other issues (`#1234`)
- Additional test scenarios mentioned by team members
- Edge cases discovered during PR review
- Platform-specific considerations (macOS, Windows, Linux)
### Step 6: Generate Verification Guide
I'll create a markdown file in `.claude/skills/positron-qa-verify/output/` with:
1. **Ticket Type** (Bug, Feature, Documentation, Maintenance)
- Helps set testing expectations
- Determines whether Root Cause section is included
2. **Issue Summary**
- What changed or what was broken
- User impact (why this matters)
- Uses H4 subsections for readability
3. **Root Cause** (Bugs only)
- What was causing the issue
- Only included for bug fixes when clearly stated in PR
- Helps understand what might break again
4. **Test Scenarios**
- Scenario titles use checkmarks (✓) for visual organization
- Test steps within scenarios use checkboxes (- [ ]) for tracking progress
- Primary scenario (the main repro steps from the issue)
- Edge cases (from comments, PR review, code analysis) with "Why test:" rationale
- Regression checks (related functionality to verify still works)
- Platform-specific scenarios if mentioned
5. **Testing Context**
- Environment requirements (Python/R version, specific packages, etc.)
- Setup steps (if any)
- Expected vs actual behavior
- Related PRs to be aware of
6. **References**
- Link to original issue
- Link to PR(s)
- Links to related issues
### Step 7: Offer Verification Comment Template (User-Triggered)
After generating the guide, I'll offer to create a verification comment template. **Only if you accept** will I run the version detection script and generate the template.
**Workflow:**
1. Generate verification guide
2. Offer: "Would you like me to generate a verification comment template?"
3. If yes → Run `detect_versions.sh` to auto-detect versions
4. Generate template and copy to clipboard
For single scenario tests (only 1 test, no edge cases or regressions), I'll use a simple format:
```markdown
### Verified Fixed
Positron Version(s): [version]
OS Version(s): [OS]
### Test scenario(s)
- [Single scenario]
### Link(s) to test cases run or created:
[links or paths to e2e tests, or n/a]
```
For everything else (2+ scenarios, or any edge cases/regressions), I'll use a grouped format for better readability:
```markdown
### Verified Fixed
Positron Version(s): [version]
OS Version(s): [OS]
### Test scenario(s)
**Primary scenario:**
- [Main test scenario]
**Edge cases:**
- [Edge case 1]
- [Edge case 2]
**Regression checks:**
- [Regression check 1]
- [Regression check 2]
### Link(s) to test cases run or created:
[links or paths to e2e tests, or n/a]
```
**Note:** The verification comment uses plain bullets. Checkmarks (✓) and checkboxes (- [ ]) are only in the verification guide for visual organization and progress tracking during testing.
The template will be pre-filled with:
- Test scenarios extracted and condensed from the verification guide
- Grouped format used by default for better readability (unless only 1 scenario)
- **Positron Version automatically detected** from installed application (using `scripts/detect_versions.sh`)
- **OS Version automatically detected** from your system (using `scripts/detect_versions.sh`)
- Ready to paste - you can adjust versions if you tested on multiple systems
**Version detection is best-effort and silent:**
- **Only runs when you request the comment template** (not during initial guide generation)
- Uses the `detect_versions.sh` script with 3-second timeouts per detection
- If detection fails, empty values are used (you can fill them in manually)
- Never prompts or shows errors - fails fast and silent
**The template will be automatically copied to your clipboard** (on macOS/Linux using `pbcopy`/`xclip`, on Windows using `clip`) when you accept the offer, making it easy to paste directly into the GitHub issue after you complete testing.
## Output Format
The verification guide is saved as a markdown file:
```
.claude/skills/positron-qa-verify/output/verify-issue-{number}-{timestamp}.md
```
Example filename: `verify-issue-4567-20260108-153045.md`
## Example Usage
```
User: /qa-verify 4567
```
I'll respond with:
1. A summary of what I found
2. Path to the generated verification guide
3. Key highlights (number of scenarios, any blockers, etc.)
## Implementation Examples
### Example 1: Parallel Execution of Steps 1 & 2
**Do this (FAST - ~2 seconds):**
Single message with multiple Bash tool calls running in parallel:
- `gh issue view <number>` fetches issue details
- `gh pr list --search "<number>"` searches for related PRs
**Saves ~1-2 seconds** compared to sequential execution.
### Example 2: Parallel Fetch of Related PRs/Issues
**Do this (FAST - ~2 seconds):**
After identifying related PRs/issues from PR body (e.g., #10625, #10753), fetch them all in parallel with a single message containing multiple Bash tool calls.
**Don't do this (SLOW - ~6 seconds):**
Sequential fetches of each related PR/issue one at a time.
**Saves ~2-4 seconds** depending on number of related items.
### Example 3: Check PR Size Before Fetching Diff
**Do this (FAST):**
1. Get PR with `--json additions,deletions` in Step 3
2. Calculate total: `additions + deletions`
3. Only fetch diff if `< 500 lines`
**Example:**
```bash
# Already have from Step 3:
# "additions": 9, "deletions": 3
# Total: 12 lines (< 500, so fetch diff)
gh pr diff 11251
```
**Don't do this (SLOW):**
Always fetch diff, then check size after.
**Saves ~1-5 seconds** on large PRs by avoiding unnecessary diff downloads.
## Helper Scripts
### `scripts/analyze_issue.sh`
This script orchestrates the data gathering:
```bash
# Usage:
./scripts/analyze_issue.sh <issue-number>
```
The script:
- Fetches issue and PR data using `gh` CLI
- Extracts linked issues from comments
- Calculates PR size to determine if code review is needed
- Outputs structured JSON for parsing
### `scripts/detect_versions.sh`
This script performs fast, silent version detection:
```bash
# Usage:
./scripts/detect_versions.sh
# With debug output:
DEBUG=1 ./scripts/detect_versions.sh
```
The script:
- Detects Positron version and build number from `product.json`
- Detects OS version using platform-specific commands
- Has 3-second timeout per detection (max 4 seconds total)
- **Never prompts or shows errors** - always outputs valid JSON
- Fails gracefully with empty values if detection fails
Output format:
```json
{
"positronVersion": "2026.02.0",
"positronBuild": "10",
"osVersion": "macOS 26.2",
"detectionStatus": "success"
}
```
Detection status values:
- `"success"` - Both Positron and OS versions detected
- `"partial"` - Only one version detected
- `"failed"` - No versions detected
## Verification Guide Template
The generated guides follow this structure:
```markdown
# Verification Guide
### [Issue Title]<br>
**Issue:** [#number](https://github.com/posit-dev/positron/issues/[number])<br>
**Type:** Bug | Feature | Documentation | Maintenance<br>
**Primary PR:** [#number](https://github.com/posit-dev/positron/pull/[number])<br>
**Component:** [area label]<br>
**Generated:** [timestamp]<br>
---
## Issue Summary
[2-3 sentences explaining the problem and user impact]
## Root Cause
[1-2 sentences if identifiable, otherwise "See PR for technical details"]
## Test Scenarios
### Primary Scenario
✓ **[Scenario title]**
**Setup:** (if needed)
- [ ] Setup step one
- [ ] Setup step two
**Test Steps:**
- [ ] Step one
- [ ] Step two
**Expected:** [What should happen]
**Previously:** [What was broken]
### Edge Cases
✓ **[Edge case scenario title]**
**_Why test:_** [Brief explanation]
- [ ] Step one
- [ ] Step two
### Regression Checks
- [ ] [What to verify]
- [ ] [Another thing to verify]
## Testing Context
**Environment:**
- Positron version: [if specified]
- OS: [if relevant]
- Language: Python/R [version if specified]
**Setup:**
[Any required setup steps]
**Related PRs:**
- [Links to related PRs with brief description]
## References
- Issue: [link]
- PR: [link]
- Related: [links to other issues]
---
*Generated by positron-qa-verify skill*
```
## Tips for Effective Verification
- **Start with the primary scenario** - Always test the exact repro steps from the issue first
- **Check edge cases** - Comments often reveal additional scenarios discovered during development
- **Test on relevant platforms** - If issue mentions "macOS only", prioritize that platform
- **Verify related functionality** - Small fixes sometimes have unintended side effects
- **Look for performance notes** - PRs sometimes mention performance implications
## Advanced Features
### Multiple PRs
If an issue has multiple related PRs (e.g., backend + frontend changes):
- I'll analyze all of them
- The guide will note which scenarios relate to which PR
- Testing order may be suggested if one depends on another
### Linked Issues
When comments reference other issues:
- I'll fetch those issue titles
- Include relevant context in the verification guide
- Help you understand if they should be tested together
### Code Analysis Insights
For small PRs where I review the code:
- I'll note if changes are isolated or touch multiple areas
- Highlight any test files modified (what the developers tested)
- Identify configuration changes that might affect behavior
## Limitations
- Cannot automatically execute tests (manual verification only)
- Code analysis is limited to small PRs to save time
- Relies on quality of issue description and PR comments
- May miss verbal discussions not captured in GitHub
## Integration with QA Workflow
This skill integrates with the typical QA verification workflow:
1. **Sign up for ticket** on the QA board
2. **Run `/qa-verify [issue-number]`** to generate guide
3. **Review the generated markdown** to understand what to test
4. **Perform manual verification** following the scenarios
5. **Update ticket status** based on results
The generated guides serve as:
- A checklist during testing
- Documentation of what was verified
- Reference for future related issues
## Success Criteria
A successful verification guide should:
- Clearly explain the issue and its impact
- Provide specific, actionable test scenarios
- Include relevant edge cases from comments/analysis
- List required environment/setup details
- Reference all related issues and PRs
- Be concise but complete (no fluff, all substance)
---
Remember: This skill generates the testing plan. You still need to execute the manual verification yourself!
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/analyze_issue.sh
```bash
#!/bin/bash
# analyze_issue.sh - Gather issue and PR data for QA verification
#
# Usage: ./analyze_issue.sh <issue-number>
#
# This script fetches comprehensive data about an issue and its related PRs
# to help generate verification guides for QA testing.
set -euo pipefail
ISSUE_NUMBER="$1"
REPO="posit-dev/positron"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}Analyzing issue #${ISSUE_NUMBER}...${NC}"
# Function to get PR size (lines changed)
get_pr_size() {
local pr_number="$1"
gh pr view "$pr_number" --repo "$REPO" --json additions,deletions --jq '.additions + .deletions' 2>/dev/null || echo "0"
}
# 1. Fetch issue details
echo -e "${YELLOW}Fetching issue details...${NC}"
ISSUE_JSON=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title,body,comments,url,labels,author,createdAt 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$ISSUE_JSON" ]; then
echo -e "${RED}Failed to fetch issue #${ISSUE_NUMBER}${NC}"
exit 1
fi
ISSUE_TITLE=$(echo "$ISSUE_JSON" | jq -r '.title')
ISSUE_BODY=$(echo "$ISSUE_JSON" | jq -r '.body // ""')
ISSUE_URL=$(echo "$ISSUE_JSON" | jq -r '.url')
ISSUE_LABELS=$(echo "$ISSUE_JSON" | jq -r '.labels[].name' | paste -sd ',' - || echo "")
echo "Title: $ISSUE_TITLE"
echo "URL: $ISSUE_URL"
echo "Labels: $ISSUE_LABELS"
# 2. Extract comments
echo -e "\n${YELLOW}Analyzing comments...${NC}"
COMMENTS_JSON=$(echo "$ISSUE_JSON" | jq '.comments')
COMMENT_COUNT=$(echo "$COMMENTS_JSON" | jq 'length')
echo "Found $COMMENT_COUNT comments"
# 3. Find linked PRs - simple approach using issue view
echo -e "\n${YELLOW}Detecting linked PRs...${NC}"
# Get PRs that mention this issue
LINKED_PRS=$(gh pr list --repo "$REPO" --search "$ISSUE_NUMBER" --state all --json number --jq '.[].number' 2>/dev/null || echo "")
# Also extract from body and comments text
ALL_PR_REFS=$(echo "$ISSUE_BODY" | grep -oE '#[0-9]+' | sed 's/#//' || echo "")
COMMENT_PR_REFS=$(echo "$COMMENTS_JSON" | jq -r '.[].body // ""' | grep -oE '#[0-9]+' | sed 's/#//' || echo "")
# Combine and deduplicate
ALL_PRS=$(echo -e "${LINKED_PRS}\n${ALL_PR_REFS}\n${COMMENT_PR_REFS}" | sort -u | grep -E '^[0-9]+$' | head -20 || echo "")
if [ -z "$ALL_PRS" ]; then
echo -e "${YELLOW}No PRs found linked to this issue${NC}"
PR_LIST="[]"
else
echo -e "${GREEN}Found potential PR(s): $(echo "$ALL_PRS" | tr '\n' ' ')${NC}"
# 4. Fetch PR details for each
PR_LIST="["
FIRST=true
for PR_NUM in $ALL_PRS; do
echo -e "\n${YELLOW}Checking PR #${PR_NUM}...${NC}"
# Verify this is actually a PR (not just an issue reference)
PR_JSON=$(gh pr view "$PR_NUM" --repo "$REPO" --json title,body,url,state,comments,author,mergedAt,number 2>/dev/null || echo "")
if [ -z "$PR_JSON" ] || [ "$PR_JSON" = "null" ]; then
echo -e "${YELLOW} #${PR_NUM} is not a PR, skipping${NC}"
continue
fi
PR_TITLE=$(echo "$PR_JSON" | jq -r '.title // ""')
PR_SIZE=$(get_pr_size "$PR_NUM")
echo " Title: $PR_TITLE"
echo " Size: $PR_SIZE lines changed"
echo " Should review code: $([ "$PR_SIZE" -lt 500 ] && echo 'Yes' || echo 'No (too large)')"
# Add to JSON array
if [ "$FIRST" = true ]; then
FIRST=false
else
PR_LIST="${PR_LIST},"
fi
PR_LIST="${PR_LIST}$(echo "$PR_JSON" | jq -c ". + {size: $PR_SIZE, shouldReviewCode: $([ "$PR_SIZE" -lt 500 ] && echo 'true' || echo 'false')}")"
done
PR_LIST="${PR_LIST}]"
fi
# 5. Extract referenced issues
echo -e "\n${YELLOW}Finding related issues...${NC}"
BODY_ISSUES=$(echo "$ISSUE_BODY" | grep -oE '#[0-9]+' | sed 's/#//' | grep -v "^${ISSUE_NUMBER}$" || echo "")
COMMENT_ISSUES=$(echo "$COMMENTS_JSON" | jq -r '.[].body // ""' | grep -oE '#[0-9]+' | sed 's/#//' | grep -v "^${ISSUE_NUMBER}$" || echo "")
RELATED_ISSUES=$(echo -e "${BODY_ISSUES}\n${COMMENT_ISSUES}" | sort -u | grep -E '^[0-9]+$' | head -20 || echo "")
if [ -n "$RELATED_ISSUES" ]; then
echo -e "${GREEN}Found related issues: $(echo "$RELATED_ISSUES" | tr '\n' ' ')${NC}"
else
echo "No related issues found"
fi
# 6. Build final JSON output
echo -e "\n${YELLOW}Building analysis output...${NC}"
OUTPUT_JSON=$(jq -n \
--arg title "$ISSUE_TITLE" \
--arg url "$ISSUE_URL" \
--arg body "$ISSUE_BODY" \
--arg labels "$ISSUE_LABELS" \
--arg number "$ISSUE_NUMBER" \
--argjson comments "$COMMENTS_JSON" \
--argjson prs "$PR_LIST" \
--arg related "$(echo "$RELATED_ISSUES" | tr '\n' ',' | sed 's/,$//')" \
'{
issue: {
number: $number,
title: $title,
url: $url,
body: $body,
labels: $labels,
commentCount: ($comments | length)
},
comments: $comments,
prs: $prs,
relatedIssues: ($related | split(",") | map(select(length > 0)))
}'
)
# Output the JSON
echo "$OUTPUT_JSON"
echo -e "\n${GREEN}Analysis complete!${NC}"
```
### scripts/detect_versions.sh
```bash
#!/bin/bash
# detect_versions.sh - Fast, silent version detection for Positron and OS
#
# This script attempts to auto-detect:
# 1. Positron version and build number
# 2. OS version
#
# DESIGN PRINCIPLES:
# - Fast: Each detection has a 3-second timeout, max 6 seconds total
# - Silent: Never prints errors, never prompts, only outputs JSON
# - Fail-safe: If detection fails, returns empty values (not errors)
# - Cross-platform: Works on macOS, Linux, Windows (Git Bash/PowerShell)
#
# Output format: JSON with keys:
# - positronVersion: string or empty
# - positronBuild: string or empty
# - osVersion: string or empty
# - detectionStatus: "success", "partial", or "failed"
set +e # Don't exit on errors
set -u # But do error on undefined variables
set -o pipefail
# Timeout for each detection attempt (seconds)
TIMEOUT=2
# Colors for debug output (only used if DEBUG=1)
if [ "${DEBUG:-0}" = "1" ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
else
RED=''
GREEN=''
YELLOW=''
NC=''
fi
debug() {
if [ "${DEBUG:-0}" = "1" ]; then
echo -e "${YELLOW}[DEBUG]${NC} $1" >&2
fi
}
# Detect platform
detect_platform() {
case "$(uname -s)" in
Darwin*) echo "macos" ;;
Linux*) echo "linux" ;;
CYGWIN*|MINGW*|MSYS*) echo "windows" ;;
*) echo "unknown" ;;
esac
}
PLATFORM=$(detect_platform)
debug "Platform: $PLATFORM"
# Function to run command with timeout (silent on failure)
run_with_timeout() {
local timeout=$1
shift
local cmd="$@"
debug "Running: $cmd"
# Try with timeout command if available, otherwise just run directly
if command -v timeout >/dev/null 2>&1; then
timeout "$timeout" bash -c "$cmd" 2>/dev/null
elif command -v gtimeout >/dev/null 2>&1; then
# macOS with coreutils installed
gtimeout "$timeout" bash -c "$cmd" 2>/dev/null
else
# No timeout available, just run directly (risky but better than nothing)
eval "$cmd" 2>/dev/null
fi
return $?
}
# Detect Positron version
detect_positron_version() {
local product_json=""
local positron_version=""
local positron_build=""
# List of paths to check (in order of likelihood)
case "$PLATFORM" in
macos)
paths=(
"/Applications/Positron.app/Contents/Resources/app/product.json"
"$HOME/Applications/Positron.app/Contents/Resources/app/product.json"
)
;;
linux)
paths=(
"/usr/share/positron/resources/app/product.json"
"/opt/positron/resources/app/product.json"
"$HOME/.local/share/positron/resources/app/product.json"
"$HOME/positron/resources/app/product.json"
)
;;
windows)
# Convert Windows paths for Git Bash/MSYS
localappdata="${LOCALAPPDATA:-$HOME/AppData/Local}"
programfiles="${PROGRAMFILES:-/c/Program Files}"
programfilesx86="${PROGRAMFILES(X86):-/c/Program Files (x86)}"
paths=(
"$localappdata/Programs/Positron/resources/app/product.json"
"$programfiles/Positron/resources/app/product.json"
"$programfilesx86/Positron/resources/app/product.json"
)
;;
*)
paths=()
;;
esac
# Try each path with timeout
for path in "${paths[@]}"; do
debug "Checking path: $path"
# Check if file exists quickly (no timeout needed)
if [ -f "$path" ]; then
debug "File exists, reading..."
# Read and parse JSON with timeout
if command -v jq >/dev/null 2>&1; then
local result=$(run_with_timeout $TIMEOUT "cat '$path' | jq -r '{positronVersion:.positronVersion, positronBuildNumber:.positronBuildNumber}'")
if [ $? -eq 0 ] && [ -n "$result" ]; then
positron_version=$(echo "$result" | jq -r '.positronVersion // empty' 2>/dev/null)
positron_build=$(echo "$result" | jq -r '.positronBuildNumber // empty' 2>/dev/null)
if [ -n "$positron_version" ] && [ "$positron_version" != "null" ]; then
debug "Found version: $positron_version build $positron_build"
break
fi
fi
else
# Fallback: try to extract without jq (less reliable)
local result=$(run_with_timeout $TIMEOUT "grep -E 'positronVersion|positronBuildNumber' '$path' | head -2")
if [ $? -eq 0 ] && [ -n "$result" ]; then
positron_version=$(echo "$result" | grep positronVersion | sed -E 's/.*"positronVersion"[^"]*"([^"]+)".*/\1/' | head -1)
positron_build=$(echo "$result" | grep positronBuildNumber | sed -E 's/.*"positronBuildNumber"[^"]*"?([^",]+)"?.*/\1/' | head -1)
if [ -n "$positron_version" ]; then
debug "Found version (no jq): $positron_version build $positron_build"
break
fi
fi
fi
fi
done
# Output results (even if empty)
echo "$positron_version"
echo "$positron_build"
}
# Detect OS version
detect_os_version() {
local os_version=""
case "$PLATFORM" in
macos)
debug "Detecting macOS version..."
os_version=$(run_with_timeout $TIMEOUT "sw_vers -productVersion 2>/dev/null | head -1")
if [ -n "$os_version" ]; then
os_version="macOS $os_version"
fi
;;
linux)
debug "Detecting Linux version..."
# Try /etc/os-release first (standard)
if [ -f /etc/os-release ]; then
local name=$(run_with_timeout $TIMEOUT "grep -E '^NAME=' /etc/os-release | cut -d'=' -f2 | tr -d '\"' | head -1")
local version=$(run_with_timeout $TIMEOUT "grep -E '^VERSION_ID=' /etc/os-release | cut -d'=' -f2 | tr -d '\"' | head -1")
if [ -n "$name" ]; then
os_version="$name"
if [ -n "$version" ]; then
os_version="$os_version $version"
fi
fi
fi
# Fallback to uname
if [ -z "$os_version" ]; then
os_version=$(run_with_timeout $TIMEOUT "uname -sr 2>/dev/null")
fi
;;
windows)
debug "Detecting Windows version..."
# Try multiple methods for Windows
# Method 1: PowerShell command (if available)
if command -v powershell.exe >/dev/null 2>&1; then
local win_version=$(run_with_timeout $TIMEOUT "powershell.exe -NoProfile -Command '[System.Environment]::OSVersion.VersionString' 2>/dev/null | tr -d '\r'")
if [ -n "$win_version" ]; then
os_version="$win_version"
fi
fi
# Method 2: Try systeminfo (slower, skip if we have version)
if [ -z "$os_version" ] && command -v systeminfo >/dev/null 2>&1; then
local win_name=$(run_with_timeout $TIMEOUT "systeminfo 2>/dev/null | grep -E 'OS Name' | cut -d':' -f2 | sed 's/^[[:space:]]*//' | head -1")
if [ -n "$win_name" ]; then
os_version="$win_name"
fi
fi
# Fallback: uname (less informative on Windows)
if [ -z "$os_version" ]; then
os_version=$(run_with_timeout $TIMEOUT "uname -sr 2>/dev/null")
fi
;;
*)
os_version=$(run_with_timeout $TIMEOUT "uname -sr 2>/dev/null")
;;
esac
# Trim whitespace
os_version=$(echo "$os_version" | xargs 2>/dev/null)
debug "OS Version: $os_version"
echo "$os_version"
}
# Main detection logic
main() {
debug "Starting version detection..."
# Detect Positron version (returns two lines)
local positron_output=$(detect_positron_version)
local positron_version=$(echo "$positron_output" | sed -n '1p')
local positron_build=$(echo "$positron_output" | sed -n '2p')
# Detect OS version
local os_version=$(detect_os_version)
# Determine detection status
local status="failed"
if [ -n "$positron_version" ] && [ -n "$os_version" ]; then
status="success"
elif [ -n "$positron_version" ] || [ -n "$os_version" ]; then
status="partial"
fi
# Output JSON (always valid, even if empty)
cat <<-EOF
{
"positronVersion": "${positron_version:-}",
"positronBuild": "${positron_build:-}",
"osVersion": "${os_version:-}",
"detectionStatus": "$status"
}
EOF
debug "Detection complete: $status"
}
# Run main function
main
```