claudeup 4.19.0 → 4.22.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/bin/claudeup.js +43 -19
- package/package.json +14 -19
- package/scripts/build-binaries.ts +77 -0
- package/scripts/check-optional-deps.ts +49 -0
- package/scripts/test-isolated.ts +43 -0
- package/src/__tests__/cli-router.test.ts +65 -0
- package/src/__tests__/conventions-integration.test.ts +745 -0
- package/src/__tests__/conventions-manager.test.ts +1172 -0
- package/src/__tests__/doctor-bins.test.ts +35 -0
- package/src/__tests__/doctor.test.ts +450 -0
- package/src/__tests__/dual-write-prevention.test.ts +14 -4
- package/src/__tests__/file-locking.test.ts +208 -0
- package/src/__tests__/gitignore-prerun.test.ts +1 -0
- package/src/__tests__/install-command.test.ts +81 -0
- package/src/__tests__/install-plan.test.ts +98 -0
- package/src/__tests__/manifest.test.ts +136 -0
- package/src/__tests__/marketplace-refresh.test.ts +267 -0
- package/src/__tests__/plugin-requires.test.ts +133 -0
- package/src/__tests__/plugin-setup.test.ts +7 -0
- package/src/__tests__/profile-command.test.ts +116 -0
- package/src/__tests__/profile-materializer.test.ts +82 -0
- package/src/__tests__/profile-sync.test.ts +136 -0
- package/src/__tests__/registry-version-resolution.test.ts +74 -0
- package/src/__tests__/resolve-executable.test.ts +42 -0
- package/src/__tests__/resolver.test.ts +218 -0
- package/src/__tests__/symlink-manager.test.ts +99 -0
- package/src/__tests__/toolchain.test.ts +56 -0
- package/src/cli/claude.ts +21 -0
- package/src/cli/doctor.ts +132 -0
- package/src/cli/install.ts +360 -0
- package/src/cli/profile.ts +166 -0
- package/src/cli/router.ts +107 -0
- package/src/cli/update.ts +85 -0
- package/src/data/cli-tools.ts +7 -7
- package/src/data/gitignore-defaults.ts +4 -0
- package/src/data/marketplaces.ts +12 -0
- package/src/data/predefined-profiles.ts +3 -4
- package/src/main.tsx +11 -154
- package/src/prerunner/index.ts +62 -27
- package/src/services/claude-cli.ts +19 -22
- package/src/services/claude-settings.ts +99 -26
- package/src/services/conventions-manager.ts +865 -0
- package/src/services/doctor-bins.ts +49 -0
- package/src/services/doctor.ts +509 -0
- package/src/services/install-plan.ts +107 -0
- package/src/services/manifest.ts +166 -0
- package/src/services/marketplace-refresh.ts +173 -0
- package/src/services/plugin-manager.ts +7 -1
- package/src/services/plugin-requires.ts +215 -0
- package/src/services/plugin-version-check.ts +9 -4
- package/src/services/profile-materializer.ts +61 -0
- package/src/services/profile-sync.ts +150 -0
- package/src/services/resolver.ts +293 -0
- package/src/services/symlink-manager.ts +146 -0
- package/src/services/toolchain.ts +97 -0
- package/src/services/version-check.ts +10 -11
- package/src/types/index.ts +138 -31
- package/src/ui/App.tsx +0 -4
- package/src/ui/screens/CliToolsScreen.tsx +11 -3
- package/src/ui/screens/index.ts +0 -1
- package/src/ui/state/reducer.ts +0 -101
- package/src/ui/state/types.ts +0 -35
- package/src/utils/command-utils.ts +23 -0
- package/src/utils/file-locking.ts +144 -0
- package/src/data/alias-flags.js +0 -205
- package/src/data/cli-tools.js +0 -123
- package/src/data/gitignore-defaults.js +0 -24
- package/src/data/gitignore-reasons.js +0 -97
- package/src/data/gitignore-templates.js +0 -21
- package/src/data/marketplaces.js +0 -138
- package/src/data/mcp-servers.js +0 -509
- package/src/data/predefined-profiles.js +0 -248
- package/src/data/settings-catalog.js +0 -625
- package/src/data/skill-repos.js +0 -160
- package/src/data/statuslines.js +0 -159
- package/src/data/statuslines.ts +0 -188
- package/src/index.js +0 -4
- package/src/index.ts +0 -5
- package/src/main.js +0 -170
- package/src/prerunner/index.js +0 -252
- package/src/services/alias-settings.js +0 -51
- package/src/services/alias-shell-writer.js +0 -1018
- package/src/services/alias-store.js +0 -129
- package/src/services/claude-cli.js +0 -189
- package/src/services/claude-runner.js +0 -28
- package/src/services/claude-settings.js +0 -1223
- package/src/services/gitignore-detector.js +0 -155
- package/src/services/gitignore-fixer.js +0 -231
- package/src/services/gitignore-prerun.js +0 -46
- package/src/services/gitignore-resolver.js +0 -143
- package/src/services/gitignore-service.js +0 -117
- package/src/services/local-marketplace.js +0 -339
- package/src/services/marketplace-fetcher.js +0 -96
- package/src/services/marketplace-sync.js +0 -94
- package/src/services/mcp-registry.js +0 -87
- package/src/services/plugin-manager.js +0 -473
- package/src/services/plugin-mcp-config.js +0 -177
- package/src/services/plugin-setup.js +0 -499
- package/src/services/plugin-version-check.js +0 -262
- package/src/services/profiles.js +0 -161
- package/src/services/settings-manager.js +0 -243
- package/src/services/skills-manager.js +0 -393
- package/src/services/skillsmp-client.js +0 -87
- package/src/services/update-cache.js +0 -52
- package/src/services/version-check.js +0 -99
- package/src/types/gitignore.js +0 -6
- package/src/types/index.js +0 -1
- package/src/ui/App.js +0 -355
- package/src/ui/adapters/pluginsAdapter.js +0 -139
- package/src/ui/adapters/settingsAdapter.js +0 -111
- package/src/ui/adapters/skillsAdapter.js +0 -154
- package/src/ui/components/CategoryHeader.js +0 -9
- package/src/ui/components/EmptyFilterState.js +0 -4
- package/src/ui/components/FlagDetailEditor.js +0 -0
- package/src/ui/components/ScopeIndicator.js +0 -30
- package/src/ui/components/ScrollableList.js +0 -36
- package/src/ui/components/SearchInput.js +0 -19
- package/src/ui/components/StyledText.js +0 -39
- package/src/ui/components/TabBar.js +0 -19
- package/src/ui/components/layout/FooterHints.js +0 -29
- package/src/ui/components/layout/Panel.js +0 -6
- package/src/ui/components/layout/ProgressBar.js +0 -14
- package/src/ui/components/layout/ScopeTabs.js +0 -6
- package/src/ui/components/layout/ScreenLayout.js +0 -16
- package/src/ui/components/layout/index.js +0 -5
- package/src/ui/components/modals/ConfirmModal.js +0 -14
- package/src/ui/components/modals/InputModal.js +0 -5
- package/src/ui/components/modals/LoadingModal.js +0 -17
- package/src/ui/components/modals/MessageModal.js +0 -16
- package/src/ui/components/modals/ModalContainer.js +0 -137
- package/src/ui/components/modals/SelectModal.js +0 -18
- package/src/ui/components/modals/VersionMismatchModal.js +0 -36
- package/src/ui/components/modals/index.js +0 -6
- package/src/ui/components/primitives/ActionHints.js +0 -13
- package/src/ui/components/primitives/DetailSection.js +0 -7
- package/src/ui/components/primitives/KeyValueLine.js +0 -8
- package/src/ui/components/primitives/ListCategoryRow.js +0 -8
- package/src/ui/components/primitives/MetaText.js +0 -8
- package/src/ui/components/primitives/ScopeDetail.js +0 -32
- package/src/ui/components/primitives/ScopeSquares.js +0 -11
- package/src/ui/components/primitives/SelectableRow.js +0 -5
- package/src/ui/components/primitives/index.js +0 -8
- package/src/ui/hooks/index.js +0 -4
- package/src/ui/hooks/useAsyncData.js +0 -77
- package/src/ui/hooks/useGitignoreModal.js +0 -74
- package/src/ui/hooks/useKeyboard.js +0 -13
- package/src/ui/hooks/useKeyboardHandler.js +0 -39
- package/src/ui/hooks/useMismatchModal.js +0 -77
- package/src/ui/registry.js +0 -1
- package/src/ui/renderers/cliToolRenderers.js +0 -54
- package/src/ui/renderers/gitignoreRenderers.js +0 -46
- package/src/ui/renderers/mcpRenderers.js +0 -26
- package/src/ui/renderers/pluginRenderers.js +0 -124
- package/src/ui/renderers/profileRenderers.js +0 -177
- package/src/ui/renderers/settingsRenderers.js +0 -73
- package/src/ui/renderers/skillRenderers.js +0 -138
- package/src/ui/screens/AliasScreen.js +0 -1111
- package/src/ui/screens/CliToolsScreen.js +0 -338
- package/src/ui/screens/EnvVarsScreen.js +0 -152
- package/src/ui/screens/GitignoreScreen.js +0 -328
- package/src/ui/screens/McpRegistryScreen.js +0 -238
- package/src/ui/screens/McpScreen.js +0 -176
- package/src/ui/screens/ModelSelectorScreen.js +0 -296
- package/src/ui/screens/ModelSelectorScreen.tsx +0 -444
- package/src/ui/screens/PluginsScreen.js +0 -769
- package/src/ui/screens/ProfilesScreen.js +0 -298
- package/src/ui/screens/SkillsScreen.js +0 -549
- package/src/ui/screens/StatusLineScreen.js +0 -206
- package/src/ui/screens/StatusLineScreen.tsx +0 -416
- package/src/ui/screens/index.js +0 -10
- package/src/ui/state/AnimationContext.js +0 -34
- package/src/ui/state/AppContext.js +0 -162
- package/src/ui/state/DimensionsContext.js +0 -71
- package/src/ui/state/reducer.js +0 -547
- package/src/ui/state/types.js +0 -1
- package/src/ui/theme.js +0 -47
- package/src/utils/clipboard.js +0 -56
- package/src/utils/command-utils.js +0 -19
- package/src/utils/fuzzy-search.js +0 -101
- package/src/utils/string-utils.js +0 -62
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claudeup subcommand router.
|
|
3
|
+
*
|
|
4
|
+
* Parses argv and dispatches to a command handler. Commands run to completion
|
|
5
|
+
* and return an exit code; bare invocation (or an unknown token) falls through
|
|
6
|
+
* to the interactive TUI, preserving claudeup's historical behavior.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { checkForUpdates } from "../services/version-check.js";
|
|
10
|
+
import { runClaudeCommand } from "./claude.js";
|
|
11
|
+
import { runUpdateCommand } from "./update.js";
|
|
12
|
+
import { runInstallCommand } from "./install.js";
|
|
13
|
+
import { runProfileCommand } from "./profile.js";
|
|
14
|
+
import { runDoctorCommand } from "./doctor.js";
|
|
15
|
+
|
|
16
|
+
export interface RouteOutcome {
|
|
17
|
+
/** A subcommand (or top-level flag) handled the invocation. */
|
|
18
|
+
handled: boolean;
|
|
19
|
+
/** Exit code to use when `handled` is true. */
|
|
20
|
+
exitCode?: number;
|
|
21
|
+
/** No subcommand matched — the caller should launch the TUI. */
|
|
22
|
+
launchTui: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const HANDLED = (exitCode: number): RouteOutcome => ({
|
|
26
|
+
handled: true,
|
|
27
|
+
exitCode,
|
|
28
|
+
launchTui: false,
|
|
29
|
+
});
|
|
30
|
+
const LAUNCH_TUI: RouteOutcome = { handled: false, launchTui: true };
|
|
31
|
+
|
|
32
|
+
export async function route(
|
|
33
|
+
argv: string[],
|
|
34
|
+
version: string,
|
|
35
|
+
): Promise<RouteOutcome> {
|
|
36
|
+
// Top-level flags take precedence over any command token.
|
|
37
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
38
|
+
console.log(`claudeup v${version}`);
|
|
39
|
+
const result = await checkForUpdates();
|
|
40
|
+
if (result.updateAvailable) {
|
|
41
|
+
console.log(`\nUpdate available: v${result.latestVersion}`);
|
|
42
|
+
console.log("Run: claudeup update");
|
|
43
|
+
}
|
|
44
|
+
return HANDLED(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
48
|
+
printHelp(version);
|
|
49
|
+
return HANDLED(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const [command, ...rest] = argv;
|
|
53
|
+
|
|
54
|
+
switch (command) {
|
|
55
|
+
case "claude":
|
|
56
|
+
return HANDLED(await runClaudeCommand(rest));
|
|
57
|
+
case "update":
|
|
58
|
+
return HANDLED(await runUpdateCommand());
|
|
59
|
+
case "install":
|
|
60
|
+
return HANDLED(await runInstallCommand(rest));
|
|
61
|
+
case "profile":
|
|
62
|
+
return HANDLED(await runProfileCommand(rest));
|
|
63
|
+
case "doctor":
|
|
64
|
+
return HANDLED(await runDoctorCommand(rest));
|
|
65
|
+
default:
|
|
66
|
+
// Bare `claudeup` or an unrecognized token → interactive TUI.
|
|
67
|
+
return LAUNCH_TUI;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function printHelp(version: string): void {
|
|
72
|
+
console.log(`claudeup v${version}
|
|
73
|
+
|
|
74
|
+
TUI tool for managing Claude Code plugins, MCPs, and configuration.
|
|
75
|
+
|
|
76
|
+
Usage: claudeup [options]
|
|
77
|
+
claudeup claude [args...] Run claude with auto-update prerunner
|
|
78
|
+
claudeup update Update claudeup to latest version
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
-v, --version Show version and check for updates
|
|
82
|
+
-h, --help Show this help message
|
|
83
|
+
--no-refresh Skip auto-refresh of marketplaces on startup
|
|
84
|
+
|
|
85
|
+
Commands:
|
|
86
|
+
claude [args...] Check for plugin updates (1h cache), then run claude
|
|
87
|
+
-f, --force Force update check (bypass 1h cache)
|
|
88
|
+
update Update claudeup itself to latest version
|
|
89
|
+
|
|
90
|
+
Experimental (in development):
|
|
91
|
+
install [profile] Install a team profile from .claude/profiles.json
|
|
92
|
+
profile <cmd> list | show | switch | sync team profiles
|
|
93
|
+
doctor Diagnose & repair plugin/marketplace/profile state
|
|
94
|
+
|
|
95
|
+
Navigation (TUI):
|
|
96
|
+
[1] Plugins [4] Settings [7] Git State
|
|
97
|
+
[2] Skills [5] Profiles [8] Alias
|
|
98
|
+
[3] MCP [6] CLI Tools
|
|
99
|
+
|
|
100
|
+
Keys:
|
|
101
|
+
↑/↓ or j/k Navigate
|
|
102
|
+
Enter Select / Toggle
|
|
103
|
+
r Refresh current screen
|
|
104
|
+
? Show help
|
|
105
|
+
q / Escape Back / Quit
|
|
106
|
+
`);
|
|
107
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `claudeup update` — self-update.
|
|
3
|
+
*
|
|
4
|
+
* Detects claudeup installs across bun + npm global, warns on duplicates
|
|
5
|
+
* (active vs shadowed), then re-installs `claudeup@latest` with whichever
|
|
6
|
+
* package manager owns the active binary. Resolves with the child's exit code.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
|
|
11
|
+
export async function runUpdateCommand(): Promise<number> {
|
|
12
|
+
const { execSync } = await import("node:child_process");
|
|
13
|
+
const { existsSync } = await import("node:fs");
|
|
14
|
+
|
|
15
|
+
// Detect all installations of claudeup across package managers
|
|
16
|
+
const installations: Array<{ manager: "bun" | "npm"; path: string }> = [];
|
|
17
|
+
|
|
18
|
+
// Check bun global
|
|
19
|
+
try {
|
|
20
|
+
const bunGlobalBin = execSync("bun pm -g bin", {
|
|
21
|
+
encoding: "utf-8",
|
|
22
|
+
timeout: 5000,
|
|
23
|
+
}).trim();
|
|
24
|
+
const bunPath = `${bunGlobalBin}/claudeup`;
|
|
25
|
+
if (existsSync(bunPath)) installations.push({ manager: "bun", path: bunPath });
|
|
26
|
+
} catch {
|
|
27
|
+
// bun not installed or no global claudeup
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check npm global
|
|
31
|
+
try {
|
|
32
|
+
const npmPrefix = execSync("npm prefix -g", {
|
|
33
|
+
encoding: "utf-8",
|
|
34
|
+
timeout: 5000,
|
|
35
|
+
}).trim();
|
|
36
|
+
const npmPath = `${npmPrefix}/bin/claudeup`;
|
|
37
|
+
if (existsSync(npmPath)) installations.push({ manager: "npm", path: npmPath });
|
|
38
|
+
} catch {
|
|
39
|
+
// npm not installed or no global claudeup
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Warn about duplicate installations
|
|
43
|
+
if (installations.length > 1) {
|
|
44
|
+
const activePath = execSync("which claudeup", {
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
timeout: 5000,
|
|
47
|
+
}).trim();
|
|
48
|
+
|
|
49
|
+
console.log(`⚠ claudeup is installed via multiple package managers:\n`);
|
|
50
|
+
for (const inst of installations) {
|
|
51
|
+
const tag = inst.path === activePath ? " (active)" : " (shadowed)";
|
|
52
|
+
console.log(` ${inst.manager}: ${inst.path}${tag}`);
|
|
53
|
+
}
|
|
54
|
+
console.log(`\nTo fix, keep one and remove the other:`);
|
|
55
|
+
for (const inst of installations) {
|
|
56
|
+
console.log(` ${inst.manager} uninstall -g claudeup`);
|
|
57
|
+
}
|
|
58
|
+
console.log();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Determine which package manager to use for the update
|
|
62
|
+
let usesBun = false;
|
|
63
|
+
try {
|
|
64
|
+
const claudeupPath = execSync("which claudeup", {
|
|
65
|
+
encoding: "utf-8",
|
|
66
|
+
}).trim();
|
|
67
|
+
usesBun = claudeupPath.includes(".bun") || claudeupPath.includes("bun/bin");
|
|
68
|
+
} catch {
|
|
69
|
+
// If which fails, default to npm
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const pkgManager = usesBun ? "bun" : "npm";
|
|
73
|
+
console.log(`Updating claudeup using ${pkgManager}...`);
|
|
74
|
+
|
|
75
|
+
const installArgs = ["install", "-g", "claudeup@latest"];
|
|
76
|
+
|
|
77
|
+
return new Promise<number>((resolve) => {
|
|
78
|
+
const proc = spawn(pkgManager, installArgs, {
|
|
79
|
+
stdio: "inherit",
|
|
80
|
+
shell: false, // Avoid shell for security (fixes DEP0190 warning)
|
|
81
|
+
});
|
|
82
|
+
proc.on("exit", (code) => resolve(code ?? 0));
|
|
83
|
+
proc.on("error", () => resolve(1));
|
|
84
|
+
});
|
|
85
|
+
}
|
package/src/data/cli-tools.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface CliTool {
|
|
|
6
6
|
checkCommand: string;
|
|
7
7
|
website: string;
|
|
8
8
|
category: "ai-coding" | "utility";
|
|
9
|
-
packageManager: "npm" | "pip";
|
|
9
|
+
packageManager: "bun" | "npm" | "pip" | "brew" | "go";
|
|
10
10
|
packageName: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -16,11 +16,11 @@ export const cliTools: CliTool[] = [
|
|
|
16
16
|
displayName: "claudeup",
|
|
17
17
|
description:
|
|
18
18
|
"TUI tool for managing Claude Code plugins, MCPs, and configuration",
|
|
19
|
-
installCommand: "
|
|
19
|
+
installCommand: "bun install -g claudeup",
|
|
20
20
|
checkCommand: "claudeup --version",
|
|
21
21
|
website: "https://github.com/MadAppGang/magus/tree/main/tools/claudeup",
|
|
22
22
|
category: "ai-coding",
|
|
23
|
-
packageManager: "
|
|
23
|
+
packageManager: "bun",
|
|
24
24
|
packageName: "claudeup",
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -28,22 +28,22 @@ export const cliTools: CliTool[] = [
|
|
|
28
28
|
displayName: "Mnemex",
|
|
29
29
|
description:
|
|
30
30
|
"AST-aware code search with PageRank, callers/callees, and semantic embeddings",
|
|
31
|
-
installCommand: "
|
|
31
|
+
installCommand: "bun install -g mnemex",
|
|
32
32
|
checkCommand: "mnemex --version",
|
|
33
33
|
website: "https://github.com/MadAppGang/mnemex",
|
|
34
34
|
category: "ai-coding",
|
|
35
|
-
packageManager: "
|
|
35
|
+
packageManager: "bun",
|
|
36
36
|
packageName: "mnemex",
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
name: "claudish",
|
|
40
40
|
displayName: "Claudish",
|
|
41
41
|
description: "Run Claude Code with OpenRouter models (Grok, GPT-5, Gemini)",
|
|
42
|
-
installCommand: "
|
|
42
|
+
installCommand: "bun install -g claudish",
|
|
43
43
|
checkCommand: "claudish --version",
|
|
44
44
|
website: "https://github.com/MadAppGang/claudish",
|
|
45
45
|
category: "ai-coding",
|
|
46
|
-
packageManager: "
|
|
46
|
+
packageManager: "bun",
|
|
47
47
|
packageName: "claudish",
|
|
48
48
|
},
|
|
49
49
|
{
|
|
@@ -12,6 +12,8 @@ export const BUILTIN_DEFAULTS: GitignoreManifest = {
|
|
|
12
12
|
".claude/scheduled_tasks.lock",
|
|
13
13
|
".claude/cache/",
|
|
14
14
|
".claude/.statusline-worktree-*",
|
|
15
|
+
// Generated, per-developer profile build output (like node_modules).
|
|
16
|
+
".claude/_profiles/",
|
|
15
17
|
"ai-docs/sessions/",
|
|
16
18
|
".mnemex/",
|
|
17
19
|
".claudemem/",
|
|
@@ -19,6 +21,8 @@ export const BUILTIN_DEFAULTS: GitignoreManifest = {
|
|
|
19
21
|
".agents/",
|
|
20
22
|
],
|
|
21
23
|
track: [
|
|
24
|
+
// The committed team source of truth when using profiles.
|
|
25
|
+
".claude/profiles.json",
|
|
22
26
|
".claude/settings.json",
|
|
23
27
|
".mcp.json",
|
|
24
28
|
"plugin.json",
|
package/src/data/marketplaces.ts
CHANGED
|
@@ -39,6 +39,18 @@ export const defaultMarketplaces: Marketplace[] = [
|
|
|
39
39
|
official: false,
|
|
40
40
|
featured: true, // Always show plugins (expanded by default)
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
name: "magus-marketing",
|
|
44
|
+
displayName: "Magus Marketing",
|
|
45
|
+
source: {
|
|
46
|
+
source: "github",
|
|
47
|
+
repo: "MadAppGang/magus-marketing",
|
|
48
|
+
},
|
|
49
|
+
description:
|
|
50
|
+
"SEO, cold email outreach, AI image generation, and video editing plugins",
|
|
51
|
+
official: false,
|
|
52
|
+
// Not featured: a niche channel, so keep it collapsed by default.
|
|
53
|
+
},
|
|
42
54
|
{
|
|
43
55
|
name: "claude-plugins-official",
|
|
44
56
|
displayName: "Anthropic Official",
|
|
@@ -127,7 +127,6 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
127
127
|
"code-analysis",
|
|
128
128
|
"terminal",
|
|
129
129
|
"statusline",
|
|
130
|
-
"conductor",
|
|
131
130
|
"multimodel",
|
|
132
131
|
"gtd",
|
|
133
132
|
],
|
|
@@ -200,10 +199,10 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
200
199
|
"code-analysis",
|
|
201
200
|
"terminal",
|
|
202
201
|
"statusline",
|
|
203
|
-
"seo",
|
|
202
|
+
"seo@magus-marketing",
|
|
204
203
|
"browser-use",
|
|
205
|
-
"nanobanana",
|
|
206
|
-
"video-editing",
|
|
204
|
+
"nanobanana@magus-marketing",
|
|
205
|
+
"video-editing@magus-marketing",
|
|
207
206
|
],
|
|
208
207
|
anthropicPlugins: [
|
|
209
208
|
"explanatory-output-style",
|
package/src/main.tsx
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import { createCliRenderer } from "@opentui/core";
|
|
4
4
|
import { createRoot } from "@opentui/react";
|
|
5
|
-
import { spawn } from "node:child_process";
|
|
6
|
-
import { createRequire } from "node:module";
|
|
7
5
|
import { App } from "./ui/App.js";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
6
|
+
import { route } from "./cli/router.js";
|
|
7
|
+
// Static import so `bun build --compile` embeds package.json into the binary;
|
|
8
|
+
// a dynamic require("../package.json") is not resolvable inside the bunfs root.
|
|
9
|
+
import pkg from "../package.json";
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
const pkg = require("../package.json") as { version: string };
|
|
13
|
-
export const VERSION = pkg.version;
|
|
11
|
+
export const VERSION = (pkg as { version: string }).version;
|
|
14
12
|
|
|
15
13
|
// Note: OpenTUI renderer handles alternate screen buffer automatically
|
|
16
14
|
// No need for manual ANSI escape codes
|
|
@@ -18,153 +16,12 @@ export const VERSION = pkg.version;
|
|
|
18
16
|
async function main(): Promise<void> {
|
|
19
17
|
const args = process.argv.slice(2);
|
|
20
18
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
claudeArgs.includes("--force") || claudeArgs.includes("-f");
|
|
28
|
-
|
|
29
|
-
// Remove prerunner flags before passing to claude
|
|
30
|
-
const filteredArgs = claudeArgs.filter(
|
|
31
|
-
(arg) => arg !== "--force" && arg !== "-f",
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const exitCode = await prerunClaude(filteredArgs, { force: forceUpdate });
|
|
35
|
-
process.exit(exitCode);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Handle "claudeup update" - self-update command
|
|
40
|
-
if (args[0] === "update") {
|
|
41
|
-
const { execSync } = await import("node:child_process");
|
|
42
|
-
const { existsSync } = await import("node:fs");
|
|
43
|
-
|
|
44
|
-
// Detect all installations of claudeup across package managers
|
|
45
|
-
const installations: Array<{
|
|
46
|
-
manager: "bun" | "npm";
|
|
47
|
-
path: string;
|
|
48
|
-
}> = [];
|
|
49
|
-
|
|
50
|
-
// Check bun global
|
|
51
|
-
try {
|
|
52
|
-
const bunGlobalBin = execSync("bun pm -g bin", {
|
|
53
|
-
encoding: "utf-8",
|
|
54
|
-
timeout: 5000,
|
|
55
|
-
}).trim();
|
|
56
|
-
const bunPath = `${bunGlobalBin}/claudeup`;
|
|
57
|
-
if (existsSync(bunPath)) installations.push({ manager: "bun", path: bunPath });
|
|
58
|
-
} catch {
|
|
59
|
-
// bun not installed or no global claudeup
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Check npm global
|
|
63
|
-
try {
|
|
64
|
-
const npmPrefix = execSync("npm prefix -g", {
|
|
65
|
-
encoding: "utf-8",
|
|
66
|
-
timeout: 5000,
|
|
67
|
-
}).trim();
|
|
68
|
-
const npmPath = `${npmPrefix}/bin/claudeup`;
|
|
69
|
-
if (existsSync(npmPath)) installations.push({ manager: "npm", path: npmPath });
|
|
70
|
-
} catch {
|
|
71
|
-
// npm not installed or no global claudeup
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Warn about duplicate installations
|
|
75
|
-
if (installations.length > 1) {
|
|
76
|
-
const activePath = execSync("which claudeup", {
|
|
77
|
-
encoding: "utf-8",
|
|
78
|
-
timeout: 5000,
|
|
79
|
-
}).trim();
|
|
80
|
-
|
|
81
|
-
console.log(
|
|
82
|
-
`⚠ claudeup is installed via multiple package managers:\n`,
|
|
83
|
-
);
|
|
84
|
-
for (const inst of installations) {
|
|
85
|
-
const tag =
|
|
86
|
-
inst.path === activePath ? " (active)" : " (shadowed)";
|
|
87
|
-
console.log(` ${inst.manager}: ${inst.path}${tag}`);
|
|
88
|
-
}
|
|
89
|
-
console.log(`\nTo fix, keep one and remove the other:`);
|
|
90
|
-
for (const inst of installations) {
|
|
91
|
-
console.log(` ${inst.manager} uninstall -g claudeup`);
|
|
92
|
-
}
|
|
93
|
-
console.log();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Determine which package manager to use for the update
|
|
97
|
-
let usesBun = false;
|
|
98
|
-
try {
|
|
99
|
-
const claudeupPath = execSync("which claudeup", {
|
|
100
|
-
encoding: "utf-8",
|
|
101
|
-
}).trim();
|
|
102
|
-
usesBun =
|
|
103
|
-
claudeupPath.includes(".bun") || claudeupPath.includes("bun/bin");
|
|
104
|
-
} catch {
|
|
105
|
-
// If which fails, default to npm
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const pkgManager = usesBun ? "bun" : "npm";
|
|
109
|
-
console.log(`Updating claudeup using ${pkgManager}...`);
|
|
110
|
-
|
|
111
|
-
const installArgs = ["install", "-g", "claudeup@latest"];
|
|
112
|
-
|
|
113
|
-
const proc = spawn(pkgManager, installArgs, {
|
|
114
|
-
stdio: "inherit",
|
|
115
|
-
shell: false, // Avoid shell for security (fixes DEP0190 warning)
|
|
116
|
-
});
|
|
117
|
-
proc.on("exit", (code) => process.exit(code || 0));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Handle --version flag - show version and check for updates
|
|
122
|
-
if (args.includes("--version") || args.includes("-v")) {
|
|
123
|
-
console.log(`claudeup v${VERSION}`);
|
|
124
|
-
const result = await checkForUpdates();
|
|
125
|
-
if (result.updateAvailable) {
|
|
126
|
-
console.log(`\nUpdate available: v${result.latestVersion}`);
|
|
127
|
-
console.log("Run: claudeup update");
|
|
128
|
-
}
|
|
129
|
-
process.exit(0);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Handle --help flag
|
|
133
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
134
|
-
console.log(`claudeup v${VERSION}
|
|
135
|
-
|
|
136
|
-
TUI tool for managing Claude Code plugins, MCPs, and configuration.
|
|
137
|
-
|
|
138
|
-
Usage: claudeup [options]
|
|
139
|
-
claudeup claude [args...] Run claude with auto-update prerunner
|
|
140
|
-
claudeup update Update claudeup to latest version
|
|
141
|
-
|
|
142
|
-
Options:
|
|
143
|
-
-v, --version Show version and check for updates
|
|
144
|
-
-h, --help Show this help message
|
|
145
|
-
--no-refresh Skip auto-refresh of marketplaces on startup
|
|
146
|
-
|
|
147
|
-
Commands:
|
|
148
|
-
claude [args...] Check for plugin updates (1h cache), then run claude
|
|
149
|
-
-f, --force Force update check (bypass 1h cache)
|
|
150
|
-
update Update claudeup itself to latest version
|
|
151
|
-
|
|
152
|
-
Navigation:
|
|
153
|
-
[1] Plugins Manage plugin marketplaces and installed plugins
|
|
154
|
-
[2] MCP Setup and manage MCP servers
|
|
155
|
-
[3] Status Configure status line display
|
|
156
|
-
[4] Env Environment variables for MCP servers
|
|
157
|
-
[5] Tools Install and update AI coding CLI tools
|
|
158
|
-
|
|
159
|
-
Keys:
|
|
160
|
-
↑/↓ or j/k Navigate
|
|
161
|
-
Enter Select / Toggle
|
|
162
|
-
g Toggle global/project scope (in Plugins)
|
|
163
|
-
r Refresh current screen
|
|
164
|
-
? Show help
|
|
165
|
-
q / Escape Back / Quit
|
|
166
|
-
`);
|
|
167
|
-
process.exit(0);
|
|
19
|
+
// Dispatch non-interactive subcommands (claude, update, install, …) and
|
|
20
|
+
// top-level flags (--version/--help). A bare invocation falls through to
|
|
21
|
+
// the interactive TUI below.
|
|
22
|
+
const outcome = await route(args, VERSION);
|
|
23
|
+
if (outcome.handled) {
|
|
24
|
+
process.exit(outcome.exitCode ?? 0);
|
|
168
25
|
}
|
|
169
26
|
|
|
170
27
|
// Create OpenTUI renderer (handles alternate screen buffer automatically)
|
package/src/prerunner/index.ts
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
import fs from "fs-extra";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import os from "node:os";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
clearMarketplaceCache,
|
|
8
|
-
} from "../services/plugin-manager.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import { isClaudeAvailable, updatePlugin } from "../services/claude-cli.js";
|
|
9
5
|
import { runClaude } from "../services/claude-runner.js";
|
|
10
6
|
import {
|
|
11
|
-
recoverMarketplaceSettings,
|
|
12
|
-
migrateMarketplaceRename,
|
|
13
7
|
cleanupExtraKnownMarketplaces,
|
|
8
|
+
gapFillInstalledPluginVersions,
|
|
9
|
+
migrateMarketplaceRename,
|
|
14
10
|
readGlobalSettings,
|
|
15
|
-
|
|
11
|
+
recoverMarketplaceSettings,
|
|
16
12
|
saveGlobalInstalledPluginVersion,
|
|
17
|
-
|
|
13
|
+
writeGlobalSettings,
|
|
18
14
|
} from "../services/claude-settings.js";
|
|
19
|
-
import {
|
|
20
|
-
checkPluginVersionMismatches,
|
|
21
|
-
formatMismatchWarning,
|
|
22
|
-
} from "../services/plugin-version-check.js";
|
|
23
|
-
import { updatePlugin, isClaudeAvailable } from "../services/claude-cli.js";
|
|
24
|
-
import { autoAddMissingMarketplaces } from "../services/marketplace-sync.js";
|
|
25
15
|
import {
|
|
26
16
|
checkGitignore,
|
|
27
17
|
formatPrerunWarning as formatGitignoreWarning,
|
|
28
18
|
} from "../services/gitignore-prerun.js";
|
|
19
|
+
import { refreshRegisteredMarketplaces } from "../services/marketplace-refresh.js";
|
|
20
|
+
import { autoAddMissingMarketplaces } from "../services/marketplace-sync.js";
|
|
21
|
+
import {
|
|
22
|
+
clearMarketplaceCache,
|
|
23
|
+
getAvailablePlugins,
|
|
24
|
+
} from "../services/plugin-manager.js";
|
|
25
|
+
import {
|
|
26
|
+
checkPluginVersionMismatches,
|
|
27
|
+
formatMismatchWarning,
|
|
28
|
+
} from "../services/plugin-version-check.js";
|
|
29
|
+
import { UpdateCache } from "../services/update-cache.js";
|
|
29
30
|
|
|
30
31
|
export interface PrerunOptions {
|
|
31
32
|
force?: boolean; // Bypass cache and force update check
|
|
@@ -133,9 +134,7 @@ export async function prerunClaude(
|
|
|
133
134
|
// otherwise a freshly cloned repo whose only @magus references live
|
|
134
135
|
// in project settings looks "clean" from the global-scope view.
|
|
135
136
|
if (await isClaudeAvailable()) {
|
|
136
|
-
const addedMarketplaces = await autoAddMissingMarketplaces(
|
|
137
|
-
process.cwd(),
|
|
138
|
-
);
|
|
137
|
+
const addedMarketplaces = await autoAddMissingMarketplaces(process.cwd());
|
|
139
138
|
if (addedMarketplaces.length > 0) {
|
|
140
139
|
console.log(
|
|
141
140
|
`✓ Auto-added marketplace(s): ${addedMarketplaces.join(", ")}`,
|
|
@@ -238,20 +237,40 @@ export async function prerunClaude(
|
|
|
238
237
|
console.log(
|
|
239
238
|
`✓ Re-registered as GitHub source: ${recovery.reregistered.join(", ")}`,
|
|
240
239
|
);
|
|
241
|
-
//
|
|
242
|
-
//
|
|
240
|
+
// Re-registration only rewrites known_marketplaces.json (directory →
|
|
241
|
+
// github source); it does NOT create the on-disk clone. Clone any whose
|
|
242
|
+
// directory is missing, using the NON-DESTRUCTIVE `marketplace add` —
|
|
243
|
+
// never `marketplace update`, which deletes the directory before
|
|
244
|
+
// re-cloning and can leave it permanently gone on failure (see
|
|
245
|
+
// marketplace-refresh.ts / marketplace-sync.ts). Clones that already
|
|
246
|
+
// exist are left to STEP 1.7's safe `git pull --ff-only`.
|
|
243
247
|
const cliAvailable = await isClaudeAvailable();
|
|
244
248
|
if (cliAvailable) {
|
|
245
|
-
const {
|
|
246
|
-
|
|
249
|
+
const { addMarketplace } = await import("../services/claude-cli.js");
|
|
250
|
+
const { defaultMarketplaces } = await import(
|
|
251
|
+
"../data/marketplaces.js"
|
|
252
|
+
);
|
|
253
|
+
const marketplacesDir = path.join(
|
|
254
|
+
os.homedir(),
|
|
255
|
+
".claude",
|
|
256
|
+
"plugins",
|
|
257
|
+
"marketplaces",
|
|
247
258
|
);
|
|
248
259
|
for (const mpName of recovery.reregistered) {
|
|
260
|
+
// Already on disk → STEP 1.7 fast-forwards it; nothing to clone.
|
|
261
|
+
if (await fs.pathExists(path.join(marketplacesDir, mpName))) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const repo = defaultMarketplaces.find(
|
|
265
|
+
(m) => m.name === mpName,
|
|
266
|
+
)?.source.repo;
|
|
267
|
+
if (!repo) continue;
|
|
249
268
|
try {
|
|
250
|
-
await
|
|
251
|
-
console.log(`✓
|
|
269
|
+
await addMarketplace(repo);
|
|
270
|
+
console.log(`✓ Cloned re-registered marketplace: ${mpName}`);
|
|
252
271
|
} catch (error) {
|
|
253
272
|
console.warn(
|
|
254
|
-
`⚠ Failed to
|
|
273
|
+
`⚠ Failed to clone marketplace ${mpName}:`,
|
|
255
274
|
error instanceof Error ? error.message : "Unknown error",
|
|
256
275
|
);
|
|
257
276
|
}
|
|
@@ -259,6 +278,22 @@ export async function prerunClaude(
|
|
|
259
278
|
}
|
|
260
279
|
}
|
|
261
280
|
|
|
281
|
+
// STEP 1.7: Fast-forward the on-disk clones of every registered
|
|
282
|
+
// marketplace. Recovery above only *clones* re-registered ones that were
|
|
283
|
+
// missing; nothing else advances an existing healthy clone, so updated
|
|
284
|
+
// plugin setup metadata — e.g. a pinned dependency version — is never seen
|
|
285
|
+
// even though the fetched plugin list is current. Non-destructive
|
|
286
|
+
// `git pull --ff-only`: a failed pull leaves the clone stale, never gone.
|
|
287
|
+
const mpRefresh = await refreshRegisteredMarketplaces();
|
|
288
|
+
if (mpRefresh.refreshed.length > 0) {
|
|
289
|
+
console.log(
|
|
290
|
+
`✓ Refreshed marketplaces: ${mpRefresh.refreshed.join(", ")}`,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
for (const name of mpRefresh.failed) {
|
|
294
|
+
console.warn(`⚠ Failed to refresh marketplace: ${name}`);
|
|
295
|
+
}
|
|
296
|
+
|
|
262
297
|
// STEP 2: Clear cache to force fresh plugin info
|
|
263
298
|
clearMarketplaceCache();
|
|
264
299
|
|