claudeup 4.0.0 → 4.1.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/package.json +1 -1
- package/src/data/cli-tools.ts +1 -2
- package/src/data/marketplaces.js +6 -2
- package/src/data/marketplaces.ts +10 -3
- package/src/data/predefined-profiles.js +69 -12
- package/src/data/predefined-profiles.ts +73 -14
- package/src/prerunner/index.js +71 -7
- package/src/prerunner/index.ts +94 -6
- package/src/services/claude-cli.js +8 -1
- package/src/services/claude-cli.ts +10 -7
- package/src/services/claude-settings.js +28 -11
- package/src/services/claude-settings.ts +47 -18
- package/src/services/plugin-manager.js +40 -4
- package/src/services/plugin-manager.ts +57 -6
- package/src/types/index.ts +33 -0
- package/src/ui/components/ScrollableDetail.js +23 -0
- package/src/ui/components/ScrollableDetail.tsx +55 -0
- package/src/ui/components/layout/ScreenLayout.js +1 -1
- package/src/ui/components/layout/ScreenLayout.tsx +11 -8
- package/src/ui/renderers/profileRenderers.js +15 -10
- package/src/ui/renderers/profileRenderers.tsx +43 -94
package/package.json
CHANGED
package/src/data/cli-tools.ts
CHANGED
|
@@ -18,8 +18,7 @@ export const cliTools: CliTool[] = [
|
|
|
18
18
|
"TUI tool for managing Claude Code plugins, MCPs, and configuration",
|
|
19
19
|
installCommand: "npm install -g claudeup",
|
|
20
20
|
checkCommand: "claudeup --version",
|
|
21
|
-
website:
|
|
22
|
-
"https://github.com/MadAppGang/magus/tree/main/tools/claudeup",
|
|
21
|
+
website: "https://github.com/MadAppGang/magus/tree/main/tools/claudeup",
|
|
23
22
|
category: "ai-coding",
|
|
24
23
|
packageManager: "npm",
|
|
25
24
|
packageName: "claudeup",
|
package/src/data/marketplaces.js
CHANGED
|
@@ -70,7 +70,8 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
70
70
|
const canonical = deprecatedMarketplaces[name];
|
|
71
71
|
if (canonical) {
|
|
72
72
|
// If canonical already in the map or in defaults, skip this entry
|
|
73
|
-
if (all.has(canonical) ||
|
|
73
|
+
if (all.has(canonical) ||
|
|
74
|
+
defaultMarketplaces.some((m) => m.name === canonical)) {
|
|
74
75
|
continue;
|
|
75
76
|
}
|
|
76
77
|
}
|
|
@@ -85,7 +86,10 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
85
86
|
name,
|
|
86
87
|
// Prefer default displayName over stale local clone data
|
|
87
88
|
displayName: defaultMp?.displayName || local.name || formatMarketplaceName(name),
|
|
88
|
-
source: {
|
|
89
|
+
source: {
|
|
90
|
+
source: "github",
|
|
91
|
+
repo: defaultMp?.source.repo || local.gitRepo || "",
|
|
92
|
+
},
|
|
89
93
|
description: defaultMp?.description || local.description || "",
|
|
90
94
|
official: defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
91
95
|
featured: defaultMp?.featured,
|
package/src/data/marketplaces.ts
CHANGED
|
@@ -85,7 +85,10 @@ export function getAllMarketplaces(
|
|
|
85
85
|
const canonical = deprecatedMarketplaces[name];
|
|
86
86
|
if (canonical) {
|
|
87
87
|
// If canonical already in the map or in defaults, skip this entry
|
|
88
|
-
if (
|
|
88
|
+
if (
|
|
89
|
+
all.has(canonical) ||
|
|
90
|
+
defaultMarketplaces.some((m) => m.name === canonical)
|
|
91
|
+
) {
|
|
89
92
|
continue;
|
|
90
93
|
}
|
|
91
94
|
}
|
|
@@ -100,8 +103,12 @@ export function getAllMarketplaces(
|
|
|
100
103
|
all.set(name, {
|
|
101
104
|
name,
|
|
102
105
|
// Prefer default displayName over stale local clone data
|
|
103
|
-
displayName:
|
|
104
|
-
|
|
106
|
+
displayName:
|
|
107
|
+
defaultMp?.displayName || local.name || formatMarketplaceName(name),
|
|
108
|
+
source: {
|
|
109
|
+
source: "github" as const,
|
|
110
|
+
repo: defaultMp?.source.repo || local.gitRepo || "",
|
|
111
|
+
},
|
|
105
112
|
description: defaultMp?.description || local.description || "",
|
|
106
113
|
official:
|
|
107
114
|
defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
@@ -1,9 +1,73 @@
|
|
|
1
1
|
export const PREDEFINED_PROFILES = [
|
|
2
|
+
{
|
|
3
|
+
id: "must-have",
|
|
4
|
+
name: "Must Have",
|
|
5
|
+
description: "Essential plugins every Claude Code user should have",
|
|
6
|
+
icon: "★",
|
|
7
|
+
magusPlugins: ["statusline", "multimodel"],
|
|
8
|
+
anthropicPlugins: [
|
|
9
|
+
"claude-code-setup",
|
|
10
|
+
"claude-md-management",
|
|
11
|
+
"code-simplifier",
|
|
12
|
+
"explanatory-output-style",
|
|
13
|
+
"playground",
|
|
14
|
+
"skill-creator",
|
|
15
|
+
],
|
|
16
|
+
skills: ["Find Skills"],
|
|
17
|
+
settings: {
|
|
18
|
+
effortLevel: "high",
|
|
19
|
+
alwaysThinkingEnabled: true,
|
|
20
|
+
outputStyle: "explanatory",
|
|
21
|
+
env: { CLAUDE_CODE_ENABLE_TASKS: "true" },
|
|
22
|
+
respectGitignore: true,
|
|
23
|
+
enableAllProjectMcpServers: true,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "developer-essentials",
|
|
28
|
+
name: "Developer Essentials",
|
|
29
|
+
description: "Must Have + full dev toolkit: code analysis, browser, terminal, design, review",
|
|
30
|
+
icon: "▶",
|
|
31
|
+
magusPlugins: [
|
|
32
|
+
"statusline",
|
|
33
|
+
"multimodel",
|
|
34
|
+
"code-analysis",
|
|
35
|
+
"dev",
|
|
36
|
+
"browser-use",
|
|
37
|
+
"designer",
|
|
38
|
+
"terminal",
|
|
39
|
+
"kanban",
|
|
40
|
+
],
|
|
41
|
+
anthropicPlugins: [
|
|
42
|
+
"claude-code-setup",
|
|
43
|
+
"claude-md-management",
|
|
44
|
+
"code-simplifier",
|
|
45
|
+
"explanatory-output-style",
|
|
46
|
+
"playground",
|
|
47
|
+
"skill-creator",
|
|
48
|
+
"code-review",
|
|
49
|
+
"commit-commands",
|
|
50
|
+
"feature-dev",
|
|
51
|
+
],
|
|
52
|
+
skills: ["Find Skills", "Systematic Debugging"],
|
|
53
|
+
settings: {
|
|
54
|
+
effortLevel: "high",
|
|
55
|
+
alwaysThinkingEnabled: true,
|
|
56
|
+
outputStyle: "explanatory",
|
|
57
|
+
env: {
|
|
58
|
+
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
59
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "true",
|
|
60
|
+
},
|
|
61
|
+
includeGitInstructions: true,
|
|
62
|
+
respectGitignore: true,
|
|
63
|
+
enableAllProjectMcpServers: true,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
2
66
|
{
|
|
3
67
|
id: "frontend-pro",
|
|
4
68
|
name: "Frontend Pro",
|
|
5
69
|
description: "UI implementation, design fidelity, browser-driven workflows",
|
|
6
|
-
icon: "
|
|
70
|
+
icon: "★",
|
|
7
71
|
magusPlugins: [
|
|
8
72
|
"dev",
|
|
9
73
|
"code-analysis",
|
|
@@ -30,7 +94,6 @@ export const PREDEFINED_PROFILES = [
|
|
|
30
94
|
settings: {
|
|
31
95
|
effortLevel: "high",
|
|
32
96
|
alwaysThinkingEnabled: true,
|
|
33
|
-
model: "claude-sonnet-4-6",
|
|
34
97
|
outputStyle: "explanatory",
|
|
35
98
|
env: {
|
|
36
99
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -45,7 +108,7 @@ export const PREDEFINED_PROFILES = [
|
|
|
45
108
|
id: "backend-forge",
|
|
46
109
|
name: "Backend Forge",
|
|
47
110
|
description: "API development, debugging, code quality, data workflows",
|
|
48
|
-
icon: "
|
|
111
|
+
icon: "★",
|
|
49
112
|
magusPlugins: [
|
|
50
113
|
"dev",
|
|
51
114
|
"code-analysis",
|
|
@@ -61,13 +124,11 @@ export const PREDEFINED_PROFILES = [
|
|
|
61
124
|
"code-simplifier",
|
|
62
125
|
"commit-commands",
|
|
63
126
|
"security-guidance",
|
|
64
|
-
"agent-sdk-dev",
|
|
65
127
|
],
|
|
66
128
|
skills: ["Systematic Debugging", "Neon Postgres", "Find Skills"],
|
|
67
129
|
settings: {
|
|
68
130
|
effortLevel: "high",
|
|
69
131
|
alwaysThinkingEnabled: true,
|
|
70
|
-
model: "claude-sonnet-4-6",
|
|
71
132
|
outputStyle: "concise",
|
|
72
133
|
env: {
|
|
73
134
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -82,7 +143,7 @@ export const PREDEFINED_PROFILES = [
|
|
|
82
143
|
id: "infra-ops",
|
|
83
144
|
name: "Infra Ops",
|
|
84
145
|
description: "Infrastructure, operational debugging, automation, terminal-first",
|
|
85
|
-
icon: "
|
|
146
|
+
icon: "★",
|
|
86
147
|
magusPlugins: [
|
|
87
148
|
"dev",
|
|
88
149
|
"code-analysis",
|
|
@@ -104,7 +165,6 @@ export const PREDEFINED_PROFILES = [
|
|
|
104
165
|
settings: {
|
|
105
166
|
effortLevel: "high",
|
|
106
167
|
alwaysThinkingEnabled: true,
|
|
107
|
-
model: "claude-opus-4-6",
|
|
108
168
|
outputStyle: "concise",
|
|
109
169
|
env: {
|
|
110
170
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -119,7 +179,7 @@ export const PREDEFINED_PROFILES = [
|
|
|
119
179
|
id: "growth-marketer",
|
|
120
180
|
name: "Growth Marketer",
|
|
121
181
|
description: "SEO, website audits, content production, marketing automation",
|
|
122
|
-
icon: "
|
|
182
|
+
icon: "★",
|
|
123
183
|
magusPlugins: [
|
|
124
184
|
"dev",
|
|
125
185
|
"code-analysis",
|
|
@@ -143,8 +203,6 @@ export const PREDEFINED_PROFILES = [
|
|
|
143
203
|
],
|
|
144
204
|
settings: {
|
|
145
205
|
effortLevel: "medium",
|
|
146
|
-
alwaysThinkingEnabled: false,
|
|
147
|
-
model: "claude-sonnet-4-6",
|
|
148
206
|
outputStyle: "explanatory",
|
|
149
207
|
env: { CLAUDE_CODE_ENABLE_TASKS: "true" },
|
|
150
208
|
respectGitignore: true,
|
|
@@ -155,7 +213,7 @@ export const PREDEFINED_PROFILES = [
|
|
|
155
213
|
id: "team-lead",
|
|
156
214
|
name: "Team Lead",
|
|
157
215
|
description: "Planning, code review, coordination, and broad repo visibility",
|
|
158
|
-
icon: "
|
|
216
|
+
icon: "★",
|
|
159
217
|
magusPlugins: [
|
|
160
218
|
"dev",
|
|
161
219
|
"code-analysis",
|
|
@@ -177,7 +235,6 @@ export const PREDEFINED_PROFILES = [
|
|
|
177
235
|
settings: {
|
|
178
236
|
effortLevel: "medium",
|
|
179
237
|
alwaysThinkingEnabled: true,
|
|
180
|
-
model: "claude-sonnet-4-6",
|
|
181
238
|
outputStyle: "explanatory",
|
|
182
239
|
env: {
|
|
183
240
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -2,7 +2,7 @@ export interface PredefinedProfile {
|
|
|
2
2
|
id: string;
|
|
3
3
|
name: string;
|
|
4
4
|
description: string;
|
|
5
|
-
icon: string;
|
|
5
|
+
icon: string;
|
|
6
6
|
magusPlugins: string[];
|
|
7
7
|
anthropicPlugins: string[];
|
|
8
8
|
skills: string[];
|
|
@@ -10,11 +10,77 @@ export interface PredefinedProfile {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
13
|
+
{
|
|
14
|
+
id: "must-have",
|
|
15
|
+
name: "Must Have",
|
|
16
|
+
description: "Essential plugins every Claude Code user should have",
|
|
17
|
+
icon: "★",
|
|
18
|
+
magusPlugins: ["statusline", "multimodel"],
|
|
19
|
+
anthropicPlugins: [
|
|
20
|
+
"claude-code-setup",
|
|
21
|
+
"claude-md-management",
|
|
22
|
+
"code-simplifier",
|
|
23
|
+
"explanatory-output-style",
|
|
24
|
+
"playground",
|
|
25
|
+
"skill-creator",
|
|
26
|
+
],
|
|
27
|
+
skills: ["Find Skills"],
|
|
28
|
+
settings: {
|
|
29
|
+
effortLevel: "high",
|
|
30
|
+
alwaysThinkingEnabled: true,
|
|
31
|
+
outputStyle: "explanatory",
|
|
32
|
+
env: { CLAUDE_CODE_ENABLE_TASKS: "true" },
|
|
33
|
+
respectGitignore: true,
|
|
34
|
+
enableAllProjectMcpServers: true,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "developer-essentials",
|
|
39
|
+
name: "Developer Essentials",
|
|
40
|
+
description:
|
|
41
|
+
"Must Have + full dev toolkit: code analysis, browser, terminal, design, review",
|
|
42
|
+
icon: "▶",
|
|
43
|
+
magusPlugins: [
|
|
44
|
+
"statusline",
|
|
45
|
+
"multimodel",
|
|
46
|
+
"code-analysis",
|
|
47
|
+
"dev",
|
|
48
|
+
"browser-use",
|
|
49
|
+
"designer",
|
|
50
|
+
"terminal",
|
|
51
|
+
"kanban",
|
|
52
|
+
],
|
|
53
|
+
anthropicPlugins: [
|
|
54
|
+
"claude-code-setup",
|
|
55
|
+
"claude-md-management",
|
|
56
|
+
"code-simplifier",
|
|
57
|
+
"explanatory-output-style",
|
|
58
|
+
"playground",
|
|
59
|
+
"skill-creator",
|
|
60
|
+
"code-review",
|
|
61
|
+
"commit-commands",
|
|
62
|
+
"feature-dev",
|
|
63
|
+
],
|
|
64
|
+
skills: ["Find Skills", "Systematic Debugging"],
|
|
65
|
+
settings: {
|
|
66
|
+
effortLevel: "high",
|
|
67
|
+
alwaysThinkingEnabled: true,
|
|
68
|
+
outputStyle: "explanatory",
|
|
69
|
+
env: {
|
|
70
|
+
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
71
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "true",
|
|
72
|
+
},
|
|
73
|
+
includeGitInstructions: true,
|
|
74
|
+
respectGitignore: true,
|
|
75
|
+
enableAllProjectMcpServers: true,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
13
78
|
{
|
|
14
79
|
id: "frontend-pro",
|
|
15
80
|
name: "Frontend Pro",
|
|
16
|
-
description:
|
|
17
|
-
|
|
81
|
+
description:
|
|
82
|
+
"UI implementation, design fidelity, browser-driven workflows",
|
|
83
|
+
icon: "★",
|
|
18
84
|
magusPlugins: [
|
|
19
85
|
"dev",
|
|
20
86
|
"code-analysis",
|
|
@@ -41,7 +107,6 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
41
107
|
settings: {
|
|
42
108
|
effortLevel: "high",
|
|
43
109
|
alwaysThinkingEnabled: true,
|
|
44
|
-
model: "claude-sonnet-4-6",
|
|
45
110
|
outputStyle: "explanatory",
|
|
46
111
|
env: {
|
|
47
112
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -56,7 +121,7 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
56
121
|
id: "backend-forge",
|
|
57
122
|
name: "Backend Forge",
|
|
58
123
|
description: "API development, debugging, code quality, data workflows",
|
|
59
|
-
icon: "
|
|
124
|
+
icon: "★",
|
|
60
125
|
magusPlugins: [
|
|
61
126
|
"dev",
|
|
62
127
|
"code-analysis",
|
|
@@ -72,13 +137,11 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
72
137
|
"code-simplifier",
|
|
73
138
|
"commit-commands",
|
|
74
139
|
"security-guidance",
|
|
75
|
-
"agent-sdk-dev",
|
|
76
140
|
],
|
|
77
141
|
skills: ["Systematic Debugging", "Neon Postgres", "Find Skills"],
|
|
78
142
|
settings: {
|
|
79
143
|
effortLevel: "high",
|
|
80
144
|
alwaysThinkingEnabled: true,
|
|
81
|
-
model: "claude-sonnet-4-6",
|
|
82
145
|
outputStyle: "concise",
|
|
83
146
|
env: {
|
|
84
147
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -94,7 +157,7 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
94
157
|
name: "Infra Ops",
|
|
95
158
|
description:
|
|
96
159
|
"Infrastructure, operational debugging, automation, terminal-first",
|
|
97
|
-
icon: "
|
|
160
|
+
icon: "★",
|
|
98
161
|
magusPlugins: [
|
|
99
162
|
"dev",
|
|
100
163
|
"code-analysis",
|
|
@@ -116,7 +179,6 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
116
179
|
settings: {
|
|
117
180
|
effortLevel: "high",
|
|
118
181
|
alwaysThinkingEnabled: true,
|
|
119
|
-
model: "claude-opus-4-6",
|
|
120
182
|
outputStyle: "concise",
|
|
121
183
|
env: {
|
|
122
184
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
|
@@ -132,7 +194,7 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
132
194
|
name: "Growth Marketer",
|
|
133
195
|
description:
|
|
134
196
|
"SEO, website audits, content production, marketing automation",
|
|
135
|
-
icon: "
|
|
197
|
+
icon: "★",
|
|
136
198
|
magusPlugins: [
|
|
137
199
|
"dev",
|
|
138
200
|
"code-analysis",
|
|
@@ -156,8 +218,6 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
156
218
|
],
|
|
157
219
|
settings: {
|
|
158
220
|
effortLevel: "medium",
|
|
159
|
-
alwaysThinkingEnabled: false,
|
|
160
|
-
model: "claude-sonnet-4-6",
|
|
161
221
|
outputStyle: "explanatory",
|
|
162
222
|
env: { CLAUDE_CODE_ENABLE_TASKS: "true" },
|
|
163
223
|
respectGitignore: true,
|
|
@@ -169,7 +229,7 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
169
229
|
name: "Team Lead",
|
|
170
230
|
description:
|
|
171
231
|
"Planning, code review, coordination, and broad repo visibility",
|
|
172
|
-
icon: "
|
|
232
|
+
icon: "★",
|
|
173
233
|
magusPlugins: [
|
|
174
234
|
"dev",
|
|
175
235
|
"code-analysis",
|
|
@@ -191,7 +251,6 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
191
251
|
settings: {
|
|
192
252
|
effortLevel: "medium",
|
|
193
253
|
alwaysThinkingEnabled: true,
|
|
194
|
-
model: "claude-sonnet-4-6",
|
|
195
254
|
outputStyle: "explanatory",
|
|
196
255
|
env: {
|
|
197
256
|
CLAUDE_CODE_ENABLE_TASKS: "true",
|
package/src/prerunner/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from "node:os";
|
|
|
4
4
|
import { UpdateCache } from "../services/update-cache.js";
|
|
5
5
|
import { getAvailablePlugins, clearMarketplaceCache, } from "../services/plugin-manager.js";
|
|
6
6
|
import { runClaude } from "../services/claude-runner.js";
|
|
7
|
-
import { recoverMarketplaceSettings, migrateMarketplaceRename, getGlobalEnabledPlugins, getEnabledPlugins, getLocalEnabledPlugins, saveGlobalInstalledPluginVersion, } from "../services/claude-settings.js";
|
|
7
|
+
import { recoverMarketplaceSettings, migrateMarketplaceRename, getGlobalEnabledPlugins, getEnabledPlugins, getLocalEnabledPlugins, saveGlobalInstalledPluginVersion, readGlobalSettings, writeGlobalSettings, } from "../services/claude-settings.js";
|
|
8
8
|
import { parsePluginId } from "../utils/string-utils.js";
|
|
9
9
|
import { defaultMarketplaces } from "../data/marketplaces.js";
|
|
10
10
|
import { updatePlugin, addMarketplace, isClaudeAvailable, } from "../services/claude-cli.js";
|
|
@@ -22,20 +22,26 @@ async function getReferencedMarketplaces(projectPath) {
|
|
|
22
22
|
for (const id of Object.keys(global))
|
|
23
23
|
allPluginIds.add(id);
|
|
24
24
|
}
|
|
25
|
-
catch {
|
|
25
|
+
catch {
|
|
26
|
+
/* skip if unreadable */
|
|
27
|
+
}
|
|
26
28
|
if (projectPath) {
|
|
27
29
|
try {
|
|
28
30
|
const project = await getEnabledPlugins(projectPath);
|
|
29
31
|
for (const id of Object.keys(project))
|
|
30
32
|
allPluginIds.add(id);
|
|
31
33
|
}
|
|
32
|
-
catch {
|
|
34
|
+
catch {
|
|
35
|
+
/* skip if unreadable */
|
|
36
|
+
}
|
|
33
37
|
try {
|
|
34
38
|
const local = await getLocalEnabledPlugins(projectPath);
|
|
35
39
|
for (const id of Object.keys(local))
|
|
36
40
|
allPluginIds.add(id);
|
|
37
41
|
}
|
|
38
|
-
catch {
|
|
42
|
+
catch {
|
|
43
|
+
/* skip if unreadable */
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
// Parse marketplace names from plugin IDs
|
|
41
47
|
for (const pluginId of allPluginIds) {
|
|
@@ -73,6 +79,57 @@ async function autoAddMissingMarketplaces(projectPath) {
|
|
|
73
79
|
}
|
|
74
80
|
return added;
|
|
75
81
|
}
|
|
82
|
+
const CONTINUITY_PLUGIN_SENTINEL = "tmux-claude-continuity";
|
|
83
|
+
const CONTINUITY_PLUGIN_SCRIPT = path.join(os.homedir(), ".tmux", "plugins", "tmux-claude-continuity", "scripts", "on_session_start.sh");
|
|
84
|
+
/**
|
|
85
|
+
* Ensure tmux-claude-continuity Claude Code hooks are present in global settings.
|
|
86
|
+
* If the tmux plugin is installed but the hooks are missing, they are appended.
|
|
87
|
+
* Returns a description of what was added, or null if nothing changed.
|
|
88
|
+
*/
|
|
89
|
+
async function ensureTmuxContinuityHooks() {
|
|
90
|
+
// Plugin not installed — nothing to do
|
|
91
|
+
if (!(await fs.pathExists(CONTINUITY_PLUGIN_SCRIPT))) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const settings = await readGlobalSettings();
|
|
95
|
+
// Check if hooks are already configured by looking for the sentinel string
|
|
96
|
+
const existingHooks = settings.hooks ?? {};
|
|
97
|
+
for (const groups of Object.values(existingHooks)) {
|
|
98
|
+
for (const group of groups) {
|
|
99
|
+
for (const hook of group.hooks) {
|
|
100
|
+
if (hook.command.includes(CONTINUITY_PLUGIN_SENTINEL)) {
|
|
101
|
+
return null; // Already configured
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Append hooks, preserving any existing entries in SessionStart and Stop
|
|
107
|
+
const sessionStartGroups = existingHooks["SessionStart"] ?? [];
|
|
108
|
+
const stopGroups = existingHooks["Stop"] ?? [];
|
|
109
|
+
sessionStartGroups.push({
|
|
110
|
+
hooks: [
|
|
111
|
+
{
|
|
112
|
+
type: "command",
|
|
113
|
+
command: "bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_session_start.sh",
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
stopGroups.push({
|
|
118
|
+
hooks: [
|
|
119
|
+
{
|
|
120
|
+
type: "command",
|
|
121
|
+
command: "bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_stop.sh",
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
settings.hooks = {
|
|
126
|
+
...existingHooks,
|
|
127
|
+
SessionStart: sessionStartGroups,
|
|
128
|
+
Stop: stopGroups,
|
|
129
|
+
};
|
|
130
|
+
await writeGlobalSettings(settings);
|
|
131
|
+
return "SessionStart + Stop hooks";
|
|
132
|
+
}
|
|
76
133
|
/**
|
|
77
134
|
* Prerun orchestration: Check for updates, apply them, then run claude
|
|
78
135
|
* @param claudeArgs - Arguments to pass to claude CLI
|
|
@@ -84,9 +141,11 @@ export async function prerunClaude(claudeArgs, options = {}) {
|
|
|
84
141
|
try {
|
|
85
142
|
// STEP 0: Migrate old marketplace names → magus (idempotent, no-ops if already migrated)
|
|
86
143
|
const migration = await migrateMarketplaceRename();
|
|
87
|
-
const migTotal = migration.projectMigrated +
|
|
88
|
-
|
|
89
|
-
|
|
144
|
+
const migTotal = migration.projectMigrated +
|
|
145
|
+
migration.globalMigrated +
|
|
146
|
+
migration.localMigrated +
|
|
147
|
+
migration.registryMigrated +
|
|
148
|
+
(migration.knownMarketplacesMigrated ? 1 : 0);
|
|
90
149
|
if (migTotal > 0) {
|
|
91
150
|
console.log(`✓ Migrated ${migTotal} plugin reference(s) → magus`);
|
|
92
151
|
}
|
|
@@ -99,6 +158,11 @@ export async function prerunClaude(claudeArgs, options = {}) {
|
|
|
99
158
|
console.log(`✓ Auto-added marketplace(s): ${addedMarketplaces.join(", ")}`);
|
|
100
159
|
}
|
|
101
160
|
}
|
|
161
|
+
// STEP 0.6: Ensure tmux-claude-continuity hooks are configured
|
|
162
|
+
const addedHooks = await ensureTmuxContinuityHooks();
|
|
163
|
+
if (addedHooks) {
|
|
164
|
+
console.log(`✓ Added tmux-claude-continuity hooks to ~/.claude/settings.json`);
|
|
165
|
+
}
|
|
102
166
|
// STEP 1: Check if we should update (time-based cache, or forced)
|
|
103
167
|
const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
|
|
104
168
|
if (options.force) {
|
package/src/prerunner/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
getEnabledPlugins,
|
|
15
15
|
getLocalEnabledPlugins,
|
|
16
16
|
saveGlobalInstalledPluginVersion,
|
|
17
|
+
readGlobalSettings,
|
|
18
|
+
writeGlobalSettings,
|
|
17
19
|
} from "../services/claude-settings.js";
|
|
18
20
|
import { parsePluginId } from "../utils/string-utils.js";
|
|
19
21
|
import { defaultMarketplaces } from "../data/marketplaces.js";
|
|
@@ -49,18 +51,24 @@ async function getReferencedMarketplaces(
|
|
|
49
51
|
try {
|
|
50
52
|
const global = await getGlobalEnabledPlugins();
|
|
51
53
|
for (const id of Object.keys(global)) allPluginIds.add(id);
|
|
52
|
-
} catch {
|
|
54
|
+
} catch {
|
|
55
|
+
/* skip if unreadable */
|
|
56
|
+
}
|
|
53
57
|
|
|
54
58
|
if (projectPath) {
|
|
55
59
|
try {
|
|
56
60
|
const project = await getEnabledPlugins(projectPath);
|
|
57
61
|
for (const id of Object.keys(project)) allPluginIds.add(id);
|
|
58
|
-
} catch {
|
|
62
|
+
} catch {
|
|
63
|
+
/* skip if unreadable */
|
|
64
|
+
}
|
|
59
65
|
|
|
60
66
|
try {
|
|
61
67
|
const local = await getLocalEnabledPlugins(projectPath);
|
|
62
68
|
for (const id of Object.keys(local)) allPluginIds.add(id);
|
|
63
|
-
} catch {
|
|
69
|
+
} catch {
|
|
70
|
+
/* skip if unreadable */
|
|
71
|
+
}
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
// Parse marketplace names from plugin IDs
|
|
@@ -108,6 +116,75 @@ async function autoAddMissingMarketplaces(
|
|
|
108
116
|
return added;
|
|
109
117
|
}
|
|
110
118
|
|
|
119
|
+
const CONTINUITY_PLUGIN_SENTINEL = "tmux-claude-continuity";
|
|
120
|
+
const CONTINUITY_PLUGIN_SCRIPT = path.join(
|
|
121
|
+
os.homedir(),
|
|
122
|
+
".tmux",
|
|
123
|
+
"plugins",
|
|
124
|
+
"tmux-claude-continuity",
|
|
125
|
+
"scripts",
|
|
126
|
+
"on_session_start.sh",
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Ensure tmux-claude-continuity Claude Code hooks are present in global settings.
|
|
131
|
+
* If the tmux plugin is installed but the hooks are missing, they are appended.
|
|
132
|
+
* Returns a description of what was added, or null if nothing changed.
|
|
133
|
+
*/
|
|
134
|
+
async function ensureTmuxContinuityHooks(): Promise<string | null> {
|
|
135
|
+
// Plugin not installed — nothing to do
|
|
136
|
+
if (!(await fs.pathExists(CONTINUITY_PLUGIN_SCRIPT))) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const settings = await readGlobalSettings();
|
|
141
|
+
|
|
142
|
+
// Check if hooks are already configured by looking for the sentinel string
|
|
143
|
+
const existingHooks = settings.hooks ?? {};
|
|
144
|
+
for (const groups of Object.values(existingHooks)) {
|
|
145
|
+
for (const group of groups) {
|
|
146
|
+
for (const hook of group.hooks) {
|
|
147
|
+
if (hook.command.includes(CONTINUITY_PLUGIN_SENTINEL)) {
|
|
148
|
+
return null; // Already configured
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Append hooks, preserving any existing entries in SessionStart and Stop
|
|
155
|
+
const sessionStartGroups = existingHooks["SessionStart"] ?? [];
|
|
156
|
+
const stopGroups = existingHooks["Stop"] ?? [];
|
|
157
|
+
|
|
158
|
+
sessionStartGroups.push({
|
|
159
|
+
hooks: [
|
|
160
|
+
{
|
|
161
|
+
type: "command",
|
|
162
|
+
command:
|
|
163
|
+
"bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_session_start.sh",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
stopGroups.push({
|
|
169
|
+
hooks: [
|
|
170
|
+
{
|
|
171
|
+
type: "command",
|
|
172
|
+
command:
|
|
173
|
+
"bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_stop.sh",
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
settings.hooks = {
|
|
179
|
+
...existingHooks,
|
|
180
|
+
SessionStart: sessionStartGroups,
|
|
181
|
+
Stop: stopGroups,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
await writeGlobalSettings(settings);
|
|
185
|
+
return "SessionStart + Stop hooks";
|
|
186
|
+
}
|
|
187
|
+
|
|
111
188
|
/**
|
|
112
189
|
* Prerun orchestration: Check for updates, apply them, then run claude
|
|
113
190
|
* @param claudeArgs - Arguments to pass to claude CLI
|
|
@@ -123,9 +200,12 @@ export async function prerunClaude(
|
|
|
123
200
|
try {
|
|
124
201
|
// STEP 0: Migrate old marketplace names → magus (idempotent, no-ops if already migrated)
|
|
125
202
|
const migration = await migrateMarketplaceRename();
|
|
126
|
-
const migTotal =
|
|
127
|
-
|
|
128
|
-
|
|
203
|
+
const migTotal =
|
|
204
|
+
migration.projectMigrated +
|
|
205
|
+
migration.globalMigrated +
|
|
206
|
+
migration.localMigrated +
|
|
207
|
+
migration.registryMigrated +
|
|
208
|
+
(migration.knownMarketplacesMigrated ? 1 : 0);
|
|
129
209
|
if (migTotal > 0) {
|
|
130
210
|
console.log(`✓ Migrated ${migTotal} plugin reference(s) → magus`);
|
|
131
211
|
}
|
|
@@ -142,6 +222,14 @@ export async function prerunClaude(
|
|
|
142
222
|
}
|
|
143
223
|
}
|
|
144
224
|
|
|
225
|
+
// STEP 0.6: Ensure tmux-claude-continuity hooks are configured
|
|
226
|
+
const addedHooks = await ensureTmuxContinuityHooks();
|
|
227
|
+
if (addedHooks) {
|
|
228
|
+
console.log(
|
|
229
|
+
`✓ Added tmux-claude-continuity hooks to ~/.claude/settings.json`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
145
233
|
// STEP 1: Check if we should update (time-based cache, or forced)
|
|
146
234
|
const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
|
|
147
235
|
|
|
@@ -12,7 +12,7 @@ import { execFile } from "node:child_process";
|
|
|
12
12
|
import { promisify } from "node:util";
|
|
13
13
|
import { which } from "../utils/command-utils.js";
|
|
14
14
|
import { removeGlobalInstalledPluginVersion, removeLocalInstalledPluginVersion, } from "./claude-settings.js";
|
|
15
|
-
import { removeInstalledPluginVersion
|
|
15
|
+
import { removeInstalledPluginVersion } from "./plugin-manager.js";
|
|
16
16
|
const execFileAsync = promisify(execFile);
|
|
17
17
|
/**
|
|
18
18
|
* Get the path to the claude CLI binary
|
|
@@ -107,6 +107,13 @@ export async function updatePlugin(pluginId, scope = "user") {
|
|
|
107
107
|
export async function addMarketplace(repo) {
|
|
108
108
|
await execClaude(["plugin", "marketplace", "add", repo], 60000);
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Update marketplace cache by running git pull via Claude CLI
|
|
112
|
+
* Uses longer timeout since this involves git network operations
|
|
113
|
+
*/
|
|
114
|
+
export async function updateMarketplace(name) {
|
|
115
|
+
await execClaude(["plugin", "marketplace", "update", name], 60000);
|
|
116
|
+
}
|
|
110
117
|
/**
|
|
111
118
|
* Check if the claude CLI is available
|
|
112
119
|
* @returns true if claude CLI is found in PATH
|