claudeup 6.2.0 → 6.3.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 (153) hide show
  1. package/README.md +22 -0
  2. package/bin/claudeup.js +6 -1
  3. package/package.json +6 -6
  4. package/src/__tests__/alias-adopt.test.ts +331 -329
  5. package/src/__tests__/alias-parser.test.ts +384 -376
  6. package/src/__tests__/alias-shell-writer.test.ts +638 -625
  7. package/src/__tests__/alias-store.test.ts +143 -143
  8. package/src/__tests__/catalog-cache-store.test.ts +265 -265
  9. package/src/__tests__/catalog-notice.test.ts +123 -123
  10. package/src/__tests__/cli-apply-seams.test.ts +12 -8
  11. package/src/__tests__/cli-router.test.ts +132 -3
  12. package/src/__tests__/cli-update-view.test.ts +27 -8
  13. package/src/__tests__/community-staleness.test.ts +0 -2
  14. package/src/__tests__/component-badge.test.ts +4 -4
  15. package/src/__tests__/content-drift.test.ts +5 -1
  16. package/src/__tests__/conventions-integration.test.ts +774 -689
  17. package/src/__tests__/conventions-manager.test.ts +1216 -1152
  18. package/src/__tests__/doctor-bins.test.ts +14 -6
  19. package/src/__tests__/doctor.test.ts +438 -425
  20. package/src/__tests__/dual-write-prevention.test.ts +277 -282
  21. package/src/__tests__/enabled-not-installed.test.ts +71 -63
  22. package/src/__tests__/file-locking.test.ts +196 -196
  23. package/src/__tests__/gap-fill-versions.test.ts +318 -311
  24. package/src/__tests__/github-budget.test.ts +170 -164
  25. package/src/__tests__/gitignore-detector.test.ts +160 -152
  26. package/src/__tests__/gitignore-fixer.test.ts +285 -247
  27. package/src/__tests__/gitignore-prerun.test.ts +57 -57
  28. package/src/__tests__/gitignore-resolver.test.ts +173 -146
  29. package/src/__tests__/gitignore-service.test.ts +121 -119
  30. package/src/__tests__/go-module.test.ts +43 -0
  31. package/src/__tests__/install-command.test.ts +3 -3
  32. package/src/__tests__/install-plan.test.ts +13 -7
  33. package/src/__tests__/manifest.test.ts +16 -5
  34. package/src/__tests__/markdown-renderer.test.ts +0 -1
  35. package/src/__tests__/marketplace-badge.test.ts +111 -90
  36. package/src/__tests__/marketplace-version.test.ts +64 -61
  37. package/src/__tests__/plugin-manager-fallback.test.ts +249 -239
  38. package/src/__tests__/plugin-requires.test.ts +55 -1
  39. package/src/__tests__/plugin-setup.test.ts +111 -9
  40. package/src/__tests__/profile-command.test.ts +1 -7
  41. package/src/__tests__/profile-materializer.test.ts +31 -8
  42. package/src/__tests__/profile-sync.test.ts +23 -5
  43. package/src/__tests__/registry-version-resolution.test.ts +61 -47
  44. package/src/__tests__/resolve-executable.test.ts +1 -1
  45. package/src/__tests__/resolver.test.ts +38 -13
  46. package/src/__tests__/scope-action.test.ts +52 -50
  47. package/src/__tests__/scope-squares.test.tsx +4 -5
  48. package/src/__tests__/skill-install-files.test.ts +111 -103
  49. package/src/__tests__/symlink-manager.test.ts +27 -10
  50. package/src/__tests__/theme-env.test.ts +281 -0
  51. package/src/__tests__/theme-resolve.test.ts +380 -0
  52. package/src/__tests__/update-apply.test.ts +1 -3
  53. package/src/__tests__/useGitignoreModal.test.ts +69 -61
  54. package/src/__tests__/version-snapshot.test.ts +183 -165
  55. package/src/cli/ansi.ts +23 -15
  56. package/src/cli/doctor.ts +10 -9
  57. package/src/cli/install.ts +3 -3
  58. package/src/cli/profile.ts +5 -4
  59. package/src/cli/prompt.ts +0 -1
  60. package/src/cli/router.ts +69 -2
  61. package/src/cli/update-view.ts +11 -6
  62. package/src/cli/update.ts +9 -4
  63. package/src/cli/upgrade.ts +6 -4
  64. package/src/data/alias-flags.ts +260 -260
  65. package/src/data/gitignore-defaults.ts +20 -20
  66. package/src/data/gitignore-reasons.ts +86 -92
  67. package/src/data/gitignore-templates.ts +14 -14
  68. package/src/data/predefined-profiles.ts +1 -2
  69. package/src/data/skill-repos.ts +43 -35
  70. package/src/main.tsx +29 -6
  71. package/src/opentui.d.ts +1 -3
  72. package/src/prerunner/index.ts +7 -8
  73. package/src/services/alias-settings.ts +20 -23
  74. package/src/services/alias-shell-writer.ts +800 -803
  75. package/src/services/alias-store.ts +77 -77
  76. package/src/services/claude-settings.ts +27 -18
  77. package/src/services/content-drift.ts +14 -4
  78. package/src/services/conventions-manager.ts +692 -617
  79. package/src/services/doctor.ts +464 -403
  80. package/src/services/gitignore-detector.ts +113 -103
  81. package/src/services/gitignore-fixer.ts +204 -189
  82. package/src/services/gitignore-prerun.ts +26 -26
  83. package/src/services/gitignore-resolver.ts +162 -144
  84. package/src/services/gitignore-service.ts +120 -117
  85. package/src/services/install-plan.ts +4 -4
  86. package/src/services/local-marketplace.ts +7 -5
  87. package/src/services/manifest.ts +1 -1
  88. package/src/services/marketplace-catalog-git.ts +5 -2
  89. package/src/services/marketplace-fetcher.ts +241 -235
  90. package/src/services/plugin-manager.ts +17 -20
  91. package/src/services/plugin-mcp-config.ts +2 -2
  92. package/src/services/plugin-requires.ts +16 -8
  93. package/src/services/plugin-setup.ts +32 -15
  94. package/src/services/plugin-version-check.ts +4 -4
  95. package/src/services/profile-materializer.ts +9 -5
  96. package/src/services/profile-sync.ts +12 -4
  97. package/src/services/profiles.ts +3 -3
  98. package/src/services/resolver.ts +10 -6
  99. package/src/services/settings-manager.ts +82 -46
  100. package/src/services/skills-manager.ts +11 -9
  101. package/src/services/symlink-manager.ts +2 -5
  102. package/src/services/toolchain.ts +3 -3
  103. package/src/services/update-cache.ts +1 -1
  104. package/src/services/update-engine.ts +4 -4
  105. package/src/services/update-plan.ts +9 -11
  106. package/src/services/version-snapshot.ts +88 -88
  107. package/src/types/gitignore.ts +28 -28
  108. package/src/ui/App.tsx +36 -36
  109. package/src/ui/adapters/settingsAdapter.ts +2 -2
  110. package/src/ui/components/CategoryHeader.tsx +1 -1
  111. package/src/ui/components/FlagDetailEditor.tsx +0 -0
  112. package/src/ui/components/ScopeIndicator.tsx +3 -1
  113. package/src/ui/components/ScrollableList.tsx +2 -1
  114. package/src/ui/components/StyledText.tsx +1 -1
  115. package/src/ui/components/layout/FooterHints.tsx +5 -3
  116. package/src/ui/components/layout/Panel.tsx +2 -2
  117. package/src/ui/components/layout/ScreenLayout.tsx +5 -4
  118. package/src/ui/components/modals/InputModal.tsx +7 -1
  119. package/src/ui/components/modals/ModalContainer.tsx +3 -3
  120. package/src/ui/components/modals/SelectModal.tsx +1 -1
  121. package/src/ui/components/primitives/DetailSection.tsx +1 -1
  122. package/src/ui/components/primitives/KeyValueLine.tsx +1 -1
  123. package/src/ui/components/primitives/ScopeSquares.tsx +2 -2
  124. package/src/ui/hooks/index.ts +0 -1
  125. package/src/ui/hooks/useGitignoreModal.ts +1 -5
  126. package/src/ui/hooks/useMismatchModal.ts +4 -10
  127. package/src/ui/renderers/cliToolRenderers.tsx +2 -2
  128. package/src/ui/renderers/gitignoreRenderers.tsx +2 -2
  129. package/src/ui/renderers/mcpRenderers.tsx +1 -1
  130. package/src/ui/renderers/pluginRenderers.tsx +3 -9
  131. package/src/ui/renderers/profileRenderers.tsx +9 -8
  132. package/src/ui/renderers/settingsRenderers.tsx +4 -4
  133. package/src/ui/renderers/skillRenderers.tsx +14 -14
  134. package/src/ui/screens/AliasScreen.tsx +31 -34
  135. package/src/ui/screens/CliToolsScreen.tsx +14 -13
  136. package/src/ui/screens/EnvVarsScreen.tsx +8 -8
  137. package/src/ui/screens/GitignoreScreen.tsx +15 -14
  138. package/src/ui/screens/McpRegistryScreen.tsx +10 -7
  139. package/src/ui/screens/McpScreen.tsx +10 -10
  140. package/src/ui/screens/PluginsScreen.tsx +17 -21
  141. package/src/ui/screens/ProfilesScreen.tsx +25 -24
  142. package/src/ui/screens/SkillsScreen.tsx +16 -14
  143. package/src/ui/state/AppContext.tsx +4 -8
  144. package/src/ui/state/DimensionsContext.tsx +3 -2
  145. package/src/ui/theme-mode.ts +20 -38
  146. package/src/ui/theme-resolve.ts +148 -0
  147. package/src/utils/clipboard.ts +5 -5
  148. package/src/utils/command-utils.ts +2 -2
  149. package/src/utils/config-dir.ts +1 -3
  150. package/src/utils/file-locking.ts +88 -86
  151. package/src/utils/go-module.ts +36 -0
  152. package/src/ui/hooks/useAsyncData.ts +0 -127
  153. package/src/ui/state/AnimationContext.tsx +0 -76
