claudeup 4.18.0 → 4.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/bin/claudeup.js +43 -19
  2. package/package.json +14 -19
  3. package/scripts/build-binaries.ts +77 -0
  4. package/scripts/check-optional-deps.ts +49 -0
  5. package/scripts/test-isolated.ts +43 -0
  6. package/src/__tests__/alias-adopt.test.ts +364 -0
  7. package/src/__tests__/alias-parser.test.ts +92 -0
  8. package/src/__tests__/alias-shell-writer.test.ts +7 -0
  9. package/src/__tests__/alias-store.test.ts +77 -0
  10. package/src/__tests__/cli-router.test.ts +65 -0
  11. package/src/__tests__/conventions-integration.test.ts +745 -0
  12. package/src/__tests__/conventions-manager.test.ts +1172 -0
  13. package/src/__tests__/doctor-bins.test.ts +35 -0
  14. package/src/__tests__/doctor.test.ts +450 -0
  15. package/src/__tests__/dual-write-prevention.test.ts +14 -4
  16. package/src/__tests__/file-locking.test.ts +208 -0
  17. package/src/__tests__/gitignore-prerun.test.ts +1 -0
  18. package/src/__tests__/install-command.test.ts +81 -0
  19. package/src/__tests__/install-plan.test.ts +98 -0
  20. package/src/__tests__/manifest.test.ts +136 -0
  21. package/src/__tests__/marketplace-refresh.test.ts +267 -0
  22. package/src/__tests__/plugin-requires.test.ts +133 -0
  23. package/src/__tests__/plugin-setup.test.ts +118 -0
  24. package/src/__tests__/profile-command.test.ts +116 -0
  25. package/src/__tests__/profile-materializer.test.ts +82 -0
  26. package/src/__tests__/profile-sync.test.ts +136 -0
  27. package/src/__tests__/registry-version-resolution.test.ts +74 -0
  28. package/src/__tests__/resolve-executable.test.ts +42 -0
  29. package/src/__tests__/resolver.test.ts +218 -0
  30. package/src/__tests__/symlink-manager.test.ts +99 -0
  31. package/src/__tests__/toolchain.test.ts +56 -0
  32. package/src/cli/claude.ts +21 -0
  33. package/src/cli/doctor.ts +132 -0
  34. package/src/cli/install.ts +360 -0
  35. package/src/cli/profile.ts +166 -0
  36. package/src/cli/router.ts +107 -0
  37. package/src/cli/update.ts +85 -0
  38. package/src/data/alias-flags.ts +11 -1
  39. package/src/data/cli-tools.ts +7 -7
  40. package/src/data/gitignore-defaults.ts +4 -0
  41. package/src/data/marketplaces.ts +12 -0
  42. package/src/data/predefined-profiles.ts +3 -4
  43. package/src/main.tsx +11 -154
  44. package/src/prerunner/index.ts +62 -27
  45. package/src/services/alias-shell-writer.ts +382 -8
  46. package/src/services/alias-store.ts +60 -0
  47. package/src/services/claude-cli.ts +19 -22
  48. package/src/services/claude-settings.ts +99 -26
  49. package/src/services/conventions-manager.ts +865 -0
  50. package/src/services/doctor-bins.ts +49 -0
  51. package/src/services/doctor.ts +509 -0
  52. package/src/services/install-plan.ts +107 -0
  53. package/src/services/manifest.ts +166 -0
  54. package/src/services/marketplace-refresh.ts +173 -0
  55. package/src/services/plugin-manager.ts +7 -1
  56. package/src/services/plugin-requires.ts +215 -0
  57. package/src/services/plugin-setup.ts +61 -4
  58. package/src/services/plugin-version-check.ts +9 -4
  59. package/src/services/profile-materializer.ts +61 -0
  60. package/src/services/profile-sync.ts +150 -0
  61. package/src/services/resolver.ts +293 -0
  62. package/src/services/symlink-manager.ts +146 -0
  63. package/src/services/toolchain.ts +97 -0
  64. package/src/services/version-check.ts +10 -11
  65. package/src/types/index.ts +138 -31
  66. package/src/ui/App.tsx +16 -11
  67. package/src/ui/components/FlagDetailEditor.tsx +0 -0
  68. package/src/ui/components/modals/ConfirmModal.tsx +1 -1
  69. package/src/ui/screens/AliasScreen.tsx +491 -359
  70. package/src/ui/screens/CliToolsScreen.tsx +11 -3
  71. package/src/ui/screens/PluginsScreen.tsx +3 -1
  72. package/src/ui/screens/index.ts +0 -1
  73. package/src/ui/state/reducer.ts +6 -102
  74. package/src/ui/state/types.ts +8 -35
  75. package/src/utils/command-utils.ts +23 -0
  76. package/src/utils/file-locking.ts +144 -0
  77. package/src/data/alias-flags.js +0 -196
  78. package/src/data/cli-tools.js +0 -123
  79. package/src/data/gitignore-defaults.js +0 -24
  80. package/src/data/gitignore-reasons.js +0 -97
  81. package/src/data/gitignore-templates.js +0 -21
  82. package/src/data/marketplaces.js +0 -138
  83. package/src/data/mcp-servers.js +0 -509
  84. package/src/data/predefined-profiles.js +0 -248
  85. package/src/data/settings-catalog.js +0 -625
  86. package/src/data/skill-repos.js +0 -160
  87. package/src/data/statuslines.js +0 -159
  88. package/src/data/statuslines.ts +0 -188
  89. package/src/index.js +0 -4
  90. package/src/index.ts +0 -5
  91. package/src/main.js +0 -170
  92. package/src/prerunner/index.js +0 -252
  93. package/src/services/alias-settings.js +0 -51
  94. package/src/services/alias-shell-writer.js +0 -764
  95. package/src/services/alias-store.js +0 -77
  96. package/src/services/claude-cli.js +0 -189
  97. package/src/services/claude-runner.js +0 -28
  98. package/src/services/claude-settings.js +0 -1223
  99. package/src/services/gitignore-detector.js +0 -155
  100. package/src/services/gitignore-fixer.js +0 -231
  101. package/src/services/gitignore-prerun.js +0 -46
  102. package/src/services/gitignore-resolver.js +0 -143
  103. package/src/services/gitignore-service.js +0 -117
  104. package/src/services/local-marketplace.js +0 -339
  105. package/src/services/marketplace-fetcher.js +0 -96
  106. package/src/services/marketplace-sync.js +0 -94
  107. package/src/services/mcp-registry.js +0 -87
  108. package/src/services/plugin-manager.js +0 -473
  109. package/src/services/plugin-mcp-config.js +0 -177
  110. package/src/services/plugin-setup.js +0 -444
  111. package/src/services/plugin-version-check.js +0 -262
  112. package/src/services/profiles.js +0 -161
  113. package/src/services/settings-manager.js +0 -243
  114. package/src/services/skills-manager.js +0 -393
  115. package/src/services/skillsmp-client.js +0 -87
  116. package/src/services/update-cache.js +0 -52
  117. package/src/services/version-check.js +0 -99
  118. package/src/types/gitignore.js +0 -6
  119. package/src/types/index.js +0 -1
  120. package/src/ui/App.js +0 -346
  121. package/src/ui/adapters/pluginsAdapter.js +0 -139
  122. package/src/ui/adapters/settingsAdapter.js +0 -111
  123. package/src/ui/adapters/skillsAdapter.js +0 -154
  124. package/src/ui/components/CategoryHeader.js +0 -9
  125. package/src/ui/components/EmptyFilterState.js +0 -4
  126. package/src/ui/components/ScopeIndicator.js +0 -30
  127. package/src/ui/components/ScrollableList.js +0 -36
  128. package/src/ui/components/SearchInput.js +0 -19
  129. package/src/ui/components/StyledText.js +0 -39
  130. package/src/ui/components/TabBar.js +0 -19
  131. package/src/ui/components/layout/FooterHints.js +0 -29
  132. package/src/ui/components/layout/Panel.js +0 -6
  133. package/src/ui/components/layout/ProgressBar.js +0 -14
  134. package/src/ui/components/layout/ScopeTabs.js +0 -6
  135. package/src/ui/components/layout/ScreenLayout.js +0 -16
  136. package/src/ui/components/layout/index.js +0 -5
  137. package/src/ui/components/modals/ConfirmModal.js +0 -14
  138. package/src/ui/components/modals/InputModal.js +0 -5
  139. package/src/ui/components/modals/LoadingModal.js +0 -17
  140. package/src/ui/components/modals/MessageModal.js +0 -16
  141. package/src/ui/components/modals/ModalContainer.js +0 -137
  142. package/src/ui/components/modals/SelectModal.js +0 -18
  143. package/src/ui/components/modals/VersionMismatchModal.js +0 -36
  144. package/src/ui/components/modals/index.js +0 -6
  145. package/src/ui/components/primitives/ActionHints.js +0 -13
  146. package/src/ui/components/primitives/DetailSection.js +0 -7
  147. package/src/ui/components/primitives/KeyValueLine.js +0 -8
  148. package/src/ui/components/primitives/ListCategoryRow.js +0 -8
  149. package/src/ui/components/primitives/MetaText.js +0 -8
  150. package/src/ui/components/primitives/ScopeDetail.js +0 -32
  151. package/src/ui/components/primitives/ScopeSquares.js +0 -11
  152. package/src/ui/components/primitives/SelectableRow.js +0 -5
  153. package/src/ui/components/primitives/index.js +0 -8
  154. package/src/ui/hooks/index.js +0 -4
  155. package/src/ui/hooks/useAsyncData.js +0 -77
  156. package/src/ui/hooks/useGitignoreModal.js +0 -74
  157. package/src/ui/hooks/useKeyboard.js +0 -13
  158. package/src/ui/hooks/useKeyboardHandler.js +0 -39
  159. package/src/ui/hooks/useMismatchModal.js +0 -77
  160. package/src/ui/registry.js +0 -1
  161. package/src/ui/renderers/cliToolRenderers.js +0 -54
  162. package/src/ui/renderers/gitignoreRenderers.js +0 -46
  163. package/src/ui/renderers/mcpRenderers.js +0 -26
  164. package/src/ui/renderers/pluginRenderers.js +0 -124
  165. package/src/ui/renderers/profileRenderers.js +0 -177
  166. package/src/ui/renderers/settingsRenderers.js +0 -73
  167. package/src/ui/renderers/skillRenderers.js +0 -138
  168. package/src/ui/screens/AliasScreen.js +0 -1008
  169. package/src/ui/screens/CliToolsScreen.js +0 -338
  170. package/src/ui/screens/EnvVarsScreen.js +0 -152
  171. package/src/ui/screens/GitignoreScreen.js +0 -328
  172. package/src/ui/screens/McpRegistryScreen.js +0 -238
  173. package/src/ui/screens/McpScreen.js +0 -176
  174. package/src/ui/screens/ModelSelectorScreen.js +0 -296
  175. package/src/ui/screens/ModelSelectorScreen.tsx +0 -444
  176. package/src/ui/screens/PluginsScreen.js +0 -766
  177. package/src/ui/screens/ProfilesScreen.js +0 -298
  178. package/src/ui/screens/SkillsScreen.js +0 -549
  179. package/src/ui/screens/StatusLineScreen.js +0 -206
  180. package/src/ui/screens/StatusLineScreen.tsx +0 -416
  181. package/src/ui/screens/index.js +0 -10
  182. package/src/ui/state/AnimationContext.js +0 -34
  183. package/src/ui/state/AppContext.js +0 -162
  184. package/src/ui/state/DimensionsContext.js +0 -71
  185. package/src/ui/state/reducer.js +0 -543
  186. package/src/ui/state/types.js +0 -1
  187. package/src/ui/theme.js +0 -47
  188. package/src/utils/clipboard.js +0 -56
  189. package/src/utils/command-utils.js +0 -19
  190. package/src/utils/fuzzy-search.js +0 -101
  191. package/src/utils/string-utils.js +0 -62
