← Files NightshiftARCHIVED FILE

hooks/windows/pulse.ps1

4.37 KB · Oct 5, 2026 · 18:31 UTC

↓ Download file

param(
    [Parameter(Mandatory = $true)]
    [ValidateSet('claude', 'codex', 'cursor')]
    [string]$HostName,
    [Parameter(ValueFromPipeline = $true)]
    [AllowEmptyString()]
    [string]$HookJson = ''
)

Set-StrictMode -Version 2.0
$ErrorActionPreference = 'Stop'
if (Test-Path Variable:PSNativeCommandUseErrorActionPreference) {
    $PSNativeCommandUseErrorActionPreference = $false
}

$pluginRoot = Resolve-Path (Join-Path $PSScriptRoot '../..')
Import-Module (Join-Path $pluginRoot 'lib/Nightshift.psm1') -Force -DisableNameChecking

if (Test-NSHookIdle) { exit 0 }

$raw = Get-NSStdinText -Piped (($input | ForEach-Object { $_ }) -join "`n")
if ([string]::IsNullOrWhiteSpace($raw) -and -not [string]::IsNullOrWhiteSpace($HookJson)) {
    $raw = $HookJson
}
try {
    $payload = $raw | ConvertFrom-Json -ErrorAction Stop
}
catch {
    exit 0
}

function Get-PropertyValue {
    param(
        [AllowNull()][object]$Object,
        [Parameter(Mandatory = $true)][string]$Name,
        [AllowEmptyString()][string]$Default = ''
    )
    if ($null -eq $Object) { return $Default }
    $property = $Object.PSObject.Properties[$Name]
    if ($null -eq $property -or $null -eq $property.Value) { return $Default }
    return [string]$property.Value
}

$sessionId = Get-PropertyValue $payload 'session_id'
if ($HostName -eq 'cursor') {
    $conversation = Get-PropertyValue $payload 'conversation_id'
    if (-not [string]::IsNullOrEmpty($conversation)) {
        $sessionId = $conversation
    }
}

$hostRoot = ''
if ($HostName -eq 'claude' -and -not [string]::IsNullOrEmpty($env:CLAUDE_PROJECT_DIR)) {
    $hostRoot = $env:CLAUDE_PROJECT_DIR
}
elseif ($HostName -eq 'codex' -and -not [string]::IsNullOrEmpty($env:CODEX_PROJECT_DIR)) {
    $hostRoot = $env:CODEX_PROJECT_DIR
}
elseif ($HostName -eq 'cursor' -and -not [string]::IsNullOrEmpty($env:CURSOR_PROJECT_DIR)) {
    $hostRoot = $env:CURSOR_PROJECT_DIR
}
elseif (-not [string]::IsNullOrEmpty((Get-PropertyValue $payload 'cwd'))) {
    $hostRoot = Get-PropertyValue $payload 'cwd'
}
else {
    $hostRoot = [Environment]::CurrentDirectory
}

try {
    $workspace = Resolve-NSWorkspaceRoot $hostRoot
}
catch {
    exit 0
}
if ((Get-NSStateKind $workspace) -in @('malformed', 'future')) {
    exit 0
}

$ns = Join-Path $workspace '.nightshift'
$punch = Get-NSLayoutPath $ns 'punch-list'
$counts = Get-NSBoxCounts $punch
if (-not (Test-Path -LiteralPath (Get-NSLayoutPath $ns 'armed') -PathType Leaf) `
    -or -not (Test-Path -LiteralPath $punch -PathType Leaf) `
    -or ((Test-Path -LiteralPath (Get-NSLayoutPath $ns 'ended') -PathType Leaf) `
        -and -not (Test-NSReparsePoint (Get-NSLayoutPath $ns 'ended')))) {
    exit 0
}

if ([string]::IsNullOrEmpty($sessionId)) {
    exit 0
}

$session = Read-NSSession $ns
$workerPath = Get-NSLayoutPath $ns 'worker'
$worker = ''
if ((Test-Path -LiteralPath $workerPath -PathType Leaf) -and -not (Test-NSReparsePoint $workerPath)) {
    try {
        $worker = (([IO.File]::ReadAllLines($workerPath) | Select-Object -First 1) + '').Trim()
    }
    catch {
        $worker = ''
    }
}
if (-not [string]::IsNullOrEmpty($worker)) {
    if ($sessionId -ne $worker) { exit 0 }
}
elseif ($null -eq $session -or [string]::IsNullOrEmpty($session.SessionId) -or $session.SessionId -ne $sessionId) {
    exit 0
}

if ($counts.Open -gt 0) {
    $pulse = Get-NSLayoutPath $ns 'pulse'
    if (Test-NSReparsePoint $pulse) {
        Remove-Item -LiteralPath $pulse -Force -ErrorAction SilentlyContinue
    }
    $line = '{0} {1}{2}' -f (Get-NSUnixTime), $sessionId, [Environment]::NewLine
    [IO.File]::WriteAllText($pulse, $line, (New-Object Text.UTF8Encoding($false)))
}

# The reading rides on the pulse: no daemon, no timer, no second session. Cursor carries its figures
# on the payload; the other two name a transcript. Never fatal - a host that reports nothing leaves
# no snapshot, and the report says `unavailable` rather than zero.
$source = $(if ($HostName -eq 'cursor') { $raw } else { Get-PropertyValue $payload 'transcript_path' })
try {
    $null = Invoke-NSPulseUsage $ns $HostName $sessionId $source
    $null = Invoke-NSPulseMarks $ns $workspace $source
}
catch {
    [Console]::Error.WriteLine('nightshift: usage accounting skipped - ' + $_.Exception.Message)
}
try {
    Write-NSPulseContext $HostName (Get-NSPulseReceiptsNotice $ns $workspace)
}
catch {
    [Console]::Error.WriteLine('nightshift: receipts notice skipped - ' + $_.Exception.Message)
}
exit 0

SHA-256: 3dbd9d19b67655feb7be02f2c23b3a1466a0f192e0802a30863ebade65f4deea