@@ -25,66 +25,66 @@ import { join } from "node:path";
25
25
  import type { ResolvedManifest, Violation } from "../types/gitignore.js";
26
26
 
27
27
  export async function detectViolations(
28
- cwd: string,
29
- resolved: ResolvedManifest,
28
+ cwd: string,
29
+ resolved: ResolvedManifest,
30
30
  ): Promise<Violation[]> {
31
- if (!(await isGitRepo(cwd))) return [];
31
+ if (!(await isGitRepo(cwd))) return [];
32
32
 
33
- const violations: Violation[] = [];
34
- const trackedFiles = await listTrackedFiles(cwd);
35
- const trackedSet = new Set(trackedFiles);
33
+ const violations: Violation[] = [];
34
+ const trackedFiles = await listTrackedFiles(cwd);
35
+ const trackedSet = new Set(trackedFiles);
36
36
 
37
- for (const rule of resolved.rules) {
38
- if (rule.action === "ignore") {
39
- const tracked = matchesTrackedFile(rule.pattern, trackedSet);
40
- if (tracked.length > 0) {
41
- for (const path of tracked) {
42
- violations.push({
43
- kind: "tracked-but-should-ignore",
44
- path,
45
- source: rule.source,
46
- severity: "destructive",
47
- });
48
- }
49
- } else {
50
- // Not tracked — check if .gitignore covers it. If not, suggest
51
- // a safe additive fix (append to .gitignore).
52
- const ignored = await pathIsIgnored(cwd, rule.pattern);
53
- if (!ignored) {
54
- violations.push({
55
- kind: "missing-from-gitignore",
56
- path: rule.pattern,
57
- source: rule.source,
58
- severity: "safe",
59
- });
60
- }
61
- }
62
- } else {
63
- // action === "track"
64
- const ignored = await pathIsIgnored(cwd, rule.pattern);
65
- if (ignored) {
66
- violations.push({
67
- kind: "ignored-but-should-track",
68
- path: rule.pattern,
69
- source: rule.source,
70
- severity: "destructive",
71
- });
72
- continue;
73
- }
74
- const isTracked = trackedSet.has(rule.pattern);
75
- const existsOnDisk = existsSync(join(cwd, rule.pattern));
76
- if (existsOnDisk && !isTracked) {
77
- violations.push({
78
- kind: "untracked-and-should-track",
79
- path: rule.pattern,
80
- source: rule.source,
81
- severity: "destructive",
82
- });
83
- }
84
- }
85
- }
37
+ for (const rule of resolved.rules) {
38
+ if (rule.action === "ignore") {
39
+ const tracked = matchesTrackedFile(rule.pattern, trackedSet);
40
+ if (tracked.length > 0) {
41
+ for (const path of tracked) {
42
+ violations.push({
43
+ kind: "tracked-but-should-ignore",
44
+ path,
45
+ source: rule.source,
46
+ severity: "destructive",
47
+ });
48
+ }
49
+ } else {
50
+ // Not tracked — check if .gitignore covers it. If not, suggest
51
+ // a safe additive fix (append to .gitignore).
52
+ const ignored = await pathIsIgnored(cwd, rule.pattern);
53
+ if (!ignored) {
54
+ violations.push({
55
+ kind: "missing-from-gitignore",
56
+ path: rule.pattern,
57
+ source: rule.source,
58
+ severity: "safe",
59
+ });
60
+ }
61
+ }
62
+ } else {
63
+ // action === "track"
64
+ const ignored = await pathIsIgnored(cwd, rule.pattern);
65
+ if (ignored) {
66
+ violations.push({
67
+ kind: "ignored-but-should-track",
68
+ path: rule.pattern,
69
+ source: rule.source,
70
+ severity: "destructive",
71
+ });
72
+ continue;
73
+ }
74
+ const isTracked = trackedSet.has(rule.pattern);
75
+ const existsOnDisk = existsSync(join(cwd, rule.pattern));
76
+ if (existsOnDisk && !isTracked) {
77
+ violations.push({
78
+ kind: "untracked-and-should-track",
79
+ path: rule.pattern,
80
+ source: rule.source,
81
+ severity: "destructive",
82
+ });
83
+ }
84
+ }
85
+ }
86
86
 
87
- return violations;
87
+ return violations;
88
88
  }