@@ -1,252 +0,0 @@
1
- import fs from "fs-extra";
2
- import path from "node:path";
3
- import os from "node:os";
4
- import { UpdateCache } from "../services/update-cache.js";
5
- import { getAvailablePlugins, clearMarketplaceCache, } from "../services/plugin-manager.js";
6
- import { runClaude } from "../services/claude-runner.js";
7
- import { recoverMarketplaceSettings, migrateMarketplaceRename, cleanupExtraKnownMarketplaces, readGlobalSettings, writeGlobalSettings, saveGlobalInstalledPluginVersion, gapFillInstalledPluginVersions, } from "../services/claude-settings.js";
8
- import { checkPluginVersionMismatches, formatMismatchWarning, } from "../services/plugin-version-check.js";
9
- import { updatePlugin, isClaudeAvailable } from "../services/claude-cli.js";
10
- import { autoAddMissingMarketplaces } from "../services/marketplace-sync.js";
11
- import { checkGitignore, formatPrerunWarning as formatGitignoreWarning, } from "../services/gitignore-prerun.js";
12
- const CONTINUITY_PLUGIN_SENTINEL = "tmux-claude-continuity";
13
- const CONTINUITY_PLUGIN_SCRIPT = path.join(os.homedir(), ".tmux", "plugins", "tmux-claude-continuity", "scripts", "on_session_start.sh");
14
- /**
15
- * Ensure tmux-claude-continuity Claude Code hooks are present in global settings.
16
- * If the tmux plugin is installed but the hooks are missing, they are appended.
17
- * Returns a description of what was added, or null if nothing changed.
18
- */
19
- async function ensureTmuxContinuityHooks() {
20
- // Plugin not installed — nothing to do
21
- if (!(await fs.pathExists(CONTINUITY_PLUGIN_SCRIPT))) {
22
- return null;
23
- }
24
- const settings = await readGlobalSettings();
25
- // Check if hooks are already configured by looking for the sentinel string
26
- const existingHooks = settings.hooks ?? {};
27
- for (const groups of Object.values(existingHooks)) {
28
- for (const group of groups) {
29
- for (const hook of group.hooks) {
30
- if (hook.command.includes(CONTINUITY_PLUGIN_SENTINEL)) {
31
- return null; // Already configured
32
- }
33
- }
34
- }
35
- }
36
- // Append hooks, preserving any existing entries in SessionStart and Stop
37
- const sessionStartGroups = existingHooks["SessionStart"] ?? [];
38
- const stopGroups = existingHooks["Stop"] ?? [];
39
- sessionStartGroups.push({
40
- hooks: [
41
- {
42
- type: "command",
43
- command: "bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_session_start.sh",
44
- },
45
- ],
46
- });
47
- stopGroups.push({
48
- hooks: [
49
- {
50
- type: "command",
51
- command: "bash ~/.tmux/plugins/tmux-claude-continuity/scripts/on_stop.sh",
52
- },
53
- ],
54
- });
55
- settings.hooks = {
56
- ...existingHooks,
57
- SessionStart: sessionStartGroups,
58
- Stop: stopGroups,
59
- };
60
- await writeGlobalSettings(settings);
61
- return "SessionStart + Stop hooks";
62
- }
63
- /**
64
- * Prerun orchestration: Check for updates, apply them, then run claude
65
- * @param claudeArgs - Arguments to pass to claude CLI
66
- * @param options - Prerun options (force, etc.)
67
- * @returns Exit code from claude process
68
- */
69
- export async function prerunClaude(claudeArgs, options = {}) {
70
- const cache = new UpdateCache();
71
- try {
72
- // STEP 0: Migrate old marketplace names → magus (idempotent, no-ops if already migrated)
73
- const migration = await migrateMarketplaceRename();
74
- const migTotal = migration.projectMigrated +
75
- migration.globalMigrated +
76
- migration.localMigrated +
77
- migration.registryMigrated +
78
- (migration.knownMarketplacesMigrated ? 1 : 0);
79
- if (migTotal > 0) {
80
- console.log(`✓ Migrated ${migTotal} plugin reference(s) → magus`);
81
- }
82
- // STEP 0.5: Auto-add missing marketplaces
83
- // When plugins reference a marketplace that's not installed locally
84
- // (e.g., settings synced from another machine or committed by a
85
- // teammate in .claude/settings.json), add it automatically. Pass
86
- // process.cwd() so project and local enabledPlugins are scanned —
87
- // otherwise a freshly cloned repo whose only @magus references live
88
- // in project settings looks "clean" from the global-scope view.
89
- if (await isClaudeAvailable()) {
90
- const addedMarketplaces = await autoAddMissingMarketplaces(process.cwd());
91
- if (addedMarketplaces.length > 0) {
92
- console.log(`✓ Auto-added marketplace(s): ${addedMarketplaces.join(", ")}`);
93
- }
94
- }
95
- // STEP 0.55: Clean up extraKnownMarketplaces entries that are now in known_marketplaces.json
96
- // extraKnownMarketplaces was the old install mechanism; the official way is known_marketplaces.json
97
- try {
98
- const cleaned = await cleanupExtraKnownMarketplaces();
99
- if (cleaned.length > 0) {
100
- console.log(`✓ Cleaned up legacy extraKnownMarketplaces: ${cleaned.join(", ")}`);
101
- }
102
- }
103
- catch {
104
- // Non-fatal: cleanup is best-effort
105
- }
106
- // STEP 0.6: Ensure tmux-claude-continuity hooks are configured
107
- const addedHooks = await ensureTmuxContinuityHooks();
108
- if (addedHooks) {
109
- console.log(`✓ Added tmux-claude-continuity hooks to ~/.claude/settings.json`);
110
- }
111
- // STEP 0.7: Gap-fill installedPluginVersions across scopes
112
- // When a plugin is updated at project/local scope, global may lag behind.
113
- // Sync the highest version from any scope up to global so Claude Code
114
- // resolves the latest cached plugin paths at session startup.
115
- try {
116
- const gapFilled = await gapFillInstalledPluginVersions(process.cwd());
117
- if (gapFilled.length > 0) {
118
- console.log(`✓ Synced ${gapFilled.length} plugin version(s) to global:`);
119
- for (const { pluginId, oldVersion, newVersion } of gapFilled) {
120
- console.log(` - ${pluginId}: ${oldVersion} → ${newVersion}`);
121
- }
122
- }
123
- }
124
- catch {
125
- // Non-fatal: gap-fill is best-effort
126
- }
127
- // STEP 0.8: Detect plugin version mismatches caused by the [0] index bug
128
- // Claude Code's pluginLoader.ts takes entries[0] regardless of project,
129
- // so if another project installed a different version first, this project
130
- // will silently load the wrong version.
131
- try {
132
- const cwd = process.cwd();
133
- const mismatches = await checkPluginVersionMismatches(cwd);
134
- if (mismatches.length > 0) {
135
- console.warn("");
136
- console.warn(formatMismatchWarning(mismatches));
137
- console.warn("");
138
- }
139
- }
140
- catch {
141
- // Non-fatal: mismatch detection is best-effort
142
- }
143
- // STEP 0.9: Detect gitignore manifest violations. Warn-only here — the
144
- // fix dialog lives in the TUI Gitignore tab, mirroring the plugin
145
- // version-mismatch flow (since destructive fixes need user confirmation).
146
- try {
147
- const cwd = process.cwd();
148
- const result = await checkGitignore(cwd);
149
- const warning = formatGitignoreWarning(result);
150
- if (warning) {
151
- console.warn("");
152
- console.warn(warning);
153
- console.warn("");
154
- }
155
- }
156
- catch {
157
- // Non-fatal: gitignore detection is best-effort
158
- }
159
- // STEP 1: Check if we should update (time-based cache, or forced)
160
- const shouldUpdate = options.force || (await cache.shouldCheckForUpdates());
161
- if (options.force) {
162
- console.log("⟳ Forcing plugin update check...");
163
- }
164
- if (shouldUpdate) {
165
- // STEP 1.5: Recover marketplace settings (enable autoUpdate, remove stale entries)
166
- const recovery = await recoverMarketplaceSettings();
167
- if (recovery.enabledAutoUpdate.length > 0) {
168
- console.log(`✓ Enabled auto-update for: ${recovery.enabledAutoUpdate.join(", ")}`);
169
- }
170
- if (recovery.removed.length > 0) {
171
- console.log(`✓ Removed stale marketplaces: ${recovery.removed.join(", ")}`);
172
- }
173
- if (recovery.reregistered.length > 0) {
174
- console.log(`✓ Re-registered as GitHub source: ${recovery.reregistered.join(", ")}`);
175
- // Trigger marketplace update for re-registered entries so the local
176
- // clone gets refreshed with the latest plugins.
177
- const cliAvailable = await isClaudeAvailable();
178
- if (cliAvailable) {
179
- const { updateMarketplace } = await import("../services/claude-cli.js");
180
- for (const mpName of recovery.reregistered) {
181
- try {
182
- await updateMarketplace(mpName);
183
- console.log(`✓ Updated marketplace: ${mpName}`);
184
- }
185
- catch (error) {
186
- console.warn(`⚠ Failed to update marketplace ${mpName}:`, error instanceof Error ? error.message : "Unknown error");
187
- }
188
- }
189
- }
190
- }
191
- // STEP 2: Clear cache to force fresh plugin info
192
- clearMarketplaceCache();
193
- // STEP 3: Get updated plugin info (to detect versions)
194
- const plugins = await getAvailablePlugins();
195
- // STEP 4: Auto-update enabled plugins via claude CLI
196
- const autoUpdatedPlugins = [];
197
- const cliAvailable = await isClaudeAvailable();
198
- for (const plugin of plugins) {
199
- // Only update if:
200
- // 1. Plugin is enabled
201
- // 2. Plugin has an update available
202
- // 3. Plugin has both installedVersion and version (newVersion)
203
- if (plugin.enabled &&
204
- plugin.hasUpdate &&
205
- plugin.installedVersion &&
206
- plugin.version) {
207
- try {
208
- if (!cliAvailable) {
209
- // CLI unavailable — skip update entirely, don't write phantom state
210
- continue;
211
- }
212
- await updatePlugin(plugin.id, "user");
213
- // CLI does NOT update installedPluginVersions — save it ourselves
214
- await saveGlobalInstalledPluginVersion(plugin.id, plugin.version);
215
- autoUpdatedPlugins.push({
216
- pluginId: plugin.id,
217
- oldVersion: plugin.installedVersion,
218
- newVersion: plugin.version,
219
- });
220
- }
221
- catch (error) {
222
- // Non-fatal: Log warning and continue
223
- console.warn(`⚠ Failed to auto-update ${plugin.id}:`, error instanceof Error ? error.message : "Unknown error");
224
- }
225
- }
226
- }
227
- // STEP 5: Save cache
228
- await cache.saveCheck({
229
- lastUpdateCheck: new Date().toISOString(),
230
- lastUpdateResult: {
231
- updated: [],
232
- failed: [],
233
- autoUpdated: autoUpdatedPlugins,
234
- },
235
- });
236
- // STEP 6: Display auto-update summary
237
- if (autoUpdatedPlugins.length > 0) {
238
- console.log(`✓ Auto-updated ${autoUpdatedPlugins.length} plugin(s):`);
239
- for (const { pluginId, oldVersion, newVersion } of autoUpdatedPlugins) {
240
- console.log(` - ${pluginId}: ${oldVersion} → ${newVersion}`);
241
- }
242
- }
243
- }
244
- // If !shouldUpdate → silent (no output)
245
- }
246
- catch (error) {
247
- // Non-fatal errors - warn and continue
248
- console.warn("Warning: Plugin update check failed:", error instanceof Error ? error.message : "Unknown error");
249
- }
250
- // STEP 8: Always run claude (even if update failed)
251
- return runClaude(claudeArgs);
252
- }
@@ -1,51 +0,0 @@
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
- }