claudeup 4.17.0 → 4.19.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.
Files changed (86) hide show
  1. package/package.json +1 -1
  2. package/src/__tests__/alias-adopt.test.ts +364 -0
  3. package/src/__tests__/alias-parser.test.ts +409 -0
  4. package/src/__tests__/alias-shell-writer.test.ts +668 -0
  5. package/src/__tests__/alias-store.test.ts +163 -0
  6. package/src/__tests__/gitignore-fixer.test.ts +64 -1
  7. package/src/__tests__/gitignore-prerun.test.ts +2 -2
  8. package/src/__tests__/gitignore-service.test.ts +42 -0
  9. package/src/__tests__/marketplaces.test.ts +40 -0
  10. package/src/__tests__/plugin-manager-fallback.test.ts +120 -0
  11. package/src/__tests__/plugin-setup.test.ts +111 -0
  12. package/src/__tests__/useGitignoreModal.test.ts +2 -2
  13. package/src/data/alias-flags.js +205 -0
  14. package/src/data/alias-flags.ts +301 -0
  15. package/src/data/gitignore-reasons.js +97 -0
  16. package/src/data/gitignore-reasons.ts +103 -0
  17. package/src/data/marketplaces.js +5 -3
  18. package/src/data/marketplaces.ts +5 -4
  19. package/src/services/alias-settings.js +51 -0
  20. package/src/services/alias-settings.ts +63 -0
  21. package/src/services/alias-shell-writer.js +1018 -0
  22. package/src/services/alias-shell-writer.ts +1247 -0
  23. package/src/services/alias-store.js +129 -0
  24. package/src/services/alias-store.ts +172 -0
  25. package/src/services/gitignore-fixer.js +70 -10
  26. package/src/services/gitignore-fixer.ts +76 -9
  27. package/src/services/gitignore-prerun.js +3 -3
  28. package/src/services/gitignore-prerun.ts +3 -3
  29. package/src/services/gitignore-service.js +20 -2
  30. package/src/services/gitignore-service.ts +23 -1
  31. package/src/services/marketplace-fetcher.js +96 -0
  32. package/src/services/marketplace-fetcher.ts +137 -0
  33. package/src/services/plugin-manager.js +6 -59
  34. package/src/services/plugin-manager.ts +16 -91
  35. package/src/services/plugin-setup.js +59 -4
  36. package/src/services/plugin-setup.ts +61 -4
  37. package/src/services/skillsmp-client.js +29 -9
  38. package/src/services/skillsmp-client.ts +38 -8
  39. package/src/types/gitignore.ts +1 -1
  40. package/src/ui/App.js +26 -11
  41. package/src/ui/App.tsx +25 -10
  42. package/src/ui/components/FlagDetailEditor.js +0 -0
  43. package/src/ui/components/FlagDetailEditor.tsx +0 -0
  44. package/src/ui/components/TabBar.js +2 -1
  45. package/src/ui/components/TabBar.tsx +2 -1
  46. package/src/ui/components/layout/FooterHints.js +29 -0
  47. package/src/ui/components/layout/FooterHints.tsx +52 -0
  48. package/src/ui/components/layout/ScreenLayout.js +2 -1
  49. package/src/ui/components/layout/ScreenLayout.tsx +12 -3
  50. package/src/ui/components/layout/index.js +1 -0
  51. package/src/ui/components/layout/index.ts +5 -0
  52. package/src/ui/components/modals/ConfirmModal.js +1 -1
  53. package/src/ui/components/modals/ConfirmModal.tsx +1 -1
  54. package/src/ui/components/modals/SelectModal.js +8 -1
  55. package/src/ui/components/modals/SelectModal.tsx +12 -1
  56. package/src/ui/hooks/useGitignoreModal.js +7 -8
  57. package/src/ui/hooks/useGitignoreModal.ts +8 -9
  58. package/src/ui/renderers/gitignoreRenderers.js +36 -23
  59. package/src/ui/renderers/gitignoreRenderers.tsx +50 -41
  60. package/src/ui/screens/AliasScreen.js +1111 -0
  61. package/src/ui/screens/AliasScreen.tsx +1534 -0
  62. package/src/ui/screens/CliToolsScreen.js +6 -1
  63. package/src/ui/screens/CliToolsScreen.tsx +6 -1
  64. package/src/ui/screens/EnvVarsScreen.js +6 -1
  65. package/src/ui/screens/EnvVarsScreen.tsx +6 -1
  66. package/src/ui/screens/GitignoreScreen.js +189 -88
  67. package/src/ui/screens/GitignoreScreen.tsx +312 -132
  68. package/src/ui/screens/McpRegistryScreen.js +13 -2
  69. package/src/ui/screens/McpRegistryScreen.tsx +13 -2
  70. package/src/ui/screens/McpScreen.js +6 -1
  71. package/src/ui/screens/McpScreen.tsx +6 -1
  72. package/src/ui/screens/ModelSelectorScreen.js +8 -2
  73. package/src/ui/screens/ModelSelectorScreen.tsx +8 -2
  74. package/src/ui/screens/PluginsScreen.js +17 -3
  75. package/src/ui/screens/PluginsScreen.tsx +16 -3
  76. package/src/ui/screens/ProfilesScreen.js +8 -1
  77. package/src/ui/screens/ProfilesScreen.tsx +8 -1
  78. package/src/ui/screens/SkillsScreen.js +21 -4
  79. package/src/ui/screens/SkillsScreen.tsx +39 -5
  80. package/src/ui/screens/StatusLineScreen.js +7 -1
  81. package/src/ui/screens/StatusLineScreen.tsx +7 -1
  82. package/src/ui/screens/index.js +1 -0
  83. package/src/ui/screens/index.ts +1 -0
  84. package/src/ui/state/reducer.js +5 -1
  85. package/src/ui/state/reducer.ts +6 -1
  86. package/src/ui/state/types.ts +12 -2
