claudeup 4.16.0 → 4.18.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/__tests__/alias-parser.test.ts +317 -0
- package/src/__tests__/alias-shell-writer.test.ts +661 -0
- package/src/__tests__/alias-store.test.ts +86 -0
- package/src/__tests__/gitignore-fixer.test.ts +64 -1
- package/src/__tests__/gitignore-prerun.test.ts +2 -2
- package/src/__tests__/gitignore-service.test.ts +42 -0
- package/src/__tests__/marketplaces.test.ts +40 -0
- package/src/__tests__/plugin-manager-fallback.test.ts +120 -0
- package/src/__tests__/useGitignoreModal.test.ts +2 -2
- package/src/data/alias-flags.js +196 -0
- package/src/data/alias-flags.ts +291 -0
- package/src/data/gitignore-reasons.js +97 -0
- package/src/data/gitignore-reasons.ts +103 -0
- package/src/data/marketplaces.js +19 -1
- package/src/data/marketplaces.ts +17 -1
- package/src/services/alias-settings.js +51 -0
- package/src/services/alias-settings.ts +63 -0
- package/src/services/alias-shell-writer.js +764 -0
- package/src/services/alias-shell-writer.ts +873 -0
- package/src/services/alias-store.js +77 -0
- package/src/services/alias-store.ts +112 -0
- package/src/services/gitignore-fixer.js +70 -10
- package/src/services/gitignore-fixer.ts +76 -9
- package/src/services/gitignore-prerun.js +3 -3
- package/src/services/gitignore-prerun.ts +3 -3
- package/src/services/gitignore-service.js +20 -2
- package/src/services/gitignore-service.ts +23 -1
- package/src/services/marketplace-fetcher.js +96 -0
- package/src/services/marketplace-fetcher.ts +137 -0
- package/src/services/plugin-manager.js +6 -59
- package/src/services/plugin-manager.ts +16 -91
- package/src/services/skillsmp-client.js +29 -9
- package/src/services/skillsmp-client.ts +38 -8
- package/src/types/gitignore.ts +1 -1
- package/src/types/index.ts +1 -0
- package/src/ui/App.js +10 -4
- package/src/ui/App.tsx +9 -3
- package/src/ui/components/TabBar.js +2 -1
- package/src/ui/components/TabBar.tsx +2 -1
- package/src/ui/components/layout/FooterHints.js +29 -0
- package/src/ui/components/layout/FooterHints.tsx +52 -0
- package/src/ui/components/layout/ScreenLayout.js +2 -1
- package/src/ui/components/layout/ScreenLayout.tsx +12 -3
- package/src/ui/components/layout/index.js +1 -0
- package/src/ui/components/layout/index.ts +5 -0
- package/src/ui/components/modals/SelectModal.js +8 -1
- package/src/ui/components/modals/SelectModal.tsx +12 -1
- package/src/ui/hooks/useGitignoreModal.js +7 -8
- package/src/ui/hooks/useGitignoreModal.ts +8 -9
- package/src/ui/renderers/gitignoreRenderers.js +36 -23
- package/src/ui/renderers/gitignoreRenderers.tsx +50 -41
- package/src/ui/screens/AliasScreen.js +1008 -0
- package/src/ui/screens/AliasScreen.tsx +1402 -0
- package/src/ui/screens/CliToolsScreen.js +6 -1
- package/src/ui/screens/CliToolsScreen.tsx +6 -1
- package/src/ui/screens/EnvVarsScreen.js +6 -1
- package/src/ui/screens/EnvVarsScreen.tsx +6 -1
- package/src/ui/screens/GitignoreScreen.js +189 -88
- package/src/ui/screens/GitignoreScreen.tsx +312 -132
- package/src/ui/screens/McpRegistryScreen.js +13 -2
- package/src/ui/screens/McpRegistryScreen.tsx +13 -2
- package/src/ui/screens/McpScreen.js +6 -1
- package/src/ui/screens/McpScreen.tsx +6 -1
- package/src/ui/screens/ModelSelectorScreen.js +8 -2
- package/src/ui/screens/ModelSelectorScreen.tsx +8 -2
- package/src/ui/screens/PluginsScreen.js +13 -2
- package/src/ui/screens/PluginsScreen.tsx +13 -2
- package/src/ui/screens/ProfilesScreen.js +8 -1
- package/src/ui/screens/ProfilesScreen.tsx +8 -1
- package/src/ui/screens/SkillsScreen.js +21 -4
- package/src/ui/screens/SkillsScreen.tsx +39 -5
- package/src/ui/screens/StatusLineScreen.js +7 -1
- package/src/ui/screens/StatusLineScreen.tsx +7 -1
- package/src/ui/screens/index.js +1 -0
- package/src/ui/screens/index.ts +1 -0
- package/src/ui/state/types.ts +4 -2
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog of `claude` CLI flags that the Alias tab can compose into a managed
|
|
3
|
+
* shell alias. Verified against `claude --help` output and binary string scan
|
|
4
|
+
* of the shipped Claude Code 2.1.x binary.
|
|
5
|
+
*
|
|
6
|
+
* The catalog drives both the UI editor for each flag and the renderer that
|
|
7
|
+
* emits the final `alias claude='claude …'` string per shell.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type FlagKind =
|
|
11
|
+
/** On/off. AliasFlagState: { enabled: boolean } */
|
|
12
|
+
| "boolean"
|
|
13
|
+
/** Three states: unset / on / off. Used for `--chrome` vs `--no-chrome`. */
|
|
14
|
+
| "tri-state"
|
|
15
|
+
/** Single value from a fixed list. AliasFlagState: { enabled, value }. */
|
|
16
|
+
| "select"
|
|
17
|
+
/** Free-form string. AliasFlagState: { enabled, value }. */
|
|
18
|
+
| "text"
|
|
19
|
+
/** Optional free-form string (flag works with or without a value). */
|
|
20
|
+
| "optional-text"
|
|
21
|
+
/** Repeatable list of strings. AliasFlagState: { enabled, values }. */
|
|
22
|
+
| "text-list"
|
|
23
|
+
/**
|
|
24
|
+
* Picklist of common tokens + free-form custom tokens, joined with commas.
|
|
25
|
+
* AliasFlagState: { enabled, picked: string[], custom: string[] }.
|
|
26
|
+
* Used for `--debug` because Claude Code's category set is dynamic.
|
|
27
|
+
*/
|
|
28
|
+
| "multi-with-custom";
|
|
29
|
+
|
|
30
|
+
export interface FlagSelectOption {
|
|
31
|
+
label: string;
|
|
32
|
+
value: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AliasFlag {
|
|
36
|
+
/** Stable identifier; used as JSON key in `~/.claude/claudeup-alias.json`. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Human label shown in the UI list. */
|
|
39
|
+
label: string;
|
|
40
|
+
/**
|
|
41
|
+
* The CLI flag as it appears on the command line. For tri-state, this is the
|
|
42
|
+
* "on" form (e.g. `--chrome`); the "off" form is in `triStateOff`.
|
|
43
|
+
*/
|
|
44
|
+
flag: string;
|
|
45
|
+
/** Optional short flag (e.g. `-d` for `--debug`). Not currently rendered. */
|
|
46
|
+
shortFlag?: string;
|
|
47
|
+
kind: FlagKind;
|
|
48
|
+
/** One-line description shown in the detail panel. */
|
|
49
|
+
description: string;
|
|
50
|
+
/** Allowed values for `kind: "select"`. */
|
|
51
|
+
options?: FlagSelectOption[];
|
|
52
|
+
/** "Off" form for tri-state flags (e.g. `--no-chrome`). */
|
|
53
|
+
triStateOff?: string;
|
|
54
|
+
/** Picklist tokens for `kind: "multi-with-custom"`. */
|
|
55
|
+
picklist?: string[];
|
|
56
|
+
/** Default seed values for `text-list` and `multi-with-custom`. */
|
|
57
|
+
defaultValues?: string[];
|
|
58
|
+
/**
|
|
59
|
+
* Validation key. The renderer / UI consult this to grey out conflicting
|
|
60
|
+
* fields. Two flags with the same `xorGroup` are mutually exclusive.
|
|
61
|
+
*/
|
|
62
|
+
xorGroup?: string;
|
|
63
|
+
/**
|
|
64
|
+
* The flag is only valid when another flag (by id) is enabled.
|
|
65
|
+
* UI greys out and shows "requires --xxx".
|
|
66
|
+
*/
|
|
67
|
+
requires?: string;
|
|
68
|
+
/**
|
|
69
|
+
* If true, the value supports `{token}` placeholders that expand at shell
|
|
70
|
+
* eval time (not at write time). The renderer emits the value as a mix of
|
|
71
|
+
* literal segments and shell substitution segments instead of one quoted
|
|
72
|
+
* token. See `TEMPLATE_TOKENS` for the supported placeholder set.
|
|
73
|
+
*/
|
|
74
|
+
templated?: boolean;
|
|
75
|
+
/** UI grouping; rendered as section headers in the list. */
|
|
76
|
+
group: FlagGroup;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Tokens supported in `templated: true` flag values. Description text is
|
|
81
|
+
* shown to the user; the actual shell-substitution code lives in the writer
|
|
82
|
+
* because it needs per-shell variants.
|
|
83
|
+
*
|
|
84
|
+
* Intentionally excludes `{hash}` for v1 — its only portable form is
|
|
85
|
+
* `od -An -N4 -tx1 /dev/urandom | tr -d ' \n'`, which looks frightening in a
|
|
86
|
+
* shell rc file. Users who want randomness can pair this prefix with bare
|
|
87
|
+
* `--remote-control` (which already auto-generates a unique suffix).
|
|
88
|
+
*/
|
|
89
|
+
export const TEMPLATE_TOKENS: Array<{ token: string; description: string }> = [
|
|
90
|
+
{ token: "{folder}", description: "current directory's basename" },
|
|
91
|
+
{ token: "{day}", description: "day of month, zero-padded (01-31)" },
|
|
92
|
+
{ token: "{month}", description: "month, zero-padded (01-12)" },
|
|
93
|
+
{ token: "{year}", description: "4-digit year" },
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
export type FlagGroup =
|
|
97
|
+
| "danger"
|
|
98
|
+
| "session"
|
|
99
|
+
| "context"
|
|
100
|
+
| "channels"
|
|
101
|
+
| "debug"
|
|
102
|
+
| "integration"
|
|
103
|
+
| "worktree";
|
|
104
|
+
|
|
105
|
+
export const FLAG_GROUPS: Array<{ id: FlagGroup; label: string }> = [
|
|
106
|
+
{ id: "danger", label: "Permissions" },
|
|
107
|
+
{ id: "session", label: "Session" },
|
|
108
|
+
{ id: "context", label: "Context" },
|
|
109
|
+
{ id: "channels", label: "Development channels" },
|
|
110
|
+
{ id: "debug", label: "Debug" },
|
|
111
|
+
{ id: "integration", label: "Integrations" },
|
|
112
|
+
{ id: "worktree", label: "Worktree" },
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
export const ALIAS_FLAGS: AliasFlag[] = [
|
|
116
|
+
{
|
|
117
|
+
id: "dangerously-skip-permissions",
|
|
118
|
+
label: "Skip permission checks",
|
|
119
|
+
flag: "--dangerously-skip-permissions",
|
|
120
|
+
kind: "boolean",
|
|
121
|
+
group: "danger",
|
|
122
|
+
description:
|
|
123
|
+
"Bypass all permission checks. Recommended only for sandboxes with no internet access.",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "allow-dangerously-skip-permissions",
|
|
127
|
+
label: "Allow skip-permissions opt-in",
|
|
128
|
+
flag: "--allow-dangerously-skip-permissions",
|
|
129
|
+
kind: "boolean",
|
|
130
|
+
group: "danger",
|
|
131
|
+
description:
|
|
132
|
+
"Enable the skip-permissions option without making it the default.",
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "remote-control",
|
|
136
|
+
label: "Remote control",
|
|
137
|
+
flag: "--remote-control",
|
|
138
|
+
kind: "boolean",
|
|
139
|
+
group: "session",
|
|
140
|
+
description:
|
|
141
|
+
"Start an interactive session with Remote Control enabled. Claude Code auto-generates a unique session name; use --remote-control-session-name-prefix to customize it.",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "remote-control-session-name-prefix",
|
|
145
|
+
label: "Remote control name prefix",
|
|
146
|
+
flag: "--remote-control-session-name-prefix",
|
|
147
|
+
kind: "text",
|
|
148
|
+
templated: true,
|
|
149
|
+
group: "session",
|
|
150
|
+
description:
|
|
151
|
+
"Prefix for auto-generated Remote Control session names. Default: hostname. Supports template tokens that expand on each shell invocation: {folder} (basename of $PWD), {day}, {month}, {year}. Example: dev-{folder}-{day} → dev-myproject-15.",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "ide",
|
|
155
|
+
label: "Auto-connect to IDE",
|
|
156
|
+
flag: "--ide",
|
|
157
|
+
kind: "boolean",
|
|
158
|
+
group: "integration",
|
|
159
|
+
description:
|
|
160
|
+
"Automatically connect to IDE on startup if exactly one valid IDE is available.",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "chrome",
|
|
164
|
+
label: "Chrome integration",
|
|
165
|
+
flag: "--chrome",
|
|
166
|
+
triStateOff: "--no-chrome",
|
|
167
|
+
kind: "tri-state",
|
|
168
|
+
group: "integration",
|
|
169
|
+
description:
|
|
170
|
+
"Enable or disable Claude in Chrome integration. Unset leaves the project default in place.",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "effort",
|
|
174
|
+
label: "Effort level",
|
|
175
|
+
flag: "--effort",
|
|
176
|
+
kind: "select",
|
|
177
|
+
group: "session",
|
|
178
|
+
description: "Effort level for the current session.",
|
|
179
|
+
options: [
|
|
180
|
+
{ label: "low", value: "low" },
|
|
181
|
+
{ label: "medium", value: "medium" },
|
|
182
|
+
{ label: "high", value: "high" },
|
|
183
|
+
{ label: "xhigh", value: "xhigh" },
|
|
184
|
+
{ label: "max", value: "max" },
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "system-prompt",
|
|
189
|
+
label: "System prompt",
|
|
190
|
+
flag: "--system-prompt",
|
|
191
|
+
kind: "text",
|
|
192
|
+
group: "context",
|
|
193
|
+
xorGroup: "system-prompt",
|
|
194
|
+
description:
|
|
195
|
+
"System prompt text to use for the session. Mutually exclusive with --system-prompt-file.",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: "system-prompt-file",
|
|
199
|
+
label: "System prompt file",
|
|
200
|
+
flag: "--system-prompt-file",
|
|
201
|
+
kind: "text",
|
|
202
|
+
group: "context",
|
|
203
|
+
xorGroup: "system-prompt",
|
|
204
|
+
description:
|
|
205
|
+
"Path to a file whose contents replace the default system prompt. Mutually exclusive with --system-prompt.",
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
id: "append-system-prompt",
|
|
209
|
+
label: "Append system prompt",
|
|
210
|
+
flag: "--append-system-prompt",
|
|
211
|
+
kind: "text",
|
|
212
|
+
group: "context",
|
|
213
|
+
description:
|
|
214
|
+
"Text appended to the default system prompt. Composes with --system-prompt.",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "append-system-prompt-file",
|
|
218
|
+
label: "Append system prompt file",
|
|
219
|
+
flag: "--append-system-prompt-file",
|
|
220
|
+
kind: "text",
|
|
221
|
+
group: "context",
|
|
222
|
+
description:
|
|
223
|
+
"Path to a file whose contents are appended to the default system prompt.",
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: "dangerously-load-development-channels",
|
|
227
|
+
label: "Load development channels",
|
|
228
|
+
flag: "--dangerously-load-development-channels",
|
|
229
|
+
kind: "text-list",
|
|
230
|
+
group: "channels",
|
|
231
|
+
description:
|
|
232
|
+
"Sideload development channels from magus plugins. Default seed: claudish (the only magus plugin currently shipping channels).",
|
|
233
|
+
defaultValues: ["plugin:claudish@magus"],
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: "debug",
|
|
237
|
+
label: "Debug categories",
|
|
238
|
+
flag: "--debug",
|
|
239
|
+
shortFlag: "-d",
|
|
240
|
+
kind: "multi-with-custom",
|
|
241
|
+
group: "debug",
|
|
242
|
+
description:
|
|
243
|
+
"Enable debug mode with optional category filter. Pick from common categories or add custom tokens (including negations like !file).",
|
|
244
|
+
picklist: [
|
|
245
|
+
"api",
|
|
246
|
+
"hooks",
|
|
247
|
+
"mcp",
|
|
248
|
+
"tools",
|
|
249
|
+
"plugins",
|
|
250
|
+
"skills",
|
|
251
|
+
"settings",
|
|
252
|
+
"permissions",
|
|
253
|
+
"auth",
|
|
254
|
+
"cache",
|
|
255
|
+
"statsig",
|
|
256
|
+
"file",
|
|
257
|
+
"1p",
|
|
258
|
+
],
|
|
259
|
+
defaultValues: [],
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: "worktree",
|
|
263
|
+
label: "Use worktree",
|
|
264
|
+
flag: "--worktree",
|
|
265
|
+
kind: "boolean",
|
|
266
|
+
group: "worktree",
|
|
267
|
+
description:
|
|
268
|
+
"Create a git worktree for the session. Prerequisite for --tmux.",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
id: "tmux",
|
|
272
|
+
label: "tmux session",
|
|
273
|
+
flag: "--tmux",
|
|
274
|
+
kind: "select",
|
|
275
|
+
group: "worktree",
|
|
276
|
+
requires: "worktree",
|
|
277
|
+
description:
|
|
278
|
+
"Create a tmux session for the worktree. Requires --worktree. iTerm2 native panes when available; classic for traditional tmux.",
|
|
279
|
+
options: [
|
|
280
|
+
{ label: "auto (iTerm2 native)", value: "" },
|
|
281
|
+
{ label: "classic", value: "classic" },
|
|
282
|
+
],
|
|
283
|
+
},
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
/** Look up a flag by id. Throws if missing — keeps callers honest. */
|
|
287
|
+
export function getFlagById(id: string): AliasFlag {
|
|
288
|
+
const f = ALIAS_FLAGS.find((flag) => flag.id === id);
|
|
289
|
+
if (!f) throw new Error(`Unknown alias flag id: ${id}`);
|
|
290
|
+
return f;
|
|
291
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const RULE_REASONS = new Map([
|
|
2
|
+
[
|
|
3
|
+
key("ignore", ".claude/settings.local.json"),
|
|
4
|
+
"Personal Claude settings belong to each developer and should not be shared.",
|
|
5
|
+
],
|
|
6
|
+
[
|
|
7
|
+
key("ignore", ".claude/scheduled_tasks.lock"),
|
|
8
|
+
"Runtime lock files are local process state and should be regenerated locally.",
|
|
9
|
+
],
|
|
10
|
+
[
|
|
11
|
+
key("ignore", ".claude/cache/"),
|
|
12
|
+
"Claude cache contents are local generated data and can grow quickly.",
|
|
13
|
+
],
|
|
14
|
+
[
|
|
15
|
+
key("ignore", ".claude/.statusline-worktree-*"),
|
|
16
|
+
"Statusline worktree markers are local runtime state.",
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
key("ignore", "ai-docs/sessions/"),
|
|
20
|
+
"Session transcripts and scratch notes are local working artifacts.",
|
|
21
|
+
],
|
|
22
|
+
[
|
|
23
|
+
key("ignore", ".mnemex/"),
|
|
24
|
+
"Local memory/index data is machine-specific and regenerated by tooling.",
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
key("ignore", ".claudemem/"),
|
|
28
|
+
"Local claudemem indexes are generated from the repo and should not be committed.",
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
key("ignore", "gtd/sessions/"),
|
|
32
|
+
"Local GTD session artifacts are personal workflow state.",
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
key("ignore", ".agents/"),
|
|
36
|
+
"Local agent workspaces and runtime artifacts should stay out of team history.",
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
key("ignore", "node_modules/"),
|
|
40
|
+
"Installed dependencies are restored from the package manager lockfile.",
|
|
41
|
+
],
|
|
42
|
+
[
|
|
43
|
+
key("ignore", ".env"),
|
|
44
|
+
"Environment files commonly contain local secrets and machine-specific values.",
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
key("ignore", ".env.local"),
|
|
48
|
+
"Local environment overrides commonly contain secrets or developer-specific values.",
|
|
49
|
+
],
|
|
50
|
+
[
|
|
51
|
+
key("ignore", ".DS_Store"),
|
|
52
|
+
"macOS Finder metadata is machine-generated noise.",
|
|
53
|
+
],
|
|
54
|
+
[
|
|
55
|
+
key("ignore", "dist/"),
|
|
56
|
+
"Distribution output is generated from source during builds.",
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
key("ignore", "build/"),
|
|
60
|
+
"Build output is generated from source during builds.",
|
|
61
|
+
],
|
|
62
|
+
[
|
|
63
|
+
key("ignore", "*.log"),
|
|
64
|
+
"Log files are runtime output and usually contain noisy local details.",
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
key("ignore", "coverage/"),
|
|
68
|
+
"Coverage reports are generated by test runs.",
|
|
69
|
+
],
|
|
70
|
+
[
|
|
71
|
+
key("ignore", ".cache/"),
|
|
72
|
+
"Tool cache contents are local generated data.",
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
key("track", ".claude/settings.json"),
|
|
76
|
+
"Team Claude settings should be committed so everyone gets the same project behavior.",
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
key("track", ".mcp.json"),
|
|
80
|
+
"Team MCP configuration should be committed so shared tools are discoverable.",
|
|
81
|
+
],
|
|
82
|
+
[
|
|
83
|
+
key("track", "plugin.json"),
|
|
84
|
+
"The plugin manifest is source metadata required by the plugin system.",
|
|
85
|
+
],
|
|
86
|
+
]);
|
|
87
|
+
export function getGitignoreRuleReason(action, pattern) {
|
|
88
|
+
const reason = RULE_REASONS.get(key(action, pattern));
|
|
89
|
+
if (reason)
|
|
90
|
+
return reason;
|
|
91
|
+
return action === "ignore"
|
|
92
|
+
? "A managed rule says this path should stay out of git."
|
|
93
|
+
: "A managed rule says this path should stay tracked in git.";
|
|
94
|
+
}
|
|
95
|
+
function key(action, pattern) {
|
|
96
|
+
return `${action}:${pattern}`;
|
|
97
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { RuleAction } from "../types/gitignore.js";
|
|
2
|
+
|
|
3
|
+
const RULE_REASONS = new Map<string, string>([
|
|
4
|
+
[
|
|
5
|
+
key("ignore", ".claude/settings.local.json"),
|
|
6
|
+
"Personal Claude settings belong to each developer and should not be shared.",
|
|
7
|
+
],
|
|
8
|
+
[
|
|
9
|
+
key("ignore", ".claude/scheduled_tasks.lock"),
|
|
10
|
+
"Runtime lock files are local process state and should be regenerated locally.",
|
|
11
|
+
],
|
|
12
|
+
[
|
|
13
|
+
key("ignore", ".claude/cache/"),
|
|
14
|
+
"Claude cache contents are local generated data and can grow quickly.",
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
key("ignore", ".claude/.statusline-worktree-*"),
|
|
18
|
+
"Statusline worktree markers are local runtime state.",
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
key("ignore", "ai-docs/sessions/"),
|
|
22
|
+
"Session transcripts and scratch notes are local working artifacts.",
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
key("ignore", ".mnemex/"),
|
|
26
|
+
"Local memory/index data is machine-specific and regenerated by tooling.",
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
key("ignore", ".claudemem/"),
|
|
30
|
+
"Local claudemem indexes are generated from the repo and should not be committed.",
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
key("ignore", "gtd/sessions/"),
|
|
34
|
+
"Local GTD session artifacts are personal workflow state.",
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
key("ignore", ".agents/"),
|
|
38
|
+
"Local agent workspaces and runtime artifacts should stay out of team history.",
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
key("ignore", "node_modules/"),
|
|
42
|
+
"Installed dependencies are restored from the package manager lockfile.",
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
key("ignore", ".env"),
|
|
46
|
+
"Environment files commonly contain local secrets and machine-specific values.",
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
key("ignore", ".env.local"),
|
|
50
|
+
"Local environment overrides commonly contain secrets or developer-specific values.",
|
|
51
|
+
],
|
|
52
|
+
[
|
|
53
|
+
key("ignore", ".DS_Store"),
|
|
54
|
+
"macOS Finder metadata is machine-generated noise.",
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
key("ignore", "dist/"),
|
|
58
|
+
"Distribution output is generated from source during builds.",
|
|
59
|
+
],
|
|
60
|
+
[
|
|
61
|
+
key("ignore", "build/"),
|
|
62
|
+
"Build output is generated from source during builds.",
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
key("ignore", "*.log"),
|
|
66
|
+
"Log files are runtime output and usually contain noisy local details.",
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
key("ignore", "coverage/"),
|
|
70
|
+
"Coverage reports are generated by test runs.",
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
key("ignore", ".cache/"),
|
|
74
|
+
"Tool cache contents are local generated data.",
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
key("track", ".claude/settings.json"),
|
|
78
|
+
"Team Claude settings should be committed so everyone gets the same project behavior.",
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
key("track", ".mcp.json"),
|
|
82
|
+
"Team MCP configuration should be committed so shared tools are discoverable.",
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
key("track", "plugin.json"),
|
|
86
|
+
"The plugin manifest is source metadata required by the plugin system.",
|
|
87
|
+
],
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
export function getGitignoreRuleReason(
|
|
91
|
+
action: RuleAction,
|
|
92
|
+
pattern: string,
|
|
93
|
+
): string {
|
|
94
|
+
const reason = RULE_REASONS.get(key(action, pattern));
|
|
95
|
+
if (reason) return reason;
|
|
96
|
+
return action === "ignore"
|
|
97
|
+
? "A managed rule says this path should stay out of git."
|
|
98
|
+
: "A managed rule says this path should stay tracked in git.";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function key(action: RuleAction, pattern: string): string {
|
|
102
|
+
return `${action}:${pattern}`;
|
|
103
|
+
}
|
package/src/data/marketplaces.js
CHANGED
|
@@ -18,6 +18,7 @@ function normalizeRepo(repo) {
|
|
|
18
18
|
export const deprecatedMarketplaces = {
|
|
19
19
|
"mag-claude-plugins": "magus",
|
|
20
20
|
"MadAppGang-claude-code": "magus",
|
|
21
|
+
superpowers: "superpowers-marketplace",
|
|
21
22
|
};
|
|
22
23
|
export const defaultMarketplaces = [
|
|
23
24
|
{
|
|
@@ -41,6 +42,16 @@ export const defaultMarketplaces = [
|
|
|
41
42
|
description: "Official Anthropic-managed directory of high quality Claude Code plugins",
|
|
42
43
|
official: true,
|
|
43
44
|
},
|
|
45
|
+
{
|
|
46
|
+
name: "superpowers-marketplace",
|
|
47
|
+
displayName: "Superpowers",
|
|
48
|
+
source: {
|
|
49
|
+
source: "github",
|
|
50
|
+
repo: "obra/superpowers-marketplace",
|
|
51
|
+
},
|
|
52
|
+
description: "Curated Claude Code plugins for skills and workflows",
|
|
53
|
+
featured: true,
|
|
54
|
+
},
|
|
44
55
|
{
|
|
45
56
|
name: "claude-code-plugins",
|
|
46
57
|
displayName: "Anthropic Deprecated",
|
|
@@ -50,6 +61,7 @@ export const defaultMarketplaces = [
|
|
|
50
61
|
},
|
|
51
62
|
description: "Legacy demo plugins from Anthropic (deprecated - use Official instead)",
|
|
52
63
|
official: true,
|
|
64
|
+
deprecated: true,
|
|
53
65
|
},
|
|
54
66
|
];
|
|
55
67
|
export function getMarketplaceByName(name) {
|
|
@@ -93,6 +105,7 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
93
105
|
description: defaultMp?.description || local.description || "",
|
|
94
106
|
official: defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
95
107
|
featured: defaultMp?.featured,
|
|
108
|
+
deprecated: defaultMp?.deprecated,
|
|
96
109
|
});
|
|
97
110
|
}
|
|
98
111
|
}
|
|
@@ -105,7 +118,7 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
105
118
|
seenRepos.add(repo);
|
|
106
119
|
}
|
|
107
120
|
}
|
|
108
|
-
// Sort: Magus first, then alphabetically
|
|
121
|
+
// Sort: Magus first, deprecated last, then alphabetically
|
|
109
122
|
return Array.from(all.values()).sort((a, b) => {
|
|
110
123
|
// Magus (MadAppGang) always first
|
|
111
124
|
const aIsMag = a.source.repo?.toLowerCase().includes("madappgang/");
|
|
@@ -114,6 +127,11 @@ export function getAllMarketplaces(localMarketplaces) {
|
|
|
114
127
|
return -1;
|
|
115
128
|
if (!aIsMag && bIsMag)
|
|
116
129
|
return 1;
|
|
130
|
+
// Deprecated entries always last
|
|
131
|
+
if (a.deprecated && !b.deprecated)
|
|
132
|
+
return 1;
|
|
133
|
+
if (!a.deprecated && b.deprecated)
|
|
134
|
+
return -1;
|
|
117
135
|
// Then alphabetically by display name
|
|
118
136
|
return (a.displayName || a.name).localeCompare(b.displayName || b.name);
|
|
119
137
|
});
|
package/src/data/marketplaces.ts
CHANGED
|
@@ -23,6 +23,7 @@ function normalizeRepo(repo: string): string {
|
|
|
23
23
|
export const deprecatedMarketplaces: Record<string, string> = {
|
|
24
24
|
"mag-claude-plugins": "magus",
|
|
25
25
|
"MadAppGang-claude-code": "magus",
|
|
26
|
+
superpowers: "superpowers-marketplace",
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
export const defaultMarketplaces: Marketplace[] = [
|
|
@@ -49,6 +50,16 @@ export const defaultMarketplaces: Marketplace[] = [
|
|
|
49
50
|
"Official Anthropic-managed directory of high quality Claude Code plugins",
|
|
50
51
|
official: true,
|
|
51
52
|
},
|
|
53
|
+
{
|
|
54
|
+
name: "superpowers-marketplace",
|
|
55
|
+
displayName: "Superpowers",
|
|
56
|
+
source: {
|
|
57
|
+
source: "github",
|
|
58
|
+
repo: "obra/superpowers-marketplace",
|
|
59
|
+
},
|
|
60
|
+
description: "Curated Claude Code plugins for skills and workflows",
|
|
61
|
+
featured: true,
|
|
62
|
+
},
|
|
52
63
|
{
|
|
53
64
|
name: "claude-code-plugins",
|
|
54
65
|
displayName: "Anthropic Deprecated",
|
|
@@ -59,6 +70,7 @@ export const defaultMarketplaces: Marketplace[] = [
|
|
|
59
70
|
description:
|
|
60
71
|
"Legacy demo plugins from Anthropic (deprecated - use Official instead)",
|
|
61
72
|
official: true,
|
|
73
|
+
deprecated: true,
|
|
62
74
|
},
|
|
63
75
|
];
|
|
64
76
|
|
|
@@ -113,6 +125,7 @@ export function getAllMarketplaces(
|
|
|
113
125
|
official:
|
|
114
126
|
defaultMp?.official ?? repo.toLowerCase().includes("anthropics/"),
|
|
115
127
|
featured: defaultMp?.featured,
|
|
128
|
+
deprecated: defaultMp?.deprecated,
|
|
116
129
|
});
|
|
117
130
|
}
|
|
118
131
|
}
|
|
@@ -126,13 +139,16 @@ export function getAllMarketplaces(
|
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
141
|
|
|
129
|
-
// Sort: Magus first, then alphabetically
|
|
142
|
+
// Sort: Magus first, deprecated last, then alphabetically
|
|
130
143
|
return Array.from(all.values()).sort((a, b) => {
|
|
131
144
|
// Magus (MadAppGang) always first
|
|
132
145
|
const aIsMag = a.source.repo?.toLowerCase().includes("madappgang/");
|
|
133
146
|
const bIsMag = b.source.repo?.toLowerCase().includes("madappgang/");
|
|
134
147
|
if (aIsMag && !bIsMag) return -1;
|
|
135
148
|
if (!aIsMag && bIsMag) return 1;
|
|
149
|
+
// Deprecated entries always last
|
|
150
|
+
if (a.deprecated && !b.deprecated) return 1;
|
|
151
|
+
if (!a.deprecated && b.deprecated) return -1;
|
|
136
152
|
// Then alphabetically by display name
|
|
137
153
|
return (a.displayName || a.name).localeCompare(b.displayName || b.name);
|
|
138
154
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read/write the managed-alias name in Claude Code's `settings.json`.
|
|
3
|
+
*
|
|
4
|
+
* The alias is computer-wide (one name per user), so it lives in
|
|
5
|
+
* `~/.claude/settings.json` only — no project scope. We store it under a
|
|
6
|
+
* `claudeup` namespace to avoid colliding with Claude Code's own keys:
|
|
7
|
+
*
|
|
8
|
+
* {
|
|
9
|
+
* "model": "sonnet",
|
|
10
|
+
* "claudeup": {
|
|
11
|
+
* "aliasName": "c"
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Flag values are NOT stored here. They live in the shell rc file's managed
|
|
16
|
+
* block and are read on screen mount via `parseAliasFromRc`.
|
|
17
|
+
*/
|
|
18
|
+
import { readGlobalSettings, writeGlobalSettings, } from "./claude-settings.js";
|
|
19
|
+
import { DEFAULT_ALIAS_NAME, validateAliasName } from "./alias-store.js";
|
|
20
|
+
/**
|
|
21
|
+
* Load the user's preferred alias name from `~/.claude/settings.json`.
|
|
22
|
+
* Returns the default `"c"` when the key is absent or invalid.
|
|
23
|
+
*/
|
|
24
|
+
export async function loadAliasName() {
|
|
25
|
+
const settings = (await readGlobalSettings());
|
|
26
|
+
const stored = settings.claudeup?.aliasName;
|
|
27
|
+
if (typeof stored !== "string")
|
|
28
|
+
return DEFAULT_ALIAS_NAME;
|
|
29
|
+
if (validateAliasName(stored) !== null)
|
|
30
|
+
return DEFAULT_ALIAS_NAME;
|
|
31
|
+
return stored;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Save the alias name to `~/.claude/settings.json`, preserving all other
|
|
35
|
+
* keys (including unrelated Claude Code settings). No-op without throwing
|
|
36
|
+
* if the name fails validation — caller should validate first.
|
|
37
|
+
*/
|
|
38
|
+
export async function saveAliasName(name) {
|
|
39
|
+
if (validateAliasName(name) !== null)
|
|
40
|
+
return;
|
|
41
|
+
const settings = (await readGlobalSettings());
|
|
42
|
+
const next = {
|
|
43
|
+
...settings,
|
|
44
|
+
claudeup: {
|
|
45
|
+
...(settings.claudeup ?? {}),
|
|
46
|
+
aliasName: name,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
// claude-settings.writeGlobalSettings accepts the same shape we received.
|
|
50
|
+
await writeGlobalSettings(next);
|
|
51
|
+
}
|