aman-intelligence 0.1.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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/dist/bin/aman.d.ts +2 -0
  4. package/dist/bin/aman.js +165 -0
  5. package/dist/cli/global-install.d.ts +7 -0
  6. package/dist/cli/global-install.js +36 -0
  7. package/dist/cli/help-text.d.ts +1 -0
  8. package/dist/cli/help-text.js +62 -0
  9. package/dist/cli/version.d.ts +1 -0
  10. package/dist/cli/version.js +6 -0
  11. package/dist/commands/backup.d.ts +11 -0
  12. package/dist/commands/backup.js +262 -0
  13. package/dist/commands/browse.d.ts +11 -0
  14. package/dist/commands/browse.js +641 -0
  15. package/dist/commands/cache.d.ts +1 -0
  16. package/dist/commands/cache.js +38 -0
  17. package/dist/commands/config.d.ts +4 -0
  18. package/dist/commands/config.js +146 -0
  19. package/dist/commands/dashboard.d.ts +1 -0
  20. package/dist/commands/dashboard.js +1004 -0
  21. package/dist/commands/doctor.d.ts +4 -0
  22. package/dist/commands/doctor.js +54 -0
  23. package/dist/commands/export.d.ts +1 -0
  24. package/dist/commands/export.js +137 -0
  25. package/dist/commands/help.d.ts +1 -0
  26. package/dist/commands/help.js +47 -0
  27. package/dist/commands/import-wizard.d.ts +7 -0
  28. package/dist/commands/import-wizard.js +374 -0
  29. package/dist/commands/import.d.ts +9 -0
  30. package/dist/commands/import.js +351 -0
  31. package/dist/commands/info.d.ts +1 -0
  32. package/dist/commands/info.js +174 -0
  33. package/dist/commands/init.d.ts +20 -0
  34. package/dist/commands/init.js +146 -0
  35. package/dist/commands/install.d.ts +10 -0
  36. package/dist/commands/install.js +342 -0
  37. package/dist/commands/pack.d.ts +23 -0
  38. package/dist/commands/pack.js +331 -0
  39. package/dist/commands/registry.d.ts +6 -0
  40. package/dist/commands/registry.js +218 -0
  41. package/dist/commands/remove.d.ts +1 -0
  42. package/dist/commands/remove.js +76 -0
  43. package/dist/commands/search.d.ts +7 -0
  44. package/dist/commands/search.js +295 -0
  45. package/dist/commands/stack.d.ts +18 -0
  46. package/dist/commands/stack.js +327 -0
  47. package/dist/commands/sync.d.ts +9 -0
  48. package/dist/commands/sync.js +428 -0
  49. package/dist/commands/update.d.ts +1 -0
  50. package/dist/commands/update.js +97 -0
  51. package/dist/config/features.d.ts +2 -0
  52. package/dist/config/features.js +2 -0
  53. package/dist/config/index.d.ts +13 -0
  54. package/dist/config/index.js +80 -0
  55. package/dist/config/paths.d.ts +23 -0
  56. package/dist/config/paths.js +45 -0
  57. package/dist/import/adapters.d.ts +14 -0
  58. package/dist/import/adapters.js +580 -0
  59. package/dist/import/discovery.service.d.ts +8 -0
  60. package/dist/import/discovery.service.js +26 -0
  61. package/dist/import/import.service.d.ts +7 -0
  62. package/dist/import/import.service.js +259 -0
  63. package/dist/import/types.d.ts +71 -0
  64. package/dist/import/types.js +1 -0
  65. package/dist/import/utils.d.ts +36 -0
  66. package/dist/import/utils.js +428 -0
  67. package/dist/marketplace/cache.d.ts +18 -0
  68. package/dist/marketplace/cache.js +141 -0
  69. package/dist/marketplace/github-search.d.ts +17 -0
  70. package/dist/marketplace/github-search.js +268 -0
  71. package/dist/marketplace/install-from-candidate.d.ts +6 -0
  72. package/dist/marketplace/install-from-candidate.js +14 -0
  73. package/dist/marketplace/install.d.ts +15 -0
  74. package/dist/marketplace/install.js +54 -0
  75. package/dist/marketplace/metadata-validator.d.ts +8 -0
  76. package/dist/marketplace/metadata-validator.js +79 -0
  77. package/dist/marketplace/types.d.ts +34 -0
  78. package/dist/marketplace/types.js +1 -0
  79. package/dist/providers/local.provider.d.ts +9 -0
  80. package/dist/providers/local.provider.js +51 -0
  81. package/dist/providers/provider.interface.d.ts +7 -0
  82. package/dist/providers/provider.interface.js +1 -0
  83. package/dist/providers/registry.provider.d.ts +2 -0
  84. package/dist/providers/registry.provider.js +42 -0
  85. package/dist/providers/skills-sh.provider.d.ts +11 -0
  86. package/dist/providers/skills-sh.provider.js +56 -0
  87. package/dist/registry/adapter.interface.d.ts +16 -0
  88. package/dist/registry/adapter.interface.js +1 -0
  89. package/dist/registry/errors.d.ts +5 -0
  90. package/dist/registry/errors.js +8 -0
  91. package/dist/registry/filesystem-registry.adapter.d.ts +25 -0
  92. package/dist/registry/filesystem-registry.adapter.js +288 -0
  93. package/dist/registry/github-registry.adapter.d.ts +11 -0
  94. package/dist/registry/github-registry.adapter.js +32 -0
  95. package/dist/registry/index.d.ts +8 -0
  96. package/dist/registry/index.js +8 -0
  97. package/dist/registry/local-registry.adapter.d.ts +6 -0
  98. package/dist/registry/local-registry.adapter.js +9 -0
  99. package/dist/registry/registry.service.d.ts +44 -0
  100. package/dist/registry/registry.service.js +163 -0
  101. package/dist/registry/slug-utils.d.ts +12 -0
  102. package/dist/registry/slug-utils.js +51 -0
  103. package/dist/registry/types.d.ts +160 -0
  104. package/dist/registry/types.js +1 -0
  105. package/dist/services/asset.service.d.ts +12 -0
  106. package/dist/services/asset.service.js +142 -0
  107. package/dist/services/backup.service.d.ts +8 -0
  108. package/dist/services/backup.service.js +169 -0
  109. package/dist/services/classification.service.d.ts +31 -0
  110. package/dist/services/classification.service.js +271 -0
  111. package/dist/services/config.service.d.ts +9 -0
  112. package/dist/services/config.service.js +20 -0
  113. package/dist/services/doctor.service.d.ts +5 -0
  114. package/dist/services/doctor.service.js +186 -0
  115. package/dist/services/environment.service.d.ts +42 -0
  116. package/dist/services/environment.service.js +227 -0
  117. package/dist/services/github.service.d.ts +7 -0
  118. package/dist/services/github.service.js +42 -0
  119. package/dist/services/lock.service.d.ts +12 -0
  120. package/dist/services/lock.service.js +71 -0
  121. package/dist/services/marketplace.service.d.ts +40 -0
  122. package/dist/services/marketplace.service.js +225 -0
  123. package/dist/services/pack.service.d.ts +9 -0
  124. package/dist/services/pack.service.js +193 -0
  125. package/dist/services/stack.service.d.ts +9 -0
  126. package/dist/services/stack.service.js +94 -0
  127. package/dist/storage/asset-layout.d.ts +46 -0
  128. package/dist/storage/asset-layout.js +277 -0
  129. package/dist/storage/filesystem.d.ts +12 -0
  130. package/dist/storage/filesystem.js +113 -0
  131. package/dist/storage/scan-by-type.d.ts +2 -0
  132. package/dist/storage/scan-by-type.js +8 -0
  133. package/dist/storage/scanner.d.ts +11 -0
  134. package/dist/storage/scanner.js +188 -0
  135. package/dist/types/asset-metadata.d.ts +84 -0
  136. package/dist/types/asset-metadata.js +104 -0
  137. package/dist/types/index.d.ts +212 -0
  138. package/dist/types/index.js +1 -0
  139. package/dist/ui/animations/ErrorIndicator.d.ts +5 -0
  140. package/dist/ui/animations/ErrorIndicator.js +6 -0
  141. package/dist/ui/animations/GithubIndicator.d.ts +6 -0
  142. package/dist/ui/animations/GithubIndicator.js +9 -0
  143. package/dist/ui/animations/ProgressBar.d.ts +5 -0
  144. package/dist/ui/animations/ProgressBar.js +15 -0
  145. package/dist/ui/animations/Spinner.d.ts +5 -0
  146. package/dist/ui/animations/Spinner.js +21 -0
  147. package/dist/ui/animations/SuccessIndicator.d.ts +5 -0
  148. package/dist/ui/animations/SuccessIndicator.js +6 -0
  149. package/dist/ui/animations/SyncActivity.d.ts +5 -0
  150. package/dist/ui/animations/SyncActivity.js +21 -0
  151. package/dist/ui/animations/TransitionScreen.d.ts +7 -0
  152. package/dist/ui/animations/TransitionScreen.js +25 -0
  153. package/dist/ui/animations/useAnimationMode.d.ts +1 -0
  154. package/dist/ui/animations/useAnimationMode.js +16 -0
  155. package/dist/ui/assetDisplay.d.ts +19 -0
  156. package/dist/ui/assetDisplay.js +59 -0
  157. package/dist/ui/components/Confirm.d.ts +8 -0
  158. package/dist/ui/components/Confirm.js +14 -0
  159. package/dist/ui/components/CustomSelect.d.ts +19 -0
  160. package/dist/ui/components/CustomSelect.js +13 -0
  161. package/dist/ui/components/Header.d.ts +6 -0
  162. package/dist/ui/components/Header.js +9 -0
  163. package/dist/ui/components/HealthReport.d.ts +7 -0
  164. package/dist/ui/components/HealthReport.js +13 -0
  165. package/dist/ui/components/MarketplaceInstallConfirm.d.ts +19 -0
  166. package/dist/ui/components/MarketplaceInstallConfirm.js +23 -0
  167. package/dist/ui/components/Narrator.d.ts +9 -0
  168. package/dist/ui/components/Narrator.js +26 -0
  169. package/dist/ui/components/ScopePrompt.d.ts +8 -0
  170. package/dist/ui/components/ScopePrompt.js +23 -0
  171. package/dist/ui/components/TooSmallScreen.d.ts +8 -0
  172. package/dist/ui/components/TooSmallScreen.js +6 -0
  173. package/dist/ui/date.d.ts +2 -0
  174. package/dist/ui/date.js +33 -0
  175. package/dist/ui/layout.d.ts +23 -0
  176. package/dist/ui/layout.js +44 -0
  177. package/dist/ui/list-item.d.ts +12 -0
  178. package/dist/ui/list-item.js +1 -0
  179. package/dist/ui/marketplaceDisplay.d.ts +10 -0
  180. package/dist/ui/marketplaceDisplay.js +36 -0
  181. package/dist/ui/theme.d.ts +42 -0
  182. package/dist/ui/theme.js +47 -0
  183. package/dist/utils/asset-list-fields.d.ts +11 -0
  184. package/dist/utils/asset-list-fields.js +28 -0
  185. package/dist/utils/error-message.d.ts +2 -0
  186. package/dist/utils/error-message.js +6 -0
  187. package/dist/utils/integrity.d.ts +9 -0
  188. package/dist/utils/integrity.js +23 -0
  189. package/dist/utils/lock-migrate.d.ts +25 -0
  190. package/dist/utils/lock-migrate.js +93 -0
  191. package/dist/utils/mcp-local.d.ts +15 -0
  192. package/dist/utils/mcp-local.js +129 -0
  193. package/dist/utils/slug.d.ts +6 -0
  194. package/dist/utils/slug.js +13 -0
  195. package/dist/utils/stack-normalize.d.ts +3 -0
  196. package/dist/utils/stack-normalize.js +43 -0
  197. package/package.json +77 -0
