magus-cli 7.7.0 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +4 -4
- package/src/__tests__/blackbox-parity.test.ts +45 -26
- package/src/__tests__/blackbox-plugin-state.test.ts +25 -6
- package/src/__tests__/blind/plugin-deps/doctor.test.ts +622 -0
- package/src/__tests__/blind/plugin-deps/helpers.ts +340 -0
- package/src/__tests__/blind/plugin-deps/hook.test.ts +328 -0
- package/src/__tests__/blind/plugin-deps/probe.test.ts +694 -0
- package/src/__tests__/blind/plugin-deps/read-only.test.ts +96 -0
- package/src/__tests__/blind/plugin-deps/schema.test.ts +390 -0
- package/src/__tests__/blind-780-cli-tools.test.ts +796 -0
- package/src/__tests__/blind-780-deprecated.test.ts +631 -0
- package/src/__tests__/blind-780-failure-reasons.test.ts +1004 -0
- package/src/__tests__/blind-780-plugin-resolution.test.ts +431 -0
- package/src/__tests__/blind-780-review2.test.ts +1178 -0
- package/src/__tests__/cli-apply-seams.test.ts +2 -67
- package/src/__tests__/cli-tool-commands.test.ts +131 -6
- package/src/__tests__/cli-tools-adapter.test.ts +52 -2
- package/src/__tests__/cli-tools-plugin-managed.test.tsx +83 -0
- package/src/__tests__/cli-update-view.test.ts +3 -3
- package/src/__tests__/deprecated-remove.test.ts +827 -0
- package/src/__tests__/deps-adapter.test.ts +191 -0
- package/src/__tests__/deps-check-hook.test.ts +220 -0
- package/src/__tests__/deps-plan.test.ts +896 -0
- package/src/__tests__/deps-report.test.ts +197 -0
- package/src/__tests__/doctor-bins.test.ts +134 -36
- package/src/__tests__/doctor-json.test.ts +261 -0
- package/src/__tests__/doctor.test.ts +159 -1
- package/src/__tests__/failure-popup-review2.test.tsx +896 -0
- package/src/__tests__/failure-popup.test.tsx +419 -0
- package/src/__tests__/final-fixes-780.test.tsx +740 -0
- package/src/__tests__/fixtures/bins.ts +55 -0
- package/src/__tests__/format-update-outcome.test.ts +6 -32
- package/src/__tests__/gitignore-profile.test.ts +1 -9
- package/src/__tests__/install-plan.test.ts +15 -1
- package/src/__tests__/marketplace-refresh.test.ts +9 -3
- package/src/__tests__/models-screen-state.test.ts +18 -40
- package/src/__tests__/no-shell-spawn.test.ts +77 -0
- package/src/__tests__/npm-package-name.test.ts +6 -9
- package/src/__tests__/plugin-requires.test.ts +138 -153
- package/src/__tests__/plugin-resolution.test.ts +52 -13
- package/src/__tests__/plugin-row-text.test.ts +30 -37
- package/src/__tests__/profile-dependencies.test.ts +7 -0
- package/src/__tests__/profile-startup-old-format.test.ts +0 -3
- package/src/__tests__/profile-startup.test.ts +40 -12
- package/src/__tests__/requires-probe.test.ts +858 -0
- package/src/__tests__/resolver.test.ts +129 -52
- package/src/__tests__/run.test.ts +108 -0
- package/src/__tests__/stale-load-repair.test.ts +31 -23
- package/src/__tests__/tool-probe.test.ts +1 -1
- package/src/__tests__/toolchain.test.ts +123 -52
- package/src/__tests__/update-apply.test.ts +13 -29
- package/src/__tests__/update-plan.test.ts +24 -18
- package/src/__tests__/useStaleLoadModal.test.ts +1 -57
- package/src/__tests__/version-unknown-state.test.ts +15 -17
- package/src/cli/ansi.ts +2 -7
- package/src/cli/deps-view.ts +213 -0
- package/src/cli/doctor.ts +320 -54
- package/src/cli/install.ts +55 -71
- package/src/cli/profile.ts +20 -2
- package/src/cli/router.ts +6 -2
- package/src/cli/update-view.ts +58 -15
- package/src/cli/update.ts +55 -12
- package/src/data/cli-tools.ts +24 -9
- package/src/services/active-closure.ts +3 -3
- package/src/services/catalog-cache-store.ts +8 -6
- package/src/services/claude-cli.ts +106 -19
- package/src/services/claude-settings.ts +88 -384
- package/src/services/cli-tool-commands.ts +104 -3
- package/src/services/deps-plan.ts +962 -0
- package/src/services/deps-report.ts +265 -0
- package/src/services/doctor-bins.ts +115 -43
- package/src/services/install-plan.ts +11 -1
- package/src/services/local-marketplace.ts +12 -206
- package/src/services/marketplace-refresh.ts +4 -4
- package/src/services/plugin-env-needs.ts +69 -0
- package/src/services/plugin-manager.ts +35 -37
- package/src/services/plugin-requires.ts +93 -162
- package/src/services/plugin-resolution.ts +34 -42
- package/src/services/profile-activate.ts +1 -2
- package/src/services/profile-startup.ts +18 -43
- package/src/services/profile-state.ts +72 -2
- package/src/services/resolver.ts +263 -59
- package/src/services/tool-probe.ts +18 -25
- package/src/services/toolchain.ts +117 -111
- package/src/services/update-engine.ts +345 -45
- package/src/services/update-plan.ts +296 -36
- package/src/shared/plugin/hooks/bun-missing.sh +39 -0
- package/src/shared/plugin/hooks/deps-check.ts +224 -0
- package/src/shared/plugin/hooks/lib/requires-probe.ts +1183 -0
- package/src/types/index.ts +60 -16
- package/src/ui/App.tsx +81 -171
- package/src/ui/adapters/cliToolsAdapter.ts +252 -12
- package/src/ui/adapters/depsAdapter.ts +129 -0
- package/src/ui/adapters/failureReport.ts +137 -0
- package/src/ui/adapters/pluginsAdapter.ts +297 -45
- package/src/ui/adapters/startupReports.ts +260 -0
- package/src/ui/components/modals/FailureListModal.tsx +231 -0
- package/src/ui/components/modals/MessageModal.tsx +7 -12
- package/src/ui/components/modals/ModalContainer.tsx +10 -5
- package/src/ui/components/modals/index.ts +1 -0
- package/src/ui/hooks/startupQueue.ts +56 -0
- package/src/ui/hooks/useGitignoreModal.ts +30 -52
- package/src/ui/hooks/useProfileStartupModal.ts +119 -142
- package/src/ui/hooks/useStaleLoadModal.ts +35 -65
- package/src/ui/keymap.ts +14 -1
- package/src/ui/renderers/cliToolRenderers.tsx +135 -2
- package/src/ui/renderers/mcpRenderers.tsx +110 -3
- package/src/ui/renderers/pluginRenderers.tsx +77 -6
- package/src/ui/renderers/pluginRowText.ts +25 -25
- package/src/ui/renderers/pluginStatusText.ts +18 -1
- package/src/ui/screens/AliasScreen.tsx +38 -45
- package/src/ui/screens/CliToolsScreen.tsx +199 -98
- package/src/ui/screens/EnvVarsScreen.tsx +17 -5
- package/src/ui/screens/GitignoreScreen.tsx +48 -67
- package/src/ui/screens/McpRegistryScreen.tsx +67 -38
- package/src/ui/screens/McpScreen.tsx +46 -19
- package/src/ui/screens/ModelsScreen.tsx +46 -86
- package/src/ui/screens/PluginsScreen.tsx +315 -259
- package/src/ui/screens/ProfilesScreen.tsx +79 -40
- package/src/ui/screens/SkillsScreen.tsx +83 -80
- package/src/ui/screens/StylesScreen.tsx +211 -275
- package/src/ui/state/AppContext.tsx +66 -44
- package/src/ui/state/DimensionsContext.tsx +3 -22
- package/src/ui/state/reducer.ts +12 -100
- package/src/ui/state/types.ts +48 -69
- package/src/utils/command-utils.ts +4 -5
- package/src/utils/run.ts +123 -52
- package/src/utils/string-utils.ts +9 -0
- package/src/utils/user-path.ts +60 -0
- package/src/__tests__/go-module.test.ts +0 -43
- package/src/__tests__/notices-rules.test.ts +0 -476
- package/src/__tests__/notices.test.tsx +0 -604
- package/src/__tests__/plugin-setup.test.ts +0 -1016
- package/src/__tests__/shell-script-callers.test.ts +0 -92
- package/src/__tests__/styles-status-line.test.ts +0 -72
- package/src/__tests__/version-snapshot.test.ts +0 -212
- package/src/services/plugin-setup.ts +0 -965
- package/src/services/version-snapshot.ts +0 -189
- package/src/utils/go-module.ts +0 -36
package/README.md
CHANGED
|
@@ -155,7 +155,7 @@ check. So does `magus install --check`.
|
|
|
155
155
|
| MCP | Add MCP servers from a curated catalog |
|
|
156
156
|
| Settings | Claude Code settings, from a catalog of known keys |
|
|
157
157
|
| Profiles | Saved plugin sets (the TUI's own, older profile concept) |
|
|
158
|
-
| CLI Tools | Install
|
|
158
|
+
| CLI Tools | Install and update CLI tools via the right package manager; a tool a plugin installs from a release shows as managed by that plugin |
|
|
159
159
|
| Git State | Gitignore conventions and repo hygiene |
|
|
160
160
|
| Alias | Shell alias + flag management for launching `claude` |
|
|
161
161
|
| Styles | Communication style presets, composed into one native output style |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magus-cli",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.9.0",
|
|
4
4
|
"description": "TUI tool for managing Claude Code plugins, MCPs, and configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.tsx",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"typescript": "^5.6.3"
|
|
66
66
|
},
|
|
67
67
|
"optionalDependencies": {
|
|
68
|
-
"magus-cli-darwin-arm64": "7.
|
|
69
|
-
"magus-cli-darwin-x64": "7.
|
|
70
|
-
"magus-cli-linux-x64": "7.
|
|
68
|
+
"magus-cli-darwin-arm64": "7.9.0",
|
|
69
|
+
"magus-cli-darwin-x64": "7.9.0",
|
|
70
|
+
"magus-cli-linux-x64": "7.9.0"
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
* _synthetic exist only to reach states the real data lacks.
|
|
18
18
|
*/
|
|
19
19
|
import { describe, expect, test } from "bun:test";
|
|
20
|
-
import { cliTools } from "../data/cli-tools.js";
|
|
21
20
|
import { selectProfileId } from "../services/active-closure.js";
|
|
22
21
|
import type { PluginInfo } from "../services/plugin-manager.js";
|
|
23
22
|
import { resolveProfile } from "../services/resolver.js";
|
|
24
23
|
import { type ToolFacts, specForCatalogTool } from "../services/tool-probe.js";
|
|
24
|
+
import { managedBins, managedTool } from "../services/toolchain.js";
|
|
25
25
|
import {
|
|
26
26
|
type BinUpdateItem,
|
|
27
27
|
type PluginUpdateItem,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
planPluginUpdates,
|
|
32
32
|
} from "../services/update-plan.js";
|
|
33
33
|
import type {
|
|
34
|
-
|
|
34
|
+
ManagedTool,
|
|
35
35
|
Marketplace,
|
|
36
36
|
ProfileManifest,
|
|
37
37
|
ResolvedClosure,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
buildPluginBrowserItems,
|
|
43
43
|
} from "../ui/adapters/pluginsAdapter.js";
|
|
44
44
|
import { pluginRowText } from "../ui/renderers/pluginRowText.js";
|
|
45
|
+
import { ownedAsDeclared, selected, testCatalogue } from "./fixtures/bins.js";
|
|
45
46
|
|
|
46
47
|
// ── fixture ────────────────────────────────────────────────────────────────
|
|
47
48
|
|
|
@@ -199,7 +200,7 @@ function makeManifest(): ProfileManifest {
|
|
|
199
200
|
};
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
const PLUGIN_BINS: Record<string,
|
|
203
|
+
const PLUGIN_BINS: Record<string, ManagedTool[]> = {
|
|
203
204
|
"terminal@magus": [
|
|
204
205
|
{ name: "tmux", via: "brew", check: "tmux -V" },
|
|
205
206
|
{
|
|
@@ -215,8 +216,8 @@ const PLUGIN_BINS: Record<string, BinRequirement[]> = {
|
|
|
215
216
|
],
|
|
216
217
|
};
|
|
217
218
|
|
|
218
|
-
async function fixtureBins(pluginId: string)
|
|
219
|
-
return (PLUGIN_BINS[pluginId] ?? []).map((b) => (
|
|
219
|
+
async function fixtureBins(pluginId: string) {
|
|
220
|
+
return (PLUGIN_BINS[pluginId] ?? []).map((b) => selected(b));
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
function facts(name: string, over: Partial<ToolFacts>): ToolFacts {
|
|
@@ -330,7 +331,9 @@ async function runBothPaths(): Promise<Paths> {
|
|
|
330
331
|
if (profileId === null) throw new Error("fixture: no profile selected");
|
|
331
332
|
const closure = await resolveProfile(manifest, profileId, {
|
|
332
333
|
binResolver: fixtureBins,
|
|
334
|
+
ownedResolver: ownedAsDeclared,
|
|
333
335
|
});
|
|
336
|
+
const tools = managedBins(closure.bins);
|
|
334
337
|
|
|
335
338
|
// CLI path
|
|
336
339
|
const cliPluginList = planPluginUpdates(
|
|
@@ -359,18 +362,18 @@ async function runBothPaths(): Promise<Paths> {
|
|
|
359
362
|
// tools
|
|
360
363
|
const factList = makeFacts();
|
|
361
364
|
const cliBins = new Map(
|
|
362
|
-
planBinUpdates(
|
|
365
|
+
planBinUpdates(tools, factList).map((b) => [b.name, b]),
|
|
363
366
|
);
|
|
364
367
|
const factsByName = new Map(factList.map((f) => [f.name, f]));
|
|
365
|
-
const declared = new Set(
|
|
368
|
+
const declared = new Set(tools.map((b) => b.name));
|
|
366
369
|
const tuiTools = new Map<string, ReturnType<typeof buildToolRow>>();
|
|
367
|
-
for (const tool of
|
|
370
|
+
for (const tool of testCatalogue()) {
|
|
368
371
|
if (!declared.has(tool.name)) continue;
|
|
369
372
|
tuiTools.set(
|
|
370
373
|
tool.name,
|
|
371
374
|
buildToolRow(
|
|
372
375
|
tool,
|
|
373
|
-
specForCatalogTool(tool,
|
|
376
|
+
specForCatalogTool(tool, tools, undefined),
|
|
374
377
|
factsByName.get(tool.name),
|
|
375
378
|
),
|
|
376
379
|
);
|
|
@@ -430,7 +433,15 @@ describe("R7 parity: one fixture through the CLI path and the TUI path", () => {
|
|
|
430
433
|
if (!row) throw new Error(`no TUI row for ${id}`);
|
|
431
434
|
const { text } = pluginRowText(row);
|
|
432
435
|
expect({ id, empty: text.trim() === "" }).toEqual({ id, empty: false });
|
|
433
|
-
|
|
436
|
+
// A deprecated row says its verdict and the key that acts on it, in the
|
|
437
|
+
// same words on every row, rather than the note — which the CLI does not
|
|
438
|
+
// print for it either (its DEPRECATED heading carries the fact).
|
|
439
|
+
if (cli.action === "remove") {
|
|
440
|
+
expect({ id, text }).toEqual({
|
|
441
|
+
id,
|
|
442
|
+
text: expect.stringContaining("deprecated — press a to remove"),
|
|
443
|
+
});
|
|
444
|
+
} else if (cli.note) {
|
|
434
445
|
expect({ id, containsNote: text.includes(cli.note) }).toEqual({
|
|
435
446
|
id,
|
|
436
447
|
containsNote: true,
|
|
@@ -490,13 +501,13 @@ describe("R7 parity: one fixture through the CLI path and the TUI path", () => {
|
|
|
490
501
|
reason: "catalog-unverified",
|
|
491
502
|
target: null,
|
|
492
503
|
},
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
"seo@magus": { action: "unknown", reason: "
|
|
504
|
+
// Its marketplace no longer lists it, but magus-marketing lists the
|
|
505
|
+
// same name: it MOVED. Not removed — the plugin still exists — and
|
|
506
|
+
// nothing is installed in its place: `unknown`, never applied.
|
|
507
|
+
"seo@magus": { action: "unknown", reason: "moved", target: null },
|
|
497
508
|
"legacy-tool@magus": {
|
|
498
|
-
action: "
|
|
499
|
-
reason: "
|
|
509
|
+
action: "remove",
|
|
510
|
+
reason: "deprecated",
|
|
500
511
|
target: null,
|
|
501
512
|
},
|
|
502
513
|
"pinned-behind@magus": {
|
|
@@ -535,7 +546,7 @@ describe("R7 parity: one fixture through the CLI path and the TUI path", () => {
|
|
|
535
546
|
expect(undeliverable?.note).toBeTruthy();
|
|
536
547
|
|
|
537
548
|
// declared but absent from the catalog: a CLI item, never a TUI row
|
|
538
|
-
expect(p.cliPlugins.get("gone@magus")?.action).toBe("
|
|
549
|
+
expect(p.cliPlugins.get("gone@magus")?.action).toBe("remove");
|
|
539
550
|
expect(p.tuiRows.has("gone@magus")).toBe(false);
|
|
540
551
|
});
|
|
541
552
|
|
|
@@ -584,9 +595,11 @@ describe("R7 parity: one fixture through the CLI path and the TUI path", () => {
|
|
|
584
595
|
// − pinned-unorderable (sha install against a semver pin)
|
|
585
596
|
// What is left is unknown because something is genuinely wrong or unread:
|
|
586
597
|
// claudish catalog-unverified — the check itself failed
|
|
587
|
-
// seo@magus
|
|
588
|
-
//
|
|
589
|
-
|
|
598
|
+
// seo@magus moved — magus-marketing lists the same name
|
|
599
|
+
// The orphan nothing else lists is deprecated:
|
|
600
|
+
// legacy-tool remove — no longer published
|
|
601
|
+
expect(cliCounts.unknown).toBe(2);
|
|
602
|
+
expect(cliCounts.remove).toBe(1);
|
|
590
603
|
expect(cliCounts.update).toBeGreaterThanOrEqual(2); // designer, pinned-behind
|
|
591
604
|
});
|
|
592
605
|
|
|
@@ -614,7 +627,8 @@ describe("R7 parity: one fixture through the CLI path and the TUI path", () => {
|
|
|
614
627
|
target: cli?.target,
|
|
615
628
|
});
|
|
616
629
|
// the TUI judges a declared tool against the closure's own spec
|
|
617
|
-
const
|
|
630
|
+
const bin = p.closure.bins.find((b) => b.name === name);
|
|
631
|
+
const declared = bin ? managedTool(bin) : null;
|
|
618
632
|
expect({ name, via: tui?.spec.via, version: tui?.spec.version }).toEqual({
|
|
619
633
|
name,
|
|
620
634
|
via: declared?.via,
|
|
@@ -687,7 +701,8 @@ describe("fixture discriminates the pre-change logic", () => {
|
|
|
687
701
|
const p = await runBothPaths();
|
|
688
702
|
|
|
689
703
|
for (const name of ["tmux", "browser-use", "mcp"]) {
|
|
690
|
-
const
|
|
704
|
+
const bin = p.closure.bins.find((b) => b.name === name);
|
|
705
|
+
const spec = bin ? managedTool(bin) : null;
|
|
691
706
|
expect(legacyPlanBin(true, Boolean(spec?.version))).toBe("upgrade");
|
|
692
707
|
expect(p.cliBins.get(name)?.action).toBe("current");
|
|
693
708
|
}
|
|
@@ -716,12 +731,16 @@ describe("fixture discriminates the pre-change logic", () => {
|
|
|
716
731
|
|
|
717
732
|
// Where they still disagree outright: an orphan carries neither
|
|
718
733
|
// `hasUpdate` nor `updateCheckFailed`, so the flags call it healthy while
|
|
719
|
-
// the classifier says no
|
|
720
|
-
|
|
734
|
+
// the classifier says it moved, or is no longer published and removes it.
|
|
735
|
+
const orphans: Array<[string, string, string]> = [
|
|
736
|
+
["seo@magus", "unknown", "moved"],
|
|
737
|
+
["legacy-tool@magus", "remove", "deprecated"],
|
|
738
|
+
];
|
|
739
|
+
for (const [id, action, reason] of orphans) {
|
|
721
740
|
const info = p.catalog.find((c) => c.id === id) as PluginInfo;
|
|
722
741
|
expect(legacyFlagState(info)).toBe("healthy");
|
|
723
|
-
expect(p.tuiRows.get(id)?.status?.action).toBe(
|
|
724
|
-
expect(p.tuiRows.get(id)?.status?.reason).toBe(
|
|
742
|
+
expect(p.tuiRows.get(id)?.status?.action).toBe(action);
|
|
743
|
+
expect(p.tuiRows.get(id)?.status?.reason).toBe(reason);
|
|
725
744
|
}
|
|
726
745
|
});
|
|
727
746
|
});
|
|
@@ -90,7 +90,7 @@ describe("indexCatalog", () => {
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
describe("classifyPlugin — one state plus a human reason", () => {
|
|
93
|
-
test("declared, absent from the catalog, marketplace read:
|
|
93
|
+
test("declared, absent from the catalog, marketplace read: remove / deprecated, no target", () => {
|
|
94
94
|
const idx = indexCatalog([info("dev@magus", "1.0.0", "1.0.0")]);
|
|
95
95
|
|
|
96
96
|
const got = classifyPlugin("gone@magus", "latest", idx);
|
|
@@ -100,8 +100,8 @@ describe("classifyPlugin — one state plus a human reason", () => {
|
|
|
100
100
|
reason: got.reason,
|
|
101
101
|
target: got.target,
|
|
102
102
|
}).toEqual({
|
|
103
|
-
action: "
|
|
104
|
-
reason: "
|
|
103
|
+
action: "remove",
|
|
104
|
+
reason: "deprecated",
|
|
105
105
|
target: null,
|
|
106
106
|
});
|
|
107
107
|
expect(got.note).toBeTruthy();
|
|
@@ -219,7 +219,11 @@ describe("classifyPlugin — one state plus a human reason", () => {
|
|
|
219
219
|
// version is `current` now, not unknown. It is the negative control
|
|
220
220
|
// below — without it this loop would pass even if every state collapsed
|
|
221
221
|
// into one.
|
|
222
|
-
|
|
222
|
+
//
|
|
223
|
+
// Neither are `b@magus` (an orphan of a marketplace we read) and `d@magus`
|
|
224
|
+
// (declared, listed nowhere, same marketplace): both are DEPRECATED now, a
|
|
225
|
+
// `remove` — not a guess. They are the second control, after the loop.
|
|
226
|
+
for (const id of ["c@magus", "e@nowhere"]) {
|
|
223
227
|
const got = classifyPlugin(id, "latest", idx);
|
|
224
228
|
expect({ id, action: got.action }).toEqual({ id, action: "unknown" });
|
|
225
229
|
expect({ id, target: got.target, hasNote: Boolean(got.note) }).toEqual({
|
|
@@ -234,6 +238,12 @@ describe("classifyPlugin — one state plus a human reason", () => {
|
|
|
234
238
|
const a = classifyPlugin("a@magus", "latest", idx);
|
|
235
239
|
expect(a.action).toBe("current");
|
|
236
240
|
expect(a.note).toBeUndefined();
|
|
241
|
+
for (const id of ["b@magus", "d@magus"]) {
|
|
242
|
+
expect({ id, action: classifyPlugin(id, "latest", idx).action }).toEqual({
|
|
243
|
+
id,
|
|
244
|
+
action: "remove",
|
|
245
|
+
});
|
|
246
|
+
}
|
|
237
247
|
});
|
|
238
248
|
});
|
|
239
249
|
|
|
@@ -318,6 +328,7 @@ describe("countPluginStates", () => {
|
|
|
318
328
|
repair: 1,
|
|
319
329
|
current: 1,
|
|
320
330
|
"stale-load": 0,
|
|
331
|
+
remove: 0,
|
|
321
332
|
unknown: 1,
|
|
322
333
|
});
|
|
323
334
|
});
|
|
@@ -329,6 +340,7 @@ describe("countPluginStates", () => {
|
|
|
329
340
|
repair: 0,
|
|
330
341
|
current: 0,
|
|
331
342
|
"stale-load": 0,
|
|
343
|
+
remove: 0,
|
|
332
344
|
unknown: 0,
|
|
333
345
|
});
|
|
334
346
|
});
|
|
@@ -499,8 +511,12 @@ describe("pluginRowText", () => {
|
|
|
499
511
|
// The fixture is an ORPHAN at 0.0.0, not a plain 0.0.0 install. A plain one
|
|
500
512
|
// is `current` with no note now, which would leave nothing for this test to
|
|
501
513
|
// find and let the gate come back unnoticed.
|
|
514
|
+
//
|
|
515
|
+
// Its marketplace is one we did NOT read, so it stays `unknown` with a note.
|
|
516
|
+
// An orphan of a marketplace we read is deprecated now, whose row says
|
|
517
|
+
// "deprecated — press a to remove" instead of its note.
|
|
502
518
|
test("a note renders on a 0.0.0 install — no version gate", () => {
|
|
503
|
-
const plugin = info("zero-version@
|
|
519
|
+
const plugin = info("zero-version@unread-mp", null, "0.0.0", {
|
|
504
520
|
isOrphaned: true,
|
|
505
521
|
});
|
|
506
522
|
const sibling = info("dev@magus", "1.0.0", "1.0.0");
|
|
@@ -529,8 +545,11 @@ describe("pluginRowText", () => {
|
|
|
529
545
|
expect(out.text).toContain(pluginStatusText(status).suffix);
|
|
530
546
|
});
|
|
531
547
|
|
|
548
|
+
// An orphan whose marketplace was not read; see the note on the 0.0.0 test.
|
|
532
549
|
test("an orphan row renders its note", () => {
|
|
533
|
-
const plugin = info("legacy@
|
|
550
|
+
const plugin = info("legacy@unread-mp", null, "0.5.0", {
|
|
551
|
+
isOrphaned: true,
|
|
552
|
+
});
|
|
534
553
|
const sibling = info("dev@magus", "1.0.0", "1.0.0");
|
|
535
554
|
const status = classifyPlugin(
|
|
536
555
|
plugin.id,
|