Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Adds MagicMCP configuration to AI IDEs (Cursor, Windsurf, Cline, etc.)

## Usage

### Install MCP Configuration

```bash
npx @21st-dev/cli@latest install <client> --api-key <key>
```
Expand All @@ -12,6 +14,21 @@ You can obtain your API key at [21st.dev Magic Console](https://21st.dev/magic/c

Supported IDEs: cursor, windsurf, cline, claude, witsy, enconvo

### Analyze GitHub Repository (Octolens)

Analyze any GitHub repository using [Octolens analyzemyrepo](https://analyzemyrepo.com):

```bash
# Analyze a specific repository
npx @21st-dev/cli@latest analyze facebook/react

# Analyze current repository (auto-detected from git remote)
npx @21st-dev/cli@latest analyze

# Open analysis in browser
npx @21st-dev/cli@latest analyze --open
```

## Manual Installation

Add to your IDE's MCP config:
Expand Down
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@21st-dev/cli",
"version": "0.0.29",
"version": "0.0.30",
"type": "module",
"description": "MCP configuration installer by 21st.dev",
"main": "dist/index.js",
Expand Down
97 changes: 97 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,103 @@ program
}
);

program
.command("analyze")
.description(
"Analyze a GitHub repository using Octolens analyzemyrepo service"
)
.argument(
"[repository]",
"GitHub repository in format owner/repo (e.g., facebook/react). Defaults to current repository."
)
.option("--open", "Open the analysis in browser")
.action(async (repository: string | undefined, options: { open?: boolean }) => {
const OCTOLENS_BASE_URL = "https://analyzemyrepo.com";

let repoToAnalyze = repository;

// If no repository provided, try to detect from git remote
if (!repoToAnalyze) {
try {
const gitRemote = execSync("git remote get-url origin", {
encoding: "utf-8",
stdio: ["pipe", "pipe", "pipe"],
}).trim();

// Parse GitHub URL formats:
// https://github.com/owner/repo.git
// git@github.com:owner/repo.git
const httpsMatch = gitRemote.match(/github\.com\/([^\/]+)\/([^\/\.]+)/);
const sshMatch = gitRemote.match(/github\.com:([^\/]+)\/([^\/\.]+)/);

if (httpsMatch) {
repoToAnalyze = `${httpsMatch[1]}/${httpsMatch[2]}`;
} else if (sshMatch) {
repoToAnalyze = `${sshMatch[1]}/${sshMatch[2]}`;
}

if (repoToAnalyze) {
console.log(chalk.blue(`Detected repository: ${repoToAnalyze}`));
}
} catch {
// Not in a git repo or no remote configured
}
}

if (!repoToAnalyze) {
console.error(
chalk.red(
"Could not detect repository. Please provide a repository in format owner/repo (e.g., facebook/react)"
)
);
process.exit(1);
}

// Validate repository format
if (!repoToAnalyze.match(/^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/)) {
console.error(
chalk.red(
`Invalid repository format: "${repoToAnalyze}". Expected format: owner/repo`
)
);
process.exit(1);
}

const analysisUrl = `${OCTOLENS_BASE_URL}/analyze/${repoToAnalyze}`;

console.log(chalk.green(`\n🔍 Octolens Repository Analysis`));
console.log(chalk.cyan(`Repository: ${repoToAnalyze}`));
console.log(chalk.cyan(`Analysis URL: ${analysisUrl}\n`));

if (options.open) {
console.log(chalk.blue("Opening in browser..."));
try {
// Cross-platform open command
const openCommand =
process.platform === "darwin"
? "open"
: process.platform === "win32"
? "start"
: "xdg-open";

execSync(`${openCommand} "${analysisUrl}"`, {
stdio: "ignore",
});
console.log(chalk.green("Browser opened successfully!"));
} catch {
console.log(
chalk.yellow(
`Could not open browser automatically. Please visit the URL above.`
)
);
}
} else {
console.log(
chalk.gray("Tip: Use --open flag to open the analysis in your browser")
);
}
});

program
.command("remove")
.description(
Expand Down