Repository navigation
Replies: 3 comments
|
Hi! I think the rollback workflow would benefit from distinguishing package installation from plugin activation. A restored package can exist on disk while its activation fails. Reporting that state as "not installed" makes recovery confusing, especially if reinstalling then reports that the package already exists. I would suggest representing these as separate states: package restored, activation pending, activation failed, and plugin active. The recovery action could then retry activation or display the underlying activation error without unnecessarily reinstalling the package. A regression test should cover a successful rollback followed by an activation failure and verify that the UI reports the actual state consistently. |
|
I hit exactly this classification problem in a third-party version manager ( The distinguishing signal is already in the
|
| question | source | wording |
|---|---|---|
| is the package there? | packageResult.exitCode, changed |
"1.0.0 is installed" / "could not restore 1.0.0 — install it again" |
| is it running? | stage, application, error.diagnostic |
"but it did not activate: <diagnostic>" + a retry-activation action |
"Not installed" then becomes reachable only when the package really is absent, and the Add-plugin suggestion is never offered for a package that is on disk. A regression covering "rollback installs the old version successfully, activation of the restored version fails" and asserting the restored-and-installed wording would pin it — that is the case where the current string is provably wrong.
(The comment is from the author of dsh-plugin-upgrader, which ships the same defect described above; I am not linking it as a solution, only as a second implementation that ran into the identical taxonomy problem.)
|
Thanks — this report found a real bug in a third-party plugin too, so I fixed mine and shipped it, rather than only commenting. My plugin had the same flaw. My Then the user goes to the Installed tab, hits install, and gets The signal was already there
My predicate is the middle row: function landedOnDisk(result: ChangeResult | undefined): boolean {
if (result === undefined || result.changed !== true) return false
if (result.stage !== 'enable') return false
const exit = result.packageResult?.exitCode
return exit === undefined || exit === 0
}Three signals, all required. One caveat: What I changed
type Rollback =
| { kind: 'back' } // old version back and running
| { kind: 'inactive'; reason: string } // on disk, host could not activate it
| { kind: 'refused'; reason: string } // really not there
Only Two things worth keeping in mind for the host fixDo not retry activation through
Published and reproducible
Write-up with the full chain: docs/rules/24-rollback-inactive.md. So from the outside: your distinction between "package restored", "activation pending", "activation failed" and "plugin running" is exactly right, and it is expressible today with |
Uh oh!
There was an error while loading. Please reload this page.
When a third-party bundle update fails, the official Plugins → Versions dialog can tell the user that the plugin is not installed and to install it again from Add plugin, even though the previous version was successfully reinstalled and only its activation failed. Following that instruction is refused with
already-installed.Version and verification scope
dsh-v0.2.2-alpha.2, commitf3803c96974ad4a94195fb97e5c637e9c2a3afe3; macOS arm64, Nodev26.10.0.versions.tsxUI.versions.tsxis byte-identical on current masterce7073d51254c26cd63b22a60835b8f948deb447.UpdateDialogand locale source.runProfilePnpmand registry answers were stubbed to create temporary package files and inject a target download failure. The Loader actually executes the fixture plugin and reports its activation error. React SSR used substitutes for visual primitives and unused discovery helpers. This is focused source/runtime verification, not a real registry download or a full Desktop/GUI test. No model calls or real user profiles were used.Minimal scenario
extra@1.0.0.apply()checks a temporary sentinel file and throwsfixture external resource unavailablewhile it exists. The initially running plugin, reinstalled plugin bytes, and bundle patch are otherwise identical.pluginManager.updateBundle('extra', '1.2.0'). The package-operation fixture makes the target download fail after removing 1.0.0, then successfully reinstalls 1.0.0. Activating that restored version fails because the resource remains unavailable.UpdateDialog.installBundle('extra@1.0.0').The relevant actual Host answer is:
{ "from": "1.0.0", "to": "1.2.0", "step": "install", "result": { "stage": "install", "application": "failed", "packageResult": { "exitCode": 1 } }, "restore": { "stage": "enable", "application": "failed", "changed": true, "bundle": "extra", "version": "1.0.0", "packageResult": { "exitCode": 0 }, "error": { "code": "operation-error", "diagnostic": "dsh: warning: 1 entry did not activate ... Error: fixture external resource unavailable" } } }At this point:
package.json.dependencies.extrais1.0.0.listBundles()reports{name: 'extra', version: '1.0.0', installed: true, enabled: true}. Hereenabledis the saved selection, not successful activation.installBundle('extra@1.0.0')returnsapplication: 'failed', error: {code: 'already-installed'}.Expected result
Distinguish a missing/uninstalled fallback from an installed fallback that could not activate. In this case, retain the fact that 1.0.0 is installed, show its activation diagnostic, and suggest fixing the activation problem and retrying activation, rather than Add plugin. Reserve “not installed” for an outcome that actually proves absence.
The original
outcomeOf()currently classifies solely byfailed(result.restore.application)and maps every failed restore toupdateBroken/updateBrokenDetail, without accounting for a successful package installation followed bystage: 'enable'failure:Verification and workaround
already-installedrefusal.The Host behavior of retaining a successful package installation after activation failure is documented and is not the behavior I am asking to change; this is a mismatch in the update dialog's diagnosis and recovery instruction. I found related reports about market updaters calling
installBundleover already-installed packages (e.g. #11250 and #10299), but those fail before pnpm and do not cover this fallback-activation result. I searched the accessible open/closed feedback and current source and the history ofversions.tsx; GitHub's PR-list endpoint returned 404 for this repository, so I could not rule out an inaccessible internal PR.This report was prepared with AI assistance. All stated test results come from actual isolated runs, with the fixture and UI-rendering boundaries described above.
All reactions