fix: give the Windows scheduled task the same FAILED-push backstop

The task now runs scheduling\run-sync.ps1 instead of an inline cmd.exe
loop: every provider is attempted, a run that dies without the app's
own report pushes a high-priority FAILED with the exception class only,
and each run's output is appended to cache\logs\scheduled-sync.log
because Task Scheduler keeps none. Verified under PowerShell 7.6 on
Linux with a stand-in cmd.exe; not yet run under Windows PowerShell 5.1
or Task Scheduler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rwKTmug58sEsJ72AuWsEi
This commit is contained in:
JesseMarkowitz
2026-10-07 06:05:20 -04:00
co-authored by Claude Opus 5.5
parent 23c6e1f512
commit 805689c649
4 changed files with 187 additions and 24 deletions
+16 -15
View File
@@ -35,6 +35,7 @@ $ErrorActionPreference = 'Stop'
$repo = Split-Path -Parent $PSScriptRoot
$launcher = Join-Path $repo 'ai-chat-exporter.cmd'
$wrapper = Join-Path $PSScriptRoot 'run-sync.ps1'
if ($Unregister) {
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
@@ -42,22 +43,22 @@ if ($Unregister) {
return
}
if (-not (Test-Path $launcher)) {
throw "Launcher not found at $launcher"
foreach ($f in $launcher, $wrapper) {
if (-not (Test-Path $f)) { throw "Not found: $f" }
}
# A single action looping over the providers, rather than one action each.
# Task Scheduler runs multiple actions in order but reports only the last one's
# result, so a failure in an earlier provider would be invisible. The loop keeps
# going after a failure and propagates a non-zero exit code.
# One action running run-sync.ps1, rather than one action per provider: Task
# Scheduler runs multiple actions in order but reports only the last one's
# result, so a failure in an earlier provider would be invisible. The script
# keeps going after a failure, exits non-zero if any provider failed, and pushes
# a FAILED notification for any run that died without sending its own.
#
# /v:on and !RC! are required, not stylistic: cmd expands every %VAR% on a
# command line *before* running any of it, so "exit /b %RC%" would report the
# value RC had before the loop ever ran - i.e. always success. Delayed expansion
# reads it at the point of use.
$loop = ($Provider | ForEach-Object { "`"$launcher`" sync --provider $_ --joplin-optional || set RC=1" }) -join ' & '
$taskArgs = "/v:on /c set RC=0 & $loop & exit /b !RC!"
$actions = New-ScheduledTaskAction -Execute 'cmd.exe' `
# Providers go as separate arguments: under -File, "chatgpt,claude" would arrive
# as one string. -WindowStyle Hidden because the output now goes to
# cache\logs\scheduled-sync.log, so the console window would only ever be blank.
$taskArgs = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden " +
"-File `"$wrapper`" $($Provider -join ' ')"
$actions = New-ScheduledTaskAction -Execute 'powershell.exe' `
-Argument $taskArgs `
-WorkingDirectory $repo
@@ -82,12 +83,12 @@ Register-ScheduledTask -TaskName $TaskName `
Write-Host "Registered '$TaskName' - daily at $Time for: $($Provider -join ', ')"
Write-Host ''
Write-Host 'Command the task will run:'
Write-Host " cmd.exe $taskArgs"
Write-Host " powershell.exe $taskArgs"
Write-Host " (working directory: $repo)"
Write-Host ''
Write-Host 'Next steps:'
Write-Host " * Run it once now: Start-ScheduledTask -TaskName $TaskName"
Write-Host " * Check the result: Get-ScheduledTaskInfo -TaskName $TaskName"
Write-Host " * Read the log: Get-Content '$repo\cache\logs\exporter.log' -Tail 50"
Write-Host " * Read the run output: Get-Content '$repo\cache\logs\scheduled-sync.log' -Tail 50"
Write-Host ' * The terms-of-service notice must have been acknowledged'
Write-Host ' interactively once on this machine, or the task exits 1.'