fix sync bug for scheduled work
This commit is contained in:
@@ -329,19 +329,44 @@ machines — coding sessions (`claude-code`, `codex`) on the Linux box, web chat
|
|||||||
conversations from everywhere, instead of per-machine islands that only meet
|
conversations from everywhere, instead of per-machine islands that only meet
|
||||||
inside Joplin.
|
inside Joplin.
|
||||||
|
|
||||||
|
**Intended split of responsibility (decided 2026-08-18).** Each machine keeps
|
||||||
|
running the exporter locally and keeps doing what it is uniquely able to do —
|
||||||
|
read that machine's local transcripts, and hold the browser session for the web
|
||||||
|
providers. What changes is where the output goes: instead of syncing to Joplin
|
||||||
|
itself, a local run **uploads its conversations to the StartOS storage area**,
|
||||||
|
and the StartOS service owns the Joplin connection for the whole corpus.
|
||||||
|
|
||||||
|
That inverts today's arrangement, where every machine talks to its own Joplin
|
||||||
|
desktop, and it removes two problems we already have:
|
||||||
|
|
||||||
|
- **The Joplin-availability race disappears from the clients.** A scheduled run
|
||||||
|
currently has to find Joplin desktop open on that same machine — the
|
||||||
|
2026-08-18 09:02 timer run exported fine and then skipped the sync because
|
||||||
|
Joplin did not start until 09:07. Uploading to a server that is always up has
|
||||||
|
no such window, and `--joplin-optional` stops being load-bearing.
|
||||||
|
- **One Joplin integration instead of N.** Notebook naming, resource upload and
|
||||||
|
note-update logic run once, server-side, against one manifest — rather than
|
||||||
|
each machine independently deciding what a notebook is called and racing to
|
||||||
|
update the same note.
|
||||||
|
|
||||||
What this would need, and what it would *not*:
|
What this would need, and what it would *not*:
|
||||||
|
|
||||||
- **Not** a headless web-provider login. The hard sub-problem the original drop
|
- **Not** a headless web-provider login. The hard sub-problem the original drop
|
||||||
retired stays retired: the web providers can keep running interactively on the
|
retired stays retired: the web providers can keep running interactively on the
|
||||||
machine that has the browser, pushing their output to the server. Only the
|
machine that has the browser, pushing their output to the server. Only the
|
||||||
local providers need to run server-side, and they need no tokens at all.
|
local providers need to run server-side, and they need no tokens at all.
|
||||||
- Machines would need to reach the server — a sync/push step, or the service
|
- An upload step in the client — the counterpart of today's `joplin` command,
|
||||||
reading transcript directories exported from each machine.
|
pointed at the StartOS service instead of a local Joplin API. Probably a
|
||||||
|
`--upload`/`push` alongside `sync`, so a scheduled client run stays one line.
|
||||||
- Per-machine identity in the corpus, which the exporter currently does not
|
- Per-machine identity in the corpus, which the exporter currently does not
|
||||||
track: `claude_code.resolve_roots` deliberately merges multiple roots with "no
|
track: `claude_code.resolve_roots` deliberately merges multiple roots with "no
|
||||||
per-machine label". Centralizing would make that label load-bearing.
|
per-machine label". Centralizing would make that label load-bearing.
|
||||||
- Conflict handling for one conversation seen by two machines. The cache
|
- Conflict handling for one conversation seen by two machines, and a decision
|
||||||
manifest is per-machine today.
|
about whether the server or the client owns the cache manifest. It is
|
||||||
|
per-machine today, and that is what makes "already up to date" mean anything.
|
||||||
|
- A story for what the client keeps locally after a successful upload. Exports
|
||||||
|
are the only copy of `claude-code` / `codex` transcripts once Codex prunes its
|
||||||
|
rollouts, so the client should probably keep them rather than move them.
|
||||||
|
|
||||||
Meanwhile Joplin is sufficient — it already syncs (encrypted) offsite, and it is
|
Meanwhile Joplin is sufficient — it already syncs (encrypted) offsite, and it is
|
||||||
where the archive is actually read. This is a "nice eventually", not a gap.
|
where the archive is actually read. This is a "nice eventually", not a gap.
|
||||||
|
|||||||
@@ -50,9 +50,15 @@ if (-not (Test-Path $launcher)) {
|
|||||||
# Task Scheduler runs multiple actions in order but reports only the last one's
|
# 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
|
# 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.
|
# going after a failure and propagates a non-zero exit code.
|
||||||
|
#
|
||||||
|
# /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 ' & '
|
$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' `
|
$actions = New-ScheduledTaskAction -Execute 'cmd.exe' `
|
||||||
-Argument "/c set RC=0 & $loop & exit /b %RC%" `
|
-Argument $taskArgs `
|
||||||
-WorkingDirectory $repo
|
-WorkingDirectory $repo
|
||||||
|
|
||||||
$trigger = New-ScheduledTaskTrigger -Daily -At $Time
|
$trigger = New-ScheduledTaskTrigger -Daily -At $Time
|
||||||
@@ -75,6 +81,10 @@ Register-ScheduledTask -TaskName $TaskName `
|
|||||||
|
|
||||||
Write-Host "Registered '$TaskName' - daily at $Time for: $($Provider -join ', ')"
|
Write-Host "Registered '$TaskName' - daily at $Time for: $($Provider -join ', ')"
|
||||||
Write-Host ''
|
Write-Host ''
|
||||||
|
Write-Host 'Command the task will run:'
|
||||||
|
Write-Host " cmd.exe $taskArgs"
|
||||||
|
Write-Host " (working directory: $repo)"
|
||||||
|
Write-Host ''
|
||||||
Write-Host 'Next steps:'
|
Write-Host 'Next steps:'
|
||||||
Write-Host " * Run it once now: Start-ScheduledTask -TaskName $TaskName"
|
Write-Host " * Run it once now: Start-ScheduledTask -TaskName $TaskName"
|
||||||
Write-Host " * Check the result: Get-ScheduledTaskInfo -TaskName $TaskName"
|
Write-Host " * Check the result: Get-ScheduledTaskInfo -TaskName $TaskName"
|
||||||
|
|||||||
Reference in New Issue
Block a user