diff --git a/copilot-instructions/Generate-ProductivityReport.ps1 b/copilot-instructions/Generate-ProductivityReport.ps1 index 25aade4..dddca64 100644 --- a/copilot-instructions/Generate-ProductivityReport.ps1 +++ b/copilot-instructions/Generate-ProductivityReport.ps1 @@ -1,4 +1,3 @@ -# (cleaned stray HTML fragment) # Copyright 2025 Kyle J. Coder # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -212,12 +211,18 @@ function Write-Log { Add-Content -Path $LogPath -Value $LogEntry } +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Conditional console writer (suppressed when -Quiet) function Write-Info { param([string]$Text, [ConsoleColor]$Color = [ConsoleColor]::Gray) if (-not $Quiet) { Write-Host $Text -ForegroundColor $Color } } +======= +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes # Read a line with timeout (returns default if user doesn't answer in time) function Read-HostWithTimeout { param( @@ -253,6 +258,8 @@ function Read-HostWithTimeout { } function Show-IntroText { +<<<<<<< Updated upstream +<<<<<<< Updated upstream Write-Host "" Write-Host "What this tool does:" -ForegroundColor Cyan Write-Host " Creates a decision-ready snapshot of development activity in this workspace for a selected period." -ForegroundColor Gray @@ -295,6 +302,20 @@ function Show-IntroText { Write-Host " - -Quiet : Minimize console output and suppress auto-open" -ForegroundColor Gray Write-Host " - -MaxCommits : Limit the Recent Commits section length (default: 10)" -ForegroundColor Gray Write-Host " - -BaselineJson : Compare against prior JSON export; deltas shown next to KPIs" -ForegroundColor Gray +======= +======= +>>>>>>> Stashed changes + Write-Host ""; Write-Host "About this tool" -ForegroundColor Cyan + Write-Host "Purpose: Generate a concise productivity snapshot for a chosen time period." -ForegroundColor Gray + Write-Host "Scope: Analyzes Git activity in this workspace and parses productivity logs (if present)." -ForegroundColor Gray + Write-Host "Intended use: Management/status reporting and personal tracking—not precise timekeeping." -ForegroundColor Gray + Write-Host "Expected results: A report file (Markdown/HTML/JSON/CSV) with commit counts, code deltas, and an effort estimate." -ForegroundColor Gray + Write-Host "Notes: The report is a snapshot of the selected period (Daily/Weekly/Monthly/All time/Custom)." -ForegroundColor Gray + Write-Host " Use Custom for exact start/end dates. Opening the report is optional and can be automated." -ForegroundColor Gray +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes } function New-Divider { @@ -322,8 +343,16 @@ function Show-ConfigSummary { [Nullable[DateTime]]$EndDate, [string]$OutputFormat, [bool]$OpenAfterGeneration, +<<<<<<< Updated upstream +<<<<<<< Updated upstream [bool]$IncludeDetailed, [string]$GitRepoPath +======= + [bool]$IncludeDetailed +>>>>>>> Stashed changes +======= + [bool]$IncludeDetailed +>>>>>>> Stashed changes ) Show-Header "Selected Options" Write-Host (" Report Type : {0}" -f $ReportType) -ForegroundColor Gray @@ -334,6 +363,8 @@ function Show-ConfigSummary { Write-Host (" Output Format: {0}" -f $OutputFormat) -ForegroundColor Gray Write-Host (" Open File : {0}" -f ($(if ($OpenAfterGeneration) { 'Yes' } else { 'No' }))) -ForegroundColor Gray Write-Host (" Detailed Mode: {0}" -f ($(if ($IncludeDetailed) { 'Yes' } else { 'No' }))) -ForegroundColor Gray +<<<<<<< Updated upstream +<<<<<<< Updated upstream if ($GitRepoPath) { Write-Host (" Git Repo Path: {0}" -f $GitRepoPath) -ForegroundColor Gray } } @@ -381,6 +412,23 @@ function Get-ReportTypeInteractive { Write-Host " 4) All time (default)" -ForegroundColor Gray Write-Host " 5) Custom (enter start and end dates)" -ForegroundColor Gray $choice = Read-HostWithTimeout -Prompt "Enter choice [1-5]" -TimeoutSeconds 15 -Default "AllTime" +======= +======= +>>>>>>> Stashed changes +} + +function Get-ReportTypeInteractive { + Write-Host "\nSelect report period:" -ForegroundColor Cyan + Write-Host " 1) Daily" -ForegroundColor Gray + Write-Host " 2) Weekly" -ForegroundColor Gray + Write-Host " 3) Monthly" -ForegroundColor Gray + Write-Host " 4) All time (default)" -ForegroundColor Gray + Write-Host " 5) Custom (enter start and end dates)" -ForegroundColor Gray + $choice = Read-HostWithTimeout -Prompt "Enter choice [1-5] or name (Daily/Weekly/Monthly/AllTime/Custom)" -TimeoutSeconds 15 -Default "AllTime" +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes switch -Regex ($choice.Trim()) { '^(1|daily)$' { return @{ ReportType = 'Daily'; StartDate = $null; EndDate = $null } } @@ -406,11 +454,25 @@ function Get-ReportTypeInteractive { } function Get-OutputFormatInteractive { +<<<<<<< Updated upstream +<<<<<<< Updated upstream Write-Host "Select output format:" -ForegroundColor Cyan Write-Host " 1) Markdown (.md)" -ForegroundColor Gray Write-Host " 2) HTML (.html) [default]" -ForegroundColor Gray Write-Host " 3) JSON (.json)" -ForegroundColor Gray Write-Host " 4) CSV (.csv)" -ForegroundColor Gray +======= +======= +>>>>>>> Stashed changes + Write-Host "\nSelect output format:" -ForegroundColor Cyan + Write-Host " 1) Markdown (.md)" -ForegroundColor Gray + Write-Host " 2) HTML (.html) [default]" -ForegroundColor Gray + Write-Host " 3) JSON (.json)" -ForegroundColor Gray + Write-Host " 4) CSV (.csv)" -ForegroundColor Gray +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes $choice = Read-HostWithTimeout -Prompt "Enter choice [1-4] or name (Markdown/HTML/JSON/CSV)" -TimeoutSeconds 15 -Default "HTML" switch -Regex ($choice.Trim()) { @@ -1191,6 +1253,8 @@ function Export-Report { ($s -replace '&','&' -replace '<','<' -replace '>','>' -replace '"','"') } +<<<<<<< Updated upstream +<<<<<<< Updated upstream $workHours = [Math]::Round(($Data.Git.EstimatedWorkMinutes / 60), 1) $repoDisplay = if ($Data.RepoPath) { & $encode $Data.RepoPath } else { 'Current workspace' } # Build a clickable file link to open the actual repo root in Explorer @@ -1210,6 +1274,18 @@ function Export-Report { $recent = @() if ($Data.Git.Commits -and $Data.Git.Commits.Count -gt 0) { $recent = $Data.Git.Commits | Sort-Object Date -Descending | Select-Object -First $MaxCommits +======= +======= +>>>>>>> Stashed changes + $workHours = [Math]::Round(($Data.Git.EstimatedWorkMinutes / 60), 1) + $commitRows = "" + $recent = @() + if ($Data.Git.Commits -and $Data.Git.Commits.Count -gt 0) { + $recent = $Data.Git.Commits | Sort-Object Date -Descending | Select-Object -First 10 +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes foreach ($c in $recent) { $short = if ($c.Hash) { $c.Hash.Substring(0, [Math]::Min(7, $c.Hash.Length)) } else { '' } $msg = & $encode $c.Message @@ -1219,6 +1295,8 @@ function Export-Report { } } +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Delta chips if baseline provided $dc = $Data.Git.BaselineDelta function New-DeltaChip([int]$v) { @@ -1390,10 +1468,88 @@ function Export-Report {
Hover bars to see period details
+======= +======= +>>>>>>> Stashed changes + $kpiHtml = @" +
+
Git Commits
$($Data.Git.CommitCount)
+
Lines Added
$($Data.Git.LinesAdded)
+
Lines Removed
$($Data.Git.LinesRemoved)
+
Lines Modified
$($Data.Git.LinesModified)
+
Files Changed
$($Data.Git.FilesChanged)
+
Est. Work
$($Data.Git.EstimatedWorkMinutes) min
($workHours h)
+
+"@ + + # Build activity trend data for a simple bar sparkline + $startChart = $null; $endChart = $null + if ($period) { + $pp = $period.Trim() + $parts = $pp -split '\s*-\s*' + if ($parts.Length -ge 2) { + try { $startChart = [DateTime]::Parse($parts[0]); $endChart = [DateTime]::Parse($parts[1]) } catch {} + } + } + if (-not $startChart -and $Data.Git.Commits) { + $startChart = ($Data.Git.Commits | Select-Object -ExpandProperty Date | Sort-Object | Select-Object -First 1) + } + if (-not $endChart -and $Data.Git.Commits) { + $endChart = ($Data.Git.Commits | Select-Object -ExpandProperty Date | Sort-Object | Select-Object -Last 1) + } + if (-not $startChart) { $startChart = (Get-Date).Date } + if (-not $endChart) { $endChart = (Get-Date).Date } + + $startChart = $startChart.Date; $endChart = $endChart.Date + $spanDays = [int]($endChart - $startChart).TotalDays + 1 + $commitDates = @() + if ($Data.Git.Commits) { $commitDates = $Data.Git.Commits | ForEach-Object { $_.Date.Date } } + $labels = New-Object System.Collections.Generic.List[string] + $counts = New-Object System.Collections.Generic.List[int] + if ($spanDays -le 14) { + for ($d=0; $d -lt $spanDays; $d++) { + $day = $startChart.AddDays($d) + [void]$labels.Add($day.ToString('MM/dd')) + $cnt = ($commitDates | Where-Object { $_ -eq $day }).Count + [void]$counts.Add([int]$cnt) + } + } elseif ($spanDays -le 120) { + $s = $startChart + while ($s -le $endChart) { + $e = $s.AddDays(6); if ($e -gt $endChart) { $e = $endChart } + [void]$labels.Add($s.ToString('MM/dd')) + $cnt = ($commitDates | Where-Object { $_ -ge $s -and $_ -le $e }).Count + [void]$counts.Add([int]$cnt) + $s = $s.AddDays(7) + } + } else { + $cursor = Get-Date -Date ($startChart.ToString('yyyy-MM-01')) + while ($cursor -le $endChart) { + $next = $cursor.AddMonths(1).AddDays(-1); if ($next -gt $endChart) { $next = $endChart } + [void]$labels.Add($cursor.ToString('MMM yy')) + $cnt = ($commitDates | Where-Object { $_ -ge $cursor -and $_ -le $next }).Count + [void]$counts.Add([int]$cnt) + $cursor = $cursor.AddMonths(1) + } + } + $labelsJson = ($labels | ConvertTo-Json -Compress) + $countsJson = ($counts | ConvertTo-Json -Compress) + + $chartSection = @" +