@@ -0,0 +1,45 @@
1
+ import path from 'path';
2
+ import os from 'os';
3
+ import { ensureDir } from '../storage/filesystem.js';
4
+ export const GLOBAL_DIR = path.join(os.homedir(), '.aman');
5
+ export const GLOBAL_SKILLS = path.join(GLOBAL_DIR, 'skills');
6
+ export const GLOBAL_PROMPTS = path.join(GLOBAL_DIR, 'prompts');
7
+ export const GLOBAL_MCPS = path.join(GLOBAL_DIR, 'mcps');
8
+ export const GLOBAL_STACKS = path.join(GLOBAL_DIR, 'stacks');
9
+ export const GLOBAL_CACHE = path.join(GLOBAL_DIR, 'cache');
10
+ export const GLOBAL_BACKUPS = path.join(GLOBAL_DIR, 'backups');
11
+ export const GLOBAL_REGISTRY_DIR = path.join(GLOBAL_DIR, 'registry');
12
+ export const GLOBAL_CONFIG_DIR = path.join(GLOBAL_DIR, 'config');
13
+ export const GLOBAL_CONFIG_FILE = path.join(GLOBAL_CONFIG_DIR, 'aman.json');
14
+ export const LOCAL_DIR = '.aman';
15
+ export const LOCAL_CONFIG_FILE = path.join(LOCAL_DIR, 'aman.json');
16
+ export const LOCAL_LOCKFILE = path.join(LOCAL_DIR, 'aman.lock');
17
+ import { fileURLToPath } from 'url';
18
+ // Works from both src/config during development and dist/config after build.
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ export const PROJECT_ROOT = path.resolve(path.dirname(__filename), '../..');
21
+ export const BUNDLED_SKILLS = path.join(PROJECT_ROOT, 'skills');
22
+ export const BUNDLED_PROMPTS = path.join(PROJECT_ROOT, 'prompts');
23
+ export const BUNDLED_MCPS = path.join(PROJECT_ROOT, 'mcps');
24
+ /**
25
+ * Creates all `~/.aman/` subdirectories.
26
+ * This is used during setup and doctor checks.
27
+ */
28
+ export async function ensureGlobalDirs() {
29
+ await ensureDir(GLOBAL_DIR);
30
+ await ensureDir(GLOBAL_SKILLS);
31
+ await ensureDir(GLOBAL_PROMPTS);
32
+ await ensureDir(GLOBAL_MCPS);
33
+ await ensureDir(GLOBAL_STACKS);
34
+ await ensureDir(GLOBAL_CACHE);
35
+ await ensureDir(GLOBAL_BACKUPS);
36
+ await ensureDir(GLOBAL_REGISTRY_DIR);
37
+ await ensureDir(GLOBAL_CONFIG_DIR);
38
+ }
39
+ export async function ensureProjectDirs() {
40
+ await ensureDir(LOCAL_DIR);
41
+ await ensureDir(path.join(LOCAL_DIR, 'skills'));
42
+ await ensureDir(path.join(LOCAL_DIR, 'prompts'));
43
+ await ensureDir(path.join(LOCAL_DIR, 'mcps'));
44
+ await ensureDir(path.join(LOCAL_DIR, 'stacks'));
45
+ }
@@ -0,0 +1,14 @@
1
+ import { ImportAdapter, ImportSourceId } from './types.js';
2
+ export declare const claudeCodeAdapter: ImportAdapter;
3
+ export declare const vscodeAdapter: ImportAdapter;
4
+ export declare const githubCopilotAdapter: ImportAdapter;
5
+ export declare const codexAdapter: ImportAdapter;
6
+ export declare const localFolderAdapter: ImportAdapter;
7
+ export declare const customPathAdapter: ImportAdapter;
8
+ export declare const cursorAdapter: ImportAdapter;
9
+ export declare const windsurfAdapter: ImportAdapter;
10
+ export declare const continueAdapter: ImportAdapter;
11
+ export declare const amanEnvironmentAdapter: ImportAdapter;
12
+ export declare const antigravityAdapter: ImportAdapter;
13
+ export declare const IMPORT_ADAPTERS: ImportAdapter[];
14
+ export declare function getAdapter(id: ImportSourceId): ImportAdapter | undefined;
@@ -0,0 +1,580 @@
1
+ import os from 'os';
2
+ import path from 'path';
3
+ import { promises as fs } from 'fs';
4
+ import { exists } from '../storage/filesystem.js';
5
+ import { discoverMcpFromJsonFile, discoverPromptFile, discoverSkillDir, expandHome, listSkillDirs, parseCodexMcpBlocks, codexBlockToMcpJson, makeAssetId, slugifyImportName, vscodeUserMcpPath, discoverRulesAsSkills, discoverContinuePrompts, discoverContinueMcpFromConfig, discoverAmanEnvironmentAssets, } from './utils.js';
6
+ function claudeJsonMcpPaths() {
7
+ const home = os.homedir();
8
+ return [
9
+ path.join(home, '.claude.json'),
10
+ path.join(process.cwd(), '.mcp.json'),
11
+ path.join(process.cwd(), '.claude', 'settings.local.json'),
12
+ ];
13
+ }
14
+ export const claudeCodeAdapter = {
15
+ id: 'claude-code',
16
+ label: 'Claude Code',
17
+ description: 'Skills, commands, and MCP configs from Claude Code',
18
+ isAvailable() {
19
+ const home = os.homedir();
20
+ return (exists(path.join(home, '.claude')) ||
21
+ exists(path.join(home, '.claude.json')) ||
22
+ exists(path.join(process.cwd(), '.claude')) ||
23
+ exists(path.join(process.cwd(), '.mcp.json')));
24
+ },
25
+ unavailableReason() {
26
+ return 'No Claude Code config found (~/.claude, ~/.claude.json, or project .claude/)';
27
+ },
28
+ async scan() {
29
+ const home = os.homedir();
30
+ const found = [];
31
+ const seen = new Set();
32
+ const skillRoots = [
33
+ path.join(home, '.claude', 'skills'),
34
+ path.join(process.cwd(), '.claude', 'skills'),
35
+ ];
36
+ for (const root of skillRoots) {
37
+ for (const dir of await listSkillDirs(root)) {
38
+ const key = `skill:${dir}`;
39
+ if (seen.has(key))
40
+ continue;
41
+ seen.add(key);
42
+ const asset = await discoverSkillDir(dir, 'claude-code', root.replace(home, '~'));
43
+ if (asset)
44
+ found.push(asset);
45
+ }
46
+ }
47
+ const commandRoots = [
48
+ path.join(home, '.claude', 'commands'),
49
+ path.join(process.cwd(), '.claude', 'commands'),
50
+ ];
51
+ for (const root of commandRoots) {
52
+ if (!exists(root))
53
+ continue;
54
+ const files = await fs.readdir(root);
55
+ for (const file of files) {
56
+ if (!file.endsWith('.md'))
57
+ continue;
58
+ const filePath = path.join(root, file);
59
+ const key = `prompt:${filePath}`;
60
+ if (seen.has(key))
61
+ continue;
62
+ seen.add(key);
63
+ found.push(await discoverPromptFile(filePath, 'claude-code', `${root.replace(home, '~')}/${file}`, file.replace(/\.md$/, '')));
64
+ }
65
+ }
66
+ for (const configPath of claudeJsonMcpPaths()) {
67
+ const mcps = await discoverMcpFromJsonFile(configPath, 'claude-code', configPath.replace(home, '~'));
68
+ for (const m of mcps) {
69
+ const key = `mcp:${m.originLabel}`;
70
+ if (seen.has(key))
71
+ continue;
72
+ seen.add(key);
73
+ found.push(m);
74
+ }
75
+ }
76
+ return found;
77
+ },
78
+ };
79
+ export const vscodeAdapter = {
80
+ id: 'vscode',
81
+ label: 'VS Code',
82
+ description: 'MCP servers from VS Code user and workspace mcp.json',
83
+ isAvailable() {
84
+ return (exists(vscodeUserMcpPath()) || exists(path.join(process.cwd(), '.vscode', 'mcp.json')));
85
+ },
86
+ unavailableReason() {
87
+ return 'No VS Code MCP config found (User/mcp.json or .vscode/mcp.json)';
88
+ },
89
+ async scan() {
90
+ const home = os.homedir();
91
+ const paths = [
92
+ vscodeUserMcpPath(),
93
+ path.join(process.cwd(), '.vscode', 'mcp.json'),
94
+ ];
95
+ const found = [];
96
+ const seen = new Set();
97
+ for (const configPath of paths) {
98
+ const mcps = await discoverMcpFromJsonFile(configPath, 'vscode', configPath.replace(home, '~'));
99
+ for (const m of mcps) {
100
+ const key = `mcp:${m.originLabel}`;
101
+ if (seen.has(key))
102
+ continue;
103
+ seen.add(key);
104
+ found.push(m);
105
+ }
106
+ }
107
+ return found;
108
+ },
109
+ };
110
+ export const githubCopilotAdapter = {
111
+ id: 'github-copilot',
112
+ label: 'GitHub Copilot',
113
+ description: 'Copilot instruction files and workspace MCP configs',
114
+ isAvailable() {
115
+ const cwd = process.cwd();
116
+ return (exists(path.join(cwd, '.github', 'copilot-instructions.md')) ||
117
+ exists(path.join(cwd, '.github', 'instructions')) ||
118
+ exists(path.join(cwd, '.vscode', 'mcp.json')));
119
+ },
120
+ unavailableReason() {
121
+ return 'No Copilot instruction files found (.github/copilot-instructions.md or .github/instructions/)';
122
+ },
123
+ async scan() {
124
+ const cwd = process.cwd();
125
+ const found = [];
126
+ const seen = new Set();
127
+ const copilotMain = path.join(cwd, '.github', 'copilot-instructions.md');
128
+ if (exists(copilotMain)) {
129
+ found.push({
130
+ ...(await discoverPromptFile(copilotMain, 'github-copilot', '.github/copilot-instructions.md', 'copilot-instructions')),
131
+ description: 'GitHub Copilot repository instructions',
132
+ confidence: 90,
133
+ });
134
+ }
135
+ const instrDir = path.join(cwd, '.github', 'instructions');
136
+ if (exists(instrDir)) {
137
+ const files = await fs.readdir(instrDir);
138
+ for (const file of files) {
139
+ if (!file.endsWith('.md') && !file.endsWith('.instructions.md'))
140
+ continue;
141
+ const filePath = path.join(instrDir, file);
142
+ const key = `prompt:${filePath}`;
143
+ if (seen.has(key))
144
+ continue;
145
+ seen.add(key);
146
+ found.push(await discoverPromptFile(filePath, 'github-copilot', `.github/instructions/${file}`, file.replace(/\.(instructions\.)?md$/, '')));
147
+ }
148
+ }
149
+ const mcpPath = path.join(cwd, '.vscode', 'mcp.json');
150
+ const mcps = await discoverMcpFromJsonFile(mcpPath, 'github-copilot', '.vscode/mcp.json');
151
+ for (const m of mcps) {
152
+ const key = `mcp:${m.originLabel}`;
153
+ if (seen.has(key))
154
+ continue;
155
+ seen.add(key);
156
+ found.push(m);
157
+ }
158
+ return found;
159
+ },
160
+ };
161
+ export const codexAdapter = {
162
+ id: 'codex',
163
+ label: 'OpenAI Codex',
164
+ description: 'Skills and MCP servers from Codex CLI config',
165
+ isAvailable() {
166
+ const home = os.homedir();
167
+ return (exists(path.join(home, '.codex')) ||
168
+ exists(path.join(home, '.codex', 'config.toml')) ||
169
+ exists(path.join(process.cwd(), '.codex', 'config.toml')));
170
+ },
171
+ unavailableReason() {
172
+ return 'No Codex config found (~/.codex/config.toml or project .codex/config.toml)';
173
+ },
174
+ async scan() {
175
+ const home = os.homedir();
176
+ const found = [];
177
+ const seen = new Set();
178
+ const skillRoots = [
179
+ path.join(home, '.codex', 'skills'),
180
+ path.join(process.cwd(), '.codex', 'skills'),
181
+ ];
182
+ for (const root of skillRoots) {
183
+ for (const dir of await listSkillDirs(root)) {
184
+ const key = `skill:${dir}`;
185
+ if (seen.has(key))
186
+ continue;
187
+ seen.add(key);
188
+ const asset = await discoverSkillDir(dir, 'codex', root.replace(home, '~'));
189
+ if (asset)
190
+ found.push(asset);
191
+ }
192
+ }
193
+ const configPaths = [
194
+ path.join(home, '.codex', 'config.toml'),
195
+ path.join(process.cwd(), '.codex', 'config.toml'),
196
+ ];
197
+ for (const configPath of configPaths) {
198
+ if (!exists(configPath))
199
+ continue;
200
+ const text = await fs.readFile(configPath, 'utf-8');
201
+ for (const block of parseCodexMcpBlocks(text)) {
202
+ const key = `mcp:${configPath}:${block.name}`;
203
+ if (seen.has(key))
204
+ continue;
205
+ seen.add(key);
206
+ const mcpJson = codexBlockToMcpJson(block);
207
+ const stagingNote = `${configPath.replace(home, '~')} [${block.name}]`;
208
+ found.push({
209
+ id: makeAssetId(),
210
+ type: 'mcp',
211
+ name: slugifyImportName(block.name),
212
+ description: `Codex MCP server "${block.name}"`,
213
+ sourcePath: configPath,
214
+ originLabel: stagingNote,
215
+ canonicalStatus: 'convertible',
216
+ canonicalNote: 'Will convert Codex TOML entry to canonical mcp.json',
217
+ confidence: 85,
218
+ adapterId: 'codex',
219
+ mcpServerName: block.name,
220
+ // stash converted json path marker via mcpServerName + codex inline
221
+ });
222
+ // Store inline json in a sidecar temp during import - import service handles codex specially
223
+ void mcpJson;
224
+ }
225
+ }
226
+ return found;
227
+ },
228
+ };
229
+ export const localFolderAdapter = {
230
+ id: 'local-folder',
231
+ label: 'Local folder',
232
+ description: 'Import from a folder on this machine',
233
+ isAvailable() {
234
+ return true;
235
+ },
236
+ unavailableReason() {
237
+ return '';
238
+ },
239
+ async scan(options) {
240
+ const root = options?.rootPath ? path.resolve(expandHome(options.rootPath)) : process.cwd();
241
+ if (!exists(root)) {
242
+ throw new Error(`Path not found: ${root}`);
243
+ }
244
+ const { classificationService } = await import('../services/classification.service.js');
245
+ const classifications = await classificationService.classifyDirectory(root);
246
+ const found = [];
247
+ for (const c of classifications) {
248
+ if (c.type !== 'skill' && c.type !== 'prompt' && c.type !== 'mcp')
249
+ continue;
250
+ let sourcePath = path.resolve(root, c.file);
251
+ let name = path.basename(c.file, path.extname(c.file)).replace(/[/\\]/g, '-');
252
+ if (c.type === 'skill') {
253
+ sourcePath = path.dirname(sourcePath);
254
+ if (sourcePath === root)
255
+ name = path.basename(root);
256
+ else
257
+ name = path.basename(sourcePath);
258
+ const asset = await discoverSkillDir(sourcePath, 'local-folder', c.file);
259
+ if (asset) {
260
+ asset.confidence = c.confidence;
261
+ asset.canonicalNote = c.reason;
262
+ if (c.confidence < 50)
263
+ asset.canonicalStatus = 'ambiguous';
264
+ found.push(asset);
265
+ }
266
+ continue;
267
+ }
268
+ found.push({
269
+ id: makeAssetId(),
270
+ type: c.type,
271
+ name: slugifyImportName(name),
272
+ description: c.reason,
273
+ sourcePath,
274
+ originLabel: c.file,
275
+ canonicalStatus: c.confidence >= 70 ? 'convertible' : 'ambiguous',
276
+ canonicalNote: c.confidence < 70 ? `Classification: ${c.reason} (${c.confidence}%)` : c.reason,
277
+ confidence: c.confidence,
278
+ adapterId: 'local-folder',
279
+ });
280
+ }
281
+ return found;
282
+ },
283
+ };
284
+ export const customPathAdapter = {
285
+ id: 'custom-path',
286
+ label: 'Custom path',
287
+ description: 'Enter any folder path to scan',
288
+ isAvailable() {
289
+ return true;
290
+ },
291
+ unavailableReason() {
292
+ return '';
293
+ },
294
+ async scan(options) {
295
+ if (!options?.rootPath) {
296
+ throw new Error('Custom path import requires a folder path');
297
+ }
298
+ return localFolderAdapter.scan(options);
299
+ },
300
+ };
301
+ // ── New adapters ────────────────────────────────────────────────────
302
+ function cursorRulesDirs() {
303
+ const home = os.homedir();
304
+ return [
305
+ path.join(home, '.cursor', 'rules'),
306
+ path.join(process.cwd(), '.cursor', 'rules'),
307
+ ];
308
+ }
309
+ function cursorDotfiles() {
310
+ return [
311
+ path.join(process.cwd(), '.cursorrules'),
312
+ ];
313
+ }
314
+ function cursorMcpPaths() {
315
+ const home = os.homedir();
316
+ return [
317
+ path.join(home, '.cursor', 'mcp.json'),
318
+ path.join(process.cwd(), '.cursor', 'mcp.json'),
319
+ ];
320
+ }
321
+ export const cursorAdapter = {
322
+ id: 'cursor',
323
+ label: 'Cursor',
324
+ description: 'Rules and MCP configs from Cursor editor',
325
+ isAvailable() {
326
+ const home = os.homedir();
327
+ return (exists(path.join(home, '.cursor')) ||
328
+ exists(path.join(process.cwd(), '.cursor')) ||
329
+ exists(path.join(process.cwd(), '.cursorrules')));
330
+ },
331
+ unavailableReason() {
332
+ return 'No Cursor config found (~/.cursor/ or project .cursor/)';
333
+ },
334
+ async scan() {
335
+ const home = os.homedir();
336
+ const found = [];
337
+ const seen = new Set();
338
+ // Skills from rules directories and dotfiles
339
+ const skills = await discoverRulesAsSkills(cursorRulesDirs(), cursorDotfiles(), 'cursor', '.cursor/rules');
340
+ for (const s of skills) {
341
+ const key = `skill:${s.sourcePath}`;
342
+ if (seen.has(key))
343
+ continue;
344
+ seen.add(key);
345
+ found.push(s);
346
+ }
347
+ // MCPs from mcp.json files
348
+ for (const configPath of cursorMcpPaths()) {
349
+ const mcps = await discoverMcpFromJsonFile(configPath, 'cursor', configPath.replace(home, '~'));
350
+ for (const m of mcps) {
351
+ const key = `mcp:${m.originLabel}`;
352
+ if (seen.has(key))
353
+ continue;
354
+ seen.add(key);
355
+ found.push(m);
356
+ }
357
+ }
358
+ return found;
359
+ },
360
+ };
361
+ function windsurfRulesDirs() {
362
+ const home = os.homedir();
363
+ return [
364
+ path.join(home, '.codeium', 'windsurf', 'rules'),
365
+ path.join(process.cwd(), '.windsurf', 'rules'),
366
+ ];
367
+ }
368
+ function windsurfDotfiles() {
369
+ return [
370
+ path.join(process.cwd(), '.windsurfrules'),
371
+ ];
372
+ }
373
+ function windsurfMcpPaths() {
374
+ const home = os.homedir();
375
+ return [
376
+ path.join(home, '.codeium', 'windsurf', 'mcp_config.json'),
377
+ path.join(process.cwd(), '.windsurf', 'mcp.json'),
378
+ ];
379
+ }
380
+ export const windsurfAdapter = {
381
+ id: 'windsurf',
382
+ label: 'Windsurf',
383
+ description: 'Rules and MCP configs from Windsurf editor',
384
+ isAvailable() {
385
+ const home = os.homedir();
386
+ return (exists(path.join(home, '.codeium', 'windsurf')) ||
387
+ exists(path.join(process.cwd(), '.windsurf')) ||
388
+ exists(path.join(process.cwd(), '.windsurfrules')));
389
+ },
390
+ unavailableReason() {
391
+ return 'No Windsurf config found (~/.codeium/windsurf/ or project .windsurf/)';
392
+ },
393
+ async scan() {
394
+ const home = os.homedir();
395
+ const found = [];
396
+ const seen = new Set();
397
+ // Skills from rules directories and dotfiles
398
+ const skills = await discoverRulesAsSkills(windsurfRulesDirs(), windsurfDotfiles(), 'windsurf', '.windsurf/rules');
399
+ for (const s of skills) {
400
+ const key = `skill:${s.sourcePath}`;
401
+ if (seen.has(key))
402
+ continue;
403
+ seen.add(key);
404
+ found.push(s);
405
+ }
406
+ // MCPs from config files
407
+ for (const configPath of windsurfMcpPaths()) {
408
+ const mcps = await discoverMcpFromJsonFile(configPath, 'windsurf', configPath.replace(home, '~'));
409
+ for (const m of mcps) {
410
+ const key = `mcp:${m.originLabel}`;
411
+ if (seen.has(key))
412
+ continue;
413
+ seen.add(key);
414
+ found.push(m);
415
+ }
416
+ }
417
+ return found;
418
+ },
419
+ };
420
+ export const continueAdapter = {
421
+ id: 'continue',
422
+ label: 'Continue.dev',
423
+ description: 'Prompts, docs, and MCP configs from Continue',
424
+ isAvailable() {
425
+ const home = os.homedir();
426
+ return exists(path.join(home, '.continue'));
427
+ },
428
+ unavailableReason() {
429
+ return 'No Continue config found (~/.continue/)';
430
+ },
431
+ async scan() {
432
+ const home = os.homedir();
433
+ const found = [];
434
+ const seen = new Set();
435
+ // Prompts from ~/.continue/prompts/
436
+ const promptsDir = path.join(home, '.continue', 'prompts');
437
+ const prompts = await discoverContinuePrompts(promptsDir, 'continue');
438
+ for (const p of prompts) {
439
+ const key = `prompt:${p.sourcePath}`;
440
+ if (seen.has(key))
441
+ continue;
442
+ seen.add(key);
443
+ found.push(p);
444
+ }
445
+ // Skills from ~/.continue/docs/ (custom documentation context)
446
+ const docsDir = path.join(home, '.continue', 'docs');
447
+ if (exists(docsDir)) {
448
+ for (const dir of await listSkillDirs(docsDir)) {
449
+ const key = `skill:${dir}`;
450
+ if (seen.has(key))
451
+ continue;
452
+ seen.add(key);
453
+ const asset = await discoverSkillDir(dir, 'continue', docsDir.replace(home, '~'));
454
+ if (asset)
455
+ found.push(asset);
456
+ }
457
+ }
458
+ // MCPs from config.json and config.yaml
459
+ const configPaths = [
460
+ path.join(home, '.continue', 'config.json'),
461
+ path.join(home, '.continue', 'config.yaml'),
462
+ ];
463
+ for (const configPath of configPaths) {
464
+ const mcps = await discoverContinueMcpFromConfig(configPath, 'continue');
465
+ for (const m of mcps) {
466
+ const key = `mcp:${m.originLabel}`;
467
+ if (seen.has(key))
468
+ continue;
469
+ seen.add(key);
470
+ found.push(m);
471
+ }
472
+ }
473
+ return found;
474
+ },
475
+ };
476
+ export const amanEnvironmentAdapter = {
477
+ id: 'aman-environment',
478
+ label: 'Aman Environment',
479
+ description: 'Import assets from another Aman environment',
480
+ isAvailable() {
481
+ // Always available when a rootPath is provided; acts as target-only
482
+ return true;
483
+ },
484
+ unavailableReason() {
485
+ return '';
486
+ },
487
+ async scan(options) {
488
+ const rootPath = options?.rootPath;
489
+ if (!rootPath) {
490
+ throw new Error('Aman environment import requires a path (the environment directory)');
491
+ }
492
+ const resolved = path.resolve(expandHome(rootPath));
493
+ if (!exists(resolved)) {
494
+ throw new Error(`Path not found: ${resolved}`);
495
+ }
496
+ // Validate it looks like an Aman environment
497
+ const hasManifest = exists(path.join(resolved, 'aman.json'));
498
+ const hasSkills = exists(path.join(resolved, 'skills'));
499
+ const hasPrompts = exists(path.join(resolved, 'prompts'));
500
+ const hasMcps = exists(path.join(resolved, 'mcps'));
501
+ if (!hasManifest && !hasSkills && !hasPrompts && !hasMcps) {
502
+ throw new Error(`Not a valid Aman environment: ${resolved}`);
503
+ }
504
+ return discoverAmanEnvironmentAssets(resolved, 'aman-environment');
505
+ },
506
+ };
507
+ export const antigravityAdapter = {
508
+ id: 'antigravity',
509
+ label: 'Antigravity',
510
+ description: 'Skills and MCP configs from Antigravity IDE',
511
+ isAvailable() {
512
+ const home = os.homedir();
513
+ return (exists(path.join(home, '.gemini')) ||
514
+ exists(path.join(home, '.gemini', 'config')));
515
+ },
516
+ unavailableReason() {
517
+ return 'No Antigravity configurations found (~/.gemini/)';
518
+ },
519
+ async scan() {
520
+ const home = os.homedir();
521
+ const found = [];
522
+ const seen = new Set();
523
+ // 1. Scan Antigravity plugins for skills
524
+ const pluginsRoot = path.join(home, '.gemini', 'config', 'plugins');
525
+ if (exists(pluginsRoot)) {
526
+ try {
527
+ const dirents = await fs.readdir(pluginsRoot, { withFileTypes: true });
528
+ const pluginDirs = dirents.filter((d) => d.isDirectory()).map((d) => d.name);
529
+ for (const pluginName of pluginDirs) {
530
+ const skillsDir = path.join(pluginsRoot, pluginName, 'skills');
531
+ const skillMd = path.join(skillsDir, 'SKILL.md');
532
+ if (exists(skillMd)) {
533
+ const key = `skill:${skillsDir}`;
534
+ if (seen.has(key))
535
+ continue;
536
+ seen.add(key);
537
+ const asset = await discoverSkillDir(skillsDir, 'antigravity', `~/.gemini/config/plugins/${pluginName}/skills`);
538
+ if (asset) {
539
+ // Custom clean name, e.g. "android-cli-plugin" -> "android-cli"
540
+ asset.name = slugifyImportName(pluginName.replace(/-plugin$/, ''));
541
+ found.push(asset);
542
+ }
543
+ }
544
+ }
545
+ }
546
+ catch {
547
+ // Ignore read errors
548
+ }
549
+ }
550
+ // 2. Scan Antigravity MCP configs
551
+ const mcpConfigPath = path.join(home, '.gemini', 'config', 'mcp_config.json');
552
+ if (exists(mcpConfigPath)) {
553
+ const mcps = await discoverMcpFromJsonFile(mcpConfigPath, 'antigravity', '~/.gemini/config/mcp_config.json');
554
+ for (const m of mcps) {
555
+ const key = `mcp:${m.originLabel}`;
556
+ if (seen.has(key))
557
+ continue;
558
+ seen.add(key);
559
+ found.push(m);
560
+ }
561
+ }
562
+ return found;
563
+ },
564
+ };
565
+ export const IMPORT_ADAPTERS = [
566
+ claudeCodeAdapter,
567
+ cursorAdapter,
568
+ windsurfAdapter,
569
+ continueAdapter,
570
+ vscodeAdapter,
571
+ githubCopilotAdapter,
572
+ codexAdapter,
573
+ localFolderAdapter,
574
+ customPathAdapter,
575
+ amanEnvironmentAdapter,
576
+ antigravityAdapter,
577
+ ];
578
+ export function getAdapter(id) {
579
+ return IMPORT_ADAPTERS.find((a) => a.id === id);
580
+ }
@@ -0,0 +1,8 @@
1
+ import { ImportAdapterDescriptor, ImportSourceId, DiscoveredImportAsset } from './types.js';
2
+ export declare class ImportDiscoveryService {
3
+ listAdapters(): ImportAdapterDescriptor[];
4
+ scan(sourceId: ImportSourceId, options?: {
5
+ rootPath?: string;
6
+ }): Promise<DiscoveredImportAsset[]>;
7
+ }
8
+ export declare const importDiscoveryService: ImportDiscoveryService;
@@ -0,0 +1,26 @@
1
+ import { IMPORT_ADAPTERS, getAdapter } from './adapters.js';
2
+ export class ImportDiscoveryService {
3
+ listAdapters() {
4
+ return IMPORT_ADAPTERS.map((adapter) => {
5
+ const available = adapter.isAvailable();
6
+ return {
7
+ id: adapter.id,
8
+ label: adapter.label,
9
+ description: adapter.description,
10
+ available,
11
+ unavailableReason: available ? undefined : adapter.unavailableReason(),
12
+ };
13
+ });
14
+ }
15
+ async scan(sourceId, options) {
16
+ const adapter = getAdapter(sourceId);
17
+ if (!adapter) {
18
+ throw new Error(`Unknown import source: ${sourceId}`);
19
+ }
20
+ if (!adapter.isAvailable() && sourceId !== 'local-folder' && sourceId !== 'custom-path' && sourceId !== 'aman-environment') {
21
+ throw new Error(adapter.unavailableReason());
22
+ }
23
+ return adapter.scan(options);
24
+ }
25
+ }
26
+ export const importDiscoveryService = new ImportDiscoveryService();
@@ -0,0 +1,7 @@
1
+ import { AssetType, Scope } from '../types/index.js';
2
+ import { DiscoveredImportAsset, ImportConflict, ImportPlan, ImportResult } from './types.js';
3
+ export declare function isGithubDestinationAvailable(): boolean;
4
+ export declare function detectImportConflicts(items: DiscoveredImportAsset[], scope: Scope): Promise<ImportConflict[]>;
5
+ export declare function executeImportPlan(plan: ImportPlan): Promise<ImportResult>;
6
+ export declare function applyAutoRenameConflicts(conflicts: ImportConflict[], mode?: 'suffix' | 'skip'): ImportConflict[];
7
+ export declare function summarizeByType(items: DiscoveredImportAsset[]): Record<AssetType, number>;