@@ -5,7 +5,7 @@ import type { ModalState } from "../state/types.js";
5
5
  /**
6
6
  * Startup gitignore-violation modal. Mirrors `useMismatchModal` so the
7
7
  * two flows feel identical to the user — claudeup launches, detects
8
- * a problem, asks "fix safe entries / open the tab / dismiss".
8
+ * a problem, asks "add missing ignores / open the tab / dismiss".
9
9
  *
10
10
  * Pure builder is exported separately for tests.
11
11
  */
@@ -24,12 +24,12 @@ export function buildGitignoreModal(args: BuildModalArgs): ModalState {
24
24
  {
25
25
  label:
26
26
  safeCount > 0
27
- ? `Append ${safeCount} safe entr${safeCount === 1 ? "y" : "ies"} to .gitignore`
28
- : "(no safe-fixable entries)",
27
+ ? `Add ${safeCount} missing .gitignore entr${safeCount === 1 ? "y" : "ies"}`
28
+ : "(no missing .gitignore entries)",
29
29
  value: "fix-safe",
30
30
  },
31
31
  {
32
- label: "Open Gitignore tab to review",
32
+ label: "Open Git State tab to review",
33
33
  value: "open-tab",
34
34
  },
35
35
  {
@@ -41,11 +41,10 @@ export function buildGitignoreModal(args: BuildModalArgs): ModalState {
41
41
  type: "select",
42
42
  title: "Gitignore violations detected",
43
43
  message:
44
- `Found ${violationCount} issue(s) where the resolved gitignore manifest ` +
45
- `disagrees with your working tree.\n\n` +
46
- `Safe fixes append to .gitignore (no index mutation). Destructive fixes ` +
47
- `(\`git rm --cached\`, removing .gitignore lines) must be applied one at ` +
48
- `a time from the Gitignore tab.`,
44
+ `Found ${violationCount} managed gitignore item(s) that do not match ` +
45
+ `the current repo state.\n\n` +
46
+ `Missing .gitignore entries can be added now. Items that change git ` +
47
+ `tracking are reviewed and fixed from the Gitignore tab.`,
49
48
  options,
50
49
  onSelect: (value: string) => {
51
50
  if (value === "fix-safe") onFixSafe();
@@ -1,33 +1,46 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- const SELECTION_BG = "#7e57c2";
3
- const SELECTION_FG = "white";
4
- // Layout: " X Verb path" 2 (gutter) + 2 (status) + 7 (verb) + 4 (gap)
5
- // = 15 prefix chars. On a 38-col panel inner width that leaves 23 chars for
6
- // the path; truncate at 22 to keep 1 col safety margin (OpenTUI <text>
7
- // reserves a second line if the rendered string equals the inner width).
2
+ // Two color channels that never collide:
3
+ // • Badge color = direction (where the item ends up): green = tracked by git,
4
+ // reddish = ignored/dropped from git. Same on clean AND violation rows.
5
+ // Filename color = severity: dim gray when fine, red when it's a violation.
6
+ // No row background tints red is reserved entirely for "needs attention".
7
+ const TRACK_FG = "#5fd787"; // green item ends up tracked by git
8
+ const IGNORE_FG = "#d78787"; // reddish — item ends up ignored / dropped
9
+ const VIOLATION_PATH_FG = "#ff5f5f"; // bright red filename = look here
10
+ const CLEAN_PATH_FG = "gray";
11
+ const SELECTED_BG = "#2a2a3a"; // faint slate highlight for the cursor row
12
+ // Violation badges are solid chips so the required direction reads at a glance:
13
+ // green chip = will be tracked, red chip = will be ignored/dropped.
14
+ const TRACK_CHIP_BG = "#1f5132";
15
+ const IGNORE_CHIP_BG = "#5a2323";
16
+ const CHIP_FG = "white";
17
+ // The only marker is the cursor: ▶ on the selected row, blank otherwise.
18
+ // Action (track/ignore) is read from the badge word and, for clean items,
19
+ // from the group the row sits under — so no per-row dot is needed.
20
+ const MARKER_SELECTED = "▶";
21
+ const MARKER_NONE = " ";
22
+ // Layout: " M action path" — keep the prefix compact so the narrow terminal
23
+ // case still has room for the path without wrapping.
8
24
  const MAX_PATH_LEN = 22;
9
25
  function truncatePath(p) {
10
26
  return p.length > MAX_PATH_LEN ? p.slice(0, MAX_PATH_LEN - 1) + "…" : p;
11
27
  }
12
28
  export function renderRuleRow(row, isSelected) {
13
- const { rule, violation } = row;
29
+ const { rule, violations } = row;
14
30
  const path = truncatePath(rule.pattern);
15
31
  const key = `${rule.action}:${rule.pattern}`;
16
- // Layout: status-glyph (2) + verb (7) + 2 spaces + path
17
- // OK rule: Ignore path
18
- // Violated:! Track path
19
- const verb = rule.action === "ignore" ? "Ignore " : "Track ";
20
- if (!violation) {
21
- // Clean rule muted, just confirmation
22
- if (isSelected) {
23
- return (_jsx("text", { bg: SELECTION_BG, fg: SELECTION_FG, children: `▶ ✓ ${verb} ${path}` }, key));
24
- }
25
- return (_jsxs("text", { children: [_jsx("span", { fg: "green", children: ` ✓ ` }), _jsx("span", { fg: "gray", children: `${verb} ${path}` })] }, key));
32
+ // Badge text padded to a fixed width so paths line up in a column.
33
+ const badge = rule.action === "ignore" ? "ignore" : "track ";
34
+ const badgeFg = rule.action === "ignore" ? IGNORE_FG : TRACK_FG;
35
+ const suffix = violations.length > 1 ? ` +${violations.length - 1}` : "";
36
+ const rowBg = isSelected ? SELECTED_BG : undefined;
37
+ const marker = isSelected ? MARKER_SELECTED : MARKER_NONE;
38
+ const isViolation = violations.length > 0;
39
+ if (isViolation) {
40
+ // Solid badge chip + red filename. The chip color is the fix direction.
41
+ const chipBg = rule.action === "ignore" ? IGNORE_CHIP_BG : TRACK_CHIP_BG;
42
+ return (_jsxs("text", { bg: rowBg, children: [_jsx("span", { fg: VIOLATION_PATH_FG, children: ` ${marker} ` }), _jsx("span", { bg: chipBg, fg: CHIP_FG, children: ` ${badge} ` }), _jsx("span", { fg: VIOLATION_PATH_FG, children: ` ${path}${suffix}` })] }, key));
26
43
  }
27
- // Violated rule color encodes severity of the fix
28
- const sevColor = violation.severity === "safe" ? "yellow" : "red";
29
- if (isSelected) {
30
- return (_jsx("text", { bg: SELECTION_BG, fg: SELECTION_FG, children: `▶ ! ${verb} ${path}` }, key));
31
- }
32
- return (_jsxs("text", { children: [_jsx("span", { fg: sevColor, children: ` ! ` }), _jsx("span", { fg: "white", children: `${verb} ${path}` })] }, key));
44
+ // Clean row: flat colored badge word, dim path, no chip.
45
+ return (_jsxs("text", { bg: rowBg, children: [_jsx("span", { fg: badgeFg, children: ` ${marker} ` }), _jsx("span", { fg: badgeFg, children: badge }), _jsx("span", { fg: CLEAN_PATH_FG, children: ` ${path}` })] }, key));
33
46
  }
@@ -3,68 +3,77 @@ import type { ResolvedRule, Violation } from "../../types/gitignore.js";
3
3
 
4
4
  /**
5
5
  * A unified row for the Gitignore screen — represents one resolved rule,
6
- * optionally annotated with the violation it has against the working tree.
6
+ * annotated with every violation it has against the working tree.
7
7
  */
8
8
  export interface RuleRow {
9
9
  rule: ResolvedRule;
10
- violation?: Violation;
10
+ violations: Violation[];
11
11
  }
12
12
 
13
- const SELECTION_BG = "#7e57c2";
14
- const SELECTION_FG = "white";
13
+ // Two color channels that never collide:
14
+ // • Badge color = direction (where the item ends up): green = tracked by git,
15
+ // reddish = ignored/dropped from git. Same on clean AND violation rows.
16
+ // • Filename color = severity: dim gray when fine, red when it's a violation.
17
+ // No row background tints — red is reserved entirely for "needs attention".
18
+ const TRACK_FG = "#5fd787"; // green — item ends up tracked by git
19
+ const IGNORE_FG = "#d78787"; // reddish — item ends up ignored / dropped
20
+ const VIOLATION_PATH_FG = "#ff5f5f"; // bright red filename = look here
21
+ const CLEAN_PATH_FG = "gray";
22
+ const SELECTED_BG = "#2a2a3a"; // faint slate highlight for the cursor row
15
23
 
16
- // Layout: " X Verb path" 2 (gutter) + 2 (status) + 7 (verb) + 4 (gap)
17
- // = 15 prefix chars. On a 38-col panel inner width that leaves 23 chars for
18
- // the path; truncate at 22 to keep 1 col safety margin (OpenTUI <text>
19
- // reserves a second line if the rendered string equals the inner width).
24
+ // Violation badges are solid chips so the required direction reads at a glance:
25
+ // green chip = will be tracked, red chip = will be ignored/dropped.
26
+ const TRACK_CHIP_BG = "#1f5132";
27
+ const IGNORE_CHIP_BG = "#5a2323";
28
+ const CHIP_FG = "white";
29
+
30
+ // The only marker is the cursor: ▶ on the selected row, blank otherwise.
31
+ // Action (track/ignore) is read from the badge word and, for clean items,
32
+ // from the group the row sits under — so no per-row dot is needed.
33
+ const MARKER_SELECTED = "▶";
34
+ const MARKER_NONE = " ";
35
+
36
+ // Layout: " M action path" — keep the prefix compact so the narrow terminal
37
+ // case still has room for the path without wrapping.
20
38
  const MAX_PATH_LEN = 22;
21
39
 
22
40
  function truncatePath(p: string): string {
23
41
  return p.length > MAX_PATH_LEN ? p.slice(0, MAX_PATH_LEN - 1) + "…" : p;
24
42
  }
25
43
 
26
- export function renderRuleRow(row: RuleRow, isSelected: boolean): React.ReactNode {
27
- const { rule, violation } = row;
44
+ export function renderRuleRow(
45
+ row: RuleRow,
46
+ isSelected: boolean,
47
+ ): React.ReactNode {
48
+ const { rule, violations } = row;
28
49
  const path = truncatePath(rule.pattern);
29
50
  const key = `${rule.action}:${rule.pattern}`;
51
+ // Badge text padded to a fixed width so paths line up in a column.
52
+ const badge = rule.action === "ignore" ? "ignore" : "track ";
53
+ const badgeFg = rule.action === "ignore" ? IGNORE_FG : TRACK_FG;
54
+ const suffix = violations.length > 1 ? ` +${violations.length - 1}` : "";
55
+ const rowBg = isSelected ? SELECTED_BG : undefined;
56
+ const marker = isSelected ? MARKER_SELECTED : MARKER_NONE;
57
+ const isViolation = violations.length > 0;
30
58
 
31
- // Layout: status-glyph (2) + verb (7) + 2 spaces + path
32
- // OK rule: Ignore path
33
- // Violated:! Track path
34
-
35
- const verb = rule.action === "ignore" ? "Ignore " : "Track ";
36
-
37
- if (!violation) {
38
- // Clean rule — muted, just confirmation
39
- if (isSelected) {
40
- return (
41
- <text key={key} bg={SELECTION_BG} fg={SELECTION_FG}>
42
- {`▶ ✓ ${verb} ${path}`}
43
- </text>
44
- );
45
- }
59
+ if (isViolation) {
60
+ // Solid badge chip + red filename. The chip color is the fix direction.
61
+ const chipBg = rule.action === "ignore" ? IGNORE_CHIP_BG : TRACK_CHIP_BG;
46
62
  return (
47
- <text key={key}>
48
- <span fg="green">{` `}</span>
49
- <span fg="gray">{`${verb} ${path}`}</span>
63
+ <text key={key} bg={rowBg}>
64
+ <span fg={VIOLATION_PATH_FG}>{` ${marker} `}</span>
65
+ <span bg={chipBg} fg={CHIP_FG}>{` ${badge} `}</span>
66
+ <span fg={VIOLATION_PATH_FG}>{` ${path}${suffix}`}</span>
50
67
  </text>
51
68
  );
52
69
  }
53
70
 
54
- // Violated rule color encodes severity of the fix
55
- const sevColor = violation.severity === "safe" ? "yellow" : "red";
56
-
57
- if (isSelected) {
58
- return (
59
- <text key={key} bg={SELECTION_BG} fg={SELECTION_FG}>
60
- {`▶ ! ${verb} ${path}`}
61
- </text>
62
- );
63
- }
71
+ // Clean row: flat colored badge word, dim path, no chip.
64
72
  return (
65
- <text key={key}>
66
- <span fg={sevColor}>{` ! `}</span>
67
- <span fg="white">{`${verb} ${path}`}</span>
73
+ <text key={key} bg={rowBg}>
74
+ <span fg={badgeFg}>{` ${marker} `}</span>
75
+ <span fg={badgeFg}>{badge}</span>
76
+ <span fg={CLEAN_PATH_FG}>{` ${path}`}</span>
68
77
  </text>
69
78
  );
70
79
  }