89
89
 
90
90
  /**
@@ -92,66 +92,76 @@ export async function detectViolations(
92
92
  * (trailing "/") match every tracked path under that prefix.
93
93
  */
94
94
  function matchesTrackedFile(pattern: string, tracked: Set<string>): string[] {
95
- if (pattern.endsWith("/")) {
96
- const prefix = pattern;
97
- return Array.from(tracked).filter((p) => p.startsWith(prefix));
98
- }
99
- if (pattern.includes("*")) {
100
- // Very limited literal-prefix glob handling. Full expansion is git's job.
101
- const star = pattern.indexOf("*");
102
- const prefix = pattern.slice(0, star);
103
- return Array.from(tracked).filter((p) => p.startsWith(prefix));
104
- }
105
- return tracked.has(pattern) ? [pattern] : [];
95
+ if (pattern.endsWith("/")) {
96
+ const prefix = pattern;
97
+ return Array.from(tracked).filter((p) => p.startsWith(prefix));
98
+ }
99
+ if (pattern.includes("*")) {
100
+ // Very limited literal-prefix glob handling. Full expansion is git's job.
101
+ const star = pattern.indexOf("*");
102
+ const prefix = pattern.slice(0, star);
103
+ return Array.from(tracked).filter((p) => p.startsWith(prefix));
104
+ }
105
+ return tracked.has(pattern) ? [pattern] : [];
106
106
  }
