claudeup 4.11.0 → 4.11.1
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
CHANGED
|
@@ -115,7 +115,7 @@ const {
|
|
|
115
115
|
fixPluginVersionMismatch,
|
|
116
116
|
fixAllPluginVersionMismatches,
|
|
117
117
|
formatMismatchWarning,
|
|
118
|
-
|
|
118
|
+
formatMismatchModal,
|
|
119
119
|
} = await import("../services/plugin-version-check.js");
|
|
120
120
|
|
|
121
121
|
// ── Test suite ───────────────────────────────────────────────────────────────
|
|
@@ -739,8 +739,8 @@ describe("formatMismatchWarning", () => {
|
|
|
739
739
|
});
|
|
740
740
|
});
|
|
741
741
|
|
|
742
|
-
describe("
|
|
743
|
-
it("formats
|
|
742
|
+
describe("formatMismatchModal", () => {
|
|
743
|
+
it("formats modal text with plugin details and bug link", () => {
|
|
744
744
|
const mismatches = [
|
|
745
745
|
{
|
|
746
746
|
pluginId: "terminal@magus",
|
|
@@ -751,10 +751,12 @@ describe("formatMismatchBanner", () => {
|
|
|
751
751
|
},
|
|
752
752
|
];
|
|
753
753
|
|
|
754
|
-
const
|
|
754
|
+
const modal = formatMismatchModal(mismatches);
|
|
755
755
|
|
|
756
|
-
expect(
|
|
757
|
-
expect(
|
|
758
|
-
expect(
|
|
756
|
+
expect(modal).toContain("terminal");
|
|
757
|
+
expect(modal).toContain("v2.0.0");
|
|
758
|
+
expect(modal).toContain("v4.0.2");
|
|
759
|
+
expect(modal).toContain("45997");
|
|
760
|
+
expect(modal).toContain("wrong plugin version");
|
|
759
761
|
});
|
|
760
762
|
});
|
|
@@ -184,11 +184,20 @@ export function formatMismatchWarning(mismatches) {
|
|
|
184
184
|
return lines.join("\n");
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
|
-
* Format mismatch info for TUI display.
|
|
187
|
+
* Format mismatch info for TUI modal display.
|
|
188
|
+
* Returns a multi-line string suitable for a modal message.
|
|
188
189
|
*/
|
|
189
|
-
export function
|
|
190
|
-
const
|
|
191
|
-
|
|
190
|
+
export function formatMismatchModal(mismatches) {
|
|
191
|
+
const lines = [];
|
|
192
|
+
lines.push("Claude Code has a bug where it loads the wrong plugin version.");
|
|
193
|
+
lines.push("It always uses the first entry in the registry, ignoring which");
|
|
194
|
+
lines.push("project you're in. These plugins are affected:\n");
|
|
195
|
+
for (const m of mismatches) {
|
|
196
|
+
const name = m.pluginId.split("@")[0];
|
|
197
|
+
lines.push(` ${name}: will load v${m.firstEntryVersion} instead of v${m.currentProjectVersion}`);
|
|
198
|
+
}
|
|
199
|
+
lines.push(`\nBug: github.com/anthropics/claude-code/issues/45997`);
|
|
200
|
+
return lines.join("\n");
|
|
192
201
|
}
|
|
193
202
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
194
203
|
/**
|
|
@@ -268,16 +268,31 @@ export function formatMismatchWarning(
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
/**
|
|
271
|
-
* Format mismatch info for TUI display.
|
|
271
|
+
* Format mismatch info for TUI modal display.
|
|
272
|
+
* Returns a multi-line string suitable for a modal message.
|
|
272
273
|
*/
|
|
273
|
-
export function
|
|
274
|
+
export function formatMismatchModal(
|
|
274
275
|
mismatches: VersionMismatchInfo[],
|
|
275
276
|
): string {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
const lines: string[] = [];
|
|
278
|
+
lines.push(
|
|
279
|
+
"Claude Code has a bug where it loads the wrong plugin version.",
|
|
280
|
+
);
|
|
281
|
+
lines.push(
|
|
282
|
+
"It always uses the first entry in the registry, ignoring which",
|
|
279
283
|
);
|
|
280
|
-
|
|
284
|
+
lines.push("project you're in. These plugins are affected:\n");
|
|
285
|
+
|
|
286
|
+
for (const m of mismatches) {
|
|
287
|
+
const name = m.pluginId.split("@")[0];
|
|
288
|
+
lines.push(
|
|
289
|
+
` ${name}: will load v${m.firstEntryVersion} instead of v${m.currentProjectVersion}`,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
lines.push(`\nBug: github.com/anthropics/claude-code/issues/45997`);
|
|
294
|
+
|
|
295
|
+
return lines.join("\n");
|
|
281
296
|
}
|
|
282
297
|
|
|
283
298
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
package/src/ui/App.js
CHANGED
|
@@ -8,7 +8,7 @@ import { ModalContainer } from "./components/modals/index.js";
|
|
|
8
8
|
import { PluginsScreen, McpScreen, McpRegistryScreen, SettingsScreen, CliToolsScreen, ModelSelectorScreen, ProfilesScreen, SkillsScreen, } from "./screens/index.js";
|
|
9
9
|
import { repairAllMarketplaces } from "../services/local-marketplace.js";
|
|
10
10
|
import { migrateMarketplaceRename, recoverMarketplaceSettings, } from "../services/claude-settings.js";
|
|
11
|
-
import { checkPluginVersionMismatches,
|
|
11
|
+
import { checkPluginVersionMismatches, fixAllPluginVersionMismatches, formatMismatchModal, } from "../services/plugin-version-check.js";
|
|
12
12
|
import { checkForUpdates, getCurrentVersion, } from "../services/version-check.js";
|
|
13
13
|
import { useKeyboardHandler } from "./hooks/useKeyboardHandler.js";
|
|
14
14
|
import { ProgressBar } from "./components/layout/ProgressBar.js";
|
|
@@ -176,11 +176,11 @@ function UpdateBanner({ result }) {
|
|
|
176
176
|
function ProgressIndicator({ message, current, total, }) {
|
|
177
177
|
return (_jsx("box", { paddingLeft: 1, paddingRight: 1, children: _jsx(ProgressBar, { message: message, current: current, total: total }) }));
|
|
178
178
|
}
|
|
179
|
-
function AppContentInner({ showDebug, onDebugToggle, updateInfo, onExit, recoveryReport,
|
|
179
|
+
function AppContentInner({ showDebug, onDebugToggle, updateInfo, onExit, recoveryReport, }) {
|
|
180
180
|
const { state } = useApp();
|
|
181
181
|
const { progress } = state;
|
|
182
182
|
const dimensions = useDimensions();
|
|
183
|
-
return (_jsxs("box", { flexDirection: "column", height: dimensions.terminalHeight, children: [updateInfo?.updateAvailable && _jsx(UpdateBanner, { result: updateInfo }), recoveryReport && (_jsx("box", { paddingLeft: 1, paddingRight: 1, children: _jsxs("text", { fg: "green", children: ["\u2713 Fixed: ", recoveryReport] }) })),
|
|
183
|
+
return (_jsxs("box", { flexDirection: "column", height: dimensions.terminalHeight, children: [updateInfo?.updateAvailable && _jsx(UpdateBanner, { result: updateInfo }), recoveryReport && (_jsx("box", { paddingLeft: 1, paddingRight: 1, children: _jsxs("text", { fg: "green", children: ["\u2713 Fixed: ", recoveryReport] }) })), showDebug && (_jsx("box", { paddingLeft: 1, paddingRight: 1, children: _jsxs("text", { fg: "#888888", children: ["DEBUG: ", dimensions.terminalWidth, "x", dimensions.terminalHeight, " | content=", dimensions.contentHeight, " | screen=", state.currentRoute.screen] }) })), progress && _jsx(ProgressIndicator, { ...progress }), _jsx("box", { flexDirection: "column", height: dimensions.contentHeight, paddingLeft: 1, paddingRight: 1, children: _jsx(Router, {}) }), _jsx(GlobalKeyHandler, { onDebugToggle: onDebugToggle, onExit: onExit }), _jsx(ModalContainer, {})] }));
|
|
184
184
|
}
|
|
185
185
|
function AppContent({ onExit }) {
|
|
186
186
|
const { state, dispatch } = useApp();
|
|
@@ -188,7 +188,7 @@ function AppContent({ onExit }) {
|
|
|
188
188
|
const [showDebug, setShowDebug] = useState(false);
|
|
189
189
|
const [updateInfo, setUpdateInfo] = useState(null);
|
|
190
190
|
const [recoveryReport, setRecoveryReport] = useState(null);
|
|
191
|
-
const [
|
|
191
|
+
const [mismatchData, setMismatchData] = useState(null);
|
|
192
192
|
// Check for updates on startup (non-blocking)
|
|
193
193
|
useEffect(() => {
|
|
194
194
|
checkForUpdates()
|
|
@@ -202,13 +202,72 @@ function AppContent({ onExit }) {
|
|
|
202
202
|
const timer = setTimeout(() => setRecoveryReport(null), 5000);
|
|
203
203
|
return () => clearTimeout(timer);
|
|
204
204
|
}, [recoveryReport]);
|
|
205
|
-
//
|
|
205
|
+
// Show mismatch modal when data arrives
|
|
206
206
|
useEffect(() => {
|
|
207
|
-
if (!
|
|
207
|
+
if (!mismatchData || mismatchData.length === 0)
|
|
208
208
|
return;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
dispatch({
|
|
210
|
+
type: "SHOW_MODAL",
|
|
211
|
+
modal: {
|
|
212
|
+
type: "select",
|
|
213
|
+
title: "⚠ Plugin Version Mismatch",
|
|
214
|
+
message: formatMismatchModal(mismatchData),
|
|
215
|
+
options: [
|
|
216
|
+
{
|
|
217
|
+
label: "Fix all projects",
|
|
218
|
+
value: "fix",
|
|
219
|
+
description: "Align all projects to this project's versions",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
label: "Dismiss",
|
|
223
|
+
value: "dismiss",
|
|
224
|
+
description: "Ignore for now",
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
onSelect: async (value) => {
|
|
228
|
+
dispatch({ type: "HIDE_MODAL" });
|
|
229
|
+
if (value === "fix") {
|
|
230
|
+
dispatch({
|
|
231
|
+
type: "SHOW_PROGRESS",
|
|
232
|
+
state: { message: "Fixing plugin versions..." },
|
|
233
|
+
});
|
|
234
|
+
try {
|
|
235
|
+
await fixAllPluginVersionMismatches(mismatchData);
|
|
236
|
+
dispatch({ type: "HIDE_PROGRESS" });
|
|
237
|
+
dispatch({
|
|
238
|
+
type: "SHOW_MODAL",
|
|
239
|
+
modal: {
|
|
240
|
+
type: "message",
|
|
241
|
+
title: "Fixed",
|
|
242
|
+
message: "All plugin versions aligned. Restart Claude Code for changes to take effect.",
|
|
243
|
+
variant: "success",
|
|
244
|
+
onDismiss: () => dispatch({ type: "HIDE_MODAL" }),
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
dispatch({ type: "HIDE_PROGRESS" });
|
|
250
|
+
dispatch({
|
|
251
|
+
type: "SHOW_MODAL",
|
|
252
|
+
modal: {
|
|
253
|
+
type: "message",
|
|
254
|
+
title: "Error",
|
|
255
|
+
message: "Failed to fix plugin versions. Try running claudeup again.",
|
|
256
|
+
variant: "error",
|
|
257
|
+
onDismiss: () => dispatch({ type: "HIDE_MODAL" }),
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
setMismatchData(null);
|
|
263
|
+
},
|
|
264
|
+
onCancel: () => {
|
|
265
|
+
dispatch({ type: "HIDE_MODAL" });
|
|
266
|
+
setMismatchData(null);
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}, [mismatchData, dispatch]);
|
|
212
271
|
// Auto-refresh marketplaces on startup
|
|
213
272
|
useEffect(() => {
|
|
214
273
|
const noRefresh = process.argv.includes("--no-refresh");
|
|
@@ -252,7 +311,7 @@ function AppContent({ onExit }) {
|
|
|
252
311
|
checkPluginVersionMismatches(process.cwd())
|
|
253
312
|
.then((mismatches) => {
|
|
254
313
|
if (mismatches.length > 0) {
|
|
255
|
-
|
|
314
|
+
setMismatchData(mismatches);
|
|
256
315
|
}
|
|
257
316
|
})
|
|
258
317
|
.catch(() => { }); // non-fatal
|
|
@@ -266,8 +325,8 @@ function AppContent({ onExit }) {
|
|
|
266
325
|
});
|
|
267
326
|
}, [dispatch]);
|
|
268
327
|
// Count transient banners for dimension calculation
|
|
269
|
-
const transientBannerCount =
|
|
270
|
-
return (_jsx(DimensionsProvider, { showProgress: !!progress, showDebug: showDebug, showUpdateBanner: !!updateInfo?.updateAvailable, transientBannerCount: transientBannerCount, children: _jsx(AppContentInner, { showDebug: showDebug, onDebugToggle: () => setShowDebug((s) => !s), updateInfo: updateInfo, onExit: onExit, recoveryReport: recoveryReport
|
|
328
|
+
const transientBannerCount = recoveryReport ? 1 : 0;
|
|
329
|
+
return (_jsx(DimensionsProvider, { showProgress: !!progress, showDebug: showDebug, showUpdateBanner: !!updateInfo?.updateAvailable, transientBannerCount: transientBannerCount, children: _jsx(AppContentInner, { showDebug: showDebug, onDebugToggle: () => setShowDebug((s) => !s), updateInfo: updateInfo, onExit: onExit, recoveryReport: recoveryReport }) }));
|
|
271
330
|
}
|
|
272
331
|
export function App({ onExit }) {
|
|
273
332
|
return (_jsx(AppProvider, { children: _jsx(AppContent, { onExit: onExit }) }));
|
package/src/ui/App.tsx
CHANGED
|
@@ -30,7 +30,9 @@ import {
|
|
|
30
30
|
} from "../services/claude-settings.js";
|
|
31
31
|
import {
|
|
32
32
|
checkPluginVersionMismatches,
|
|
33
|
-
|
|
33
|
+
fixAllPluginVersionMismatches,
|
|
34
|
+
formatMismatchModal,
|
|
35
|
+
type VersionMismatchInfo,
|
|
34
36
|
} from "../services/plugin-version-check.js";
|
|
35
37
|
import {
|
|
36
38
|
checkForUpdates,
|
|
@@ -255,7 +257,6 @@ interface AppContentInnerProps {
|
|
|
255
257
|
updateInfo: VersionCheckResult | null;
|
|
256
258
|
onExit: () => void;
|
|
257
259
|
recoveryReport: string | null;
|
|
258
|
-
mismatchWarning: string | null;
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
function AppContentInner({
|
|
@@ -264,7 +265,6 @@ function AppContentInner({
|
|
|
264
265
|
updateInfo,
|
|
265
266
|
onExit,
|
|
266
267
|
recoveryReport,
|
|
267
|
-
mismatchWarning,
|
|
268
268
|
}: AppContentInnerProps) {
|
|
269
269
|
const { state } = useApp();
|
|
270
270
|
const { progress } = state;
|
|
@@ -278,11 +278,6 @@ function AppContentInner({
|
|
|
278
278
|
<text fg="green">✓ Fixed: {recoveryReport}</text>
|
|
279
279
|
</box>
|
|
280
280
|
)}
|
|
281
|
-
{mismatchWarning && (
|
|
282
|
-
<box paddingLeft={1} paddingRight={1}>
|
|
283
|
-
<text fg="yellow">⚠ {mismatchWarning} (bug #45997)</text>
|
|
284
|
-
</box>
|
|
285
|
-
)}
|
|
286
281
|
{showDebug && (
|
|
287
282
|
<box paddingLeft={1} paddingRight={1}>
|
|
288
283
|
<text fg="#888888">
|
|
@@ -321,7 +316,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
321
316
|
const [showDebug, setShowDebug] = useState(false);
|
|
322
317
|
const [updateInfo, setUpdateInfo] = useState<VersionCheckResult | null>(null);
|
|
323
318
|
const [recoveryReport, setRecoveryReport] = useState<string | null>(null);
|
|
324
|
-
const [
|
|
319
|
+
const [mismatchData, setMismatchData] = useState<VersionMismatchInfo[] | null>(null);
|
|
325
320
|
|
|
326
321
|
// Check for updates on startup (non-blocking)
|
|
327
322
|
useEffect(() => {
|
|
@@ -337,12 +332,71 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
337
332
|
return () => clearTimeout(timer);
|
|
338
333
|
}, [recoveryReport]);
|
|
339
334
|
|
|
340
|
-
//
|
|
335
|
+
// Show mismatch modal when data arrives
|
|
341
336
|
useEffect(() => {
|
|
342
|
-
if (!
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
337
|
+
if (!mismatchData || mismatchData.length === 0) return;
|
|
338
|
+
dispatch({
|
|
339
|
+
type: "SHOW_MODAL",
|
|
340
|
+
modal: {
|
|
341
|
+
type: "select",
|
|
342
|
+
title: "⚠ Plugin Version Mismatch",
|
|
343
|
+
message: formatMismatchModal(mismatchData),
|
|
344
|
+
options: [
|
|
345
|
+
{
|
|
346
|
+
label: "Fix all projects",
|
|
347
|
+
value: "fix",
|
|
348
|
+
description: "Align all projects to this project's versions",
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
label: "Dismiss",
|
|
352
|
+
value: "dismiss",
|
|
353
|
+
description: "Ignore for now",
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
onSelect: async (value: string) => {
|
|
357
|
+
dispatch({ type: "HIDE_MODAL" });
|
|
358
|
+
if (value === "fix") {
|
|
359
|
+
dispatch({
|
|
360
|
+
type: "SHOW_PROGRESS",
|
|
361
|
+
state: { message: "Fixing plugin versions..." },
|
|
362
|
+
});
|
|
363
|
+
try {
|
|
364
|
+
await fixAllPluginVersionMismatches(mismatchData);
|
|
365
|
+
dispatch({ type: "HIDE_PROGRESS" });
|
|
366
|
+
dispatch({
|
|
367
|
+
type: "SHOW_MODAL",
|
|
368
|
+
modal: {
|
|
369
|
+
type: "message",
|
|
370
|
+
title: "Fixed",
|
|
371
|
+
message:
|
|
372
|
+
"All plugin versions aligned. Restart Claude Code for changes to take effect.",
|
|
373
|
+
variant: "success",
|
|
374
|
+
onDismiss: () => dispatch({ type: "HIDE_MODAL" }),
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
} catch {
|
|
378
|
+
dispatch({ type: "HIDE_PROGRESS" });
|
|
379
|
+
dispatch({
|
|
380
|
+
type: "SHOW_MODAL",
|
|
381
|
+
modal: {
|
|
382
|
+
type: "message",
|
|
383
|
+
title: "Error",
|
|
384
|
+
message: "Failed to fix plugin versions. Try running claudeup again.",
|
|
385
|
+
variant: "error",
|
|
386
|
+
onDismiss: () => dispatch({ type: "HIDE_MODAL" }),
|
|
387
|
+
},
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
setMismatchData(null);
|
|
392
|
+
},
|
|
393
|
+
onCancel: () => {
|
|
394
|
+
dispatch({ type: "HIDE_MODAL" });
|
|
395
|
+
setMismatchData(null);
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
}, [mismatchData, dispatch]);
|
|
346
400
|
|
|
347
401
|
// Auto-refresh marketplaces on startup
|
|
348
402
|
useEffect(() => {
|
|
@@ -391,7 +445,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
391
445
|
checkPluginVersionMismatches(process.cwd())
|
|
392
446
|
.then((mismatches) => {
|
|
393
447
|
if (mismatches.length > 0) {
|
|
394
|
-
|
|
448
|
+
setMismatchData(mismatches);
|
|
395
449
|
}
|
|
396
450
|
})
|
|
397
451
|
.catch(() => {}); // non-fatal
|
|
@@ -408,7 +462,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
408
462
|
|
|
409
463
|
// Count transient banners for dimension calculation
|
|
410
464
|
const transientBannerCount =
|
|
411
|
-
|
|
465
|
+
recoveryReport ? 1 : 0;
|
|
412
466
|
|
|
413
467
|
return (
|
|
414
468
|
<DimensionsProvider
|
|
@@ -423,8 +477,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
423
477
|
updateInfo={updateInfo}
|
|
424
478
|
onExit={onExit}
|
|
425
479
|
recoveryReport={recoveryReport}
|
|
426
|
-
|
|
427
|
-
/>
|
|
480
|
+
/>
|
|
428
481
|
</DimensionsProvider>
|
|
429
482
|
);
|
|
430
483
|
}
|