mirror of
https://github.com/aljazceru/mcp-code.git
synced 2025-12-17 04:35:19 +01:00
initial commit
This commit is contained in:
45
commands/find-snippets.ts
Normal file
45
commands/find-snippets.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Command } from 'commander';
|
||||
import {
|
||||
formatPartialMatches,
|
||||
formatSnippets,
|
||||
getSnippets
|
||||
} from '../lib/nostr/snippets.js';
|
||||
|
||||
export function registerFindSnippetsCommand(program: Command): void {
|
||||
program
|
||||
.command('find-snippets')
|
||||
.description('Find code snippets with optional filters')
|
||||
.option('--limit <number>', 'Maximum number of snippets to return')
|
||||
.option('--languages <list>', 'Comma-separated list of languages to filter by')
|
||||
.option('--tags <list>', 'Comma-separated list of tags to filter by')
|
||||
.option('--authors <list>', 'Comma-separated list of authors to filter by')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
// Parse options
|
||||
const limit = options.limit ? parseInt(options.limit, 10) : undefined;
|
||||
const languages = options.languages ? options.languages.split(',') : undefined;
|
||||
const tags = options.tags ? options.tags.split(',') : undefined;
|
||||
const authors = options.authors ? options.authors.split(',') : undefined;
|
||||
|
||||
const { snippets, otherSnippets } = await getSnippets({
|
||||
limit,
|
||||
languages,
|
||||
tags,
|
||||
authors,
|
||||
});
|
||||
|
||||
if (snippets.length === 0) {
|
||||
console.log("No code snippets found matching the criteria.");
|
||||
} else {
|
||||
const formattedSnippets = formatSnippets(snippets);
|
||||
const partialMatchesText = formatPartialMatches(otherSnippets);
|
||||
console.log(
|
||||
`Found ${snippets.length} code snippets:\n\n${formattedSnippets}${partialMatchesText}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error executing find-snippets command:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
43
commands/find-user.ts
Normal file
43
commands/find-user.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Command } from 'commander';
|
||||
import { ndk } from '../ndk.js';
|
||||
import { knownUsers } from '../users.js';
|
||||
import { identifierToPubkeys } from '../lib/nostr/utils.js';
|
||||
|
||||
export function registerFindUserCommand(program: Command): void {
|
||||
program
|
||||
.command('find-user')
|
||||
.description('Find a user by identifier')
|
||||
.argument('<query>', 'User identifier to search for')
|
||||
.action(async (query: string) => {
|
||||
try {
|
||||
const pubkeys = identifierToPubkeys(query);
|
||||
|
||||
if (pubkeys.length > 0) {
|
||||
const result = pubkeys.map(formatUser).join('\n\n---\n\n');
|
||||
console.log(result);
|
||||
} else {
|
||||
console.log("No user found matching the query.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error executing find-user command:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to format user profiles
|
||||
function formatUser(pubkey: string) {
|
||||
const profile = knownUsers[pubkey]?.profile;
|
||||
const user = ndk.getUser({ pubkey });
|
||||
const keys: Record<string, string> = {
|
||||
Npub: user.npub,
|
||||
};
|
||||
|
||||
if (profile?.name) keys.Name = profile.name;
|
||||
if (profile?.about) keys.About = profile.about;
|
||||
if (profile?.picture) keys.Picture = profile.picture;
|
||||
|
||||
return Object.entries(keys)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join("\n");
|
||||
}
|
||||
34
commands/index.ts
Normal file
34
commands/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Command } from 'commander';
|
||||
import { registerFindUserCommand } from './find-user.js';
|
||||
import { registerFindSnippetsCommand } from './find-snippets.js';
|
||||
import { registerWotCommand } from './wot.js';
|
||||
import { registerListUsernamesCommand } from './list-usernames.js';
|
||||
import { registerMcpCommand } from './mcp.js';
|
||||
import { registerSetupCommand } from './setup.js';
|
||||
|
||||
// Create a new Commander program
|
||||
const program = new Command();
|
||||
|
||||
// Setup program metadata
|
||||
program
|
||||
.name('mcp-nostr')
|
||||
.description('Model Context Protocol for Nostr')
|
||||
.version('1.0.0');
|
||||
|
||||
// Register all commands
|
||||
registerMcpCommand(program);
|
||||
registerFindUserCommand(program);
|
||||
registerFindSnippetsCommand(program);
|
||||
registerWotCommand(program);
|
||||
registerListUsernamesCommand(program);
|
||||
registerSetupCommand(program);
|
||||
|
||||
// Function to run the CLI
|
||||
export async function runCli(args: string[]) {
|
||||
program.parse(args);
|
||||
|
||||
// If no command was specified, show help by default
|
||||
if (args.length <= 2) {
|
||||
program.help();
|
||||
}
|
||||
}
|
||||
24
commands/list-usernames.ts
Normal file
24
commands/list-usernames.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Command } from 'commander';
|
||||
import { listUsernames } from '../logic/list_usernames.js';
|
||||
|
||||
export function registerListUsernamesCommand(program: Command): void {
|
||||
program
|
||||
.command('list-usernames')
|
||||
.description('List all usernames in the database')
|
||||
.action(async () => {
|
||||
try {
|
||||
const result = await listUsernames();
|
||||
|
||||
// Extract text content from the response
|
||||
if (result.content && result.content.length > 0) {
|
||||
const textContent = result.content.find(item => item.type === 'text');
|
||||
if (textContent) {
|
||||
console.log(textContent.text);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error executing list-usernames command:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
74
commands/mcp.ts
Normal file
74
commands/mcp.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Command } from 'commander';
|
||||
import { readConfig } from "../config.js";
|
||||
import { addCreatePubkeyCommand } from "../logic/create-pubkey.js";
|
||||
import { addFindSnippetsCommand } from "../logic/find_snippets.js";
|
||||
import { addFindUserCommand } from "../logic/find_user.js";
|
||||
import { addListUsernamesCommand } from "../logic/list_usernames.js";
|
||||
import { addPublishCodeSnippetCommand } from "../logic/publish-code-snippet.js";
|
||||
import { addPublishCommand } from "../logic/publish.js";
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
|
||||
// Define type for command functions
|
||||
type CommandFunction = (server: McpServer) => void;
|
||||
|
||||
// Map of command names to their registration functions
|
||||
const commandMap: Record<string, CommandFunction> = {
|
||||
publish: addPublishCommand,
|
||||
"publish-snippet": addPublishCodeSnippetCommand,
|
||||
"create-pubkey": addCreatePubkeyCommand,
|
||||
"find-user": addFindUserCommand,
|
||||
"find-snippets": addFindSnippetsCommand,
|
||||
"list-usernames": addListUsernamesCommand,
|
||||
};
|
||||
|
||||
// Global server instance
|
||||
let mcpServer: McpServer | null = null;
|
||||
|
||||
export function registerMcpCommand(program: Command): void {
|
||||
program
|
||||
.command('mcp')
|
||||
.description('Start the MCP server')
|
||||
.action(async () => {
|
||||
try {
|
||||
// Create the MCP server
|
||||
mcpServer = new McpServer({
|
||||
name: "Nostr Publisher",
|
||||
version: "1.0.0",
|
||||
});
|
||||
|
||||
// Register all MCP commands
|
||||
registerMcpCommands(mcpServer);
|
||||
|
||||
// Connect the server to the transport
|
||||
const transport = new StdioServerTransport();
|
||||
await mcpServer.connect(transport);
|
||||
} catch (error) {
|
||||
console.error("Error starting MCP server:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Register all MCP commands, filtered by config if specified
|
||||
export function registerMcpCommands(server: McpServer) {
|
||||
const config = readConfig();
|
||||
const enabledCommands = config.mcpCommands;
|
||||
|
||||
// If mcpCommands is specified in config, only register those commands
|
||||
if (enabledCommands && enabledCommands.length > 0) {
|
||||
for (const cmd of enabledCommands) {
|
||||
if (commandMap[cmd]) {
|
||||
commandMap[cmd](server);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise register all commands
|
||||
addPublishCommand(server);
|
||||
addPublishCodeSnippetCommand(server);
|
||||
addCreatePubkeyCommand(server);
|
||||
addFindUserCommand(server);
|
||||
addFindSnippetsCommand(server);
|
||||
addListUsernamesCommand(server);
|
||||
}
|
||||
}
|
||||
18
commands/setup.ts
Normal file
18
commands/setup.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Command } from "commander";
|
||||
import { runConfigWizard } from "../wizard";
|
||||
import { readConfig } from "../config.js";
|
||||
|
||||
/**
|
||||
* Register the setup command with the Commander program
|
||||
* @param program The Commander program instance
|
||||
*/
|
||||
export function registerSetupCommand(program: Command) {
|
||||
program
|
||||
.command("setup")
|
||||
.description("Run the configuration wizard to set up MCP-Nostr")
|
||||
.action(async () => {
|
||||
const config = readConfig();
|
||||
await runConfigWizard(config);
|
||||
console.log("Setup complete! You can now use MCP-Nostr.");
|
||||
});
|
||||
}
|
||||
92
commands/wot.ts
Normal file
92
commands/wot.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { Command } from 'commander';
|
||||
import { ndk } from '../ndk.js';
|
||||
import { db } from '../db.js';
|
||||
import { knownUsers } from '../users.js';
|
||||
import { getFollowerCount, getFollowing } from '../wot.js';
|
||||
|
||||
export function registerWotCommand(program: Command): void {
|
||||
program
|
||||
.command('wot')
|
||||
.description('Get Web of Trust information for a user')
|
||||
.argument('<pubkey>', 'Public key or npub of the user')
|
||||
.action(async (pubkey: string) => {
|
||||
try {
|
||||
if (!pubkey) {
|
||||
console.log("Missing pubkey parameter. Usage: wot <pubkey>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Validate pubkey format (simple check - proper validation would be more complex)
|
||||
if (pubkey.length !== 64 && !pubkey.startsWith("npub")) {
|
||||
console.log(
|
||||
"Invalid pubkey format. Please provide a valid hex pubkey or npub."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get actual hex pubkey if npub was provided
|
||||
let hexPubkey = pubkey;
|
||||
if (pubkey.startsWith("npub")) {
|
||||
hexPubkey = ndk.getUser({ npub: pubkey }).pubkey;
|
||||
}
|
||||
|
||||
// Get follower count
|
||||
const followerCount = getFollowerCount(hexPubkey);
|
||||
|
||||
// Get following count
|
||||
const following = getFollowing(hexPubkey);
|
||||
const followingCount = following.length;
|
||||
|
||||
// Get profile info if available
|
||||
const profile = knownUsers[hexPubkey]?.profile;
|
||||
const name = profile?.name || hexPubkey;
|
||||
|
||||
console.log(`Web of Trust for ${name}:`);
|
||||
console.log(`Pubkey: ${hexPubkey}`);
|
||||
if (ndk.getUser({ pubkey: hexPubkey }).npub) {
|
||||
console.log(`Npub: ${ndk.getUser({ pubkey: hexPubkey }).npub}`);
|
||||
}
|
||||
console.log(`Followers: ${followerCount}`);
|
||||
console.log(`Following: ${followingCount}`);
|
||||
|
||||
// Calculate follow score ratio (simple metric)
|
||||
const ratio =
|
||||
followingCount > 0
|
||||
? (followerCount / followingCount).toFixed(2)
|
||||
: "N/A";
|
||||
console.log(`Follower/Following Ratio: ${ratio}`);
|
||||
|
||||
// Most popular followers (if any)
|
||||
if (followerCount > 0) {
|
||||
const popularFollowers = db
|
||||
.query(`
|
||||
SELECT f.follower, COUNT(*) as count
|
||||
FROM wot f
|
||||
JOIN wot f2 ON f.follower = f2.followed
|
||||
WHERE f.followed = ?
|
||||
GROUP BY f.follower
|
||||
ORDER BY count DESC
|
||||
LIMIT 5
|
||||
`)
|
||||
.all(hexPubkey) as { follower: string; count: number }[];
|
||||
|
||||
if (popularFollowers.length > 0) {
|
||||
console.log("\nMost influential followers:");
|
||||
for (const follower of popularFollowers) {
|
||||
const followerProfile =
|
||||
knownUsers[follower.follower]?.profile;
|
||||
const followerName =
|
||||
followerProfile?.name ||
|
||||
`${follower.follower.substring(0, 8)}...`;
|
||||
console.log(
|
||||
`- ${followerName} (followed by ${follower.count} users)`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error executing wot command:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user