107
107
 
108
108
  async function isGitRepo(cwd: string): Promise<boolean> {
109
- try {
110
- await runGit(["rev-parse", "--is-inside-work-tree"], cwd);
111
- return true;
112
- } catch {
113
- return false;
114
- }
109
+ try {
110
+ await runGit(["rev-parse", "--is-inside-work-tree"], cwd);
111
+ return true;
112
+ } catch {
113
+ return false;
114
+ }
115
115
  }
116
116
 
117
117
  async function listTrackedFiles(cwd: string): Promise<string[]> {
118
- try {
119
- const out = await runGit(["ls-files"], cwd);
120
- return out.split("\n").map((l) => l.trim()).filter(Boolean);
121
- } catch {
122
- return [];
123
- }
118
+ try {
119
+ const out = await runGit(["ls-files"], cwd);
120
+ return out
121
+ .split("\n")
122
+ .map((l) => l.trim())
123
+ .filter(Boolean);
124
+ } catch {
125
+ return [];
126
+ }
124
127
  }
125
128
 
126
129
  async function pathIsIgnored(cwd: string, path: string): Promise<boolean> {
127
- try {
128
- // git check-ignore exits 0 when path IS ignored, 1 when NOT, >1 on error.
129
- await runGit(["check-ignore", "--quiet", "--", path], cwd);
130
- return true;
131
- } catch (err) {
132
- // exit code 1 = not ignored (expected), anything else swallowed.
133
- if (err instanceof GitError && err.code === 1) return false;
134
- return false;
135
- }
130
+ try {
131
+ // git check-ignore exits 0 when path IS ignored, 1 when NOT, >1 on error.
132
+ await runGit(["check-ignore", "--quiet", "--", path], cwd);
133
+ return true;
134
+ } catch (err) {
135
+ // exit code 1 = not ignored (expected), anything else swallowed.
136
+ if (err instanceof GitError && err.code === 1) return false;
137
+ return false;
138
+ }
136
139
  }
