Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
145 commits
Select commit Hold shift + click to select a range
af0f610
Update .gitignore
potatoqualitee Apr 9, 2026
f8926f2
fix(commit-bug-review): review 899ea759c - honor decrypt exception mode
potatoqualitee Apr 9, 2026
cf577b9
Update .gitignore
potatoqualitee Apr 9, 2026
647e56c
Copy-DbaLinkedServer - Fix forced Get-DecryptedObject exception mode …
potatoqualitee Apr 9, 2026
e0bfb2e
chore: Mark #10168 reviewed - follow-up fix already present
potatoqualitee Apr 9, 2026
a498f07
chore: Mark #10169 reviewed - metadata only
potatoqualitee Apr 9, 2026
81eba24
Get-DbaDbTable - Fix ClearAndInitialize config bypass (review of #10157)
potatoqualitee Apr 9, 2026
9ec4380
Export-DbaCredential - Fix forced decryption exceptions (review of #1…
potatoqualitee Apr 9, 2026
956b370
Export-DbaLinkedServer - Fix forced decryption exception mode (review…
potatoqualitee Apr 9, 2026
b9e072a
Invoke-DbaDbDecryptObject - Fix DAC reuse disconnect regression (revi…
potatoqualitee Apr 9, 2026
3a00a9b
Start-DbaDbEncryption - Fix WhatIf cleanup disconnects (review of #10…
potatoqualitee Apr 9, 2026
09c3250
Sync-DbaAvailabilityGroup - Fix forced DAC sync regression (review of…
potatoqualitee Apr 9, 2026
b02afdb
Get-DbaNetworkConfiguration - Fix remote certificate test cleanup (re…
potatoqualitee Apr 9, 2026
435aec1
New-DbaComputerCertificate - Fix remote NonExportable export regressi…
potatoqualitee Apr 10, 2026
b60e475
Find-DbaDbGrowthEvent - Reviewed #10171, no bugs found
potatoqualitee Apr 10, 2026
1559732
Export-DbaInstance - Fix DAC cleanup on export failures (review of #1…
potatoqualitee Apr 10, 2026
4d70f37
Add-DbaComputerCertificate - Fix UserProtected remote flag check (rev…
potatoqualitee Apr 10, 2026
4bd15ef
Get-DecryptedObject - Fix password query error handling (review of #1…
potatoqualitee Apr 10, 2026
4593777
Install-DbaMaintenanceSolution - Reviewed #10172, bug already fixed b…
potatoqualitee Apr 10, 2026
c22aeac
Start-DbaMigration - Fix null DAC/source connection handling (review …
potatoqualitee Apr 10, 2026
204397b
test: fix appveyor.common review findings (review of #10179)
potatoqualitee Apr 10, 2026
c845edf
chore: Mark cb7a5d77a reviewed - CI fix
potatoqualitee Apr 10, 2026
06d191c
Connect-DbaInstance - Reviewed #10175, no bugs found
potatoqualitee Apr 10, 2026
7b61cff
Test-DbaNetworkCertificate - Fix configured certificate NotBefore val…
potatoqualitee Apr 10, 2026
94cfcc9
Get-DbaDbTable - Fix Azure default view for unsupported size properti…
potatoqualitee Apr 10, 2026
34079a0
Test-DbaLsnChain - Fix direct Pester parameter validation (review of …
potatoqualitee Apr 10, 2026
8c6b097
Backup-DbaDatabase - Fix StorageBaseUrl stripe count mismatch (review…
potatoqualitee Apr 10, 2026
bf4c57d
Copy-DbaDatabase - Fix literal rename handling for regex tokens (revi…
potatoqualitee Apr 10, 2026
201b940
Start-DbaDbEncryption - Fix parallel exclusion key creation (review o…
potatoqualitee Apr 10, 2026
846dd2f
Import-DbaCsv - Fix SupportsMultiline opt-out in AutoCreateTable (rev…
potatoqualitee Apr 10, 2026
0cf6ac0
Import-DbaCsv - Reviewed #10195, no bugs found
potatoqualitee Apr 10, 2026
cef85e6
Test-DbaLsnChain - Fix deserialized LSN sorting for file-backed histo…
potatoqualitee Apr 10, 2026
1bd28db
Get-DbaAgentJob - Fix AG job sync filtering by job type (review of #1…
potatoqualitee Apr 10, 2026
1489644
Test-DbaBackupInformation - Fix missing IsVerified flag on failed inp…
potatoqualitee Apr 10, 2026
4ca5750
Connect-DbaInstance - Reviewed #10199, follow-up fix already merged
potatoqualitee Apr 10, 2026
518e840
Export-DbaLogin - Fix role permission ordering and duplicate role cre…
potatoqualitee Apr 10, 2026
3e60146
Get-DbaUserPermission - Reviewed #10210, no bugs found
potatoqualitee Apr 10, 2026
cb33b7f
Export-DbaInstance - Fix skipped progress completion on continued fai…
potatoqualitee Apr 10, 2026
b3b515d
Get-DbaReportingService - Reviewed #10207, no bugs found
potatoqualitee Apr 10, 2026
ccab0c1
New-DbaLogin - Fix invalid external provider fallback options (review…
potatoqualitee Apr 10, 2026
51e4613
Get-DbaStartupParameter - Fix WMI service lookup validation (review o…
potatoqualitee Apr 10, 2026
4952d7a
Test-DbaKerberos - Fix stale help check counts (review of #10209)
potatoqualitee Apr 10, 2026
6d64d19
Update-DbaInstance - Fix CredSSP auth propagation in remote prep (rev…
potatoqualitee Apr 10, 2026
00480fe
New-DbaDbMailProfile - Reviewed #10214, no bugs found
potatoqualitee Apr 10, 2026
34c0547
Connect-DbaInstance - Fix mirrored failover retries for connection st…
potatoqualitee Apr 10, 2026
c78ec1b
Export-DbaScript - Fix broken escaping in distributed AG scripts (rev…
potatoqualitee Apr 10, 2026
803f028
Get-DbaReplSubscription - Fix cross-publisher distribution fallback f…
potatoqualitee Apr 10, 2026
32f961f
Invoke-DbaDbLogShipping - Fix IgnoreFileChecks root path validation (…
potatoqualitee Apr 10, 2026
2fed2c3
Copy-DbaPolicyManagement - Fix object set filtering for selected poli…
potatoqualitee Apr 10, 2026
3e28a31
Get-DbaDbStoredProcedure - Reviewed #10226, no bugs found
potatoqualitee Apr 10, 2026
a437032
Backup-DbaDatabase - Fix CreateFolder dbname detection for filename t…
potatoqualitee Apr 10, 2026
012775c
Invoke-DbaDbDataMasking - Fix WhatIf filter and helper side effects (…
potatoqualitee Apr 10, 2026
2be0af6
Invoke-DbaDbDataMasking - Reviewed #10222, no bugs found
potatoqualitee Apr 10, 2026
e80b11b
Read-DbaXEFile - Reviewed #10221, no bugs found
potatoqualitee Apr 10, 2026
82e5d85
chore: Mark #10230 reviewed - buildref update
potatoqualitee Apr 10, 2026
661c3ca
Invoke-SmoCheck - Reviewed #10229, no bugs found
potatoqualitee Apr 10, 2026
d65d54a
Set-DbaPrivilege - Reviewed #10228, no bugs found
potatoqualitee Apr 10, 2026
b2f6663
chore: Mark #10231 reviewed - buildref metadata
potatoqualitee Apr 10, 2026
15ea95a
Test-DbaInstantFileInitialization - Fix best-practice detection for v…
potatoqualitee Apr 10, 2026
d1303d7
Add-DbaAgDatabase - Validate replica TDE certificates early (review o…
potatoqualitee Apr 10, 2026
ed2168c
Get-DbaRegServer - Fix IncludeSelf output for multiple CMS instances …
potatoqualitee Apr 10, 2026
527536c
Get-DbaLastBackup - Skip backup history lookup when filters remove al…
potatoqualitee Apr 10, 2026
c79d9d7
Export-DbaInstance - Fix staged cert and key export handling (review …
potatoqualitee Apr 10, 2026
4c34619
New-DbaAgentJobStep - Reviewed #10244, no bugs found
potatoqualitee Apr 10, 2026
65c775f
Set-DbaDbCompression - Fix indexed view metadata for compression outp…
potatoqualitee Apr 10, 2026
a269116
Set-DbaPrivilege - Fix blank security policy entry updates (review of…
potatoqualitee Apr 10, 2026
f72d98a
Get-DbaDbRestoreHistory - Fix LastRestorePoint fallback logic (review…
potatoqualitee Apr 10, 2026
efdc26e
New-DbaDbMailAccount - Fix conflicting SMTP authentication validation…
potatoqualitee Apr 10, 2026
34d47df
Restore-DbaDatabase - Fix ErrorBrokerConversations restore handling (…
potatoqualitee Apr 10, 2026
dbdd892
Connect-DbaInstance - Fix AccessToken NonPooledConnection regression …
potatoqualitee Apr 10, 2026
abf56fc
Get-DbaCmObject - Fix missing CIM timeout initialization in Test-DbaC…
potatoqualitee Apr 10, 2026
8ed1a3a
Import-DbaXESessionTemplate - Fix event_file XML target matching (rev…
potatoqualitee Apr 10, 2026
7e144fa
Connect-DbaInstance - Reviewed #10263, no bugs found
potatoqualitee Apr 10, 2026
4d8eef6
Restore-DbaDatabase - Fix backup filtering examples to only include f…
potatoqualitee Apr 10, 2026
b387111
Read-DbaXEFile - Reviewed #10243, no bugs found
potatoqualitee Apr 10, 2026
122c034
Test-DbaLastBackup - Fix path filtering and source grouping (review o…
potatoqualitee Apr 10, 2026
259d297
New-DbaComputerCertificate - Fix default CA template validation for D…
potatoqualitee Apr 10, 2026
ba4689a
Get-DbaAgDatabase - Reviewed #10269, no bugs found
potatoqualitee Apr 10, 2026
58fd6f0
New-DbaDbTable - Fix three-part Name database mismatch (review of #10…
potatoqualitee Apr 10, 2026
dd4a0eb
Save-DbaKbUpdate - Fix BITS fallback when transfer errors are non-ter…
potatoqualitee Apr 10, 2026
9a9236a
Get-DbaWaitStatistic - Fix unsafe wait type SQL filter (review of #10…
potatoqualitee Apr 10, 2026
9eeef8b
Expand-DbaDbLogFile - Fix TargetVlfCount mixed growth planning (revie…
potatoqualitee Apr 10, 2026
877b604
Test-DbaLastBackup - Fix Start-DbccCheck compatibility regression (re…
potatoqualitee Apr 10, 2026
afe35fa
Update-DbaInstance - Fix whitespace-only Path validation gap (review …
potatoqualitee Apr 10, 2026
58acc28
Get-DbaAgRingBuffer - Fix timestamp query handling (review of #10282)
potatoqualitee Apr 10, 2026
43d7d05
Invoke-DbaDbDataMasking - Fix action FilterQuery row targeting (revie…
potatoqualitee Apr 10, 2026
de2f36c
Update-ServiceStatus - Fix worker CIM session cleanup and credential …
potatoqualitee Apr 10, 2026
2ae040c
Remove-DbaAgentJobSchedule - Fix duplicate-name detach handling and f…
potatoqualitee Apr 10, 2026
195fbac
Connect-DbaInstance - Fix AuthenticationType credential routing (revi…
potatoqualitee Apr 10, 2026
b19c245
Get-DbaDbOrphanUser - Fix pre-SQL 2012 containment check (review of #…
potatoqualitee Apr 10, 2026
cc136ba
Test-DbaAgPolicyState - Fix Always On policy coverage (review of #10246)
potatoqualitee Apr 10, 2026
594dd6a
Install-DbaMaintenanceSolution - Fix NUL backup validation for stored…
potatoqualitee Apr 10, 2026
fce4c2a
Get-DbaDbMailAccount - Reviewed #10280, no bugs found
potatoqualitee Apr 10, 2026
52a1e5f
Invoke-DbaDbShrink - Fix failure path interrupt on shrink errors (rev…
potatoqualitee Apr 10, 2026
3d41703
Export-DbaUser - Fix SQL Server 2000 schema ownership scripting (revi…
potatoqualitee Apr 10, 2026
b37ad76
Test-DbaPath - Fix EnableException handling for xp_fileexist failures…
potatoqualitee Apr 10, 2026
2ae37b8
Invoke-DbaCycleErrorLog - Reviewed #10290, no bugs found
potatoqualitee Apr 10, 2026
0e95414
Update-SqlPermission - Fix SMO reader conflicts during permission syn…
potatoqualitee Apr 10, 2026
6dd5947
Restore-DbaDatabase - Fix StopAtLsn format handling (review of #10245)
potatoqualitee Apr 10, 2026
e81cc4c
New-DbaFirewallRule - Fix program rule path matching (review of #10294)
potatoqualitee Apr 10, 2026
fcea771
Get-DbaBuild - Mark #10277 reviewed, follow-up fix already merged
potatoqualitee Apr 10, 2026
9a26414
Export-DbaCredential - Reviewed #10295, no bugs found
potatoqualitee Apr 10, 2026
f802188
Compare-DbaDbSchema - Fix pipeline binding and credential logging (re…
potatoqualitee Apr 10, 2026
76846f4
Get-DbaNetworkEncryption - Fix SQL Browser endpoint selection (review…
potatoqualitee Apr 10, 2026
804347a
Add-DbaInstanceList - Fix stale TEPP cache removal behavior (review o…
potatoqualitee Apr 10, 2026
172add7
Invoke-DbaDbShrink - Fix WAIT_AT_LOW_PRIORITY test race (review of #1…
potatoqualitee Apr 10, 2026
cc72908
Copy-DbaLogin - Fix ExcludeDatabaseMapping in -OutFile exports (revie…
potatoqualitee Apr 10, 2026
bbc86cb
Get-DbaHelpIndex - Reviewed #10302, no bugs found
potatoqualitee Apr 10, 2026
412839d
Install-DbaMaintenanceSolution - Fix AutoScheduleJobs validation gaps…
potatoqualitee Apr 10, 2026
649d95a
Copy-DbaAgentJob - Reviewed #10297, no bugs found
potatoqualitee Apr 10, 2026
8e9adfc
ConvertTo-DbaTimeline - Fix JavaScript escaping for growth event data…
potatoqualitee Apr 10, 2026
d699697
Set-DbaNetworkCertificate - Fix restart credential passthrough (revie…
potatoqualitee Apr 10, 2026
97cfd07
Set-DbaDbCompression - Fix schema-qualified table matching (review of…
potatoqualitee Apr 10, 2026
24c8ec9
Invoke-TlsWebRequest - Fix configured proxy detection without Address…
potatoqualitee Apr 10, 2026
8db64a1
New-DbaDatabase - Fix rooted path validation (review of #10315)
potatoqualitee Apr 10, 2026
4ffb606
Test-DbaDbCompression - Fix schema-qualified table filtering (review …
potatoqualitee Apr 10, 2026
52ee5ca
Export-DbaCsv - Fix table-name validation regression (review of #10314)
potatoqualitee Apr 10, 2026
fcdca10
Invoke-DbaBalanceDataFiles - Fix empty target filegroup validation (r…
potatoqualitee Apr 10, 2026
5e3c3bb
Remove-DbaDbTableData - Fix normalized table quoting edge cases (revi…
potatoqualitee Apr 10, 2026
a3d27b4
chore: Mark #10335 reviewed - CI fix
potatoqualitee Apr 10, 2026
8d05059
Invoke-DbaAdvancedUpdate - Reviewed #10334, no bugs found
potatoqualitee Apr 10, 2026
344df53
Test-DbaSpn - Reviewed #10331, no bugs found
potatoqualitee Apr 10, 2026
af835fb
Stop-Function - Reviewed #10332, no bugs found
potatoqualitee Apr 10, 2026
f6fb7d3
Test-DbaBuild - Reviewed #10328, no bugs found
potatoqualitee Apr 10, 2026
991a084
Test-DbaLinkedServerConnection - Reviewed #10326, no bugs found
potatoqualitee Apr 10, 2026
f539083
Get-DbaWaitStatistic - Reviewed #10323, no bugs found
potatoqualitee Apr 10, 2026
7ad5506
chore: Correct #10323 review note
potatoqualitee Apr 10, 2026
97775b6
Find-DbaInstance - Fix default instance port fallback (review of #10327)
potatoqualitee Apr 10, 2026
177aa89
Get-DbaPermission - Reviewed #10320, no bugs found
potatoqualitee Apr 10, 2026
d2d0ccc
Get-DbaDbIdentity - Fix escaped bracket table-name normalization (rev…
potatoqualitee Apr 10, 2026
5cc3cbb
Copy-DbaDbTableData - Fix missing Copy-DbaDbViewData scripting option…
potatoqualitee Apr 10, 2026
7e66769
Backup-DbaDbCertificate - Reviewed #10329, no bugs found
potatoqualitee Apr 10, 2026
98f3c52
Find-DbaObject - Fix missing database DDL trigger matches (review of …
potatoqualitee Apr 10, 2026
70dcc26
Compare-DbaLogin - Fix stale destination reuse on connection failure …
potatoqualitee Apr 10, 2026
c87ad29
Copy-DbaSsisCatalog - Fix Start-DbaMigration SSISDB gating (review of…
potatoqualitee Apr 10, 2026
db82668
Get-DbaService - Fix PowerBI-only service lookup (review of #10298)
potatoqualitee Apr 10, 2026
b4b7678
Revert "Update-SqlPermission - Fix SMO reader conflicts during permis…
potatoqualitee Apr 11, 2026
8657130
Fix PS 5.1 compatibility in review commits
potatoqualitee Apr 11, 2026
8d2dbee
Fix bugs introduced in GPT review commits
potatoqualitee Apr 11, 2026
5cce09f
Start-DbaMigration.Tests - Fix additional PS 5.1 .Count issues
potatoqualitee Apr 11, 2026
b87f095
Test-DbaLastBackup - Fix -Path workflow restore failure
potatoqualitee Apr 11, 2026
7d33993
Export-DbaCredential.Tests - Add EnableException to Context BeforeAll…
potatoqualitee Apr 11, 2026
3db358e
build(.claude): add validation hooks and settings
potatoqualitee Apr 15, 2026
15a082d
build(gitignore): clean up and add .claude settings
potatoqualitee Apr 15, 2026
cb2e39f
fix(compare-dbalogin): add null check after connection attempt
potatoqualitee Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
447 changes: 447 additions & 0 deletions .claude/commands/ralph.md

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions .claude/hooks/pre-bash-backslash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
input=$(cat)
command=$(echo "$input" | grep -oP '"command"\s*:\s*"\K[^"]*' | head -1)

if echo "$command" | grep -qP '[A-Za-z]:\\\\'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"Windows backslash paths are mangled by Git Bash. Use forward slashes instead (e.g. C:/github/LeLab/scratchpad/foo.ps1). PowerShell handles forward slashes fine on Windows."}}
EOF
exit 0
fi

exit 0
23 changes: 23 additions & 0 deletions .claude/hooks/pre-bash-pwsh-script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
input=$(cat)
command=$(echo "$input" | grep -oP '"command"\s*:\s*"\K[^"]*' | head -1)

# Block powershell.exe entirely
if echo "$command" | grep -qiP '\bpowershell(\.exe)?\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"Do not use powershell.exe (Windows PowerShell 5.1). Write a .ps1 file and run: pwsh -NoProfile -File <script.ps1>"}}
EOF
exit 0
fi

# Block pwsh -Command / pwsh -c
if echo "$command" | grep -qiP 'pwsh(\s+-\w+)*\s+-(c|Command)\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"Do not run inline PowerShell via pwsh -Command. Write the script to scratchpad/<name>.ps1 first, then execute with: pwsh -NoProfile -File scratchpad/<name>.ps1"}}
EOF
exit 0
fi

exit 0
68 changes: 68 additions & 0 deletions .claude/hooks/prevent-destructive-git.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
input=$(cat)
command=$(echo "$input" | grep -oP '"command"\s*:\s*"\K[^"]*' | head -1)

# Block git push --force and variants (-f, --force-with-lease, --force-if-includes)
if echo "$command" | grep -qiP 'git\s+push\s+.*(-f|--force)\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"Force push is blocked. Use regular git push instead. If you need to force push, ask the user to do it manually."}}
EOF
exit 0
fi

# Block git reset --hard
if echo "$command" | grep -qiP 'git\s+reset\s+.*--hard\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"git reset --hard is blocked because it discards uncommitted changes. Use git stash or git checkout -- <file> instead."}}
EOF
exit 0
fi

# Block git clean -f (force delete untracked files)
if echo "$command" | grep -qiP 'git\s+clean\s+.*-[a-zA-Z]*f'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"git clean -f is blocked because it permanently deletes untracked files. Ask the user to run it manually if needed."}}
EOF
exit 0
fi

# Block git checkout with --force/-f on branches (not file restores)
if echo "$command" | grep -qiP 'git\s+checkout\s+(-f|--force)\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"git checkout --force is blocked because it discards local changes. Use git stash first, then checkout."}}
EOF
exit 0
fi

# Block git branch -D (force delete)
if echo "$command" | grep -qiP 'git\s+branch\s+.*-D\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"git branch -D (force delete) is blocked. Use git branch -d for safe deletion, or ask the user to force-delete manually."}}
EOF
exit 0
fi

# Block git rebase on shared/remote branches (rebase with upstream refs)
if echo "$command" | grep -qiP 'git\s+rebase\s+.*(origin|upstream)\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"Rebasing against remote branches is blocked to prevent history rewrites. Ask the user before rebasing."}}
EOF
exit 0
fi

# Block amending commits (could rewrite published history)
if echo "$command" | grep -qiP 'git\s+commit\s+.*--amend\b'; then
cat <<'EOF'
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",
"permissionDecisionReason":"git commit --amend is blocked because it rewrites commit history. Create a new commit instead, or ask the user to amend manually."}}
EOF
exit 0
fi

exit 0
27 changes: 27 additions & 0 deletions .claude/hooks/redirect-glob.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
input=$(cat)
tool=$(echo "$input" | grep -oP '"tool_name"\s*:\s*"\K[^"]*' | head -1)

if [ "$tool" != "Glob" ]; then
exit 0
fi

pattern=$(echo "$input" | grep -oP '"pattern"\s*:\s*"\K[^"]*' | head -1)
path=$(echo "$input" | grep -oP '"path"\s*:\s*"\K[^"]*' | head -1)

search_in=""
if [ -n "$path" ]; then
search_in=" \"$path\""
fi

cat >&2 <<EOF
BLOCKED: Glob tool is unreliable on Windows (timeouts, silent failures).
Use fd via Bash instead. fd respects .gitignore and is much faster.

Your pattern was: $pattern
Equivalent fd commands:
/c/ProgramData/chocolatey/bin/fd.exe --type f --glob '$pattern'$search_in
/c/ProgramData/chocolatey/bin/fd.exe --type f --extension ps1$search_in
/c/ProgramData/chocolatey/bin/fd.exe --type f 'keyword'$search_in
EOF
exit 2
44 changes: 44 additions & 0 deletions .claude/hooks/stop-todo-report.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
# stop-todo-report.sh - Scan changed files for TODO/FIXME and report with header
# Runs at Stop to surface any incomplete work left in the code.

INPUT=$(cat)

# Prevent re-entry if stop hook is already active
STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
if [[ "$STOP_ACTIVE" == "true" ]]; then
exit 0
fi

# Get all modified/added files from git (staged + unstaged + untracked)
CHANGED_FILES=$(git diff --name-only HEAD 2>/dev/null; git diff --cached --name-only 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null)
CHANGED_FILES=$(echo "$CHANGED_FILES" | sort -u | grep -E '\.(ps1|psm1|psd1|cs|sql|js|ts|html|go|py|sh)$')

if [[ -z "$CHANGED_FILES" ]]; then
exit 0
fi

# Scan for TODO/FIXME/HACK/XXX/WORKAROUND in changed files
TODO_REPORT=""
while IFS= read -r file; do
[[ -f "$file" ]] || continue
HITS=$(grep -n -i -E '\b(TODO|FIXME|HACK|XXX|WORKAROUND)\b' "$file" 2>/dev/null)
if [[ -n "$HITS" ]]; then
TODO_REPORT+="### $file\n"
while IFS= read -r line; do
TODO_REPORT+=" $line\n"
done <<< "$HITS"
TODO_REPORT+="\n"
fi
done <<< "$CHANGED_FILES"

if [[ -n "$TODO_REPORT" ]]; then
# Escape for JSON
ESCAPED=$(echo -e "$TODO_REPORT" | jq -Rs .)
jq -n --argjson report "$ESCAPED" '{
decision: "block",
reason: ("⚠️ UNFINISHED WORK DETECTED — do not stop until resolved.\n\nThe following TODO/FIXME/HACK items were found in changed files.\nFor each one you MUST either:\n\n 1. Resolve it now (implement the missing code), OR\n\n 2. If you cannot finish due to context window size or complexity, write a self-contained prompt to docs/prompts/ that a fresh Claude session can run to complete the work. The prompt MUST:\n - Describe exactly what each TODO requires\n - Include all relevant file paths and line numbers\n - Use the Agent tool with specialized subagents where appropriate (e.g. psu-developer, hugo-frontend, csharp-engineer)\n - End with an instruction to commit the completed work using conventional commits\n Then tell the user: \"I wrote a completion prompt to docs/prompts/<filename>.md — run it in a new session to finish.\"\n\n 3. As a last resort only: explicitly tell the user what remains and why it cannot be done at all.\n\nDo NOT silently leave TODOs behind. Go finish them.\n\n" + $report + "\n--- End of TODO Report ---")
}'
fi

exit 0
22 changes: 22 additions & 0 deletions .claude/hooks/stop-verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash
# stop-verify.sh - Comprehensive quality gate when Claude finishes responding
# Incorporates: doublecheck, simplify, review, verify, and completeness checks.
# Injects a reminder to self-verify. Does NOT hard-block (no infinite loops).
# Guards against re-entry via stop_hook_active flag.

INPUT=$(cat)

# Prevent infinite loops: if stop hook is already active, exit immediately
STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
if [[ "$STOP_ACTIVE" == "true" ]]; then
exit 0
fi

jq -n '{
hookSpecificOutput: {
hookEventName: "Stop",
additionalContext: "QUALITY GATE — If you wrote or modified code in this response, perform ALL checks below before finishing. If you only answered a question or did research, skip this.\n\n## 1. VERIFY (does it work?)\n- Check for syntax errors in changed files\n- Run tests if applicable (Pester for PS, dotnet test for C#)\n- Confirm imports, dependencies, and module loading work\n- Report what works and what does not\n\n## 2. REVIEW (is it safe and correct?)\n- Logic errors and edge cases\n- Security: credential handling, injection vulnerabilities (SQL, XSS)\n- Missing validation on user input\n- Error responses must not expose stack traces\n- Destructive operations need confirmation\n- API naming contract (plural URLs, kebab-case)\n- PSU endpoints use New-ProtectedEndpoint\n\n## 3. SIMPLIFY (is it clean?)\n- Remove unnecessary complexity\n- Consolidate duplicate logic\n- Use idiomatic patterns (PowerShell best practices for .ps1)\n- Remove dead code, unused variables, unused imports\n- Do not add features or change functionality — only simplify\n\n## 4. DOUBLECHECK (final verification)\nCreate a table:\n| Claim/Item | Verified? | Notes |\n|------------|-----------|-------|\nInclude: primary functionality, tests passing, security, naming conventions.\nBe thorough and honest about what you could not verify.\n\n## 5. COMPLETENESS\n- Were ALL requested changes made?\n- Any TODO/FIXME left behind that should be resolved?\n- Files over 400 lines that need splitting?\n- OBSERVABILITY IN ACTION: If you built or modified a page displaying fleet data, does it include action capabilities (Fix Now / Schedule / Execute buttons)? Display-only pages are not acceptable unless purely audit/history.\n\nIf anything fails, fix it before finishing."
}
}'

exit 0
150 changes: 150 additions & 0 deletions .claude/hooks/validate-style.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/env pwsh
# PreToolUse hook: Consolidated style validation for dbatools
# Runs all style checks in a single PowerShell process for performance

$ErrorActionPreference = "Stop"

try {
$inputJson = $input | Out-String | ConvertFrom-Json
} catch {
exit 0
}

$toolInput = $inputJson.tool_input
$filePath = $toolInput.file_path
if (-not $filePath) { exit 0 }
if ($filePath -notlike "*.ps1") { exit 0 }

$content = if ($toolInput.new_string) { $toolInput.new_string } else { $toolInput.content }
if (-not $content) { exit 0 }

$violations = @()
$lines = $content -split "`n"

# Track state for multi-line constructs
$inHereStringSingle = $false
$inHereStringDouble = $false
$inHashtable = $false
$hashtableLines = @()
$hashtableStart = 0
$misalignedHashtables = @()

# Patterns (using double quotes with escaping)
$patternComment = "^\s*#"
$patternHereStringSingleStart = "@'"
$patternHereStringDoubleStart = "@`""
$patternHereStringSingleEnd = "^'@"
$patternHereStringDoubleEnd = "^`"@"
$patternBacktick = "``\s*$"
$patternBoolAttribute = "\[\s*(Parameter|CmdletBinding|OutputType|ValidateSet)\s*\([^]]*=\s*\`$(true|false)"
$patternStaticNew = "::new\s*\("
$patternSingleQuote = "(?<![@])'.+'"
$patternPlainSplat = "\`$splat\s*="
$patternNamedSplat = "\`$splat[A-Z][a-zA-Z0-9]*\s*="
$patternArrayList = "ArrayList"
$patternGenericList = "Generic\.List"
$patternStandaloneBrace = "^\s*\{\s*$"
$patternPrevLineEnd = "\)\s*$"
$patternControlKeyword = "(if|else|elseif|foreach|for|while|switch|try|catch|finally)\s*$"
$patternHashtableStart = "@\{"
$patternHashtableEnd = "^\s*\}"
$patternTrailingSpace = "\s+$"

for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i].TrimEnd("`r")
$lineNum = $i + 1
$isComment = $line -match $patternComment

# Track here-string state
if ($line -match $patternHereStringSingleStart) { $inHereStringSingle = $true }
if ($line -match $patternHereStringDoubleStart) { $inHereStringDouble = $true }
if ($line -match $patternHereStringSingleEnd) { $inHereStringSingle = $false; continue }
if ($line -match $patternHereStringDoubleEnd) { $inHereStringDouble = $false; continue }
if ($inHereStringSingle -or $inHereStringDouble) { continue }

# Skip comments for most checks
if (-not $isComment) {
# 1. No backticks for line continuation
if ($line -match $patternBacktick) {
$violations += "Line ${lineNum}: Backtick line continuation. Use splatting instead."
}

# 2. No = $true in parameter attributes
if ($line -match $patternBoolAttribute) {
$violations += "Line ${lineNum}: Use [Parameter(Mandatory)] not = `$true syntax."
}

# 3. No static new method (PowerShell v3 compatibility)
if ($line -match $patternStaticNew) {
$violations += "Line ${lineNum}: Use New-Object for PS v3 compatibility."
}

# 4. No single quotes (except here-strings already handled above)
if ($line -match $patternSingleQuote) {
$violations += "Line ${lineNum}: Use double quotes instead of single quotes."
}

# 5. No plain $splat variable names
if ($line -match $patternPlainSplat -and $line -notmatch $patternNamedSplat) {
$violations += "Line ${lineNum}: Use `$splat<Purpose> naming (e.g., `$splatConnection)."
}

# 6. No ArrayList or Generic.List collection
if ($line -match $patternArrayList) {
$violations += "Line ${lineNum}: Output directly to pipeline, not ArrayList."
}
if ($line -match $patternGenericList) {
$violations += "Line ${lineNum}: Output directly to pipeline, not Generic.List."
}

# 7. OTBS - no standalone opening brace (Allman style)
if ($line -match $patternStandaloneBrace -and $i -gt 0) {
$prevLine = $lines[$i - 1].TrimEnd("`r")
if ($prevLine -match $patternPrevLineEnd -or $prevLine -match $patternControlKeyword) {
$violations += "Line ${lineNum}: Use OTBS - opening brace on same line as statement."
}
}

# 8. Track hashtables for alignment check
if ($line -match $patternHashtableStart) {
$inHashtable = $true
$hashtableLines = @()
$hashtableStart = $lineNum
# Don't add this line to hashtableLines - it's the opening, not an entry
} elseif ($inHashtable) {
if ($line -match $patternHashtableEnd) {
if ($hashtableLines.Count -ge 2) {
$equalsPositions = $hashtableLines | ForEach-Object {
$pos = $_.IndexOf("=")
if ($pos -ge 0) { $pos }
} | Where-Object { $null -ne $_ } | Select-Object -Unique
if ($equalsPositions.Count -gt 1) {
$misalignedHashtables += "Lines $hashtableStart-$lineNum"
}
}
$inHashtable = $false
} elseif ($line -match "=" -and $line.Trim() -ne "") {
$hashtableLines += $line
}
}
}

# 9. No trailing spaces (check even in comments)
if ($line -match $patternTrailingSpace) {
$violations += "Line ${lineNum}: Trailing whitespace."
}
}

# Add hashtable alignment violations
foreach ($ht in $misalignedHashtables) {
$violations += "${ht}: Hashtable = signs must be vertically aligned."
}

if ($violations.Count -gt 0) {
$summary = ($violations | Select-Object -First 5) -join "`n"
$more = if ($violations.Count -gt 5) { "`n... and $($violations.Count - 5) more violations" } else { "" }
[Console]::Error.WriteLine("BLOCKED: dbatools style violations:`n$summary$more")
exit 2
}

exit 0
24 changes: 24 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "pwsh -NoProfile -File .claude/hooks/validate-style.ps1"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/prevent-destructive-git.sh"
}
]
}
]
}
}
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ allcommands.ps1
/.aitools/.aitools/.aider
/.aitools
.aider*
/.shadowgit.git
/.claude
publish.ps1
/.shadowgit.git
publish.ps1

PR_BODY.md

PR_DESCRIPTION.md
nul
nul
.claude/settings.local.json
/scripts
Loading
Loading