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.
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/dist/bin/aman.d.ts +2 -0
- package/dist/bin/aman.js +165 -0
- package/dist/cli/global-install.d.ts +7 -0
- package/dist/cli/global-install.js +36 -0
- package/dist/cli/help-text.d.ts +1 -0
- package/dist/cli/help-text.js +62 -0
- package/dist/cli/version.d.ts +1 -0
- package/dist/cli/version.js +6 -0
- package/dist/commands/backup.d.ts +11 -0
- package/dist/commands/backup.js +262 -0
- package/dist/commands/browse.d.ts +11 -0
- package/dist/commands/browse.js +641 -0
- package/dist/commands/cache.d.ts +1 -0
- package/dist/commands/cache.js +38 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.js +146 -0
- package/dist/commands/dashboard.d.ts +1 -0
- package/dist/commands/dashboard.js +1004 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +54 -0
- package/dist/commands/export.d.ts +1 -0
- package/dist/commands/export.js +137 -0
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +47 -0
- package/dist/commands/import-wizard.d.ts +7 -0
- package/dist/commands/import-wizard.js +374 -0
- package/dist/commands/import.d.ts +9 -0
- package/dist/commands/import.js +351 -0
- package/dist/commands/info.d.ts +1 -0
- package/dist/commands/info.js +174 -0
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/init.js +146 -0
- package/dist/commands/install.d.ts +10 -0
- package/dist/commands/install.js +342 -0
- package/dist/commands/pack.d.ts +23 -0
- package/dist/commands/pack.js +331 -0
- package/dist/commands/registry.d.ts +6 -0
- package/dist/commands/registry.js +218 -0
- package/dist/commands/remove.d.ts +1 -0
- package/dist/commands/remove.js +76 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.js +295 -0
- package/dist/commands/stack.d.ts +18 -0
- package/dist/commands/stack.js +327 -0
- package/dist/commands/sync.d.ts +9 -0
- package/dist/commands/sync.js +428 -0
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.js +97 -0
- package/dist/config/features.d.ts +2 -0
- package/dist/config/features.js +2 -0
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.js +80 -0
- package/dist/config/paths.d.ts +23 -0
- package/dist/config/paths.js +45 -0
- package/dist/import/adapters.d.ts +14 -0
- package/dist/import/adapters.js +580 -0
- package/dist/import/discovery.service.d.ts +8 -0
- package/dist/import/discovery.service.js +26 -0
- package/dist/import/import.service.d.ts +7 -0
- package/dist/import/import.service.js +259 -0
- package/dist/import/types.d.ts +71 -0
- package/dist/import/types.js +1 -0
- package/dist/import/utils.d.ts +36 -0
- package/dist/import/utils.js +428 -0
- package/dist/marketplace/cache.d.ts +18 -0
- package/dist/marketplace/cache.js +141 -0
- package/dist/marketplace/github-search.d.ts +17 -0
- package/dist/marketplace/github-search.js +268 -0
- package/dist/marketplace/install-from-candidate.d.ts +6 -0
- package/dist/marketplace/install-from-candidate.js +14 -0
- package/dist/marketplace/install.d.ts +15 -0
- package/dist/marketplace/install.js +54 -0
- package/dist/marketplace/metadata-validator.d.ts +8 -0
- package/dist/marketplace/metadata-validator.js +79 -0
- package/dist/marketplace/types.d.ts +34 -0
- package/dist/marketplace/types.js +1 -0
- package/dist/providers/local.provider.d.ts +9 -0
- package/dist/providers/local.provider.js +51 -0
- package/dist/providers/provider.interface.d.ts +7 -0
- package/dist/providers/provider.interface.js +1 -0
- package/dist/providers/registry.provider.d.ts +2 -0
- package/dist/providers/registry.provider.js +42 -0
- package/dist/providers/skills-sh.provider.d.ts +11 -0
- package/dist/providers/skills-sh.provider.js +56 -0
- package/dist/registry/adapter.interface.d.ts +16 -0
- package/dist/registry/adapter.interface.js +1 -0
- package/dist/registry/errors.d.ts +5 -0
- package/dist/registry/errors.js +8 -0
- package/dist/registry/filesystem-registry.adapter.d.ts +25 -0
- package/dist/registry/filesystem-registry.adapter.js +288 -0
- package/dist/registry/github-registry.adapter.d.ts +11 -0
- package/dist/registry/github-registry.adapter.js +32 -0
- package/dist/registry/index.d.ts +8 -0
- package/dist/registry/index.js +8 -0
- package/dist/registry/local-registry.adapter.d.ts +6 -0
- package/dist/registry/local-registry.adapter.js +9 -0
- package/dist/registry/registry.service.d.ts +44 -0
- package/dist/registry/registry.service.js +163 -0
- package/dist/registry/slug-utils.d.ts +12 -0
- package/dist/registry/slug-utils.js +51 -0
- package/dist/registry/types.d.ts +160 -0
- package/dist/registry/types.js +1 -0
- package/dist/services/asset.service.d.ts +12 -0
- package/dist/services/asset.service.js +142 -0
- package/dist/services/backup.service.d.ts +8 -0
- package/dist/services/backup.service.js +169 -0
- package/dist/services/classification.service.d.ts +31 -0
- package/dist/services/classification.service.js +271 -0
- package/dist/services/config.service.d.ts +9 -0
- package/dist/services/config.service.js +20 -0
- package/dist/services/doctor.service.d.ts +5 -0
- package/dist/services/doctor.service.js +186 -0
- package/dist/services/environment.service.d.ts +42 -0
- package/dist/services/environment.service.js +227 -0
- package/dist/services/github.service.d.ts +7 -0
- package/dist/services/github.service.js +42 -0
- package/dist/services/lock.service.d.ts +12 -0
- package/dist/services/lock.service.js +71 -0
- package/dist/services/marketplace.service.d.ts +40 -0
- package/dist/services/marketplace.service.js +225 -0
- package/dist/services/pack.service.d.ts +9 -0
- package/dist/services/pack.service.js +193 -0
- package/dist/services/stack.service.d.ts +9 -0
- package/dist/services/stack.service.js +94 -0
- package/dist/storage/asset-layout.d.ts +46 -0
- package/dist/storage/asset-layout.js +277 -0
- package/dist/storage/filesystem.d.ts +12 -0
- package/dist/storage/filesystem.js +113 -0
- package/dist/storage/scan-by-type.d.ts +2 -0
- package/dist/storage/scan-by-type.js +8 -0
- package/dist/storage/scanner.d.ts +11 -0
- package/dist/storage/scanner.js +188 -0
- package/dist/types/asset-metadata.d.ts +84 -0
- package/dist/types/asset-metadata.js +104 -0
- package/dist/types/index.d.ts +212 -0
- package/dist/types/index.js +1 -0
- package/dist/ui/animations/ErrorIndicator.d.ts +5 -0
- package/dist/ui/animations/ErrorIndicator.js +6 -0
- package/dist/ui/animations/GithubIndicator.d.ts +6 -0
- package/dist/ui/animations/GithubIndicator.js +9 -0
- package/dist/ui/animations/ProgressBar.d.ts +5 -0
- package/dist/ui/animations/ProgressBar.js +15 -0
- package/dist/ui/animations/Spinner.d.ts +5 -0
- package/dist/ui/animations/Spinner.js +21 -0
- package/dist/ui/animations/SuccessIndicator.d.ts +5 -0
- package/dist/ui/animations/SuccessIndicator.js +6 -0
- package/dist/ui/animations/SyncActivity.d.ts +5 -0
- package/dist/ui/animations/SyncActivity.js +21 -0
- package/dist/ui/animations/TransitionScreen.d.ts +7 -0
- package/dist/ui/animations/TransitionScreen.js +25 -0
- package/dist/ui/animations/useAnimationMode.d.ts +1 -0
- package/dist/ui/animations/useAnimationMode.js +16 -0
- package/dist/ui/assetDisplay.d.ts +19 -0
- package/dist/ui/assetDisplay.js +59 -0
- package/dist/ui/components/Confirm.d.ts +8 -0
- package/dist/ui/components/Confirm.js +14 -0
- package/dist/ui/components/CustomSelect.d.ts +19 -0
- package/dist/ui/components/CustomSelect.js +13 -0
- package/dist/ui/components/Header.d.ts +6 -0
- package/dist/ui/components/Header.js +9 -0
- package/dist/ui/components/HealthReport.d.ts +7 -0
- package/dist/ui/components/HealthReport.js +13 -0
- package/dist/ui/components/MarketplaceInstallConfirm.d.ts +19 -0
- package/dist/ui/components/MarketplaceInstallConfirm.js +23 -0
- package/dist/ui/components/Narrator.d.ts +9 -0
- package/dist/ui/components/Narrator.js +26 -0
- package/dist/ui/components/ScopePrompt.d.ts +8 -0
- package/dist/ui/components/ScopePrompt.js +23 -0
- package/dist/ui/components/TooSmallScreen.d.ts +8 -0
- package/dist/ui/components/TooSmallScreen.js +6 -0
- package/dist/ui/date.d.ts +2 -0
- package/dist/ui/date.js +33 -0
- package/dist/ui/layout.d.ts +23 -0
- package/dist/ui/layout.js +44 -0
- package/dist/ui/list-item.d.ts +12 -0
- package/dist/ui/list-item.js +1 -0
- package/dist/ui/marketplaceDisplay.d.ts +10 -0
- package/dist/ui/marketplaceDisplay.js +36 -0
- package/dist/ui/theme.d.ts +42 -0
- package/dist/ui/theme.js +47 -0
- package/dist/utils/asset-list-fields.d.ts +11 -0
- package/dist/utils/asset-list-fields.js +28 -0
- package/dist/utils/error-message.d.ts +2 -0
- package/dist/utils/error-message.js +6 -0
- package/dist/utils/integrity.d.ts +9 -0
- package/dist/utils/integrity.js +23 -0
- package/dist/utils/lock-migrate.d.ts +25 -0
- package/dist/utils/lock-migrate.js +93 -0
- package/dist/utils/mcp-local.d.ts +15 -0
- package/dist/utils/mcp-local.js +129 -0
- package/dist/utils/slug.d.ts +6 -0
- package/dist/utils/slug.js +13 -0
- package/dist/utils/stack-normalize.d.ts +3 -0
- package/dist/utils/stack-normalize.js +43 -0
- package/package.json +77 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Scope } from '../types/index.js';
|
|
3
|
+
export interface ImportAppProps {
|
|
4
|
+
source: string;
|
|
5
|
+
initialScope?: Scope;
|
|
6
|
+
onBack?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const ImportApp: React.FC<ImportAppProps>;
|
|
9
|
+
export declare function importCommand(args: string[], options: any): Promise<void>;
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
4
|
+
import { CustomSelectInput } from '../ui/components/CustomSelect.js';
|
|
5
|
+
import { githubService } from '../services/github.service.js';
|
|
6
|
+
import { classificationService } from '../services/classification.service.js';
|
|
7
|
+
import { assetService } from '../services/asset.service.js';
|
|
8
|
+
import { ScopePrompt } from '../ui/components/ScopePrompt.js';
|
|
9
|
+
import { Narrator } from '../ui/components/Narrator.js';
|
|
10
|
+
import { Header } from '../ui/components/Header.js';
|
|
11
|
+
import { theme } from '../ui/theme.js';
|
|
12
|
+
import { averageConfidence, assetTypeBadge } from '../ui/assetDisplay.js';
|
|
13
|
+
import { removeDir, isPathSafe } from '../storage/filesystem.js';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { ProgressBar } from '../ui/animations/ProgressBar.js';
|
|
16
|
+
import { TransitionScreen } from '../ui/animations/TransitionScreen.js';
|
|
17
|
+
import { ImportWizardApp } from './import-wizard.js';
|
|
18
|
+
import { importDiscoveryService } from '../import/discovery.service.js';
|
|
19
|
+
import { applyAutoRenameConflicts, detectImportConflicts, executeImportPlan, isGithubDestinationAvailable, } from '../import/import.service.js';
|
|
20
|
+
import { environmentService } from '../services/environment.service.js';
|
|
21
|
+
export const ImportApp = ({ source, initialScope, onBack }) => {
|
|
22
|
+
const { exit } = useApp();
|
|
23
|
+
const handleExit = () => {
|
|
24
|
+
if (onBack)
|
|
25
|
+
onBack();
|
|
26
|
+
else
|
|
27
|
+
exit();
|
|
28
|
+
};
|
|
29
|
+
const [mode, setMode] = useState('cloning');
|
|
30
|
+
const [state, setState] = useState('searching');
|
|
31
|
+
const [message, setMessage] = useState(`Cloning ${source}...`);
|
|
32
|
+
const [tempDir, setTempDir] = useState('');
|
|
33
|
+
const [classifications, setClassifications] = useState([]);
|
|
34
|
+
const [scope, setScope] = useState(initialScope);
|
|
35
|
+
const [progress, setProgress] = useState(0);
|
|
36
|
+
useInput((input, key) => {
|
|
37
|
+
if (input === 'q' || key.escape) {
|
|
38
|
+
if (tempDir)
|
|
39
|
+
removeDir(tempDir).catch(() => { });
|
|
40
|
+
handleExit();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// Step 1: Clone
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
async function clone() {
|
|
46
|
+
try {
|
|
47
|
+
const dir = await githubService.import(source);
|
|
48
|
+
setTempDir(dir);
|
|
49
|
+
setMode('scanning');
|
|
50
|
+
setMessage(`Scanning ${source}...`);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
setState('error');
|
|
54
|
+
setMessage(`Error: ${err.message}`);
|
|
55
|
+
setMode('done');
|
|
56
|
+
setTimeout(() => handleExit(), 1800);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
clone();
|
|
60
|
+
}, [source]);
|
|
61
|
+
// Step 2: Classify
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (mode !== 'scanning' || !tempDir)
|
|
64
|
+
return;
|
|
65
|
+
async function classify() {
|
|
66
|
+
const results = await classificationService.classifyDirectory(tempDir);
|
|
67
|
+
setClassifications(results);
|
|
68
|
+
setMode('preview');
|
|
69
|
+
}
|
|
70
|
+
classify();
|
|
71
|
+
}, [mode, tempDir]);
|
|
72
|
+
// Step 3: Install after scope selection
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (mode !== 'installing' || !scope || !tempDir)
|
|
75
|
+
return;
|
|
76
|
+
const targetScope = scope;
|
|
77
|
+
async function install() {
|
|
78
|
+
setState('installing');
|
|
79
|
+
const highConf = classificationService.highConfidence(classifications);
|
|
80
|
+
let installed = 0;
|
|
81
|
+
let processed = 0;
|
|
82
|
+
for (const c of highConf) {
|
|
83
|
+
let filePath = path.resolve(tempDir, c.file);
|
|
84
|
+
// Priority 2: Security check
|
|
85
|
+
const safe = await isPathSafe(filePath, tempDir);
|
|
86
|
+
if (!safe) {
|
|
87
|
+
setState('error');
|
|
88
|
+
setMessage(`Security Error: Path traversal escape attempt detected inside file: ${c.file}`);
|
|
89
|
+
setMode('done');
|
|
90
|
+
setTimeout(() => handleExit(), 3000);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
let baseName = c.file.replace(/\.[^.]+$/, '').replace(/[/\\]/g, '-');
|
|
94
|
+
if (c.type === 'skill') {
|
|
95
|
+
filePath = path.dirname(filePath);
|
|
96
|
+
if (filePath === tempDir) {
|
|
97
|
+
baseName = path.basename(source).replace(/\.git$/, '');
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
baseName = path.basename(filePath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
if (c.type === 'skill' || c.type === 'prompt' || c.type === 'mcp') {
|
|
105
|
+
// Priority 4: Collision safety check
|
|
106
|
+
const existingAssets = await assetService.list(c.type, targetScope);
|
|
107
|
+
let name = baseName;
|
|
108
|
+
let suffix = 1;
|
|
109
|
+
while (existingAssets.some((item) => item.name === name)) {
|
|
110
|
+
name = `${baseName}-${suffix}`;
|
|
111
|
+
suffix++;
|
|
112
|
+
}
|
|
113
|
+
const metadataOverride = {};
|
|
114
|
+
if (name !== baseName) {
|
|
115
|
+
metadataOverride.originalName = baseName;
|
|
116
|
+
metadataOverride.resolvedName = name;
|
|
117
|
+
}
|
|
118
|
+
await assetService.install(name, c.type, targetScope, filePath, source, metadataOverride);
|
|
119
|
+
installed++;
|
|
120
|
+
}
|
|
121
|
+
// Remember classification for future syncs
|
|
122
|
+
await classificationService.remember(c.file, c.type);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Skip failures silently
|
|
126
|
+
}
|
|
127
|
+
processed++;
|
|
128
|
+
setProgress(Math.round((processed / highConf.length) * 100));
|
|
129
|
+
}
|
|
130
|
+
setState('success');
|
|
131
|
+
setMessage(`Imported ${installed} assets → ${scope === 'project' ? 'project' : 'global'}`);
|
|
132
|
+
setMode('done');
|
|
133
|
+
// Cleanup
|
|
134
|
+
await removeDir(tempDir).catch(() => { });
|
|
135
|
+
setTimeout(() => handleExit(), 1200);
|
|
136
|
+
}
|
|
137
|
+
install();
|
|
138
|
+
}, [mode, scope, tempDir, classifications]);
|
|
139
|
+
// Cloning / scanning
|
|
140
|
+
if (mode === 'cloning' || mode === 'scanning') {
|
|
141
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { compact: true }), _jsx(Narrator, { state: state, message: message })] }));
|
|
142
|
+
}
|
|
143
|
+
// Installing / done
|
|
144
|
+
if (mode === 'installing' || mode === 'done') {
|
|
145
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Narrator, { state: state, message: message }), mode === 'installing' && (_jsx(Box, { marginTop: 1, children: _jsx(ProgressBar, { progress: progress }) }))] }));
|
|
146
|
+
}
|
|
147
|
+
// Scope selection
|
|
148
|
+
if (mode === 'scope') {
|
|
149
|
+
const summary = classificationService.summarize(classificationService.highConfidence(classifications));
|
|
150
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { compact: true }), _jsxs(Text, { children: ["Import ", summary.skills + summary.prompts + summary.mcps, " assets"] }), _jsx(Box, { marginTop: 1, children: _jsx(ScopePrompt, { onSelect: (s) => { setScope(s); setMode('installing'); } }) })] }));
|
|
151
|
+
}
|
|
152
|
+
// Preview
|
|
153
|
+
if (mode === 'preview') {
|
|
154
|
+
const summary = classificationService.summarize(classifications);
|
|
155
|
+
const lowConf = classificationService.lowConfidence(classifications);
|
|
156
|
+
const reviewItems = [
|
|
157
|
+
{ label: 'Continue', value: 'continue' },
|
|
158
|
+
...(lowConf.length > 0 ? [{ label: `Review ${lowConf.length} unknown files`, value: 'review' }] : []),
|
|
159
|
+
];
|
|
160
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { compact: true }), _jsxs(Text, { bold: true, children: ["Detected Assets in ", source, ":"] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [" Skills: ", _jsx(Text, { color: theme.primary, bold: true, children: summary.skills })] }), _jsxs(Text, { children: [" Prompts: ", _jsx(Text, { color: theme.success, bold: true, children: summary.prompts })] }), _jsxs(Text, { children: [" MCPs: ", _jsx(Text, { color: theme.warning, bold: true, children: summary.mcps })] }), summary.stacks > 0 && _jsxs(Text, { children: [" Stacks: ", _jsx(Text, { color: theme.accent, bold: true, children: summary.stacks })] }), summary.unknown > 0 && _jsxs(Text, { children: [" Unknown: ", _jsx(Text, { color: theme.dim, children: summary.unknown })] }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [' ', "Confidence (auto-import \u226550%):", ' ', _jsxs(Text, { bold: true, color: theme.primary, children: [averageConfidence(classificationService.highConfidence(classifications)), "%"] })] }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: theme.dim, children: "Ready to import:" }), classificationService.highConfidence(classifications).slice(0, 10).map((c, i) => (_jsxs(Text, { color: theme.dim, children: [' ', c.type === 'skill' || c.type === 'prompt' || c.type === 'mcp'
|
|
161
|
+
? assetTypeBadge(c.type)
|
|
162
|
+
: `[${c.type}]`, ' ', c.file, " \u2014 ", c.confidence, "% (", c.reason, ")"] }, i))), classificationService.highConfidence(classifications).length > 10 && (_jsxs(Text, { color: theme.dim, children: [' ', "\u2026and ", classificationService.highConfidence(classifications).length - 10, " more"] }))] })] }), _jsx(Box, { marginTop: 1, children: _jsx(CustomSelectInput, { items: reviewItems, onSelect: (item) => {
|
|
163
|
+
if (item.value === 'continue') {
|
|
164
|
+
if (initialScope) {
|
|
165
|
+
setScope(initialScope);
|
|
166
|
+
setMode('installing');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
setMode('scope');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (item.value === 'review')
|
|
173
|
+
setMode('review');
|
|
174
|
+
} }) })] }));
|
|
175
|
+
}
|
|
176
|
+
// Review unknown files
|
|
177
|
+
if (mode === 'review') {
|
|
178
|
+
const lowConf = classificationService.lowConfidence(classifications);
|
|
179
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { compact: true }), _jsx(Text, { bold: true, children: "Review unknown files" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: lowConf.map((c, i) => (_jsxs(Text, { color: theme.dim, children: [c.file, " \u2192 ", c.type, " (", c.confidence, "%) \u2014 ", c.reason] }, i))) }), _jsx(Box, { marginTop: 1, children: _jsx(CustomSelectInput, { items: [{ label: 'Continue without unknowns', value: 'continue' }], onSelect: () => {
|
|
180
|
+
if (initialScope) {
|
|
181
|
+
setScope(initialScope);
|
|
182
|
+
setMode('installing');
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
setMode('scope');
|
|
186
|
+
}
|
|
187
|
+
} }) })] }));
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
};
|
|
191
|
+
export async function importCommand(args, options) {
|
|
192
|
+
const source = args[0];
|
|
193
|
+
let fromSource = options.from;
|
|
194
|
+
const useGithubDest = Boolean(options.githubDest || options.github);
|
|
195
|
+
const importAll = Boolean(options.all);
|
|
196
|
+
const skipConfirm = Boolean(options.yes || options.y);
|
|
197
|
+
const initialScope = options.project || options.p
|
|
198
|
+
? 'project'
|
|
199
|
+
: options.global || options.g
|
|
200
|
+
? 'global'
|
|
201
|
+
: undefined;
|
|
202
|
+
// Shorthand: `aman import cursor --global` → `aman import --from cursor --global`
|
|
203
|
+
const KNOWN_SOURCE_IDS = new Set([
|
|
204
|
+
'claude-code', 'cursor', 'windsurf', 'continue',
|
|
205
|
+
'vscode', 'github-copilot', 'codex',
|
|
206
|
+
'local-folder', 'custom-path', 'aman-environment',
|
|
207
|
+
'antigravity',
|
|
208
|
+
]);
|
|
209
|
+
if (source && KNOWN_SOURCE_IDS.has(source) && !fromSource) {
|
|
210
|
+
fromSource = source;
|
|
211
|
+
}
|
|
212
|
+
// Interactive wizard when no source path and no --from
|
|
213
|
+
if (!source && !fromSource) {
|
|
214
|
+
if (!process.stdin.isTTY) {
|
|
215
|
+
console.error('\n Error: Interactive import wizard requires a TTY.');
|
|
216
|
+
console.error(' Use: aman import <path> --global|--project');
|
|
217
|
+
console.error(' Or: aman import claude-code --all --global\n');
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const { waitUntilExit } = render(_jsx(ImportWizardApp, {}));
|
|
221
|
+
await waitUntilExit();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// Adapter-based headless / flagged import
|
|
225
|
+
if (fromSource) {
|
|
226
|
+
if (!initialScope) {
|
|
227
|
+
console.error('Import requires --global or --project when using --from.');
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
if (useGithubDest && !isGithubDestinationAvailable()) {
|
|
231
|
+
console.error('\n GitHub is not configured.');
|
|
232
|
+
console.error(' Run `aman init --github` or connect GitHub first.\n');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
if (!environmentService.isEnvironmentInitialized(initialScope)) {
|
|
236
|
+
console.error('\n Aman Intelligence is not initialized yet.');
|
|
237
|
+
console.error(' Run: aman init --local\n');
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
// When using shorthand (aman import cursor ./path), the path is args[1]
|
|
242
|
+
// When using --from (aman import ./path --from cursor), the path is args[0]
|
|
243
|
+
const rootPath = (source && KNOWN_SOURCE_IDS.has(source)) ? args[1] : source;
|
|
244
|
+
console.log(`\n ◌ Scanning ${fromSource}...`);
|
|
245
|
+
const discovered = await importDiscoveryService.scan(fromSource, rootPath ? { rootPath } : undefined);
|
|
246
|
+
if (discovered.length === 0) {
|
|
247
|
+
console.log(' No recognizable assets found. Nothing imported.');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const items = importAll
|
|
251
|
+
? discovered
|
|
252
|
+
: discovered.filter((d) => d.confidence >= 50 && d.canonicalStatus !== 'ambiguous');
|
|
253
|
+
if (items.length === 0) {
|
|
254
|
+
console.log(' No high-confidence assets to import. Use --all to include ambiguous items.');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
let conflicts = await detectImportConflicts(items, initialScope);
|
|
258
|
+
conflicts = applyAutoRenameConflicts(conflicts, skipConfirm ? 'suffix' : 'suffix');
|
|
259
|
+
const plan = {
|
|
260
|
+
sourceId: fromSource,
|
|
261
|
+
sourceLabel: fromSource,
|
|
262
|
+
destination: useGithubDest ? 'github' : 'local',
|
|
263
|
+
scope: initialScope,
|
|
264
|
+
items,
|
|
265
|
+
conflicts,
|
|
266
|
+
};
|
|
267
|
+
console.log(` Found ${items.length} assets to import → ${initialScope}`);
|
|
268
|
+
const result = await executeImportPlan(plan);
|
|
269
|
+
console.log(` ✓ Imported ${result.imported} (skipped ${result.skipped}, renamed ${result.renamed})\n`);
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
console.error(` ✗ Import failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (!source) {
|
|
278
|
+
console.log(' Usage: aman import [source] [options]');
|
|
279
|
+
console.log(' Examples:');
|
|
280
|
+
console.log(' aman import # interactive wizard (TTY)');
|
|
281
|
+
console.log(' aman import cursor --global # shorthand: import from Cursor');
|
|
282
|
+
console.log(' aman import claude-code --all -g # import all from Claude Code');
|
|
283
|
+
console.log(' aman import ./local-folder --global');
|
|
284
|
+
console.log(' aman import user/repo --global');
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (!process.stdin.isTTY) {
|
|
288
|
+
if (!initialScope) {
|
|
289
|
+
console.error('\n \x1b[31;1mError: Interactive mode unavailable in non-TTY terminals.\x1b[0m');
|
|
290
|
+
console.error(' Please specify target scope using \x1b[33m--project\x1b[0m or \x1b[33m--global\x1b[0m.\n');
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
console.log(`\n ◌ Cloning ${source}...`);
|
|
294
|
+
try {
|
|
295
|
+
const tempDir = await githubService.import(source);
|
|
296
|
+
console.log(` ◌ Scanning ${source}...`);
|
|
297
|
+
const classifications = await classificationService.classifyDirectory(tempDir);
|
|
298
|
+
const highConf = classificationService.highConfidence(classifications);
|
|
299
|
+
if (highConf.length === 0) {
|
|
300
|
+
await removeDir(tempDir).catch(() => { });
|
|
301
|
+
console.log(' No recognizable assets found in source. Nothing imported.');
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
console.log(` Found ${highConf.length} high-confidence assets to import.`);
|
|
305
|
+
let installed = 0;
|
|
306
|
+
for (const c of highConf) {
|
|
307
|
+
let filePath = path.resolve(tempDir, c.file);
|
|
308
|
+
const safe = await isPathSafe(filePath, tempDir);
|
|
309
|
+
if (!safe) {
|
|
310
|
+
throw new Error(`Security Exception: Path traversal escape attempt detected inside file: ${c.file}`);
|
|
311
|
+
}
|
|
312
|
+
let baseName = c.file.replace(/\.[^.]+$/, '').replace(/[/\\]/g, '-');
|
|
313
|
+
if (c.type === 'skill') {
|
|
314
|
+
filePath = path.dirname(filePath);
|
|
315
|
+
if (filePath === tempDir) {
|
|
316
|
+
baseName = path.basename(source).replace(/\.git$/, '');
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
baseName = path.basename(filePath);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (c.type === 'skill' || c.type === 'prompt' || c.type === 'mcp') {
|
|
323
|
+
const existingAssets = await assetService.list(c.type, initialScope);
|
|
324
|
+
let name = baseName;
|
|
325
|
+
let suffix = 1;
|
|
326
|
+
while (existingAssets.some((item) => item.name === name)) {
|
|
327
|
+
name = `${baseName}-${suffix}`;
|
|
328
|
+
suffix++;
|
|
329
|
+
}
|
|
330
|
+
const metadataOverride = {};
|
|
331
|
+
if (name !== baseName) {
|
|
332
|
+
metadataOverride.originalName = baseName;
|
|
333
|
+
metadataOverride.resolvedName = name;
|
|
334
|
+
}
|
|
335
|
+
await assetService.install(name, c.type, initialScope, filePath, source, metadataOverride);
|
|
336
|
+
installed++;
|
|
337
|
+
}
|
|
338
|
+
await classificationService.remember(c.file, c.type);
|
|
339
|
+
}
|
|
340
|
+
await removeDir(tempDir).catch(() => { });
|
|
341
|
+
console.log(` \x1b[32m✓ Imported ${installed} assets to ${initialScope} scope successfully.\x1b[0m\n`);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
console.error(` \x1b[31m✗ Import failed: ${err.message}\x1b[0m\n`);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const { waitUntilExit } = render(_jsx(TransitionScreen, { message: `Preparing to import ${source}...`, children: _jsx(ImportApp, { source: source, initialScope: initialScope }) }));
|
|
350
|
+
await waitUntilExit();
|
|
351
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function infoCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
4
|
+
import { CustomSelectInput } from '../ui/components/CustomSelect.js';
|
|
5
|
+
import { marketplaceService } from '../services/marketplace.service.js';
|
|
6
|
+
import { assetService } from '../services/asset.service.js';
|
|
7
|
+
import { ScopePrompt } from '../ui/components/ScopePrompt.js';
|
|
8
|
+
import { Narrator } from '../ui/components/Narrator.js';
|
|
9
|
+
import { Header } from '../ui/components/Header.js';
|
|
10
|
+
import { theme } from '../ui/theme.js';
|
|
11
|
+
import { metadataParts, titleize } from '../ui/marketplaceDisplay.js';
|
|
12
|
+
import { assetTypeBadge, ASSET_TYPES } from '../ui/assetDisplay.js';
|
|
13
|
+
import { assetListDescription, assetListOrganization, assetListTags, assetListVersion, } from '../utils/asset-list-fields.js';
|
|
14
|
+
function normalizeLookupName(value) {
|
|
15
|
+
return value.toLowerCase().replace(/[\s_]+/g, '-');
|
|
16
|
+
}
|
|
17
|
+
async function findAssetByName(name) {
|
|
18
|
+
const normalized = normalizeLookupName(name);
|
|
19
|
+
for (const type of ASSET_TYPES) {
|
|
20
|
+
for (const scope of ['global', 'project']) {
|
|
21
|
+
const installed = await assetService.list(type, scope);
|
|
22
|
+
const match = installed.find((i) => normalizeLookupName(i.name) === normalized);
|
|
23
|
+
if (match) {
|
|
24
|
+
return {
|
|
25
|
+
type,
|
|
26
|
+
name: match.name,
|
|
27
|
+
source: match.source || scope,
|
|
28
|
+
description: assetListDescription(match),
|
|
29
|
+
tags: assetListTags(match),
|
|
30
|
+
version: assetListVersion(match),
|
|
31
|
+
organization: assetListOrganization(match),
|
|
32
|
+
installed: true,
|
|
33
|
+
confidence: 1,
|
|
34
|
+
slug: match.slug,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const marketplaceResults = await marketplaceService.search(name);
|
|
40
|
+
const exact = marketplaceResults.find((r) => normalizeLookupName(r.name) === normalized);
|
|
41
|
+
if (exact) {
|
|
42
|
+
for (const scope of ['global', 'project']) {
|
|
43
|
+
const installed = await assetService.list(exact.type, scope);
|
|
44
|
+
if (installed.some((i) => i.name === exact.name)) {
|
|
45
|
+
exact.installed = true;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return exact;
|
|
50
|
+
}
|
|
51
|
+
const candidate = await marketplaceService.findInstallCandidate(name);
|
|
52
|
+
if (candidate) {
|
|
53
|
+
return {
|
|
54
|
+
type: candidate.type,
|
|
55
|
+
name: candidate.name,
|
|
56
|
+
source: candidate.source,
|
|
57
|
+
sources: candidate.sources,
|
|
58
|
+
description: candidate.description,
|
|
59
|
+
tags: candidate.tags,
|
|
60
|
+
category: candidate.category,
|
|
61
|
+
installs: candidate.installs,
|
|
62
|
+
rating: candidate.rating,
|
|
63
|
+
updated: candidate.updated,
|
|
64
|
+
version: candidate.version,
|
|
65
|
+
organization: candidate.organization,
|
|
66
|
+
installed: candidate.installed,
|
|
67
|
+
confidence: 1,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const InfoApp = ({ name }) => {
|
|
73
|
+
const { exit } = useApp();
|
|
74
|
+
const [item, setItem] = useState(null);
|
|
75
|
+
const [mode, setMode] = useState('loading');
|
|
76
|
+
const [mochiState, setMochiState] = useState('searching');
|
|
77
|
+
const [message, setMessage] = useState(`Looking up ${name}...`);
|
|
78
|
+
useInput((input) => {
|
|
79
|
+
if (input === 'q')
|
|
80
|
+
exit();
|
|
81
|
+
});
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
async function lookup() {
|
|
84
|
+
const exact = await findAssetByName(name);
|
|
85
|
+
if (!exact) {
|
|
86
|
+
setMochiState('error');
|
|
87
|
+
setMessage(`Could not find asset "${name}" (skill, prompt, or MCP)`);
|
|
88
|
+
setMode('done');
|
|
89
|
+
setTimeout(() => exit(), 1500);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setItem(exact);
|
|
93
|
+
setMode('detail');
|
|
94
|
+
}
|
|
95
|
+
lookup();
|
|
96
|
+
}, [exit, name]);
|
|
97
|
+
async function doInstall(scope) {
|
|
98
|
+
if (!item)
|
|
99
|
+
return;
|
|
100
|
+
setMode('installing');
|
|
101
|
+
setMochiState('installing');
|
|
102
|
+
setMessage(`Installing ${assetTypeBadge(item.type)} ${titleize(item.name)}...`);
|
|
103
|
+
try {
|
|
104
|
+
const candidate = await marketplaceService.findInstallCandidate(item.name);
|
|
105
|
+
if (candidate && candidate.type === item.type) {
|
|
106
|
+
await assetService.install(candidate.name, candidate.type, scope, candidate.sourcePath, candidate.source);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
await assetService.install(item.name, item.type, scope, undefined, item.source || 'local');
|
|
110
|
+
}
|
|
111
|
+
setMochiState('success');
|
|
112
|
+
setMessage(`Installed ${assetTypeBadge(item.type)} ${titleize(item.name)} → ${scope === 'project' ? 'project' : 'global'}`);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
setMochiState('error');
|
|
116
|
+
setMessage(`Error: ${err.message}`);
|
|
117
|
+
}
|
|
118
|
+
setMode('done');
|
|
119
|
+
setTimeout(() => exit(), 1000);
|
|
120
|
+
}
|
|
121
|
+
if (mode === 'loading') {
|
|
122
|
+
return (_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsx(Narrator, { state: mochiState, message: message }) }));
|
|
123
|
+
}
|
|
124
|
+
if (mode === 'installing' || mode === 'done') {
|
|
125
|
+
return (_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsx(Narrator, { state: mochiState, message: message }) }));
|
|
126
|
+
}
|
|
127
|
+
if (mode === 'scope' && item) {
|
|
128
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { bold: true, children: [assetTypeBadge(item.type), " ", titleize(item.name)] }), _jsx(Box, { marginTop: 1, children: _jsx(ScopePrompt, { onSelect: (s) => doInstall(s) }) })] }));
|
|
129
|
+
}
|
|
130
|
+
if (mode === 'detail' && item) {
|
|
131
|
+
const actions = item.installed
|
|
132
|
+
? [{ label: 'Back', value: 'back' }]
|
|
133
|
+
: [
|
|
134
|
+
{ label: 'Install', value: 'install' },
|
|
135
|
+
{ label: 'Back', value: 'back' },
|
|
136
|
+
];
|
|
137
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { compact: true }), _jsxs(Text, { bold: true, children: [assetTypeBadge(item.type), " ", titleize(item.name)] }), item.installed && _jsx(Text, { color: theme.success, children: "installed" }), item.description && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.secondary, children: item.description }) })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [metadataParts(item).map((part, i) => (_jsx(Text, { color: theme.dim, children: part }, i))), item.tags && item.tags.length > 0 && _jsxs(Text, { color: theme.dim, children: ["Tags: ", item.tags.join(', ')] }), item.category && _jsxs(Text, { color: theme.dim, children: ["Category: ", item.category] }), item.organization && _jsxs(Text, { color: theme.dim, children: ["Author: ", item.organization] })] }), _jsx(Box, { marginTop: 1, children: _jsx(CustomSelectInput, { items: actions, onSelect: (a) => {
|
|
138
|
+
if (a.value === 'install')
|
|
139
|
+
setMode('scope');
|
|
140
|
+
if (a.value === 'back')
|
|
141
|
+
exit();
|
|
142
|
+
} }) })] }));
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
};
|
|
146
|
+
export async function infoCommand(args) {
|
|
147
|
+
const name = args.join(' ');
|
|
148
|
+
if (!name) {
|
|
149
|
+
console.log(' Usage: aman info <name>');
|
|
150
|
+
console.log(' Works for skills, prompts, and MCPs (installed or registry catalog).');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
154
|
+
const item = await findAssetByName(name);
|
|
155
|
+
if (!item) {
|
|
156
|
+
console.error(` No asset found for "${name}".`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
console.log(`\n ${assetTypeBadge(item.type)} ${titleize(item.name)}`);
|
|
160
|
+
if (item.description)
|
|
161
|
+
console.log(` ${item.description}`);
|
|
162
|
+
for (const part of metadataParts(item)) {
|
|
163
|
+
console.log(` ${part}`);
|
|
164
|
+
}
|
|
165
|
+
if (item.tags?.length)
|
|
166
|
+
console.log(` Tags: ${item.tags.join(', ')}`);
|
|
167
|
+
if (item.installed)
|
|
168
|
+
console.log(' Status: installed');
|
|
169
|
+
console.log('');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const { waitUntilExit } = render(_jsx(InfoApp, { name: name }));
|
|
173
|
+
await waitUntilExit();
|
|
174
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type GithubMode = 'create' | 'existing';
|
|
3
|
+
export type InitResult = {
|
|
4
|
+
action: 'local';
|
|
5
|
+
} | {
|
|
6
|
+
action: 'github';
|
|
7
|
+
repository: string;
|
|
8
|
+
mode: GithubMode;
|
|
9
|
+
} | {
|
|
10
|
+
action: 'exit';
|
|
11
|
+
};
|
|
12
|
+
export interface InitFlowProps {
|
|
13
|
+
startWithGithub?: boolean;
|
|
14
|
+
repository?: string;
|
|
15
|
+
githubMode?: GithubMode;
|
|
16
|
+
exitOnDone?: boolean;
|
|
17
|
+
onDone: (result: InitResult) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const InitFlow: React.FC<InitFlowProps>;
|
|
20
|
+
export declare function initCommand(args: string[], options: any): Promise<void>;
|