@within-7/minto 0.3.6 → 0.3.10

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 (238) hide show
  1. package/{cli.js → cli.cjs} +25 -23
  2. package/dist/commands/agents/AgentsCommand.js +459 -655
  3. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  4. package/dist/commands/agents/types.js +1 -0
  5. package/dist/commands/agents/types.js.map +2 -2
  6. package/dist/commands/agents/utils/fileOperations.js +96 -36
  7. package/dist/commands/agents/utils/fileOperations.js.map +3 -3
  8. package/dist/commands/agents/utils/index.js +3 -1
  9. package/dist/commands/agents/utils/index.js.map +2 -2
  10. package/dist/commands/context.js +54 -23
  11. package/dist/commands/context.js.map +2 -2
  12. package/dist/commands/export.js +673 -93
  13. package/dist/commands/export.js.map +2 -2
  14. package/dist/commands/language.js +110 -0
  15. package/dist/commands/language.js.map +7 -0
  16. package/dist/commands/mcp-interactive.js +419 -217
  17. package/dist/commands/mcp-interactive.js.map +2 -2
  18. package/dist/commands/model.js +415 -66
  19. package/dist/commands/model.js.map +2 -2
  20. package/dist/commands/new.js +56 -0
  21. package/dist/commands/new.js.map +7 -0
  22. package/dist/commands/permissions.js +75 -49
  23. package/dist/commands/permissions.js.map +2 -2
  24. package/dist/commands/plugin.js +882 -185
  25. package/dist/commands/plugin.js.map +3 -3
  26. package/dist/commands/resume.js +251 -16
  27. package/dist/commands/resume.js.map +2 -2
  28. package/dist/commands/sandbox.js +168 -70
  29. package/dist/commands/sandbox.js.map +2 -2
  30. package/dist/commands/sessions.js +224 -0
  31. package/dist/commands/sessions.js.map +7 -0
  32. package/dist/commands/setup.js +596 -109
  33. package/dist/commands/setup.js.map +2 -2
  34. package/dist/commands/stats.js +292 -0
  35. package/dist/commands/stats.js.map +7 -0
  36. package/dist/commands/status.js +75 -7
  37. package/dist/commands/status.js.map +2 -2
  38. package/dist/commands/undo.js +154 -180
  39. package/dist/commands/undo.js.map +2 -2
  40. package/dist/commands.js +6 -0
  41. package/dist/commands.js.map +2 -2
  42. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  43. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  44. package/dist/components/Config.js +9 -8
  45. package/dist/components/Config.js.map +2 -2
  46. package/dist/components/HeaderBar.js +2 -1
  47. package/dist/components/HeaderBar.js.map +2 -2
  48. package/dist/components/Help.js +166 -32
  49. package/dist/components/Help.js.map +2 -2
  50. package/dist/components/HotkeyHelpPanel.js +46 -44
  51. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  52. package/dist/components/InfoPanel/InfoPanel.js +123 -0
  53. package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
  54. package/dist/components/InfoPanel/index.js +5 -0
  55. package/dist/components/InfoPanel/index.js.map +7 -0
  56. package/dist/components/InfoPanel/types.js +1 -0
  57. package/dist/components/InfoPanel/types.js.map +7 -0
  58. package/dist/components/Logo.js +5 -2
  59. package/dist/components/Logo.js.map +2 -2
  60. package/dist/components/MCPServerApprovalDialog.js +6 -5
  61. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  62. package/dist/components/MCPServerMultiselectDialog.js +5 -4
  63. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  64. package/dist/components/MessageSelector.js +4 -3
  65. package/dist/components/MessageSelector.js.map +2 -2
  66. package/dist/components/ModelConfig.js +13 -12
  67. package/dist/components/ModelConfig.js.map +2 -2
  68. package/dist/components/ModelListManager.js +4 -3
  69. package/dist/components/ModelListManager.js.map +2 -2
  70. package/dist/components/ModelSelector/BrandTextInput.js +43 -0
  71. package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
  72. package/dist/components/ModelSelector/ModelSelector.js +419 -501
  73. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  74. package/dist/components/ModelSelector/WizardContainer.js +45 -0
  75. package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
  76. package/dist/components/ModelSelector/index.js +1 -3
  77. package/dist/components/ModelSelector/index.js.map +2 -2
  78. package/dist/components/PromptInput.js +77 -44
  79. package/dist/components/PromptInput.js.map +2 -2
  80. package/dist/components/SensitiveFileWarning.js +12 -8
  81. package/dist/components/SensitiveFileWarning.js.map +2 -2
  82. package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
  83. package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
  84. package/dist/components/SimpleSelector/index.js +5 -0
  85. package/dist/components/SimpleSelector/index.js.map +7 -0
  86. package/dist/components/SimpleSelector/types.js +1 -0
  87. package/dist/components/SimpleSelector/types.js.map +7 -0
  88. package/dist/components/StatusOverlayContent.js +21 -0
  89. package/dist/components/StatusOverlayContent.js.map +7 -0
  90. package/dist/components/TabbedListView/ScrollableList.js +117 -0
  91. package/dist/components/TabbedListView/ScrollableList.js.map +7 -0
  92. package/dist/components/TabbedListView/SearchInput.js +23 -0
  93. package/dist/components/TabbedListView/SearchInput.js.map +7 -0
  94. package/dist/components/TabbedListView/TabBar.js +20 -0
  95. package/dist/components/TabbedListView/TabBar.js.map +7 -0
  96. package/dist/components/TabbedListView/TabbedListView.js +246 -0
  97. package/dist/components/TabbedListView/TabbedListView.js.map +7 -0
  98. package/dist/components/TabbedListView/index.js +11 -0
  99. package/dist/components/TabbedListView/index.js.map +7 -0
  100. package/dist/components/TabbedListView/types.js +1 -0
  101. package/dist/components/TabbedListView/types.js.map +7 -0
  102. package/dist/components/TodoChangeBlock.js +6 -5
  103. package/dist/components/TodoChangeBlock.js.map +3 -3
  104. package/dist/components/TodoPanel.js +6 -3
  105. package/dist/components/TodoPanel.js.map +3 -3
  106. package/dist/components/TrustDialog.js +6 -5
  107. package/dist/components/TrustDialog.js.map +2 -2
  108. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +2 -1
  109. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +2 -2
  110. package/dist/constants/macros.js +1 -1
  111. package/dist/constants/macros.js.map +1 -1
  112. package/dist/constants/product.js +2 -2
  113. package/dist/constants/product.js.map +1 -1
  114. package/dist/constants/prompts.js +17 -0
  115. package/dist/constants/prompts.js.map +2 -2
  116. package/dist/constants/toolInputExamples.js +5 -1
  117. package/dist/constants/toolInputExamples.js.map +2 -2
  118. package/dist/core/backupHook.js +29 -0
  119. package/dist/core/backupHook.js.map +7 -0
  120. package/dist/core/config/defaults.js +8 -2
  121. package/dist/core/config/defaults.js.map +2 -2
  122. package/dist/core/config/schema.js +14 -2
  123. package/dist/core/config/schema.js.map +2 -2
  124. package/dist/core/costTracker.js +0 -16
  125. package/dist/core/costTracker.js.map +2 -2
  126. package/dist/core/tokenStatsManager.js +5 -0
  127. package/dist/core/tokenStatsManager.js.map +2 -2
  128. package/dist/cost-tracker.js +0 -16
  129. package/dist/cost-tracker.js.map +2 -2
  130. package/dist/entrypoints/bootstrap.js +56 -0
  131. package/dist/entrypoints/bootstrap.js.map +7 -0
  132. package/dist/entrypoints/cli.js +164 -23
  133. package/dist/entrypoints/cli.js.map +3 -3
  134. package/dist/history.js +75 -15
  135. package/dist/history.js.map +2 -2
  136. package/dist/i18n/index.js +2 -2
  137. package/dist/i18n/index.js.map +2 -2
  138. package/dist/i18n/locales/en.js +582 -1
  139. package/dist/i18n/locales/en.js.map +2 -2
  140. package/dist/i18n/locales/zh-CN.js +582 -1
  141. package/dist/i18n/locales/zh-CN.js.map +2 -2
  142. package/dist/i18n/types.js.map +1 -1
  143. package/dist/index.js +1 -1
  144. package/dist/index.js.map +2 -2
  145. package/dist/messages.js +11 -0
  146. package/dist/messages.js.map +2 -2
  147. package/dist/permissions.js.map +2 -2
  148. package/dist/query.js +9 -0
  149. package/dist/query.js.map +2 -2
  150. package/dist/screens/REPL.js +45 -7
  151. package/dist/screens/REPL.js.map +2 -2
  152. package/dist/services/customCommands.js +44 -16
  153. package/dist/services/customCommands.js.map +2 -2
  154. package/dist/services/plugins/lspServers.js +1 -1
  155. package/dist/services/plugins/lspServers.js.map +2 -2
  156. package/dist/services/plugins/pluginRuntime.js +2 -1
  157. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  158. package/dist/services/plugins/pluginValidation.js +10 -3
  159. package/dist/services/plugins/pluginValidation.js.map +2 -2
  160. package/dist/services/plugins/skillMarketplace.js +16 -8
  161. package/dist/services/plugins/skillMarketplace.js.map +2 -2
  162. package/dist/services/systemReminder.js +17 -6
  163. package/dist/services/systemReminder.js.map +2 -2
  164. package/dist/tools/FileEditTool/FileEditTool.js +7 -0
  165. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  166. package/dist/tools/FileWriteTool/FileWriteTool.js +7 -0
  167. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  168. package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
  169. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  170. package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
  171. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  172. package/dist/tools/TaskTool/TaskTool.js +179 -1
  173. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  174. package/dist/tools/TodoWriteTool/prompt.js +21 -0
  175. package/dist/tools/TodoWriteTool/prompt.js.map +2 -2
  176. package/dist/tools/URLFetcherTool/prompt.js +14 -9
  177. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  178. package/dist/tools/WebSearchTool/prompt.js +12 -6
  179. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  180. package/dist/types/PermissionMode.js +30 -1
  181. package/dist/types/PermissionMode.js.map +2 -2
  182. package/dist/types/plugin.js +2 -4
  183. package/dist/types/plugin.js.map +2 -2
  184. package/dist/utils/agentHookExecutor.js +103 -0
  185. package/dist/utils/agentHookExecutor.js.map +7 -0
  186. package/dist/utils/agentLoader.js +272 -32
  187. package/dist/utils/agentLoader.js.map +2 -2
  188. package/dist/utils/agentMemory.js +134 -0
  189. package/dist/utils/agentMemory.js.map +7 -0
  190. package/dist/utils/claudeCodeSync.js +439 -0
  191. package/dist/utils/claudeCodeSync.js.map +7 -0
  192. package/dist/utils/config.js +52 -24
  193. package/dist/utils/config.js.map +2 -2
  194. package/dist/utils/configPaths.js +199 -0
  195. package/dist/utils/configPaths.js.map +7 -0
  196. package/dist/utils/execFileNoThrow.js +2 -1
  197. package/dist/utils/execFileNoThrow.js.map +2 -2
  198. package/dist/utils/historyManager.js +234 -0
  199. package/dist/utils/historyManager.js.map +7 -0
  200. package/dist/utils/marketplaceManager.js +80 -43
  201. package/dist/utils/marketplaceManager.js.map +2 -2
  202. package/dist/utils/messages.js +13 -8
  203. package/dist/utils/messages.js.map +2 -2
  204. package/dist/utils/migration/index.js +37 -0
  205. package/dist/utils/migration/index.js.map +7 -0
  206. package/dist/utils/migration/migrateHistory.js +273 -0
  207. package/dist/utils/migration/migrateHistory.js.map +7 -0
  208. package/dist/utils/migration/migrateTodos.js +323 -0
  209. package/dist/utils/migration/migrateTodos.js.map +7 -0
  210. package/dist/utils/pasteCache.js +309 -0
  211. package/dist/utils/pasteCache.js.map +7 -0
  212. package/dist/utils/pluginInstaller.js +34 -24
  213. package/dist/utils/pluginInstaller.js.map +2 -2
  214. package/dist/utils/pluginLoader.js +54 -28
  215. package/dist/utils/pluginLoader.js.map +2 -2
  216. package/dist/utils/repoFetcher.js +110 -0
  217. package/dist/utils/repoFetcher.js.map +7 -0
  218. package/dist/utils/sessionIndex.js +192 -0
  219. package/dist/utils/sessionIndex.js.map +7 -0
  220. package/dist/utils/sessionTracker.js +170 -0
  221. package/dist/utils/sessionTracker.js.map +7 -0
  222. package/dist/utils/skillLoader.js +103 -5
  223. package/dist/utils/skillLoader.js.map +2 -2
  224. package/dist/utils/stats.js +417 -0
  225. package/dist/utils/stats.js.map +7 -0
  226. package/dist/utils/stringSubstitution.js +106 -0
  227. package/dist/utils/stringSubstitution.js.map +7 -0
  228. package/dist/utils/teamConfig.js +156 -14
  229. package/dist/utils/teamConfig.js.map +2 -2
  230. package/dist/utils/terminal.js +1 -1
  231. package/dist/utils/terminal.js.map +2 -2
  232. package/dist/utils/todoStorage.js +51 -19
  233. package/dist/utils/todoStorage.js.map +2 -2
  234. package/dist/utils/tooling/safeRender.js.map +2 -2
  235. package/dist/version.js +2 -2
  236. package/dist/version.js.map +1 -1
  237. package/package.json +71 -28
  238. package/scripts/{postinstall.js → postinstall.cjs} +1 -1
