feat: unified praxis + raptor freshness engine#63
Conversation
One multi-tool freshness engine (generalize cmd/update_check.go); praxis's own self-update nag migrates onto it, raptor is a second toolSpec. Shared cache, comparator, renderer, throttle. Nudge-only for raptor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize the praxis update-check into a multi-tool freshness engine so
raptor freshness reuses it rather than fragmenting into a parallel path.
- internal/selfupdate: LatestReleaseTagFor(repo) + a shared releaseURL builder,
so any repo's latest tag is fetchable (praxis-cli AND raptor-releases) through
one path. praxis self-update URL now routes through the same builder.
- cmd/update_check.go: a toolSpec registry (praxis, raptor) drives one engine —
shared compareSemver, one per-tool cache file (map keyed by tool), one
fetch-with-retry, one 24h throttle. `checkForUpdate()` (praxis's nag) is now a
thin call over `checkTool(praxisSpec)`. raptor: version from `raptor --version`,
latest from Facets-cloud/raptor-releases; installed/checkable gating.
- Freshness{tool, installed, current, latest, stale} is the result surfaced to
status/login/nag (next tasks).
All pre-existing update-check tests stay green (behavior preserved); added raptor
engine tests + per-tool cache-isolation test. Nudge-only: no code runs raptor upgrade.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Execute-time TTY nag now loops the tool registry (collectStaleNags) and
renders each stale tool with one parameterized box (printFreshnessBox).
raptor's line is nudge-only ('ask your user, then raptor upgrade — praxis
won't run it').
- praxis status --json gains a 'tools' block from the shared engine: freshCached
(local-only, no network) by default; --refresh forces freshLive. A cache-only
freshMode keeps plain status network-free.
- Tests: raptor + praxis box rendering, nudge-only nag copy, status tools block,
status --refresh live check.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- praxis login prints a one-line notice per stale tool (praxis/raptor) via the shared engine, recording state.staleTools; warms the cache for later status. - praxis driver skill + execution preamble teach the freshness step: check status --json tools, offer `raptor upgrade` when stale, ask first (nudge-only). - Guard tests for skill + preamble copy; noticeFreshness unit test. Completes the unified praxis+raptor freshness feature (one engine, four surfaces). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughChangesThe update system now evaluates Praxis and Raptor freshness independently through shared release-tag fetching, caching, and semver logic. Results appear in status and login JSON, interactive notices, asynchronous nags, and ask-first Raptor upgrade guidance. Unified tool freshness
Sequence Diagram(s)sequenceDiagram
participant User
participant PraxisCLI
participant FreshnessEngine
participant GitHubReleases
participant FreshnessCache
User->>PraxisCLI: run status, login, or interactive command
PraxisCLI->>FreshnessEngine: evaluate Praxis and Raptor
FreshnessEngine->>FreshnessCache: read throttled per-tool entries
FreshnessEngine->>GitHubReleases: fetch missing or live release tags
GitHubReleases-->>FreshnessEngine: return release tags
FreshnessEngine-->>PraxisCLI: return Freshness results
PraxisCLI-->>User: render status data or stale notices
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/login_setup.go`:
- Around line 261-264: Update the noticeFreshness call in the login setup flow
to execute with a short overall deadline covering all serial tool checks,
including retries and delays. Ensure the deadline stops further work and returns
cached or already completed freshness results, while preserving the existing
best-effort, non-fatal behavior and JSON handling.
In `@cmd/root.go`:
- Around line 52-58: Update the stale-nag collection flow around
collectStaleNags and notify so results are emitted per tool rather than only
after every freshness check completes. Ensure a stalled Raptor lookup or release
fetch cannot delay already-available Praxis notifications past the three-second
deadline, using per-tool deadlines or partial-result delivery while preserving
existing notification rendering.
In `@cmd/status_test.go`:
- Around line 81-104: Update TestStatusCmd_RefreshDoesLiveFreshness to
prepopulate the current Raptor cache entry before running statusCmd.RunE, using
the existing cache setup symbols and the local version “0.1.0”. Then retain the
fetchRaptorTag spy and assert it is called, ensuring the test distinguishes
--refresh’s live fetch from the empty-cache fallback.
In `@cmd/status.go`:
- Around line 71-78: Update the `statusRefresh` CLI flag help and long
description to state that `status --refresh` checks `/ai-api/auth/me` and
performs live tool-release freshness checks via `toolsFreshness`, rather than
describing it as auth-only. Keep the existing refresh behavior unchanged.
In `@cmd/update_check.go`:
- Around line 318-325: Update putCacheEntry to serialize the entire
readFreshnessCache, merge, and saveFreshnessCache sequence with a cross-process
lock, ensuring concurrent Praxis processes cannot overwrite each other’s tool
entries. Make saveFreshnessCache persist the updated cache via atomic rename,
while preserving the existing best-effort behavior.
- Around line 269-275: Update execRaptorVersion to create a short-lived timeout
context and invoke raptor --version through exec.CommandContext instead of
exec.Command, ensuring a stalled process returns "", false when the deadline
expires. Add a regression test that exercises a hung raptor binary and verifies
the function does not wait indefinitely.
In `@docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md`:
- Around line 98-102: Fix the nested Markdown code spans in the Execute()
notification description by replacing the outer backtick delimiters with a
non-conflicting presentation, while preserving the inline command spans for
`praxis update` and `raptor upgrade`.
In `@internal/render/preamble.go`:
- Around line 38-40: Correct the documented tools JSON shape: in
internal/render/preamble.go lines 38-40 and internal/skillinstall/dummy.go lines
166-170, instruct agents to locate the tools array entry where tool == "raptor"
and then inspect that entry’s stale field. Update the assertions in
internal/render/preamble_test.go lines 28-31 and
internal/skillinstall/dummy_test.go lines 40-46 to require this same array-entry
wording.
In `@internal/selfupdate/selfupdate_test.go`:
- Around line 81-85: Strengthen the 404 case in the releaseTagFrom test by
asserting that the returned error matches the specific “no releases published
yet” contract, checking its message or the appropriate typed sentinel rather
than only verifying err is non-nil. Keep the existing bad test server setup and
ensure unexpected errors fail the test.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 72a0bd07-026e-4ce1-9da1-71573b6accdd
📒 Files selected for processing (14)
cmd/login_setup.gocmd/root.gocmd/status.gocmd/status_test.gocmd/update.gocmd/update_check.gocmd/update_check_test.godocs/superpowers/plans/2026-07-16-raptor-praxis-freshness.mdinternal/render/preamble.gointernal/render/preamble_test.gointernal/selfupdate/selfupdate.gointernal/selfupdate/selfupdate_test.gointernal/skillinstall/dummy.gointernal/skillinstall/dummy_test.go
Robustness around the new network/exec calls: - Bound `raptor --version` with a context timeout (raptorVersionCmd seam) so a wedged raptor can't hang a login/nag check. Regression test for a hung binary. - checkToolsBounded: run tool checks CONCURRENTLY with an overall deadline, used by login (caps offline latency) and the Execute nag (a slow raptor no longer suppresses a cached praxis nag; partial results returned). - Atomic cache write (temp + rename) so a concurrent praxis never reads a torn cache; last-writer-wins is benign for a throttle (≤ one extra fetch). - Correct the driver-skill + preamble copy: `tools` is a JSON ARRAY — find the entry whose `tool` is raptor and read its `stale`, not `raptor.stale`. Guards assert the wrong object-path is absent. - status --refresh help/Long now state it also re-fetches tool latest versions. - status --refresh test seeds a fresh raptor cache entry so it proves freshLive bypasses the cache (not just an empty-cache fetch). - selfupdate: assert the 404 "no releases" error contract, not just err != nil. - plan doc: remove nested code-span backticks (MD038). go test ./... + vet green; live status --refresh still flags raptor stale. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/update_check_test.go`:
- Around line 287-289: Remove the exec.LookPath guard from the timeout test in
raptorVersionCmd, since the command is replaced with a blocking stub and must
run even when Raptor is unavailable. Delete the resulting unused os/exec import
while preserving the existing timeout assertions and test setup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 51abfd5b-3053-4c1c-becd-f58f13701d76
📒 Files selected for processing (11)
cmd/login_setup.gocmd/status.gocmd/status_test.gocmd/update_check.gocmd/update_check_test.godocs/superpowers/plans/2026-07-16-raptor-praxis-freshness.mdinternal/render/preamble.gointernal/render/preamble_test.gointernal/selfupdate/selfupdate_test.gointernal/skillinstall/dummy.gointernal/skillinstall/dummy_test.go
🚧 Files skipped from review as they are similar to previous changes (9)
- internal/render/preamble_test.go
- internal/skillinstall/dummy_test.go
- cmd/status_test.go
- internal/render/preamble.go
- docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md
- internal/selfupdate/selfupdate_test.go
- cmd/login_setup.go
- internal/skillinstall/dummy.go
- cmd/update_check.go
execRaptorVersion no longer does a separate exec.LookPath — a missing binary
already errors from CommandContext (same ("",false) result), so the timeout
test needs no skip guard and verifies the timeout on CI without raptor too.
Drops the redundant LookPath + the now-unused os/exec test import.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep raptor (and praxis itself) fresh — one unified freshness engine, not a raptor path bolted beside praxis's existing self-update.
Why unify
praxis already had a self-update posture (
checkForUpdate, a 24h cache,compareSemver, the TTY nag box). Adding raptor as a separateinternal/freshnesswould have duplicated the cache/comparator/renderer and drifted. Instead this generalizes the existing engine to a tool registry — praxis's own nag is migrated onto it, raptor is a secondtoolSpec. They share one cache, one comparator, one renderer, one throttle; they differ only in their spec (version resolver, releases repo, upgrade hint).What's here (6 TDD tasks)
selfupdate.LatestReleaseTagFor(repo)+ one shared release-URL builder.toolSpecregistry +checkTool+ per-tool cache map; praxis'scheckForUpdate()migrated ontocheckTool(praxisSpec); raptor version fromraptor --version, latest fromFacets-cloud/raptor-releases.printFreshnessBoxrenders each stale tool.status --jsontoolsblock (freshCachedlocal-only default;freshLiveon--refresh).praxis loginstale notice +state.staleTools.Guardrails
raptor upgrade.praxis updatestays praxis-only (self-replaces its binary).PRAXIS_NO_UPDATE_CHECK, 24h throttle, TTY nag, box format; every pre-existing update-check test stays green.Testing
go test ./...+go vetgreen;gofmtclean;goreleaser-checkCI unaffected.status --refresh --jsoncorrectly reports raptor0.1.81<v0.1.82→stale:trueagainst real raptor-releases; praxis dev build correctly skipped.Plan:
docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md.🤖 Generated with Claude Code
Summary by CodeRabbit
status --jsonnow includes atoolsfreshness array;--refreshperforms live freshness checks and auth verification.raptor whoamifailures and stale Raptor upgrades.