137
140
 
138
141
  class GitError extends Error {
139
- constructor(public code: number, public stderr: string) {
140
- super(`git exited ${code}: ${stderr}`);
141
- }
142
+ constructor(
143
+ public code: number,
144
+ public stderr: string,
145
+ ) {
146
+ super(`git exited ${code}: ${stderr}`);
147
+ }
142
148
  }
143
149
 
144
150
  function runGit(args: string[], cwd: string): Promise<string> {
145
- return new Promise((resolve, reject) => {
146
- const proc = spawn("git", args, { cwd });
147
- let stdout = "";
148
- let stderr = "";
149
- proc.stdout.on("data", (b) => { stdout += b.toString(); });
150
- proc.stderr.on("data", (b) => { stderr += b.toString(); });
151
- proc.on("error", reject);
152
- proc.on("close", (code) => {
153
- if (code === 0) resolve(stdout);
154
- else reject(new GitError(code ?? -1, stderr));
155
- });
156
- });
151
+ return new Promise((resolve, reject) => {
152
+ const proc = spawn("git", args, { cwd });
153
+ let stdout = "";
154
+ let stderr = "";
155
+ proc.stdout.on("data", (b) => {
156
+ stdout += b.toString();
157
+ });
158
+ proc.stderr.on("data", (b) => {
159
+ stderr += b.toString();
160
+ });
161
+ proc.on("error", reject);
162
+ proc.on("close", (code) => {
163
+ if (code === 0) resolve(stdout);
164
+ else reject(new GitError(code ?? -1, stderr));
165
+ });
166
+ });
157
167
  }