Problem
cloneRepoInBackground (server/services/brain.js) stamps cloneStatus: 'cloning' and only resets it from the promise callbacks of githubCloner.cloneRepo. If the server restarts (or is killed) while a clone is running, those callbacks never fire and the link record stays at cloning forever.
That state has no exit:
POST /api/brain/links/:id/clone (server/routes/brainLinks.js:177-182) rejects with 409 CLONE_IN_PROGRESS whenever cloneStatus === 'cloning'.
- The Links tab only renders a Clone button for
cloneStatus === 'none' and a Retry button for 'failed' — a cloning record gets neither (client/src/components/brain/tabs/LinksTab.jsx).
So the bookmark is permanently stuck showing a clone spinner with no way to retry short of editing the record by hand.
Fix
Give a stale cloning record a way back. Options, in order of preference:
- Reconcile at boot. On server start, sweep links with
cloneStatus === 'cloning' and reset them to failed with a cloneError explaining the interruption — no in-process clone can survive a restart, so any such record at boot is by definition orphaned. This alone restores the existing Retry affordance with no new UI or API.
- Optionally, let the clone route force-restart a clone whose record has been
cloning past a staleness threshold, instead of a blanket 409.
Note this is a record-state sweep, not an AI or network call, so it is fine to run at boot (no cold-bootstrap LLM concern).
Acceptance criteria
Related to #5442 — that issue bounded the client poll for a stuck clone (it now gives up after 10 minutes and labels the badge (stalled)), but deliberately left the stranded server-side record alone as out of scope.
Problem
cloneRepoInBackground(server/services/brain.js) stampscloneStatus: 'cloning'and only resets it from the promise callbacks ofgithubCloner.cloneRepo. If the server restarts (or is killed) while a clone is running, those callbacks never fire and the link record stays atcloningforever.That state has no exit:
POST /api/brain/links/:id/clone(server/routes/brainLinks.js:177-182) rejects with 409CLONE_IN_PROGRESSwhenevercloneStatus === 'cloning'.cloneStatus === 'none'and a Retry button for'failed'— acloningrecord gets neither (client/src/components/brain/tabs/LinksTab.jsx).So the bookmark is permanently stuck showing a clone spinner with no way to retry short of editing the record by hand.
Fix
Give a stale
cloningrecord a way back. Options, in order of preference:cloneStatus === 'cloning'and reset them tofailedwith acloneErrorexplaining the interruption — no in-process clone can survive a restart, so any such record at boot is by definition orphaned. This alone restores the existing Retry affordance with no new UI or API.cloningpast a staleness threshold, instead of a blanket 409.Note this is a record-state sweep, not an AI or network call, so it is fine to run at boot (no cold-bootstrap LLM concern).
Acceptance criteria
Clone failedwith an explanatorycloneErrorand offers Retry.cloningis reset, and records in every othercloneStatusare untouched.Related to #5442 — that issue bounded the client poll for a stuck clone (it now gives up after 10 minutes and labels the badge
(stalled)), but deliberately left the stranded server-side record alone as out of scope.