Activity Trend

+
+ +
Commits per period
+<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes
+"@ + + $commitTable = if ($commitRows) { +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes @"

Recent Commits

@@ -1805,12 +1999,20 @@ function Export-Report { $commitRows
+<<<<<<< Updated upstream +<<<<<<< Updated upstream $(if ($Data.Git.Commits.Count -gt $MaxCommits) { '
…and ' + ($Data.Git.Commits.Count - $MaxCommits) + ' more
' } else { '' }) +======= +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes "@ } else { '

No commits found in the selected period.

' } +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Filesystem card (if present) $fsCard = '' try { @@ -1914,6 +2116,10 @@ function Export-Report { if ($metaGeneratedText){ [void]$metaChips.Add("$metaGeneratedText") } $metaChipsHtml = [string]::Join("`n ", $metaChips) +======= +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes $FullHtml = @" @@ -1929,12 +2135,26 @@ function Export-Report { @media (prefers-color-scheme: dark){ :root{ --bg:#0b0f14; --fg:#e5e7eb; --muted:#94a3b8; --card:#0f172a; --border:#233044; } } +<<<<<<< Updated upstream +<<<<<<< Updated upstream body{ margin:0; padding:32px; font-family:Segoe UI, Roboto, Arial, sans-serif; background:var(--bg); color:var(--fg); display:flex; min-height:100vh; flex-direction:column; } .container{ max-width:1100px; margin:0 auto; width:100%; flex:1; display:block; } header h1{ margin:0; font-size:26px; color:var(--brand); } header .meta{ color:var(--muted); margin-top:4px; } .cards{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin:24px 0; } .cards-single{ grid-template-columns:1fr; } +======= +======= +>>>>>>> Stashed changes + body{ margin:32px; font-family:Segoe UI, Roboto, Arial, sans-serif; background:var(--bg); color:var(--fg); } + .container{ max-width:1100px; margin:0 auto; } + header h1{ margin:0; font-size:26px; color:var(--brand); } + header .meta{ color:var(--muted); margin-top:4px; } + .cards{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin:24px 0; } +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes .card{ background:var(--card); border:1px solid var(--border); border-radius:10px; padding:16px 18px; } .kpis{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:12px; margin-top:8px; } .kpi{ background:#fff0; border:1px dashed var(--border); border-radius:8px; padding:12px; text-align:center; } @@ -1944,15 +2164,23 @@ function Export-Report { .kpi-value.add{ color:var(--add); } .kpi-value.remove{ color:var(--remove); } .kpi-value.mod{ color:var(--mod); } +<<<<<<< Updated upstream +<<<<<<< Updated upstream .delta-chip{ display:inline-block; margin-left:6px; padding:2px 6px; border-radius:999px; font-size:11px; line-height:1; border:1px solid var(--border); vertical-align:middle; } .delta-chip.up{ color:var(--add); border-color:var(--add); } .delta-chip.down{ color:var(--remove); border-color:var(--remove); } .delta-chip.neutral{ color:var(--muted); } +======= +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes h2{ color:var(--brand2); margin:22px 0 10px; font-size:20px; } .table{ width:100%; border-collapse:collapse; border:1px solid var(--border); border-radius:8px; overflow:hidden; } .table thead{ background:var(--card); } .table th, .table td{ padding:10px 12px; border-bottom:1px solid var(--border); vertical-align:top; } .muted{ color:var(--muted); } +<<<<<<< Updated upstream +<<<<<<< Updated upstream footer{ margin-top:24px; color:var(--muted); font-size:12px; padding-top:8px; border-top:1px solid var(--border); } footer .meta-row{ margin-top:6px; } code{ background:var(--card); padding:2px 6px; border-radius:6px; } @@ -1977,12 +2205,25 @@ function Export-Report { details[open] summary::before { transform: rotate(90deg); } .details-content { margin-top:8px; color:var(--fg); } .details-content a { color:var(--brand2); text-decoration:underline; } +======= +======= +>>>>>>> Stashed changes + footer{ margin-top:24px; color:var(--muted); font-size:12px; } + code{ background:var(--card); padding:2px 6px; border-radius:6px; } + #trend{ width:100%; display:block; } + .chart-card{ background:var(--card); border:1px solid var(--border); border-radius:10px; padding:16px 18px; margin-top:16px; } +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes

VA Power Platform Productivity Report

+<<<<<<< Updated upstream +<<<<<<< Updated upstream
@@ -2132,6 +2373,45 @@ function Export-Report {
$metaChipsHtml
+======= +======= +>>>>>>> Stashed changes +
$((if ($period) { "Period: $period" } else { '' }))
+
$((if ($generated) { "Generated: $generated" } else { "Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" }))
+
$((if ($author) { "Author: $author" } else { '' }))
+
$((if ($team) { "Team: $team" } else { '' }))
+
$((if ($facility) { "Facility: $facility" } else { '' }))
+ + +
+
+

Executive Summary

+

Snapshot of development activity and estimated effort for the selected period.

+ $kpiHtml +
+
+

Code Development Statistics

+
    +
  • Commits: $($Data.Git.CommitCount)
  • +
  • Lines Added: $($Data.Git.LinesAdded)
  • +
  • Lines Removed: $($Data.Git.LinesRemoved)
  • +
  • Lines Modified: $($Data.Git.LinesModified)
  • +
  • Files Changed: $($Data.Git.FilesChanged)
  • +
  • Estimated Time: $($Data.Git.EstimatedWorkMinutes) minutes ($workHours hours)
  • +
+
+
+ + $chartSection + + $commitTable + +
@@ -2179,6 +2459,7 @@ Filesystem Last Modified,$((if ($Data.Filesystem.LastModified) { $Data.Filesyste try { Write-Log "Starting productivity report generation" "INFO" +<<<<<<< Updated upstream if (-not $Quiet) { Write-Host "VA Power Platform Productivity Report Generator" -ForegroundColor Green Write-Host "================================================" -ForegroundColor Green @@ -2194,6 +2475,21 @@ try { # Determine date range (interactive if no parameters provided) if (-not $NonInteractive -and -not $PSBoundParameters.ContainsKey('ReportType') -and -not $PSBoundParameters.ContainsKey('StartDate') -and -not $PSBoundParameters.ContainsKey('EndDate')) { +======= + Write-Host "VA Power Platform Productivity Report Generator" -ForegroundColor Green + Write-Host "================================================" -ForegroundColor Green + Show-IntroText + New-Divider + + $progressId = 1 + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Preparing..." -PercentComplete 5 + + # Determine date range (interactive if no parameters provided) + if (-not $PSBoundParameters.ContainsKey('ReportType') -and -not $PSBoundParameters.ContainsKey('StartDate') -and -not $PSBoundParameters.ContainsKey('EndDate')) { +<<<<<<< Updated upstream +>>>>>>> Stashed changes +======= +>>>>>>> Stashed changes Show-Header "Report Setup" $selection = Get-ReportTypeInteractive $ReportType = $selection.ReportType @@ -2254,6 +2550,26 @@ try { if (-not $Quiet) { Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Analyzing workspace activity..." -PercentComplete 35 } + # Select output format (interactive if not provided) + if (-not $PSBoundParameters.ContainsKey('OutputFormat')) { + $OutputFormat = Get-OutputFormatInteractive + } + Write-Host "Output Format: $OutputFormat" -ForegroundColor Yellow + + Show-ConfigSummary -ReportType $ReportType -StartDate $StartDate -EndDate $EndDate -OutputFormat $OutputFormat -OpenAfterGeneration:$OpenAfterGeneration -IncludeDetailed:$IncludeDetailed + + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Analyzing workspace activity..." -PercentComplete 35 + + # Select output format (interactive if not provided) + if (-not $PSBoundParameters.ContainsKey('OutputFormat')) { + $OutputFormat = Get-OutputFormatInteractive + } + Write-Host "Output Format: $OutputFormat" -ForegroundColor Yellow + + Show-ConfigSummary -ReportType $ReportType -StartDate $StartDate -EndDate $EndDate -OutputFormat $OutputFormat -OpenAfterGeneration:$OpenAfterGeneration -IncludeDetailed:$IncludeDetailed + + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Analyzing workspace activity..." -PercentComplete 35 + # Generate output path if not specified if ([string]::IsNullOrEmpty($OutputPath)) { $ReportsPath = if ($OutputDir) { $OutputDir } else { "$PSScriptRoot\..\docs\reports" } @@ -2276,11 +2592,21 @@ try { } } +<<<<<<< Updated upstream +<<<<<<< Updated upstream if (-not $Quiet) { Show-Header "Analyzing Workspace Activity" } +======= + Show-Header "Analyzing Workspace Activity" +>>>>>>> Stashed changes +======= + Show-Header "Analyzing Workspace Activity" +>>>>>>> Stashed changes # Collect productivity data $ProductivityData = Get-ProductivityData -DateRange $DateRange -RepoPath $GitRepoPath -GitRef $GitRef -AllBranches:$AllBranches +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Optional baseline comparison $Baseline = $null if ($BaselineJson -and (Test-Path -LiteralPath $BaselineJson)) { @@ -2303,10 +2629,20 @@ try { if (-not $Quiet) { Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Generating report..." -PercentComplete 70 } if (-not $Quiet) { Show-Header "Generating Report" } +======= + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Generating report..." -PercentComplete 70 + Show-Header "Generating Report" +>>>>>>> Stashed changes +======= + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Generating report..." -PercentComplete 70 + Show-Header "Generating Report" +>>>>>>> Stashed changes # Generate report content $ReportContent = Format-MarkdownReport -Data $ProductivityData -DateRange $DateRange +<<<<<<< Updated upstream +<<<<<<< Updated upstream if (-not $Quiet) { Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Exporting report..." -PercentComplete 85 } # Export report(s) if ($ExportFormats -and $ExportFormats.Count -gt 0) { @@ -2328,10 +2664,19 @@ try { } else { Export-Report -Content $ReportContent -Format $OutputFormat -OutputPath $OutputPath -Data $ProductivityData } +======= +======= +>>>>>>> Stashed changes + Write-Progress -Id $progressId -Activity "Productivity Report" -Status "Exporting report..." -PercentComplete 85 + # Export report + Export-Report -Content $ReportContent -Format $OutputFormat -OutputPath $OutputPath -Data $ProductivityData +>>>>>>> Stashed changes # Summary $FileSize = (Get-Item $OutputPath).Length +<<<<<<< Updated upstream +<<<<<<< Updated upstream if (-not $Quiet) { Write-Progress -Id $progressId -Activity "Productivity Report" -Completed } if (-not $Quiet) { @@ -2347,6 +2692,21 @@ try { Write-Host " Lines Changed: $($ProductivityData.Git.LinesAdded + $ProductivityData.Git.LinesRemoved + $ProductivityData.Git.LinesModified)" -ForegroundColor Gray Write-Host " Estimated Work: $($ProductivityData.Git.EstimatedWorkMinutes) minutes" -ForegroundColor Gray } +======= +======= +>>>>>>> Stashed changes + Write-Progress -Id $progressId -Activity "Productivity Report" -Completed + + Show-Header "Report Generated" + Write-Host "Productivity report generated successfully!" -ForegroundColor Green + Write-Host "Report file: $OutputPath" -ForegroundColor Cyan + Write-Host "File size: $([math]::Round($FileSize / 1KB, 2)) KB" -ForegroundColor Yellow + + Show-SubHeader "Report Summary" + Write-Host " Git Commits: $($ProductivityData.Git.CommitCount)" -ForegroundColor Gray + Write-Host " Lines Changed: $($ProductivityData.Git.LinesAdded + $ProductivityData.Git.LinesRemoved + $ProductivityData.Git.LinesModified)" -ForegroundColor Gray + Write-Host " Estimated Work: $($ProductivityData.Git.EstimatedWorkMinutes) minutes" -ForegroundColor Gray +>>>>>>> Stashed changes # Open file if requested $opened = $false @@ -2372,6 +2732,8 @@ try { Write-Log "Productivity report generated successfully: $OutputPath" "SUCCESS" +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Exit behavior: if the HTML report was opened successfully, don't prompt (allow window/process to close). # If it was not opened (error or non-HTML), keep the prompt so the user can read output/errors. $isHtml = $false @@ -2384,13 +2746,31 @@ try { # Restore original progress preference if ($PSBoundParameters.ContainsKey('origProgressPreference') -or $null -ne $origProgressPreference) { $ProgressPreference = $origProgressPreference } +======= + # Keep window open so user can read output + try { [void](Read-Host -Prompt "\nPress Enter to exit") } catch {} +>>>>>>> Stashed changes +======= + # Keep window open so user can read output + try { [void](Read-Host -Prompt "\nPress Enter to exit") } catch {} +>>>>>>> Stashed changes } catch { Write-Log "Error generating productivity report: $($_.Exception.Message)" "ERROR" Write-Host "Error generating report: $($_.Exception.Message)" -ForegroundColor Red +<<<<<<< Updated upstream +<<<<<<< Updated upstream # Pause on error as well so the user can read the message (if interactive) if (-not $NonInteractive -and -not $Quiet) { try { [void](Read-Host -Prompt "Press Enter to exit") } catch {} } # Restore original progress preference on error if ($PSBoundParameters.ContainsKey('origProgressPreference') -or $null -ne $origProgressPreference) { $ProgressPreference = $origProgressPreference } +======= + # Pause on error as well so the user can read the message + try { [void](Read-Host -Prompt "\nPress Enter to exit") } catch {} +>>>>>>> Stashed changes +======= + # Pause on error as well so the user can read the message + try { [void](Read-Host -Prompt "\nPress Enter to exit") } catch {} +>>>>>>> Stashed changes exit 1 } diff --git a/copilot-instructions/Recursive-Directory-Analysis.ps1 b/copilot-instructions/Recursive-Directory-Analysis.ps1 index ffad265..0cae770 100644 --- a/copilot-instructions/Recursive-Directory-Analysis.ps1 +++ b/copilot-instructions/Recursive-Directory-Analysis.ps1 @@ -460,6 +460,73 @@ function New-RowObject { return [PSCustomObject]$obj } + <# + --------------------------------------------------------------------- +function New-RowObject { + param( + [string]$ItemType, + [System.IO.FileSystemInfo]$Item, + [Nullable[int64]]$SizeBytes, + [string]$Author, + [Nullable[int]]$Lines, + [Nullable[int64]]$Chars) + + $ext = if (-not $Item.PSIsContainer) { ($Item.Extension.ToLowerInvariant()); } else { $null } + $attrs = Get-ItemAttributesBooleans -Item $Item + + $created = try { $Item.CreationTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK") } catch { '' } + $modified = try { $Item.LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK") } catch { '' } + + $name = try { $Item.Name } catch { [System.IO.Path]::GetFileName($Item.FullName) } + $full = try { $Item.FullName } catch { $null } + + $extVal = if ($ext) { $ext } else { '' } + $sizeVal = if ($null -ne $SizeBytes) { [string]$SizeBytes } else { '' } + $linesVal = if ($null -ne $Lines) { [string]$Lines } else { '' } + $charsVal = if ($null -ne $Chars) { [string]$Chars } else { '' } + + # Build Excel HYPERLINK formula for the FullPath column + # Requirement: clicking opens the containing folder/location, not the item itself. + $fullForLink = if ($full) { $full } else { '' } + $containingFolder = try { + if ($Item.PSIsContainer) { + if ($Item.Parent) { $Item.Parent.FullName } else { $Item.FullName } + } else { + $Item.DirectoryName + } + } catch { $fullForLink } + if ([string]::IsNullOrWhiteSpace($containingFolder)) { $containingFolder = $fullForLink } + # Escape double quotes for CSV/formula safety (Excel uses doubled quotes inside formulas) + $dispText = $fullForLink -replace '"','""' + $targetPath = $containingFolder -replace '"','""' + $fullHyperlink = if ([string]::IsNullOrEmpty($fullForLink)) { '' } else { [string]::Format('=HYPERLINK("{0}","{1}")', $targetPath, $dispText) } + + # Reordered columns: + # Far left: CreatedTime, LastModifiedTime, Author, IsReparsePoint, IsHidden, IsReadOnly, IsSystem, IsArchive + # Then FullPath (as hyperlink), Name, and remaining columns + $obj = [ordered]@{ + CreatedTime = $created + LastModifiedTime = $modified + Author = $Author + IsReparsePoint = [string](Test-ReparsePoint -Item $Item) + IsHidden = [string]$($attrs.IsHidden) + IsReadOnly = [string]$($attrs.IsReadOnly) + IsSystem = [string]$($attrs.IsSystem) + IsArchive = [string]$($attrs.IsArchive) + FullPath = $fullHyperlink + Name = $name + ItemType = $ItemType + Extension = $extVal + SizeBytes = $sizeVal + LinesOfText = $linesVal + CharacterCount = $charsVal + } + return [PSCustomObject]$obj +} + + ---------------------------------------------------------------------- + #> + function Build-CsvSummaryLine { param( [int]$TotalItems, diff --git a/copilot-instructions/Validate-WorkspaceSetup.ps1 b/copilot-instructions/Validate-WorkspaceSetup.ps1 index 1ace09a..57af4e1 100644 --- a/copilot-instructions/Validate-WorkspaceSetup.ps1 +++ b/copilot-instructions/Validate-WorkspaceSetup.ps1 @@ -286,8 +286,8 @@ Generated by VA Power Platform Workspace Template (updated Aug 2025) } } -# Always produce a JSON report to a temp file if errors were found, then trigger guidance generator -if ($ErrorCount -gt 0) { +# Always produce a JSON report to a temp file if errors or warnings were found, then trigger guidance generator +if ($ErrorCount -gt 0 -or $WarningCount -gt 0) { try { $ts = (Get-Date).ToString('yyyyMMdd-HHmmss') $tempJson = Join-Path $env:TEMP "workspace-validation-$ts.json" diff --git a/copilot-instructions/tasks.json b/copilot-instructions/tasks.json index dbfa7bf..a37ccb3 100644 --- a/copilot-instructions/tasks.json +++ b/copilot-instructions/tasks.json @@ -27,7 +27,7 @@ limitations under the License. "label": "Install/Update Copilot Instructions (.github)", "type": "shell", "command": "cmd.exe", - "args": ["/c", "\"${workspaceFolder}\\copilot-instructions\\Install-Copilot-Instructions.bat\""] , + "args": ["/c", "\"${workspaceFolder}\\copilot-instructions\\Install-Copilot-Instructions.bat\""] "group": { "kind": "build", "isDefault": true