feat: automatically prepare compatible updates - #14
Conversation
Prepare npm latest releases for restart while preserving incompatible, pinned, and local installs. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Greptile SummaryThis PR adds automatic update handling for npm-installed Kagan plugins.
Confidence Score: 4/5The update flow has one cache-promotion issue to fix before merging. Registry checks and wrapper validation are conservative, and pinned, local, development, failed, and incompatible update paths leave the install unchanged. src/tui/update-manager.ts needs attention because shutdown-time promotion can leave the active cache path missing if disposal does not wait for the async rename sequence.
What T-Rex did
|
| Filename | Overview |
|---|---|
| src/tui/updates.ts | Adds strict release parsing, npm manifest caching, and OpenCode compatibility classification. |
| src/tui/update-paths.ts | Adds cache path derivation and wrapper validation for non-symlinked Kagan package wrappers. |
| src/tui/update-manager.ts | Adds update preparation, marker writing, cleanup, and shutdown-time promotion, with a risk around async disposal promotion. |
| src/tui.tsx | Wires update cleanup, checking, preparation, status storage, and route-aware toasts into TUI startup. |
| src/tui/board/store.tsx | Replaces the old update-available signal with structured ready or blocked update status. |
| src/tui/board/board.tsx | Renders persistent update status in the board footer. |
| scripts/package-check.ts | Extends package validation across the pinned and minimum supported OpenCode versions. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant TUI as Kagan TUI
participant NPM as npm registry
participant API as OpenCode plugin API
participant FS as package cache
participant UI as board/toast UI
TUI->>FS: cleanup marker and backup from prior update
TUI->>NPM: fetch latest tag and manifest
NPM-->>TUI: version and engines.opencode
alt compatible latest
TUI->>API: add exact Kagan release
API->>FS: prepare package wrapper
TUI->>FS: validate wrappers and write marker
TUI->>UI: show ready status
TUI->>FS: promote prepared wrapper on disposal
else incompatible latest
TUI->>UI: show blocked status
else pinned, local, dev, or failure
TUI-->>TUI: leave install unchanged
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant TUI as Kagan TUI
participant NPM as npm registry
participant API as OpenCode plugin API
participant FS as package cache
participant UI as board/toast UI
TUI->>FS: cleanup marker and backup from prior update
TUI->>NPM: fetch latest tag and manifest
NPM-->>TUI: version and engines.opencode
alt compatible latest
TUI->>API: add exact Kagan release
API->>FS: prepare package wrapper
TUI->>FS: validate wrappers and write marker
TUI->>UI: show ready status
TUI->>FS: promote prepared wrapper on disposal
else incompatible latest
TUI->>UI: show blocked status
else pinned, local, dev, or failure
TUI-->>TUI: leave install unchanged
end
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
src/tui/update-manager.ts:99
**Async Shutdown Promotion**
When a compatible update is prepared, this registers an async cache rename for TUI disposal. If the host does not wait for returned disposal promises, shutdown can cut off the sequence after `current` is moved to `backup` and before `prepared` is moved into place or restored, so the next restart can find `kagan@latest` missing.
Reviews (1): Last reviewed commit: "feat: automatically prepare compatible u..." | Re-trigger Greptile
| } | ||
| await fs.writeFile(paths.marker, JSON.stringify(marker)) | ||
| if (api.lifecycle.signal.aborted) return false | ||
| api.lifecycle.onDispose(() => promotePreparedUpdate(paths, currentVersion, status.version, fs)) |
There was a problem hiding this comment.
When a compatible update is prepared, this registers an async cache rename for TUI disposal. If the host does not wait for returned disposal promises, shutdown can cut off the sequence after current is moved to backup and before prepared is moved into place or restored, so the next restart can find kagan@latest missing.
Context Used: AGENTS.md (source)
Artifacts
Repro: Bun TypeScript harness for non-awaited async disposal promotion
- Contains supporting evidence from the run (text/typescript; charset=utf-8).
Repro: harness output showing rename order and missing current cache path
- Keeps the command output available without making the summary code-heavy.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tui/update-manager.ts
Line: 99
Comment:
**Async Shutdown Promotion**
When a compatible update is prepared, this registers an async cache rename for TUI disposal. If the host does not wait for returned disposal promises, shutdown can cut off the sequence after `current` is moved to `backup` and before `prepared` is moved into place or restored, so the next restart can find `kagan@latest` missing.
**Context Used:** AGENTS.md ([source](https://app.greptile.com/kagan/github/kagan-sh/kagan/-/custom-context?memory=88a14340-9a15-4297-925d-3656d144ad2a))
How can I resolve this? If you propose a fix, please make it concise.|
🎉 This PR is included in version 0.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Prepares the latest npm release for the next restart when it is compatible with the running OpenCode, while leaving incompatible, pinned, and local installs untouched.
What it does
src/tui/updates.tschecks npmlatestonce per hour for bare/@latestinstalls, fetches the candidate'sengines.opencode, and classifies it asready(compatible) orblocked(needs a newer OpenCode).src/tui/update-manager.tsprepares a compatible exact release viaapi.plugins.add, writes a marker, and promotes it into place only onapi.lifecycle.onDisposeso the next restart loads it. Failed promotion restores the backup.src/tui/update-paths.tsholds the cache-path resolution and validation: only non-symlinked@kagan-sh/kaganwrappers are accepted, and cleanup removes only its own marker and single backup.Notes
file:installs, and development builds are never touched.verifyxreorg: source lives undersrc/tui/, and the update code passes the new complexity gate.Verification
bun run verifypasses (all built-in verifyx checks, format, lint, types, 602 tests, package validation).