magus-cli 7.5.3 → 7.5.4
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/package.json +4 -4
- package/src/__tests__/blackbox-convergence.test.ts +1 -2
- package/src/__tests__/blackbox-parity.test.ts +16 -14
- package/src/__tests__/blackbox-plugin-state.test.ts +13 -15
- package/src/__tests__/cli-apply-seams.test.ts +3 -3
- package/src/__tests__/cli-profile-prompts.test.ts +1165 -0
- package/src/__tests__/content-drift.test.ts +0 -1
- package/src/__tests__/files-missing-scope.test.ts +235 -0
- package/src/__tests__/{enabled-not-installed.test.ts → files-missing.test.ts} +32 -26
- package/src/__tests__/format-update-outcome.test.ts +367 -0
- package/src/__tests__/installed-version-scope.test.tsx +425 -0
- package/src/__tests__/mate-availability.test.ts +11 -13
- package/src/__tests__/plugin-contents.test.ts +0 -1
- package/src/__tests__/plugin-detail-scopes.test.tsx +270 -0
- package/src/__tests__/plugin-row-text.test.ts +18 -21
- package/src/__tests__/profile-command.test.ts +2 -2
- package/src/__tests__/profile-migration-offer.test.ts +5 -4
- package/src/__tests__/profile-skills.test.ts +3 -3
- package/src/__tests__/profile-startup-nested.test.ts +329 -0
- package/src/__tests__/profile-startup-old-format.test.ts +390 -0
- package/src/__tests__/profile-state.test.ts +27 -22
- package/src/__tests__/scope-action.test.ts +35 -38
- package/src/__tests__/scope-row-lookup.test.ts +126 -0
- package/src/__tests__/select-restore.test.ts +209 -0
- package/src/__tests__/stale-load-repair.test.ts +1 -2
- package/src/__tests__/update-apply.test.ts +18 -2
- package/src/__tests__/update-null-readback.test.ts +300 -0
- package/src/__tests__/update-plan-parity.test.ts +249 -0
- package/src/__tests__/update-plan.test.ts +66 -67
- package/src/__tests__/version-unknown-state.test.ts +38 -39
- package/src/cli/bootstrap.ts +239 -66
- package/src/cli/doctor.ts +4 -3
- package/src/cli/install.ts +83 -27
- package/src/cli/prompt.ts +7 -3
- package/src/cli/router.ts +1 -0
- package/src/cli/select.ts +168 -0
- package/src/cli/update-view.ts +118 -6
- package/src/cli/update.ts +6 -4
- package/src/services/claude-settings.ts +28 -0
- package/src/services/manifest.ts +31 -0
- package/src/services/mate-availability.ts +23 -29
- package/src/services/plugin-manager.ts +247 -105
- package/src/services/profile-absorb.ts +10 -7
- package/src/services/profile-activate.ts +39 -18
- package/src/services/profile-startup.ts +160 -4
- package/src/services/profile-state.ts +7 -6
- package/src/services/tracked-live-files.ts +24 -3
- package/src/services/update-engine.ts +28 -10
- package/src/services/update-plan.ts +78 -94
- package/src/ui/App.tsx +7 -2
- package/src/ui/adapters/pluginsAdapter.ts +1 -1
- package/src/ui/components/primitives/ScopeSquares.tsx +10 -5
- package/src/ui/hooks/useProfileStartupModal.ts +87 -7
- package/src/ui/keymap.ts +1 -1
- package/src/ui/renderers/pluginRenderers.tsx +39 -45
- package/src/ui/renderers/pluginRowText.ts +6 -2
- package/src/ui/renderers/pluginStatusText.ts +4 -3
- package/src/ui/screens/PluginsScreen.tsx +28 -41
- package/src/cli/tui-prompt.tsx +0 -143
|
@@ -36,7 +36,6 @@ function info(overrides: Partial<PluginInfo> & { id: string }): PluginInfo {
|
|
|
36
36
|
description: "",
|
|
37
37
|
marketplace: overrides.id.split("@")[1] ?? "magus",
|
|
38
38
|
marketplaceDisplay: "",
|
|
39
|
-
enabled: true,
|
|
40
39
|
...overrides,
|
|
41
40
|
} as PluginInfo;
|
|
42
41
|
}
|
|
@@ -111,7 +110,7 @@ describe("planPluginUpdates — advancing a 'latest' pin", () => {
|
|
|
111
110
|
info({
|
|
112
111
|
id: "dev@magus",
|
|
113
112
|
version: "4.7.0",
|
|
114
|
-
projectScope: {
|
|
113
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
115
114
|
}),
|
|
116
115
|
),
|
|
117
116
|
);
|
|
@@ -131,7 +130,7 @@ describe("planPluginUpdates — advancing a 'latest' pin", () => {
|
|
|
131
130
|
info({
|
|
132
131
|
id: "dev@magus",
|
|
133
132
|
version: "4.7.0",
|
|
134
|
-
projectScope: {
|
|
133
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
135
134
|
}),
|
|
136
135
|
),
|
|
137
136
|
);
|
|
@@ -146,7 +145,7 @@ describe("planPluginUpdates — advancing a 'latest' pin", () => {
|
|
|
146
145
|
info({
|
|
147
146
|
id: "dev@magus",
|
|
148
147
|
version: "4.5.0",
|
|
149
|
-
projectScope: {
|
|
148
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
150
149
|
}),
|
|
151
150
|
),
|
|
152
151
|
);
|
|
@@ -165,7 +164,7 @@ describe("planPluginUpdates — a failed check is never 'up to date'", () => {
|
|
|
165
164
|
// The stale local clone reports the same version we have installed:
|
|
166
165
|
// without the flag this is indistinguishable from a clean check.
|
|
167
166
|
version: "4.6.1",
|
|
168
|
-
projectScope: {
|
|
167
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
169
168
|
updateCheckFailed: true,
|
|
170
169
|
updateCheckFailure: {
|
|
171
170
|
marketplace: "magus",
|
|
@@ -192,7 +191,7 @@ describe("planPluginUpdates — a failed check is never 'up to date'", () => {
|
|
|
192
191
|
info({
|
|
193
192
|
id: "dev@magus",
|
|
194
193
|
version: "4.6.1",
|
|
195
|
-
projectScope: {
|
|
194
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
196
195
|
updateCheckFailed: true,
|
|
197
196
|
}),
|
|
198
197
|
),
|
|
@@ -212,8 +211,8 @@ describe("planPluginUpdates — content drift", () => {
|
|
|
212
211
|
id: "dev@magus",
|
|
213
212
|
version: "4.6.1",
|
|
214
213
|
contentStale: true,
|
|
215
|
-
userScope: {
|
|
216
|
-
projectScope: {
|
|
214
|
+
userScope: { installed: true, version: "4.6.1" },
|
|
215
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
217
216
|
}),
|
|
218
217
|
),
|
|
219
218
|
);
|
|
@@ -236,7 +235,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
236
235
|
info({
|
|
237
236
|
id: "dev@magus",
|
|
238
237
|
version: "9.9.9",
|
|
239
|
-
projectScope: {
|
|
238
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
240
239
|
}),
|
|
241
240
|
),
|
|
242
241
|
);
|
|
@@ -251,7 +250,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
251
250
|
info({
|
|
252
251
|
id: "dev@magus",
|
|
253
252
|
version: "9.9.9",
|
|
254
|
-
projectScope: {
|
|
253
|
+
projectScope: { installed: true, version: "9.9.9" },
|
|
255
254
|
}),
|
|
256
255
|
),
|
|
257
256
|
);
|
|
@@ -271,7 +270,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
271
270
|
info({
|
|
272
271
|
id: "dev@magus",
|
|
273
272
|
version: "9.9.9",
|
|
274
|
-
projectScope: {
|
|
273
|
+
projectScope: { installed: true, version: "9.9.9" },
|
|
275
274
|
}),
|
|
276
275
|
),
|
|
277
276
|
);
|
|
@@ -288,7 +287,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
288
287
|
info({
|
|
289
288
|
id: "dev@magus",
|
|
290
289
|
version: "9.9.9",
|
|
291
|
-
projectScope: {
|
|
290
|
+
projectScope: { installed: true, version: "9.9.9" },
|
|
292
291
|
}),
|
|
293
292
|
),
|
|
294
293
|
),
|
|
@@ -303,7 +302,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
303
302
|
info({
|
|
304
303
|
id: "dev@magus",
|
|
305
304
|
version: "4.6.1",
|
|
306
|
-
projectScope: {
|
|
305
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
307
306
|
}),
|
|
308
307
|
),
|
|
309
308
|
);
|
|
@@ -319,7 +318,7 @@ describe("planPluginUpdates — an exact pin plans against what is deliverable",
|
|
|
319
318
|
info({
|
|
320
319
|
id: "dev@magus",
|
|
321
320
|
version: null,
|
|
322
|
-
projectScope: {
|
|
321
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
323
322
|
}),
|
|
324
323
|
),
|
|
325
324
|
);
|
|
@@ -339,8 +338,8 @@ describe("per-scope decisions — a stale scope is never masked", () => {
|
|
|
339
338
|
info({
|
|
340
339
|
id: "dev@magus",
|
|
341
340
|
version: "4.7.0",
|
|
342
|
-
userScope: {
|
|
343
|
-
projectScope: {
|
|
341
|
+
userScope: { installed: true, version: "4.7.0" },
|
|
342
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
344
343
|
}),
|
|
345
344
|
),
|
|
346
345
|
);
|
|
@@ -360,8 +359,8 @@ describe("per-scope decisions — a stale scope is never masked", () => {
|
|
|
360
359
|
info({
|
|
361
360
|
id: "dev@magus",
|
|
362
361
|
version: "4.6.1",
|
|
363
|
-
userScope: {
|
|
364
|
-
projectScope: {
|
|
362
|
+
userScope: { installed: true, version: "4.6.1" },
|
|
363
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
365
364
|
}),
|
|
366
365
|
),
|
|
367
366
|
);
|
|
@@ -377,8 +376,8 @@ describe("per-scope decisions — a stale scope is never masked", () => {
|
|
|
377
376
|
info({
|
|
378
377
|
id: "dev@magus",
|
|
379
378
|
version: "9.9.9",
|
|
380
|
-
userScope: {
|
|
381
|
-
projectScope: {
|
|
379
|
+
userScope: { installed: true, version: "4.6.1" },
|
|
380
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
382
381
|
}),
|
|
383
382
|
),
|
|
384
383
|
);
|
|
@@ -394,8 +393,8 @@ describe("per-scope decisions — a stale scope is never masked", () => {
|
|
|
394
393
|
info({
|
|
395
394
|
id: "dev@magus",
|
|
396
395
|
version: "4.7.0",
|
|
397
|
-
userScope: {
|
|
398
|
-
projectScope: {
|
|
396
|
+
userScope: { installed: true, version: "4.7.0" },
|
|
397
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
399
398
|
}),
|
|
400
399
|
),
|
|
401
400
|
);
|
|
@@ -422,7 +421,7 @@ describe("per-scope decisions — a stale scope is never masked", () => {
|
|
|
422
421
|
info({
|
|
423
422
|
id: "dev@magus",
|
|
424
423
|
version: null,
|
|
425
|
-
projectScope: {
|
|
424
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
426
425
|
}),
|
|
427
426
|
),
|
|
428
427
|
);
|
|
@@ -529,7 +528,7 @@ describe("planIsBehind — the --check gate", () => {
|
|
|
529
528
|
info({
|
|
530
529
|
id: "dev@magus",
|
|
531
530
|
version: "4.6.1",
|
|
532
|
-
projectScope: {
|
|
531
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
533
532
|
updateCheckFailed: true,
|
|
534
533
|
}),
|
|
535
534
|
),
|
|
@@ -549,7 +548,7 @@ describe("planIsBehind — the --check gate", () => {
|
|
|
549
548
|
info({
|
|
550
549
|
id: "code-review@claude-plugins-official",
|
|
551
550
|
version: null,
|
|
552
|
-
projectScope: {
|
|
551
|
+
projectScope: { installed: true, version: "3ea32df27be7" },
|
|
553
552
|
}),
|
|
554
553
|
),
|
|
555
554
|
),
|
|
@@ -566,7 +565,7 @@ describe("planIsBehind — the --check gate", () => {
|
|
|
566
565
|
info({
|
|
567
566
|
id: "dev@magus",
|
|
568
567
|
version: "4.7.0",
|
|
569
|
-
projectScope: {
|
|
568
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
570
569
|
}),
|
|
571
570
|
),
|
|
572
571
|
),
|
|
@@ -590,7 +589,7 @@ describe("planIsBehind — the --check gate", () => {
|
|
|
590
589
|
info({
|
|
591
590
|
id: "dev@magus",
|
|
592
591
|
version: "4.6.1",
|
|
593
|
-
projectScope: {
|
|
592
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
594
593
|
contentStale: true,
|
|
595
594
|
}),
|
|
596
595
|
),
|
|
@@ -608,7 +607,7 @@ describe("planIsBehind — the --check gate", () => {
|
|
|
608
607
|
info({
|
|
609
608
|
id: "dev@magus",
|
|
610
609
|
version: "4.7.0",
|
|
611
|
-
projectScope: {
|
|
610
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
612
611
|
}),
|
|
613
612
|
),
|
|
614
613
|
),
|
|
@@ -635,7 +634,7 @@ describe("nothing ever plans a downgrade", () => {
|
|
|
635
634
|
info({
|
|
636
635
|
id: "dev@magus",
|
|
637
636
|
version: "9.9.9",
|
|
638
|
-
projectScope: {
|
|
637
|
+
projectScope: { installed: true, version: "10.0.0" },
|
|
639
638
|
}),
|
|
640
639
|
),
|
|
641
640
|
);
|
|
@@ -653,7 +652,7 @@ describe("nothing ever plans a downgrade", () => {
|
|
|
653
652
|
info({
|
|
654
653
|
id: "dev@magus",
|
|
655
654
|
version: null,
|
|
656
|
-
projectScope: {
|
|
655
|
+
projectScope: { installed: true, version: "5.0.0" },
|
|
657
656
|
}),
|
|
658
657
|
),
|
|
659
658
|
);
|
|
@@ -669,8 +668,8 @@ describe("nothing ever plans a downgrade", () => {
|
|
|
669
668
|
info({
|
|
670
669
|
id: "dev@magus",
|
|
671
670
|
version: "9.9.9",
|
|
672
|
-
userScope: {
|
|
673
|
-
projectScope: {
|
|
671
|
+
userScope: { installed: true, version: "10.0.0" },
|
|
672
|
+
projectScope: { installed: true, version: "4.0.0" },
|
|
674
673
|
}),
|
|
675
674
|
),
|
|
676
675
|
);
|
|
@@ -681,9 +680,9 @@ describe("nothing ever plans a downgrade", () => {
|
|
|
681
680
|
test("scopesNeeding never returns a scope ahead of the target", () => {
|
|
682
681
|
const i = info({
|
|
683
682
|
id: "dev@magus",
|
|
684
|
-
userScope: {
|
|
685
|
-
projectScope: {
|
|
686
|
-
localScope: {
|
|
683
|
+
userScope: { installed: true, version: "10.0.0" },
|
|
684
|
+
projectScope: { installed: true, version: "9.9.9" },
|
|
685
|
+
localScope: { installed: true, version: "1.0.0" },
|
|
687
686
|
});
|
|
688
687
|
expect(scopesNeeding(i, "9.9.9")).toEqual(["local"]);
|
|
689
688
|
});
|
|
@@ -695,9 +694,9 @@ describe("scopesNeeding", () => {
|
|
|
695
694
|
// reappears on every run.
|
|
696
695
|
const i = info({
|
|
697
696
|
id: "dev@magus",
|
|
698
|
-
userScope: {
|
|
699
|
-
projectScope: {
|
|
700
|
-
localScope: {
|
|
697
|
+
userScope: { installed: true, version: "4.6.1" },
|
|
698
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
699
|
+
localScope: { installed: true, version: "4.7.0" },
|
|
701
700
|
});
|
|
702
701
|
expect(scopesNeeding(i, "4.7.0")).toEqual(["user", "project"]);
|
|
703
702
|
});
|
|
@@ -705,7 +704,7 @@ describe("scopesNeeding", () => {
|
|
|
705
704
|
test("a scope already on the target is left alone", () => {
|
|
706
705
|
const i = info({
|
|
707
706
|
id: "dev@magus",
|
|
708
|
-
projectScope: {
|
|
707
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
709
708
|
});
|
|
710
709
|
expect(scopesNeeding(i, "4.7.0")).toEqual([]);
|
|
711
710
|
});
|
|
@@ -897,7 +896,7 @@ describe("planHasWork / summarizePlan", () => {
|
|
|
897
896
|
info({
|
|
898
897
|
id: "dev@magus",
|
|
899
898
|
version: "4.7.0",
|
|
900
|
-
projectScope: {
|
|
899
|
+
projectScope: { installed: true, version: "4.7.0" },
|
|
901
900
|
}),
|
|
902
901
|
),
|
|
903
902
|
),
|
|
@@ -915,7 +914,7 @@ describe("planHasWork / summarizePlan", () => {
|
|
|
915
914
|
info({
|
|
916
915
|
id: "b@magus",
|
|
917
916
|
version: "2.0.0",
|
|
918
|
-
projectScope: {
|
|
917
|
+
projectScope: { installed: true, version: "1.0.0" },
|
|
919
918
|
}),
|
|
920
919
|
),
|
|
921
920
|
),
|
|
@@ -977,7 +976,7 @@ function orphan(
|
|
|
977
976
|
version: installedVersion,
|
|
978
977
|
installedVersion,
|
|
979
978
|
isOrphaned: true,
|
|
980
|
-
projectScope: {
|
|
979
|
+
projectScope: { installed: true, version: installedVersion },
|
|
981
980
|
...over,
|
|
982
981
|
});
|
|
983
982
|
}
|
|
@@ -1092,7 +1091,7 @@ describe("classifyPlugin — an unorderable version is assumed current", () => {
|
|
|
1092
1091
|
info({
|
|
1093
1092
|
id: "playground@official",
|
|
1094
1093
|
version: "7.3.0",
|
|
1095
|
-
projectScope: {
|
|
1094
|
+
projectScope: { installed: true, version: "unknown" },
|
|
1096
1095
|
}),
|
|
1097
1096
|
),
|
|
1098
1097
|
);
|
|
@@ -1109,7 +1108,7 @@ describe("classifyPlugin — an unorderable version is assumed current", () => {
|
|
|
1109
1108
|
info({
|
|
1110
1109
|
id: "playground@official",
|
|
1111
1110
|
version: null,
|
|
1112
|
-
projectScope: {
|
|
1111
|
+
projectScope: { installed: true, version: "3ea32df27be7" },
|
|
1113
1112
|
}),
|
|
1114
1113
|
),
|
|
1115
1114
|
);
|
|
@@ -1130,8 +1129,8 @@ describe("classifyPlugin — an unorderable version is assumed current", () => {
|
|
|
1130
1129
|
info({
|
|
1131
1130
|
id: "dev@magus",
|
|
1132
1131
|
version: "4.7.0",
|
|
1133
|
-
userScope: {
|
|
1134
|
-
projectScope: {
|
|
1132
|
+
userScope: { installed: true, version: "unknown" },
|
|
1133
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
1135
1134
|
}),
|
|
1136
1135
|
),
|
|
1137
1136
|
);
|
|
@@ -1140,21 +1139,21 @@ describe("classifyPlugin — an unorderable version is assumed current", () => {
|
|
|
1140
1139
|
});
|
|
1141
1140
|
|
|
1142
1141
|
describe("classifyPlugin — install reasons", () => {
|
|
1143
|
-
test("
|
|
1142
|
+
test("installed with no files anywhere says files missing", () => {
|
|
1144
1143
|
const [item] = planPluginUpdates(
|
|
1145
1144
|
{ "dev@magus": "latest" },
|
|
1146
1145
|
catalog(
|
|
1147
1146
|
info({
|
|
1148
1147
|
id: "dev@magus",
|
|
1149
1148
|
version: "4.7.0",
|
|
1150
|
-
projectScope: {
|
|
1149
|
+
projectScope: { installed: true },
|
|
1151
1150
|
}),
|
|
1152
1151
|
),
|
|
1153
1152
|
);
|
|
1154
1153
|
expect(item).toMatchObject({
|
|
1155
1154
|
action: "install",
|
|
1156
|
-
reason: "
|
|
1157
|
-
note: "
|
|
1155
|
+
reason: "files-missing",
|
|
1156
|
+
note: "files missing",
|
|
1158
1157
|
});
|
|
1159
1158
|
});
|
|
1160
1159
|
|
|
@@ -1176,9 +1175,9 @@ describe("classifyPlugin — beforeVersions records every installed scope", () =
|
|
|
1176
1175
|
info({
|
|
1177
1176
|
id: "dev@magus",
|
|
1178
1177
|
version: "4.7.0",
|
|
1179
|
-
userScope: {
|
|
1180
|
-
projectScope: {
|
|
1181
|
-
localScope: {
|
|
1178
|
+
userScope: { installed: true, version: "4.6.0" },
|
|
1179
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
1180
|
+
localScope: { installed: true },
|
|
1182
1181
|
}),
|
|
1183
1182
|
),
|
|
1184
1183
|
);
|
|
@@ -1242,7 +1241,7 @@ describe("classifyPlugin and planPluginUpdates are the same function", () => {
|
|
|
1242
1241
|
info({
|
|
1243
1242
|
id: "b@magus",
|
|
1244
1243
|
version: "2.0.0",
|
|
1245
|
-
projectScope: {
|
|
1244
|
+
projectScope: { installed: true, version: "1.0.0" },
|
|
1246
1245
|
}),
|
|
1247
1246
|
info({ id: "a@magus", version: "1.0.0" }),
|
|
1248
1247
|
);
|
|
@@ -1259,7 +1258,7 @@ describe("pinForRow — which pin a TUI row is judged against", () => {
|
|
|
1259
1258
|
test("the profile's pin wins, exact or latest", () => {
|
|
1260
1259
|
const i = info({
|
|
1261
1260
|
id: "dev@magus",
|
|
1262
|
-
projectScope: {
|
|
1261
|
+
projectScope: { installed: true, version: "1.0.0" },
|
|
1263
1262
|
});
|
|
1264
1263
|
expect(pinForRow(i, { "dev@magus": "4.6.1" })).toBe("4.6.1");
|
|
1265
1264
|
expect(pinForRow(i, { "dev@magus": "latest" })).toBe("latest");
|
|
@@ -1275,19 +1274,19 @@ describe("pinForRow — which pin a TUI row is judged against", () => {
|
|
|
1275
1274
|
for (const scope of ["userScope", "projectScope", "localScope"] as const) {
|
|
1276
1275
|
const i = info({
|
|
1277
1276
|
id: "dev@magus",
|
|
1278
|
-
[scope]: {
|
|
1277
|
+
[scope]: { installed: true, version: "1.0.0" },
|
|
1279
1278
|
});
|
|
1280
1279
|
expect(pinForRow(i, {})).toBe("latest");
|
|
1281
1280
|
}
|
|
1282
1281
|
});
|
|
1283
1282
|
|
|
1284
|
-
test("undeclared,
|
|
1283
|
+
test("undeclared, files missing is judged against latest", () => {
|
|
1285
1284
|
expect(
|
|
1286
|
-
pinForRow(info({ id: "dev@magus", localScope: {
|
|
1285
|
+
pinForRow(info({ id: "dev@magus", localScope: { installed: true } }), {}),
|
|
1287
1286
|
).toBe("latest");
|
|
1288
1287
|
});
|
|
1289
1288
|
|
|
1290
|
-
test("undeclared and
|
|
1289
|
+
test("undeclared and not installed gets NO status", () => {
|
|
1291
1290
|
// A catalog entry the user is only browsing. `install` would claim the
|
|
1292
1291
|
// profile wants it, which nothing says.
|
|
1293
1292
|
expect(
|
|
@@ -1309,7 +1308,7 @@ describe("classifyPluginRows", () => {
|
|
|
1309
1308
|
info({
|
|
1310
1309
|
id: "installed@magus",
|
|
1311
1310
|
version: "2.0.0",
|
|
1312
|
-
projectScope: {
|
|
1311
|
+
projectScope: { installed: true, version: "1.0.0" },
|
|
1313
1312
|
}),
|
|
1314
1313
|
info({ id: "browse@magus", version: "3.0.0" }),
|
|
1315
1314
|
];
|
|
@@ -1334,7 +1333,7 @@ describe("classifyPluginRows", () => {
|
|
|
1334
1333
|
info({
|
|
1335
1334
|
id: "dev@magus",
|
|
1336
1335
|
version: "4.7.0",
|
|
1337
|
-
projectScope: {
|
|
1336
|
+
projectScope: { installed: true, version: "4.6.1" },
|
|
1338
1337
|
}),
|
|
1339
1338
|
info({ id: "terminal@magus", version: "5.0.1" }),
|
|
1340
1339
|
];
|
|
@@ -1413,7 +1412,7 @@ describe("classifyPlugin — an older version LOADS than the one installed", ()
|
|
|
1413
1412
|
version: "0.5.0",
|
|
1414
1413
|
installedVersion: "0.5.0",
|
|
1415
1414
|
loadedVersion: "0.3.0",
|
|
1416
|
-
projectScope: {
|
|
1415
|
+
projectScope: { installed: true, version: "0.5.0" },
|
|
1417
1416
|
...over,
|
|
1418
1417
|
});
|
|
1419
1418
|
|
|
@@ -1463,7 +1462,7 @@ describe("classifyPlugin — an older version LOADS than the one installed", ()
|
|
|
1463
1462
|
catalog(
|
|
1464
1463
|
madbench({
|
|
1465
1464
|
installedVersion: "0.4.0",
|
|
1466
|
-
projectScope: {
|
|
1465
|
+
projectScope: { installed: true, version: "0.4.0" },
|
|
1467
1466
|
}),
|
|
1468
1467
|
),
|
|
1469
1468
|
);
|
|
@@ -1502,7 +1501,7 @@ describe("classifyPlugin — an older version LOADS than the one installed", ()
|
|
|
1502
1501
|
catalog(
|
|
1503
1502
|
madbench({
|
|
1504
1503
|
installedVersion: "0.4.0",
|
|
1505
|
-
projectScope: {
|
|
1504
|
+
projectScope: { installed: true, version: "0.4.0" },
|
|
1506
1505
|
}),
|
|
1507
1506
|
),
|
|
1508
1507
|
);
|
|
@@ -1631,9 +1630,9 @@ describe("classifyPlugin — an older version LOADS than the one installed", ()
|
|
|
1631
1630
|
version: "0.3.0",
|
|
1632
1631
|
installedVersion: "0.3.0",
|
|
1633
1632
|
loadedVersion: "0.3.0",
|
|
1634
|
-
projectScope: {
|
|
1633
|
+
projectScope: { installed: true, version: "0.3.0" },
|
|
1635
1634
|
// Higher, in a scope this project did not ask for and cannot downgrade.
|
|
1636
|
-
userScope: {
|
|
1635
|
+
userScope: { installed: true, version: "0.5.0" },
|
|
1637
1636
|
...over,
|
|
1638
1637
|
});
|
|
1639
1638
|
|
|
@@ -1721,7 +1720,7 @@ describe("classifyPlugin — an older version LOADS than the one installed", ()
|
|
|
1721
1720
|
version: "7.4.0",
|
|
1722
1721
|
installedVersion: "7.4.0",
|
|
1723
1722
|
loadedVersion: "7.4.0",
|
|
1724
|
-
projectScope: {
|
|
1723
|
+
projectScope: { installed: true, version: "7.4.0" },
|
|
1725
1724
|
}),
|
|
1726
1725
|
),
|
|
1727
1726
|
),
|
|
@@ -106,45 +106,46 @@ describe("isBehind — the question callers actually ask", () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
describe("buildScopeStatus —
|
|
110
|
-
test("
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
// identically to one that was never installed.
|
|
109
|
+
describe("buildScopeStatus — installed is the settings flag", () => {
|
|
110
|
+
test("a registry row with no settings key reports its scope, not installed", () => {
|
|
111
|
+
// A registry row alone never makes Claude Code load a plugin — it can be
|
|
112
|
+
// inherited from another checkout of the same repository.
|
|
114
113
|
const scope = buildScopeStatus({}, { "dev@magus": "7.2.0" }, "dev@magus");
|
|
115
114
|
expect(scope).toBeDefined();
|
|
116
115
|
expect(scope?.version).toBe("7.2.0");
|
|
117
|
-
expect(scope?.
|
|
118
|
-
expect(isInstalledInScope(scope)).toBe(
|
|
116
|
+
expect(scope?.installed).toBe(false);
|
|
117
|
+
expect(isInstalledInScope(scope)).toBe(false);
|
|
119
118
|
});
|
|
120
119
|
|
|
121
|
-
test("
|
|
120
|
+
test("installed with no version is still reported — files missing", () => {
|
|
122
121
|
const scope = buildScopeStatus({ "dev@magus": true }, {}, "dev@magus");
|
|
123
122
|
expect(scope).toBeDefined();
|
|
124
|
-
expect(scope?.
|
|
123
|
+
expect(scope?.installed).toBe(true);
|
|
125
124
|
expect(scope?.version).toBeUndefined();
|
|
126
|
-
expect(isInstalledInScope(scope)).toBe(
|
|
125
|
+
expect(isInstalledInScope(scope)).toBe(true);
|
|
127
126
|
});
|
|
128
127
|
|
|
129
|
-
test("neither
|
|
128
|
+
test("neither a settings key nor a registry row has no scope at all", () => {
|
|
130
129
|
expect(buildScopeStatus({}, {}, "dev@magus")).toBeUndefined();
|
|
131
130
|
});
|
|
132
131
|
});
|
|
133
132
|
|
|
134
|
-
describe("isInstalledInScope —
|
|
135
|
-
test("
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
describe("isInstalledInScope — the settings flag, not a registry row", () => {
|
|
134
|
+
test("a registry version with the flag off is not installed", () => {
|
|
135
|
+
expect(isInstalledInScope({ installed: false, version: "7.2.0" })).toBe(
|
|
136
|
+
false,
|
|
137
|
+
);
|
|
139
138
|
});
|
|
140
139
|
|
|
141
140
|
test("the 0.0.0 sentinel counts as installed", () => {
|
|
142
|
-
expect(isInstalledInScope({
|
|
141
|
+
expect(isInstalledInScope({ installed: true, version: "0.0.0" })).toBe(
|
|
142
|
+
true,
|
|
143
|
+
);
|
|
143
144
|
});
|
|
144
145
|
|
|
145
|
-
test("
|
|
146
|
-
expect(isInstalledInScope({
|
|
147
|
-
|
|
146
|
+
test("installed with no version is installed — files missing", () => {
|
|
147
|
+
expect(isInstalledInScope({ installed: true, version: undefined })).toBe(
|
|
148
|
+
true,
|
|
148
149
|
);
|
|
149
150
|
});
|
|
150
151
|
});
|
|
@@ -157,7 +158,6 @@ const info = (over: Partial<PluginInfo>): PluginInfo =>
|
|
|
157
158
|
description: "",
|
|
158
159
|
marketplace: "magus",
|
|
159
160
|
marketplaceDisplay: "Magus",
|
|
160
|
-
enabled: true,
|
|
161
161
|
...over,
|
|
162
162
|
}) as PluginInfo;
|
|
163
163
|
|
|
@@ -265,7 +265,7 @@ describe("REVIEW-B regressions — found by the patch-quality panel", () => {
|
|
|
265
265
|
info({
|
|
266
266
|
id: "playground@official",
|
|
267
267
|
version: "7.3.0",
|
|
268
|
-
projectScope: {
|
|
268
|
+
projectScope: { installed: true, version: "unknown" },
|
|
269
269
|
}),
|
|
270
270
|
],
|
|
271
271
|
]),
|
|
@@ -286,7 +286,7 @@ describe("REVIEW-B regressions — found by the patch-quality panel", () => {
|
|
|
286
286
|
info({
|
|
287
287
|
id: "dev@magus",
|
|
288
288
|
version: "7.3.0",
|
|
289
|
-
projectScope: {
|
|
289
|
+
projectScope: { installed: true, version: "7.3.0" },
|
|
290
290
|
}),
|
|
291
291
|
],
|
|
292
292
|
]),
|
|
@@ -297,26 +297,25 @@ describe("REVIEW-B regressions — found by the patch-quality panel", () => {
|
|
|
297
297
|
});
|
|
298
298
|
|
|
299
299
|
describe("resolveScopeAction — the scope key must never silently uninstall", () => {
|
|
300
|
-
test("
|
|
300
|
+
test("a registry row that is not installed resolves to install, not uninstall", () => {
|
|
301
301
|
// The hazard: the scope key runs cliUninstallPlugin with no confirmation.
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
// switched off would delete it.
|
|
302
|
+
// A registry row with the settings flag off is not installed here, so the
|
|
303
|
+
// key must add it, never delete it.
|
|
305
304
|
expect(
|
|
306
|
-
resolveScopeAction({
|
|
305
|
+
resolveScopeAction({ installed: false, version: "3.0.2" }, false),
|
|
307
306
|
).toBe("install");
|
|
308
307
|
});
|
|
309
308
|
|
|
310
|
-
test("installed
|
|
311
|
-
expect(
|
|
312
|
-
"
|
|
313
|
-
);
|
|
309
|
+
test("installed at the latest version still offers uninstall", () => {
|
|
310
|
+
expect(
|
|
311
|
+
resolveScopeAction({ installed: true, version: "3.0.2" }, false),
|
|
312
|
+
).toBe("uninstall");
|
|
314
313
|
});
|
|
315
314
|
|
|
316
|
-
test("installed
|
|
317
|
-
expect(
|
|
318
|
-
"
|
|
319
|
-
);
|
|
315
|
+
test("installed and behind still offers update", () => {
|
|
316
|
+
expect(
|
|
317
|
+
resolveScopeAction({ installed: true, version: "3.0.1" }, true),
|
|
318
|
+
).toBe("update");
|
|
320
319
|
});
|
|
321
320
|
|
|
322
321
|
test("not installed at all resolves to install", () => {
|
|
@@ -338,7 +337,7 @@ describe("installed with no comparable catalog version — two different causes"
|
|
|
338
337
|
info({
|
|
339
338
|
id: "feature-dev@official",
|
|
340
339
|
version: null,
|
|
341
|
-
projectScope: {
|
|
340
|
+
projectScope: { installed: true, version: "3ea32df27be7" },
|
|
342
341
|
}),
|
|
343
342
|
],
|
|
344
343
|
]),
|
|
@@ -362,7 +361,7 @@ describe("installed with no comparable catalog version — two different causes"
|
|
|
362
361
|
info({
|
|
363
362
|
id: "other@magus",
|
|
364
363
|
version: "1.0.0",
|
|
365
|
-
projectScope: {
|
|
364
|
+
projectScope: { installed: true, version: "1.0.0" },
|
|
366
365
|
}),
|
|
367
366
|
],
|
|
368
367
|
]),
|
|
@@ -392,7 +391,7 @@ describe('the "0.0.0" registry value keeps its reason', () => {
|
|
|
392
391
|
info({
|
|
393
392
|
id: "explanatory-output-style@official",
|
|
394
393
|
version: null,
|
|
395
|
-
projectScope: {
|
|
394
|
+
projectScope: { installed: true, version: "0.0.0" },
|
|
396
395
|
}),
|
|
397
396
|
],
|
|
398
397
|
]),
|