@@ -0,0 +1,439 @@
1
+ import {
2
+ existsSync,
3
+ readFileSync,
4
+ writeFileSync,
5
+ mkdirSync,
6
+ rmSync,
7
+ cpSync,
8
+ readdirSync,
9
+ statSync
10
+ } from "fs";
11
+ import { join, basename } from "path";
12
+ import { homedir } from "os";
13
+ import {
14
+ isMarketplaceRegistered,
15
+ registerMarketplaceFromDirectory
16
+ } from "./marketplaceManager.js";
17
+ const CC_HOME = join(homedir(), ".claude");
18
+ const CC_REGISTRY_PATH = join(CC_HOME, "plugins", "installed_plugins.json");
19
+ const CC_SETTINGS_PATH = join(CC_HOME, "settings.json");
20
+ const CC_MARKETPLACES_PATH = join(CC_HOME, "plugins", "known_marketplaces.json");
21
+ const MINTO_HOME = join(homedir(), ".minto");
22
+ const MINTO_SYNC_STATE_PATH = join(MINTO_HOME, "cc-sync-state.json");
23
+ const MINTO_PLUGINS_DIR = join(MINTO_HOME, "plugins");
24
+ function loadJSON(path) {
25
+ if (!existsSync(path)) return null;
26
+ try {
27
+ return JSON.parse(readFileSync(path, "utf-8"));
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function loadCCRegistry() {
33
+ return loadJSON(CC_REGISTRY_PATH);
34
+ }
35
+ function loadCCSettings() {
36
+ return loadJSON(CC_SETTINGS_PATH) ?? {};
37
+ }
38
+ function loadCCKnownMarketplaces() {
39
+ return loadJSON(CC_MARKETPLACES_PATH);
40
+ }
41
+ function convertCCSourceToMintoSource(ccSource) {
42
+ switch (ccSource.source) {
43
+ case "github":
44
+ if (!ccSource.repo) return null;
45
+ return { type: "github", repo: ccSource.repo, ref: ccSource.ref };
46
+ case "url":
47
+ if (!ccSource.url) return null;
48
+ return { type: "url", url: ccSource.url, ref: ccSource.ref };
49
+ case "local":
50
+ return null;
51
+ default:
52
+ return null;
53
+ }
54
+ }
55
+ function resolveMarketplaceSource(marketplace, knownMarketplaces) {
56
+ if (!knownMarketplaces) return null;
57
+ const mp = knownMarketplaces[marketplace];
58
+ if (!mp) return null;
59
+ return convertCCSourceToMintoSource(mp.source);
60
+ }
61
+ function syncMarketplaces(knownMarketplaces, dryRun, onProgress) {
62
+ const result = {
63
+ registered: [],
64
+ skipped: [],
65
+ failed: []
66
+ };
67
+ if (!knownMarketplaces) return result;
68
+ for (const [name, mp] of Object.entries(knownMarketplaces)) {
69
+ try {
70
+ if (isMarketplaceRegistered(name)) {
71
+ result.skipped.push(name);
72
+ continue;
73
+ }
74
+ const mintoSource = convertCCSourceToMintoSource(mp.source);
75
+ if (!mintoSource) {
76
+ result.skipped.push(name);
77
+ continue;
78
+ }
79
+ if (!mp.installLocation || !existsSync(mp.installLocation)) {
80
+ result.failed.push({
81
+ name,
82
+ error: `Install location not found: ${mp.installLocation || "(empty)"}`
83
+ });
84
+ continue;
85
+ }
86
+ if (dryRun) {
87
+ result.registered.push(name);
88
+ continue;
89
+ }
90
+ onProgress?.(`Registering marketplace ${name}...`);
91
+ const registered = registerMarketplaceFromDirectory(
92
+ name,
93
+ mintoSource,
94
+ mp.installLocation
95
+ );
96
+ if (registered) {
97
+ result.registered.push(name);
98
+ } else {
99
+ result.skipped.push(name);
100
+ }
101
+ } catch (err) {
102
+ result.failed.push({
103
+ name,
104
+ error: err instanceof Error ? err.message : String(err)
105
+ });
106
+ }
107
+ }
108
+ return result;
109
+ }
110
+ function loadSyncState() {
111
+ return loadJSON(MINTO_SYNC_STATE_PATH);
112
+ }
113
+ function saveSyncState(state) {
114
+ if (!existsSync(MINTO_HOME)) {
115
+ mkdirSync(MINTO_HOME, { recursive: true });
116
+ }
117
+ writeFileSync(MINTO_SYNC_STATE_PATH, JSON.stringify(state, null, 2), "utf-8");
118
+ }
119
+ function hasClaudeCodeInstallation() {
120
+ return existsSync(CC_REGISTRY_PATH);
121
+ }
122
+ function getClaudeCodePluginCount() {
123
+ const registry = loadCCRegistry();
124
+ if (!registry) return 0;
125
+ return Object.keys(registry.plugins).length;
126
+ }
127
+ function needsSync() {
128
+ if (!existsSync(CC_REGISTRY_PATH)) return false;
129
+ const state = loadSyncState();
130
+ if (!state) return true;
131
+ try {
132
+ const stat = statSync(CC_REGISTRY_PATH);
133
+ const mtime = stat.mtime.toISOString();
134
+ return mtime !== state.lastRegistryModified;
135
+ } catch {
136
+ return false;
137
+ }
138
+ }
139
+ const EXCLUDE_PATTERNS = /* @__PURE__ */ new Set([
140
+ ".git",
141
+ ".orphaned_at",
142
+ ".DS_Store",
143
+ "node_modules",
144
+ ".github"
145
+ ]);
146
+ function shouldCopy(src) {
147
+ const name = basename(src);
148
+ return !EXCLUDE_PATTERNS.has(name);
149
+ }
150
+ function copyPluginFromCache(sourcePath, targetPath) {
151
+ if (!existsSync(sourcePath)) {
152
+ throw new Error(`Source path does not exist: ${sourcePath}`);
153
+ }
154
+ if (!existsSync(targetPath)) {
155
+ mkdirSync(targetPath, { recursive: true });
156
+ }
157
+ cpSync(sourcePath, targetPath, {
158
+ recursive: true,
159
+ filter: shouldCopy
160
+ });
161
+ }
162
+ function loadMarketplacePluginMeta(marketplaceName, pluginName) {
163
+ const knownMPs = loadCCKnownMarketplaces();
164
+ if (!knownMPs) return null;
165
+ const mp = knownMPs[marketplaceName];
166
+ if (!mp?.installLocation) return null;
167
+ const mpJsonPath = join(
168
+ mp.installLocation,
169
+ ".claude-plugin",
170
+ "marketplace.json"
171
+ );
172
+ if (!existsSync(mpJsonPath)) return null;
173
+ try {
174
+ const manifest = JSON.parse(readFileSync(mpJsonPath, "utf-8"));
175
+ const plugins = manifest.plugins || [];
176
+ return plugins.find((p) => p.name === pluginName) ?? null;
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+ function generatePluginManifest(pluginName, marketplace, ccEntry, meta) {
182
+ const agents = [];
183
+ const commands = [];
184
+ const skills = [];
185
+ const agentsDir = join(ccEntry.installPath, "agents");
186
+ if (existsSync(agentsDir)) {
187
+ try {
188
+ agents.push(
189
+ ...readdirSync(agentsDir).filter((f) => f.endsWith(".md")).map((f) => `agents/${f}`)
190
+ );
191
+ } catch {
192
+ }
193
+ }
194
+ const commandsDir = join(ccEntry.installPath, "commands");
195
+ if (existsSync(commandsDir)) {
196
+ try {
197
+ commands.push(
198
+ ...readdirSync(commandsDir).filter((f) => f.endsWith(".md")).map((f) => `commands/${f}`)
199
+ );
200
+ } catch {
201
+ }
202
+ }
203
+ const skillsDir = join(ccEntry.installPath, "skills");
204
+ if (existsSync(skillsDir)) {
205
+ try {
206
+ for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
207
+ if (entry.isDirectory()) {
208
+ const skillMd = join(skillsDir, entry.name, "SKILL.md");
209
+ if (existsSync(skillMd)) {
210
+ skills.push(`skills/${entry.name}/SKILL.md`);
211
+ }
212
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
213
+ skills.push(`skills/${entry.name}`);
214
+ }
215
+ }
216
+ } catch {
217
+ }
218
+ }
219
+ return {
220
+ name: pluginName,
221
+ version: meta?.version || ccEntry.version || "1.0.0",
222
+ description: meta?.description || `Claude Code plugin: ${pluginName}`,
223
+ displayName: pluginName,
224
+ author: meta?.author,
225
+ homepage: meta?.homepage,
226
+ repository: meta?.repository,
227
+ license: meta?.license,
228
+ agents,
229
+ commands,
230
+ skills
231
+ };
232
+ }
233
+ function syncSinglePlugin(pluginName, marketplace, entry, enabled, syncState, dryRun, knownMarketplaces) {
234
+ const targetPath = join(MINTO_PLUGINS_DIR, pluginName);
235
+ const ccSyncPath = join(targetPath, ".cc-sync.json");
236
+ if (existsSync(targetPath) && !existsSync(ccSyncPath)) {
237
+ return "skipped";
238
+ }
239
+ if (existsSync(ccSyncPath)) {
240
+ try {
241
+ const existing = JSON.parse(readFileSync(ccSyncPath, "utf-8"));
242
+ if (existing.version === entry.version && existing.gitCommitSha === entry.gitCommitSha) {
243
+ return "skipped";
244
+ }
245
+ } catch {
246
+ }
247
+ }
248
+ const isUpdate = existsSync(targetPath);
249
+ if (dryRun) {
250
+ return isUpdate ? "updated" : "installed";
251
+ }
252
+ if (isUpdate) {
253
+ rmSync(targetPath, { recursive: true, force: true });
254
+ }
255
+ copyPluginFromCache(entry.installPath, targetPath);
256
+ const meta = loadMarketplacePluginMeta(marketplace, pluginName);
257
+ const manifest = generatePluginManifest(pluginName, marketplace, entry, meta);
258
+ const mintoPluginDir = join(targetPath, ".minto-plugin");
259
+ mkdirSync(mintoPluginDir, { recursive: true });
260
+ writeFileSync(
261
+ join(mintoPluginDir, "plugin.json"),
262
+ JSON.stringify(manifest, null, 2),
263
+ "utf-8"
264
+ );
265
+ const realSource = resolveMarketplaceSource(marketplace, knownMarketplaces);
266
+ writeFileSync(
267
+ join(targetPath, ".marketplace-meta.json"),
268
+ JSON.stringify(
269
+ {
270
+ marketplace,
271
+ plugin: pluginName,
272
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
273
+ source: realSource ?? { source: "claude-code" },
274
+ ...realSource ? { syncedFrom: "claude-code" } : {}
275
+ },
276
+ null,
277
+ 2
278
+ ),
279
+ "utf-8"
280
+ );
281
+ writeFileSync(
282
+ join(targetPath, ".cc-sync.json"),
283
+ JSON.stringify(
284
+ {
285
+ name: pluginName,
286
+ version: entry.version,
287
+ gitCommitSha: entry.gitCommitSha,
288
+ marketplace,
289
+ syncedAt: (/* @__PURE__ */ new Date()).toISOString(),
290
+ source: entry.installPath
291
+ },
292
+ null,
293
+ 2
294
+ ),
295
+ "utf-8"
296
+ );
297
+ writeFileSync(
298
+ join(targetPath, ".plugin-config.json"),
299
+ JSON.stringify({ enabled }, null, 2),
300
+ "utf-8"
301
+ );
302
+ return isUpdate ? "updated" : "installed";
303
+ }
304
+ async function syncFromClaudeCode(options = {}) {
305
+ const { force = false, clean = false, dryRun = false, onProgress } = options;
306
+ const result = {
307
+ installed: [],
308
+ updated: [],
309
+ skipped: [],
310
+ failed: [],
311
+ cleaned: [],
312
+ total: 0,
313
+ marketplaces: { registered: [], skipped: [], failed: [] }
314
+ };
315
+ const registry = loadCCRegistry();
316
+ if (!registry) {
317
+ return result;
318
+ }
319
+ const settings = loadCCSettings();
320
+ const enabledPlugins = settings.enabledPlugins || {};
321
+ const syncState = force ? null : loadSyncState();
322
+ const knownMarketplaces = loadCCKnownMarketplaces();
323
+ if (!existsSync(MINTO_PLUGINS_DIR)) {
324
+ mkdirSync(MINTO_PLUGINS_DIR, { recursive: true });
325
+ }
326
+ try {
327
+ for (const dir of readdirSync(MINTO_PLUGINS_DIR, { withFileTypes: true })) {
328
+ if (!dir.isDirectory()) continue;
329
+ const pluginDir = join(MINTO_PLUGINS_DIR, dir.name);
330
+ const rootManifest = join(pluginDir, "plugin.json");
331
+ const mintoManifest = join(pluginDir, ".minto-plugin", "plugin.json");
332
+ const ccSyncMarker = join(pluginDir, ".cc-sync.json");
333
+ if (existsSync(ccSyncMarker) && existsSync(rootManifest) && !existsSync(mintoManifest)) {
334
+ mkdirSync(join(pluginDir, ".minto-plugin"), { recursive: true });
335
+ cpSync(rootManifest, mintoManifest);
336
+ }
337
+ }
338
+ } catch {
339
+ }
340
+ onProgress?.("Scanning Claude Code registry...");
341
+ const pluginKeys = Object.keys(registry.plugins);
342
+ result.total = pluginKeys.length;
343
+ for (const pluginKey of pluginKeys) {
344
+ const atIdx = pluginKey.indexOf("@");
345
+ if (atIdx === -1) continue;
346
+ const pluginName = pluginKey.slice(0, atIdx);
347
+ const marketplace = pluginKey.slice(atIdx + 1);
348
+ const entries = registry.plugins[pluginKey];
349
+ const entry = entries.find((e) => e.scope === "user") || entries[0];
350
+ if (!entry) continue;
351
+ const enabled = enabledPlugins[pluginKey] !== false;
352
+ try {
353
+ onProgress?.(
354
+ existsSync(join(MINTO_PLUGINS_DIR, pluginName)) ? `Updating ${pluginName}...` : `Installing ${pluginName}...`
355
+ );
356
+ const action = syncSinglePlugin(
357
+ pluginName,
358
+ marketplace,
359
+ entry,
360
+ enabled,
361
+ syncState,
362
+ dryRun,
363
+ knownMarketplaces
364
+ );
365
+ switch (action) {
366
+ case "installed":
367
+ result.installed.push(pluginName);
368
+ break;
369
+ case "updated":
370
+ result.updated.push(pluginName);
371
+ break;
372
+ case "skipped":
373
+ result.skipped.push(pluginName);
374
+ break;
375
+ }
376
+ } catch (err) {
377
+ result.failed.push({
378
+ name: pluginName,
379
+ error: err instanceof Error ? err.message : String(err)
380
+ });
381
+ }
382
+ }
383
+ if (clean && !dryRun && existsSync(MINTO_PLUGINS_DIR)) {
384
+ const ccPluginNames = new Set(
385
+ pluginKeys.map((k) => k.slice(0, k.indexOf("@")))
386
+ );
387
+ for (const dir of readdirSync(MINTO_PLUGINS_DIR)) {
388
+ const pluginPath = join(MINTO_PLUGINS_DIR, dir);
389
+ const ccSyncPath = join(pluginPath, ".cc-sync.json");
390
+ if (!existsSync(ccSyncPath)) continue;
391
+ if (ccPluginNames.has(dir)) continue;
392
+ rmSync(pluginPath, { recursive: true, force: true });
393
+ result.cleaned.push(dir);
394
+ }
395
+ }
396
+ try {
397
+ onProgress?.("Syncing marketplaces...");
398
+ result.marketplaces = syncMarketplaces(
399
+ knownMarketplaces,
400
+ dryRun,
401
+ onProgress
402
+ );
403
+ } catch {
404
+ }
405
+ if (!dryRun) {
406
+ const registryStat = statSync(CC_REGISTRY_PATH);
407
+ const newState = {
408
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
409
+ lastRegistryModified: registryStat.mtime.toISOString(),
410
+ plugins: {}
411
+ };
412
+ if (existsSync(MINTO_PLUGINS_DIR)) {
413
+ for (const dir of readdirSync(MINTO_PLUGINS_DIR)) {
414
+ const ccSyncPath = join(MINTO_PLUGINS_DIR, dir, ".cc-sync.json");
415
+ if (!existsSync(ccSyncPath)) continue;
416
+ try {
417
+ const meta = JSON.parse(readFileSync(ccSyncPath, "utf-8"));
418
+ newState.plugins[dir] = {
419
+ version: meta.version,
420
+ gitCommitSha: meta.gitCommitSha,
421
+ syncedAt: meta.syncedAt,
422
+ marketplace: meta.marketplace
423
+ };
424
+ } catch {
425
+ }
426
+ }
427
+ }
428
+ saveSyncState(newState);
429
+ }
430
+ return result;
431
+ }
432
+ export {
433
+ getClaudeCodePluginCount,
434
+ hasClaudeCodeInstallation,
435
+ loadCCKnownMarketplaces,
436
+ needsSync,
437
+ syncFromClaudeCode
438
+ };
439
+ //# sourceMappingURL=claudeCodeSync.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/claudeCodeSync.ts"],
4
+ "sourcesContent": ["/**\n * Claude Code \u2192 Minto Plugin Sync\n *\n * Reads Claude Code's installed_plugins.json registry, compares with Minto's\n * sync state, and copies new/updated plugins into ~/.minto/plugins/.\n *\n * Design:\n * - Never modifies Claude Code files\n * - Minto-manual plugins (no .cc-sync.json) are never overwritten\n * - Sync state tracked in ~/.minto/cc-sync-state.json\n */\n\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n mkdirSync,\n rmSync,\n cpSync,\n readdirSync,\n statSync,\n} from 'fs'\nimport { join, basename } from 'path'\nimport { homedir } from 'os'\nimport type { MarketplaceSource } from '../types/marketplace'\nimport {\n isMarketplaceRegistered,\n registerMarketplaceFromDirectory,\n} from './marketplaceManager'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface CCPluginEntry {\n scope: 'user' | 'project'\n installPath: string\n version: string\n installedAt: string\n lastUpdated: string\n gitCommitSha?: string\n}\n\ninterface CCRegistry {\n version: number\n plugins: Record<string, CCPluginEntry[]> // key = \"name@marketplace\"\n}\n\ninterface CCSettings {\n enabledPlugins?: Record<string, boolean>\n}\n\ninterface CCKnownMarketplace {\n source: { source: string; repo?: string; url?: string; ref?: string }\n installLocation: string\n lastUpdated: string\n}\n\ninterface CCSyncPluginState {\n version: string\n gitCommitSha?: string\n syncedAt: string\n marketplace: string\n}\n\ninterface CCSyncState {\n lastSyncedAt: string\n lastRegistryModified: string // mtime ISO string\n plugins: Record<string, CCSyncPluginState> // key = plugin name\n}\n\nexport interface MarketplaceSyncResult {\n registered: string[]\n skipped: string[]\n failed: Array<{ name: string; error: string }>\n}\n\nexport interface SyncResult {\n installed: string[]\n updated: string[]\n skipped: string[]\n failed: Array<{ name: string; error: string }>\n cleaned: string[]\n total: number\n marketplaces: MarketplaceSyncResult\n}\n\nexport interface SyncOptions {\n force?: boolean\n clean?: boolean\n dryRun?: boolean\n onProgress?: (msg: string) => void\n}\n\n// ---------------------------------------------------------------------------\n// Path constants\n// ---------------------------------------------------------------------------\n\nconst CC_HOME = join(homedir(), '.claude')\nconst CC_REGISTRY_PATH = join(CC_HOME, 'plugins', 'installed_plugins.json')\nconst CC_SETTINGS_PATH = join(CC_HOME, 'settings.json')\nconst CC_MARKETPLACES_PATH = join(CC_HOME, 'plugins', 'known_marketplaces.json')\nconst MINTO_HOME = join(homedir(), '.minto')\nconst MINTO_SYNC_STATE_PATH = join(MINTO_HOME, 'cc-sync-state.json')\nconst MINTO_PLUGINS_DIR = join(MINTO_HOME, 'plugins')\n\n// ---------------------------------------------------------------------------\n// Helpers \u2014 load CC data\n// ---------------------------------------------------------------------------\n\nfunction loadJSON<T>(path: string): T | null {\n if (!existsSync(path)) return null\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as T\n } catch {\n return null\n }\n}\n\nfunction loadCCRegistry(): CCRegistry | null {\n return loadJSON<CCRegistry>(CC_REGISTRY_PATH)\n}\n\nfunction loadCCSettings(): CCSettings {\n return loadJSON<CCSettings>(CC_SETTINGS_PATH) ?? {}\n}\n\nexport function loadCCKnownMarketplaces(): Record<\n string,\n CCKnownMarketplace\n> | null {\n return loadJSON<Record<string, CCKnownMarketplace>>(CC_MARKETPLACES_PATH)\n}\n\n// ---------------------------------------------------------------------------\n// Helpers \u2014 CC\u2192Minto source conversion\n// ---------------------------------------------------------------------------\n\n/**\n * Convert Claude Code's marketplace source format to Minto's MarketplaceSource.\n * CC uses `{ source: 'github', repo }` while Minto uses `{ type: 'github', repo }`.\n * Returns null for unknown types or missing required fields.\n */\nfunction convertCCSourceToMintoSource(\n ccSource: CCKnownMarketplace['source'],\n): MarketplaceSource | null {\n switch (ccSource.source) {\n case 'github':\n if (!ccSource.repo) return null\n return { type: 'github', repo: ccSource.repo, ref: ccSource.ref }\n case 'url':\n if (!ccSource.url) return null\n return { type: 'url', url: ccSource.url, ref: ccSource.ref }\n case 'local':\n // Local sources from CC don't transfer meaningfully\n return null\n default:\n return null\n }\n}\n\n/**\n * Resolve a marketplace source for a plugin from CC's known_marketplaces.json.\n * Used to write real source info into .marketplace-meta.json instead of `{ source: 'claude-code' }`.\n */\nfunction resolveMarketplaceSource(\n marketplace: string,\n knownMarketplaces: Record<string, CCKnownMarketplace> | null,\n): MarketplaceSource | null {\n if (!knownMarketplaces) return null\n const mp = knownMarketplaces[marketplace]\n if (!mp) return null\n return convertCCSourceToMintoSource(mp.source)\n}\n\n/**\n * Sync marketplaces from Claude Code's known_marketplaces.json into Minto's registry.\n * Non-blocking: errors per-marketplace are caught and recorded.\n */\nfunction syncMarketplaces(\n knownMarketplaces: Record<string, CCKnownMarketplace> | null,\n dryRun: boolean,\n onProgress?: (msg: string) => void,\n): MarketplaceSyncResult {\n const result: MarketplaceSyncResult = {\n registered: [],\n skipped: [],\n failed: [],\n }\n\n if (!knownMarketplaces) return result\n\n for (const [name, mp] of Object.entries(knownMarketplaces)) {\n try {\n // Already in Minto registry?\n if (isMarketplaceRegistered(name)) {\n result.skipped.push(name)\n continue\n }\n\n // Convert source format\n const mintoSource = convertCCSourceToMintoSource(mp.source)\n if (!mintoSource) {\n result.skipped.push(name)\n continue\n }\n\n // Verify CC's local clone exists\n if (!mp.installLocation || !existsSync(mp.installLocation)) {\n result.failed.push({\n name,\n error: `Install location not found: ${mp.installLocation || '(empty)'}`,\n })\n continue\n }\n\n if (dryRun) {\n result.registered.push(name)\n continue\n }\n\n onProgress?.(`Registering marketplace ${name}...`)\n const registered = registerMarketplaceFromDirectory(\n name,\n mintoSource,\n mp.installLocation,\n )\n\n if (registered) {\n result.registered.push(name)\n } else {\n result.skipped.push(name) // race: registered between check and call\n }\n } catch (err) {\n result.failed.push({\n name,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Helpers \u2014 sync state\n// ---------------------------------------------------------------------------\n\nfunction loadSyncState(): CCSyncState | null {\n return loadJSON<CCSyncState>(MINTO_SYNC_STATE_PATH)\n}\n\nfunction saveSyncState(state: CCSyncState): void {\n if (!existsSync(MINTO_HOME)) {\n mkdirSync(MINTO_HOME, { recursive: true })\n }\n writeFileSync(MINTO_SYNC_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8')\n}\n\n// ---------------------------------------------------------------------------\n// Public \u2014 quick checks\n// ---------------------------------------------------------------------------\n\n/** Returns true if Claude Code is installed with plugins */\nexport function hasClaudeCodeInstallation(): boolean {\n return existsSync(CC_REGISTRY_PATH)\n}\n\n/** Returns total plugin count in CC registry (for prompts) */\nexport function getClaudeCodePluginCount(): number {\n const registry = loadCCRegistry()\n if (!registry) return 0\n return Object.keys(registry.plugins).length\n}\n\n/**\n * Fast check: does Minto need to sync from CC?\n * O(1) \u2014 only stats one file.\n */\nexport function needsSync(): boolean {\n if (!existsSync(CC_REGISTRY_PATH)) return false\n\n const state = loadSyncState()\n if (!state) return true // never synced\n\n try {\n const stat = statSync(CC_REGISTRY_PATH)\n const mtime = stat.mtime.toISOString()\n return mtime !== state.lastRegistryModified\n } catch {\n return false\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core \u2014 copy plugin from CC cache\n// ---------------------------------------------------------------------------\n\nconst EXCLUDE_PATTERNS = new Set([\n '.git',\n '.orphaned_at',\n '.DS_Store',\n 'node_modules',\n '.github',\n])\n\nfunction shouldCopy(src: string): boolean {\n const name = basename(src)\n return !EXCLUDE_PATTERNS.has(name)\n}\n\nfunction copyPluginFromCache(sourcePath: string, targetPath: string): void {\n if (!existsSync(sourcePath)) {\n throw new Error(`Source path does not exist: ${sourcePath}`)\n }\n\n if (!existsSync(targetPath)) {\n mkdirSync(targetPath, { recursive: true })\n }\n\n cpSync(sourcePath, targetPath, {\n recursive: true,\n filter: shouldCopy,\n })\n}\n\n// ---------------------------------------------------------------------------\n// Core \u2014 generate Minto plugin.json from CC metadata\n// ---------------------------------------------------------------------------\n\ninterface MarketplacePluginMeta {\n name: string\n description?: string\n version?: string\n author?: string | { name: string; url?: string; email?: string }\n homepage?: string\n repository?: string\n license?: string\n keywords?: string[]\n category?: string\n}\n\nfunction loadMarketplacePluginMeta(\n marketplaceName: string,\n pluginName: string,\n): MarketplacePluginMeta | null {\n const knownMPs = loadCCKnownMarketplaces()\n if (!knownMPs) return null\n\n const mp = knownMPs[marketplaceName]\n if (!mp?.installLocation) return null\n\n // Try .claude-plugin/marketplace.json\n const mpJsonPath = join(\n mp.installLocation,\n '.claude-plugin',\n 'marketplace.json',\n )\n if (!existsSync(mpJsonPath)) return null\n\n try {\n const manifest = JSON.parse(readFileSync(mpJsonPath, 'utf-8'))\n const plugins: MarketplacePluginMeta[] = manifest.plugins || []\n return plugins.find(p => p.name === pluginName) ?? null\n } catch {\n return null\n }\n}\n\nfunction generatePluginManifest(\n pluginName: string,\n marketplace: string,\n ccEntry: CCPluginEntry,\n meta: MarketplacePluginMeta | null,\n): Record<string, unknown> {\n // Scan for component directories\n const agents: string[] = []\n const commands: string[] = []\n const skills: string[] = []\n\n const agentsDir = join(ccEntry.installPath, 'agents')\n if (existsSync(agentsDir)) {\n try {\n agents.push(\n ...readdirSync(agentsDir)\n .filter(f => f.endsWith('.md'))\n .map(f => `agents/${f}`),\n )\n } catch {\n /* ignore */\n }\n }\n\n const commandsDir = join(ccEntry.installPath, 'commands')\n if (existsSync(commandsDir)) {\n try {\n commands.push(\n ...readdirSync(commandsDir)\n .filter(f => f.endsWith('.md'))\n .map(f => `commands/${f}`),\n )\n } catch {\n /* ignore */\n }\n }\n\n const skillsDir = join(ccEntry.installPath, 'skills')\n if (existsSync(skillsDir)) {\n try {\n for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n const skillMd = join(skillsDir, entry.name, 'SKILL.md')\n if (existsSync(skillMd)) {\n skills.push(`skills/${entry.name}/SKILL.md`)\n }\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n skills.push(`skills/${entry.name}`)\n }\n }\n } catch {\n /* ignore */\n }\n }\n\n return {\n name: pluginName,\n version: meta?.version || ccEntry.version || '1.0.0',\n description: meta?.description || `Claude Code plugin: ${pluginName}`,\n displayName: pluginName,\n author: meta?.author,\n homepage: meta?.homepage,\n repository: meta?.repository,\n license: meta?.license,\n agents,\n commands,\n skills,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core \u2014 sync a single plugin\n// ---------------------------------------------------------------------------\n\ntype SyncAction = 'installed' | 'updated' | 'skipped'\n\nfunction syncSinglePlugin(\n pluginName: string,\n marketplace: string,\n entry: CCPluginEntry,\n enabled: boolean,\n syncState: CCSyncState | null,\n dryRun: boolean,\n knownMarketplaces: Record<string, CCKnownMarketplace> | null,\n): SyncAction {\n const targetPath = join(MINTO_PLUGINS_DIR, pluginName)\n const ccSyncPath = join(targetPath, '.cc-sync.json')\n\n // Conflict check: plugin exists without .cc-sync.json \u2192 manually installed, skip\n if (existsSync(targetPath) && !existsSync(ccSyncPath)) {\n return 'skipped'\n }\n\n // Already synced and up to date?\n if (existsSync(ccSyncPath)) {\n try {\n const existing = JSON.parse(readFileSync(ccSyncPath, 'utf-8'))\n if (\n existing.version === entry.version &&\n existing.gitCommitSha === entry.gitCommitSha\n ) {\n return 'skipped'\n }\n } catch {\n /* re-sync on corrupt file */\n }\n }\n\n const isUpdate = existsSync(targetPath)\n\n if (dryRun) {\n return isUpdate ? 'updated' : 'installed'\n }\n\n // Clear target for update\n if (isUpdate) {\n rmSync(targetPath, { recursive: true, force: true })\n }\n\n // Copy from CC cache\n copyPluginFromCache(entry.installPath, targetPath)\n\n // Generate plugin.json in .minto-plugin/ (highest priority for loadManifest)\n const meta = loadMarketplacePluginMeta(marketplace, pluginName)\n const manifest = generatePluginManifest(pluginName, marketplace, entry, meta)\n const mintoPluginDir = join(targetPath, '.minto-plugin')\n mkdirSync(mintoPluginDir, { recursive: true })\n writeFileSync(\n join(mintoPluginDir, 'plugin.json'),\n JSON.stringify(manifest, null, 2),\n 'utf-8',\n )\n\n // Write .marketplace-meta.json with real source info when available\n const realSource = resolveMarketplaceSource(marketplace, knownMarketplaces)\n writeFileSync(\n join(targetPath, '.marketplace-meta.json'),\n JSON.stringify(\n {\n marketplace,\n plugin: pluginName,\n installedAt: new Date().toISOString(),\n source: realSource ?? { source: 'claude-code' },\n ...(realSource ? { syncedFrom: 'claude-code' } : {}),\n },\n null,\n 2,\n ),\n 'utf-8',\n )\n\n // Write .cc-sync.json\n writeFileSync(\n join(targetPath, '.cc-sync.json'),\n JSON.stringify(\n {\n name: pluginName,\n version: entry.version,\n gitCommitSha: entry.gitCommitSha,\n marketplace,\n syncedAt: new Date().toISOString(),\n source: entry.installPath,\n },\n null,\n 2,\n ),\n 'utf-8',\n )\n\n // Write .plugin-config.json (enabled state)\n writeFileSync(\n join(targetPath, '.plugin-config.json'),\n JSON.stringify({ enabled }, null, 2),\n 'utf-8',\n )\n\n return isUpdate ? 'updated' : 'installed'\n}\n\n// ---------------------------------------------------------------------------\n// Public \u2014 full sync\n// ---------------------------------------------------------------------------\n\nexport async function syncFromClaudeCode(\n options: SyncOptions = {},\n): Promise<SyncResult> {\n const { force = false, clean = false, dryRun = false, onProgress } = options\n\n const result: SyncResult = {\n installed: [],\n updated: [],\n skipped: [],\n failed: [],\n cleaned: [],\n total: 0,\n marketplaces: { registered: [], skipped: [], failed: [] },\n }\n\n // Load CC data\n const registry = loadCCRegistry()\n if (!registry) {\n return result\n }\n\n const settings = loadCCSettings()\n const enabledPlugins = settings.enabledPlugins || {}\n const syncState = force ? null : loadSyncState()\n const knownMarketplaces = loadCCKnownMarketplaces()\n\n // Ensure plugins directory\n if (!existsSync(MINTO_PLUGINS_DIR)) {\n mkdirSync(MINTO_PLUGINS_DIR, { recursive: true })\n }\n\n // Migrate: promote root plugin.json \u2192 .minto-plugin/plugin.json for older syncs\n try {\n for (const dir of readdirSync(MINTO_PLUGINS_DIR, { withFileTypes: true })) {\n if (!dir.isDirectory()) continue\n const pluginDir = join(MINTO_PLUGINS_DIR, dir.name)\n const rootManifest = join(pluginDir, 'plugin.json')\n const mintoManifest = join(pluginDir, '.minto-plugin', 'plugin.json')\n const ccSyncMarker = join(pluginDir, '.cc-sync.json')\n if (\n existsSync(ccSyncMarker) &&\n existsSync(rootManifest) &&\n !existsSync(mintoManifest)\n ) {\n mkdirSync(join(pluginDir, '.minto-plugin'), { recursive: true })\n cpSync(rootManifest, mintoManifest)\n }\n }\n } catch {\n /* non-fatal */\n }\n\n onProgress?.('Scanning Claude Code registry...')\n\n // Process each CC plugin\n const pluginKeys = Object.keys(registry.plugins)\n result.total = pluginKeys.length\n\n for (const pluginKey of pluginKeys) {\n // Parse \"name@marketplace\"\n const atIdx = pluginKey.indexOf('@')\n if (atIdx === -1) continue\n const pluginName = pluginKey.slice(0, atIdx)\n const marketplace = pluginKey.slice(atIdx + 1)\n\n // Get the user-scope entry (prefer user over project)\n const entries = registry.plugins[pluginKey]\n const entry = entries.find(e => e.scope === 'user') || entries[0]\n if (!entry) continue\n\n const enabled = enabledPlugins[pluginKey] !== false\n\n try {\n onProgress?.(\n existsSync(join(MINTO_PLUGINS_DIR, pluginName))\n ? `Updating ${pluginName}...`\n : `Installing ${pluginName}...`,\n )\n\n const action = syncSinglePlugin(\n pluginName,\n marketplace,\n entry,\n enabled,\n syncState,\n dryRun,\n knownMarketplaces,\n )\n\n switch (action) {\n case 'installed':\n result.installed.push(pluginName)\n break\n case 'updated':\n result.updated.push(pluginName)\n break\n case 'skipped':\n result.skipped.push(pluginName)\n break\n }\n } catch (err) {\n result.failed.push({\n name: pluginName,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n // Clean orphans: CC-synced plugins that are no longer in CC registry\n if (clean && !dryRun && existsSync(MINTO_PLUGINS_DIR)) {\n const ccPluginNames = new Set(\n pluginKeys.map(k => k.slice(0, k.indexOf('@'))),\n )\n\n for (const dir of readdirSync(MINTO_PLUGINS_DIR)) {\n const pluginPath = join(MINTO_PLUGINS_DIR, dir)\n const ccSyncPath = join(pluginPath, '.cc-sync.json')\n\n if (!existsSync(ccSyncPath)) continue // not CC-synced\n if (ccPluginNames.has(dir)) continue // still in CC\n\n rmSync(pluginPath, { recursive: true, force: true })\n result.cleaned.push(dir)\n }\n }\n\n // Sync marketplaces from CC \u2192 Minto registry (non-blocking)\n try {\n onProgress?.('Syncing marketplaces...')\n result.marketplaces = syncMarketplaces(\n knownMarketplaces,\n dryRun,\n onProgress,\n )\n } catch {\n // Never block plugin sync if marketplace sync fails\n }\n\n // Save sync state\n if (!dryRun) {\n const registryStat = statSync(CC_REGISTRY_PATH)\n const newState: CCSyncState = {\n lastSyncedAt: new Date().toISOString(),\n lastRegistryModified: registryStat.mtime.toISOString(),\n plugins: {},\n }\n\n // Rebuild state from what's now on disk\n if (existsSync(MINTO_PLUGINS_DIR)) {\n for (const dir of readdirSync(MINTO_PLUGINS_DIR)) {\n const ccSyncPath = join(MINTO_PLUGINS_DIR, dir, '.cc-sync.json')\n if (!existsSync(ccSyncPath)) continue\n try {\n const meta = JSON.parse(readFileSync(ccSyncPath, 'utf-8'))\n newState.plugins[dir] = {\n version: meta.version,\n gitCommitSha: meta.gitCommitSha,\n syncedAt: meta.syncedAt,\n marketplace: meta.marketplace,\n }\n } catch {\n /* ignore corrupt */\n }\n }\n }\n\n saveSyncState(newState)\n }\n\n return result\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -40,23 +40,6 @@ function getVerboseLabel(verbose) {
40
40
  return verbose ? "Verbose: On" : "Verbose: Off";
41
41
  }
42
42
  }
43
- function getDisplayModeLabel(mode) {
44
- return mode === "detailed" ? "Verbose: On" : "Verbose: Off";
45
- }
46
- const DISPLAY_MODE_LABELS = {
47
- minimal: "Verbose: Off",
48
- compact: "Verbose: Off",
49
- detailed: "Verbose: On"
50
- };
51
- function getNextDisplayMode(current) {
52
- return current === "detailed" ? "compact" : "detailed";
53
- }
54
- function displayModeToVerbose(mode) {
55
- return mode === "detailed";
56
- }
57
- function verboseToDisplayMode(verbose) {
58
- return verbose ? "detailed" : "compact";
59
- }
60
43
  const DEFAULT_GLOBAL_CONFIG = {
61
44
  numStartups: 0,
62
45
  autoUpdaterStatus: "not_configured",
@@ -181,7 +164,39 @@ function getGlobalConfig() {
181
164
  }
182
165
  const config = getConfig(GLOBAL_CONFIG_FILE, DEFAULT_GLOBAL_CONFIG);
183
166
  const migratedConfig = migrateModelProfilesRemoveId(config);
184
- return migrateDisplayModeToVerbose(migratedConfig);
167
+ const displayMigratedConfig = migrateDisplayModeToVerbose(migratedConfig);
168
+ if (displayMigratedConfig.modelProfiles && displayMigratedConfig.modelProfiles.length > 0) {
169
+ const originalCount = displayMigratedConfig.modelProfiles.length;
170
+ const deduplicatedProfiles = deduplicateModelProfiles(
171
+ displayMigratedConfig.modelProfiles
172
+ );
173
+ const deduplicatedCount = deduplicatedProfiles.length;
174
+ if (deduplicatedCount < originalCount) {
175
+ debugLogger.state("CONFIG_DEDUPLICATE_PROFILES", {
176
+ originalCount: String(originalCount),
177
+ deduplicatedCount: String(deduplicatedCount),
178
+ removedCount: String(originalCount - deduplicatedCount)
179
+ });
180
+ const configToSave = {
181
+ ...displayMigratedConfig,
182
+ modelProfiles: deduplicatedProfiles
183
+ };
184
+ saveConfig(
185
+ GLOBAL_CONFIG_FILE,
186
+ {
187
+ ...configToSave,
188
+ projects: config.projects
189
+ },
190
+ DEFAULT_GLOBAL_CONFIG
191
+ );
192
+ return configToSave;
193
+ }
194
+ return {
195
+ ...displayMigratedConfig,
196
+ modelProfiles: deduplicatedProfiles
197
+ };
198
+ }
199
+ return displayMigratedConfig;
185
200
  }
186
201
  function getAnthropicApiKey() {
187
202
  return process.env.ANTHROPIC_API_KEY || null;
@@ -547,6 +562,23 @@ function migrateModelProfilesRemoveId(config) {
547
562
  defaultModelName
548
563
  };
549
564
  }
565
+ function deduplicateModelProfiles(profiles) {
566
+ if (!profiles || profiles.length === 0) {
567
+ return [];
568
+ }
569
+ const profileMap = /* @__PURE__ */ new Map();
570
+ for (const profile of profiles) {
571
+ const existing = profileMap.get(profile.modelName);
572
+ if (!existing) {
573
+ profileMap.set(profile.modelName, profile);
574
+ } else {
575
+ if (profile.createdAt > existing.createdAt) {
576
+ profileMap.set(profile.modelName, profile);
577
+ }
578
+ }
579
+ }
580
+ return Array.from(profileMap.values());
581
+ }
550
582
  function setAllPointersToModel(modelName) {
551
583
  const config = getGlobalConfig();
552
584
  const updatedConfig = {
@@ -721,7 +753,6 @@ function createGPT5ModelProfile(name, modelName, apiKey, baseURL, provider = "op
721
753
  }
722
754
  export {
723
755
  DEFAULT_GLOBAL_CONFIG,
724
- DISPLAY_MODE_LABELS,
725
756
  GLOBAL_CONFIG_KEYS,
726
757
  PROJECT_CONFIG_KEYS,
727
758
  TEST_MCPRC_CONFIG_FOR_TESTING,
@@ -729,18 +760,16 @@ export {
729
760
  checkHasTrustDialogAccepted,
730
761
  clearMcprcConfigForTesting,
731
762
  createGPT5ModelProfile,
763
+ deduplicateModelProfiles,
732
764
  deleteConfigForCLI,
733
- displayModeToVerbose,
734
765
  enableConfigs,
735
766
  getAnthropicApiKey,
736
767
  getConfigForCLI,
737
768
  getCurrentProjectConfig,
738
769
  getCustomApiKeyStatus,
739
- getDisplayModeLabel,
740
770
  getGPT5ConfigRecommendations,
741
771
  getGlobalConfig,
742
772
  getMcprcConfig,
743
- getNextDisplayMode,
744
773
  getOpenAIApiKey,
745
774
  getOrCreateUserID,
746
775
  getVerboseLabel,
@@ -759,7 +788,6 @@ export {
759
788
  setConfigForCLI,
760
789
  setModelPointer,
761
790
  validateAndRepairAllGPT5Profiles,
762
- validateAndRepairGPT5Profile,
763
- verboseToDisplayMode
791
+ validateAndRepairGPT5Profile
764
792
  };
765
793
  //# sourceMappingURL=config.js.map