release: v0.33.0 — plugin contract bundle + install error surfacing#57
Merged
DavidsonGomes merged 1 commit intodevelopfrom Apr 26, 2026
Merged
Conversation
Bumps version to 0.33.0 so the plugin nutri (which requires this version) can install. Bundles the five plugin-contract PRs (#52→#56) merged today into a single release. Plus a UX fix on the install wizard so 409s say why they conflicted. The fix - lib/api.ts buildError now falls back to data.conflicts[0] when the standard error/message fields are absent. The plugin preview endpoint returns {conflicts: string[], manifest, ...} on 409 — without this fix the wizard showed only "409 CONFLICT" with the actual reason hidden. - PluginInstallModal: conflicts type was Record<string, unknown>, backend always returned string[]; the JSON.keys() coercion produced index strings. Now typed as string[] and rendered as a list. Tested - Frontend tsc --noEmit clean - Plugin nutri 200 pytest still pass after the 11 `# nosec B603` markers added to subprocess.run calls (false positives from regex security scan — all calls use list args, no shell=True) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviewer's GuideReleases EvoNexus 0.33.0, bundling several backend plugin-contract features and updates while fixing plugin install UX by surfacing detailed 409 conflict messages and correctly handling conflicts in the install modal. Sequence diagram for plugin install preview 409 conflict handlingsequenceDiagram
actor User
participant PluginInstallModal
participant ApiClient
participant Backend
User->>PluginInstallModal: Start plugin install
PluginInstallModal->>Backend: POST /api/plugin/preview
Backend-->>PluginInstallModal: 409 CONFLICT { conflicts: [ "Plugin 'nutri' requires EvoNexus >= 0.33.0, but installed version is 0.32.3." ], manifest, ... }
PluginInstallModal->>ApiClient: Handle 409 via buildError(res)
ApiClient->>ApiClient: Parse JSON body
ApiClient->>ApiClient: Try data.error || data.description || data.message
ApiClient->>ApiClient: Fallback to data.conflicts.join(" • ") or data.details.join(" • ")
ApiClient-->>PluginInstallModal: Error("409 CONFLICT: Plugin 'nutri' requires EvoNexus >= 0.33.0, but installed version is 0.32.3.")
PluginInstallModal->>PluginInstallModal: Treat preview.conflicts as string[]
PluginInstallModal-->>User: Render conflicts as <ul><li>…</li></ul>
Class diagram for updated PreviewResult and error handlingclassDiagram
class PreviewResult {
manifest: Record<string, unknown>
warnings: string[]
conflicts: string[]
}
class PluginInstallModalProps {
onClose(): void
onInstalled(): void
}
class PluginInstallModalState {
preview: PreviewResult
conflicts: string[]
}
class PluginInstallModal {
+render(): JSXElement
+handlePreviewResponse(preview: PreviewResult): void
+renderConflicts(conflicts: string[]): JSXElement
}
class ApiClient {
+buildError(res: Response): Promise~Error~
}
class ErrorDetailResolution {
+resolveDetail(data: any): string
-fromStandardFields(data: any): string
-fromConflictsArray(conflicts: string[]): string
-fromDetailsArray(details: string[]): string
}
PluginInstallModal --> PreviewResult : uses
PluginInstallModal --> PluginInstallModalProps : receives
PluginInstallModal --> PluginInstallModalState : manages
ApiClient --> ErrorDetailResolution : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
buildError, the newconflicts/detailshandling assumes arrays of strings and calls.joindirectly; to avoid[object Object]or runtime surprises if the backend ever sends structured items, consider mirroring the type-guarding you did inPluginInstallModal(e.g. filter to string entries before joining). - The
conflictsderivation inPluginInstallModaluses a non-null assertion and cast (preview!.conflicts as string[]) even though you already guard withArray.isArray; you can simplify this to avoid the assertion and keep runtime safety (e.g.const conflicts = Array.isArray(preview?.conflicts) ? preview.conflicts.filter(...) : []).
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `buildError`, the new `conflicts`/`details` handling assumes arrays of strings and calls `.join` directly; to avoid `[object Object]` or runtime surprises if the backend ever sends structured items, consider mirroring the type-guarding you did in `PluginInstallModal` (e.g. filter to string entries before joining).
- The `conflicts` derivation in `PluginInstallModal` uses a non-null assertion and cast (`preview!.conflicts as string[]`) even though you already guard with `Array.isArray`; you can simplify this to avoid the assertion and keep runtime safety (e.g. `const conflicts = Array.isArray(preview?.conflicts) ? preview.conflicts.filter(...) : []`).Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bumps EvoNexus to 0.33.0 so the plugin nutri (and any future plugin requiring
min_evonexus_version: 0.33.0) can install. Bundles the five plugin-contract PRs merged today (#52→#56) into a single release, plus a UX fix on the install wizard so409 CONFLICTactually says why it conflicted.The fix (UX bug)
Found while installing the plugin nutri end-to-end: the wizard showed
⚠ 409 CONFLICTwith no detail. The 409 body was actually{conflicts: ["Plugin 'nutri' requires EvoNexus >= 0.33.0, but installed version is 0.32.3."], manifest, ...}butlib/api.ts buildErroronly checkeddata.error / data.message / data.description— none of which the preview endpoint emits.lib/api.ts buildErrornow falls back todata.conflicts[0](anddata.details[0]) when the standard fields are absent.PluginInstallModalhadconflicts: Record<string, unknown>(wrong type — backend always returnedstring[]); theObject.keys()coercion produced["0", "1"]index strings on render. Now typed correctly and rendered as a<ul>.What's bundled in 0.33.0
public_pagescapability — token-bound public portalssafe_uninstallcapability — wizard with phrase + ZIP password, sandboxed hookrequires_roleon writable_data + auto-injected:current_user_idon readonlyCompat
All existing plugins (PM Essentials) work unchanged. The new manifest fields default to absent /
None. The 409 body shape was already{conflicts, manifest, ...}— only the frontend's interpretation changed.Test plan
tsc --noEmitclean on frontend# nosec B603markers added tosubprocess.run([list], ...)calls (false positives from a regex security scan — all calls use list args, noshell=True)"409 CONFLICT: Plugin 'nutri' requires EvoNexus >= 0.33.0, but installed version is 0.32.3."(verified against the JSON response body the user captured)🤖 Generated with Claude Code
Summary by Sourcery
Release version 0.33.0 with plugin contract capabilities and improved plugin install error reporting.
New Features:
Bug Fixes:
Build:
Documentation: