feat(diagnostic): 阶段 0A 输入链路被动探测与线程归属复现
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$resolved = Resolve-Path -LiteralPath $Path
|
||||
$item = Get-Item -LiteralPath $resolved
|
||||
$file = if ($item.PSIsContainer) {
|
||||
Get-ChildItem -LiteralPath $item.FullName -Filter '*.jsonl' -File |
|
||||
Sort-Object LastWriteTime -Descending |
|
||||
Select-Object -First 1
|
||||
}
|
||||
else {
|
||||
$item
|
||||
}
|
||||
if (-not $file) { throw "No JSONL file found: $Path" }
|
||||
|
||||
$records = New-Object System.Collections.Generic.List[object]
|
||||
$lineNumber = 0
|
||||
Get-Content -LiteralPath $file.FullName | ForEach-Object {
|
||||
$lineNumber++
|
||||
try { $records.Add(($_ | ConvertFrom-Json)) }
|
||||
catch { throw "Invalid JSONL at line $lineNumber in $($file.FullName): $($_.Exception.Message)" }
|
||||
}
|
||||
|
||||
$sequenceStrict = $true
|
||||
for ($index = 1; $index -lt $records.Count; $index++) {
|
||||
if ([uint64]$records[$index].sequence -le [uint64]$records[$index - 1].sequence) {
|
||||
$sequenceStrict = $false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$immQueries = @($records | Where-Object recordType -eq 'imm_query')
|
||||
$successfulResults = @($immQueries | Where-Object immQueryStatus -eq 'success')
|
||||
$echoSummaries = @($records | Where-Object recordType -eq 'echo_correlation')
|
||||
$textLeaks = @($records | Where-Object {
|
||||
$_.messageCategory -eq 'text' -and $_.wParamHex -ne $null
|
||||
})
|
||||
$lost = @($records | Where-Object recordType -eq 'records_lost')
|
||||
$attach = $records | Where-Object recordType -eq 'window_attach' | Select-Object -First 1
|
||||
|
||||
$correlationCounts = [ordered]@{}
|
||||
foreach ($entry in $echoSummaries) {
|
||||
$key = "$($entry.echoChannel):$($entry.correlationStatus)"
|
||||
if (-not $correlationCounts.Contains($key)) { $correlationCounts[$key] = 0 }
|
||||
$correlationCounts[$key]++
|
||||
}
|
||||
|
||||
[pscustomobject]@{
|
||||
file = $file.FullName
|
||||
recordCount = $records.Count
|
||||
sequenceStrict = $sequenceStrict
|
||||
recordsLost = $lost.Count
|
||||
textRawWParamLeaks = $textLeaks.Count
|
||||
isWindowUnicode = $attach.isWindowUnicode
|
||||
ansiCodePage = $attach.ansiCodePage
|
||||
wndProcThreadIds = @($records | Where-Object sourceBackend -eq 'Win32WndProc' |
|
||||
Select-Object -ExpandProperty threadId -Unique)
|
||||
hostThreadIds = @($records | Where-Object sourceBackend -eq 'HostEventLoop' |
|
||||
Select-Object -ExpandProperty threadId -Unique)
|
||||
imeStartCount = @($records | Where-Object messageName -eq 'WM_IME_STARTCOMPOSITION').Count
|
||||
imeCompositionCount = @($records | Where-Object messageName -eq 'WM_IME_COMPOSITION').Count
|
||||
imeEndCount = @($records | Where-Object messageName -eq 'WM_IME_ENDCOMPOSITION').Count
|
||||
inputLanguageChangeRequestCount = @($records |
|
||||
Where-Object messageName -eq 'WM_INPUTLANGCHANGEREQUEST').Count
|
||||
inputLanguageChangeCount = @($records | Where-Object messageName -eq 'WM_INPUTLANGCHANGE').Count
|
||||
immQueryCount = $immQueries.Count
|
||||
successfulResultCount = $successfulResults.Count
|
||||
successfulUtf16Lengths = @($successfulResults | Select-Object -ExpandProperty utf16Length)
|
||||
successfulScalarCounts = @($successfulResults | Select-Object -ExpandProperty scalarCount)
|
||||
digestPresentCount = @($successfulResults | Where-Object sessionDigest -ne $null).Count
|
||||
correlationCounts = [pscustomobject]$correlationCounts
|
||||
closeObserved = @($records | Where-Object messageName -eq 'WM_CLOSE').Count -gt 0
|
||||
sessionEndObserved = @($records | Where-Object recordType -eq 'session_end').Count -gt 0
|
||||
}
|
||||
Reference in New Issue
Block a user