mirror of
https://github.com/aljazceru/mcp-code.git
synced 2025-12-17 04:35:19 +01:00
wip
This commit is contained in:
@@ -1,25 +1,37 @@
|
|||||||
import { Command } from 'commander';
|
import { Command } from "commander";
|
||||||
import {
|
import {
|
||||||
formatPartialMatches,
|
formatPartialMatches,
|
||||||
formatSnippets,
|
formatSnippets,
|
||||||
getSnippets
|
getSnippets,
|
||||||
} from '../lib/nostr/snippets.js';
|
} from "../lib/nostr/snippets.js";
|
||||||
|
|
||||||
export function registerFindSnippetsCommand(program: Command): void {
|
export function registerFindSnippetsCommand(program: Command): void {
|
||||||
program
|
program
|
||||||
.command('find-snippets')
|
.command("find-snippets")
|
||||||
.description('Find code snippets with optional filters')
|
.description("Find code snippets with optional filters")
|
||||||
.option('--limit <number>', 'Maximum number of snippets to return')
|
.option("--limit <number>", "Maximum number of snippets to return")
|
||||||
.option('--languages <list>', 'Comma-separated list of languages to filter by')
|
.option(
|
||||||
.option('--tags <list>', 'Comma-separated list of tags to filter by')
|
"--languages <list>",
|
||||||
.option('--authors <list>', 'Comma-separated list of authors to filter by')
|
"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) => {
|
.action(async (options) => {
|
||||||
try {
|
try {
|
||||||
// Parse options
|
// Parse options
|
||||||
const limit = options.limit ? parseInt(options.limit, 10) : undefined;
|
const limit = options.limit
|
||||||
const languages = options.languages ? options.languages.split(',') : undefined;
|
? parseInt(options.limit, 10)
|
||||||
const tags = options.tags ? options.tags.split(',') : undefined;
|
: undefined;
|
||||||
const authors = options.authors ? options.authors.split(',') : 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({
|
const { snippets, otherSnippets } = await getSnippets({
|
||||||
limit,
|
limit,
|
||||||
@@ -29,10 +41,13 @@ export function registerFindSnippetsCommand(program: Command): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (snippets.length === 0) {
|
if (snippets.length === 0) {
|
||||||
console.log("No code snippets found matching the criteria.");
|
console.log(
|
||||||
|
"No code snippets found matching the criteria."
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const formattedSnippets = formatSnippets(snippets);
|
const formattedSnippets = formatSnippets(snippets);
|
||||||
const partialMatchesText = formatPartialMatches(otherSnippets);
|
const partialMatchesText =
|
||||||
|
formatPartialMatches(otherSnippets);
|
||||||
console.log(
|
console.log(
|
||||||
`Found ${snippets.length} code snippets:\n\n${formattedSnippets}${partialMatchesText}`
|
`Found ${snippets.length} code snippets:\n\n${formattedSnippets}${partialMatchesText}`
|
||||||
);
|
);
|
||||||
@@ -42,4 +57,4 @@ export function registerFindSnippetsCommand(program: Command): void {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|||||||
import type { Command } from "commander";
|
import type { Command } from "commander";
|
||||||
import { readConfig } from "../config.js";
|
import { readConfig } from "../config.js";
|
||||||
import { addCreatePubkeyCommand } from "../logic/create-pubkey.js";
|
import { addCreatePubkeyCommand } from "../logic/create-pubkey.js";
|
||||||
|
import { addDepositCommand } from "../logic/deposit.js";
|
||||||
import { addFetchSnippetByIdCommand } from "../logic/fetch_snippet_by_id.js";
|
import { addFetchSnippetByIdCommand } from "../logic/fetch_snippet_by_id.js";
|
||||||
import { addFindSnippetsCommand } from "../logic/find_snippets.js";
|
import { addFindSnippetsCommand } from "../logic/find_snippets.js";
|
||||||
import { addFindUserCommand } from "../logic/find_user.js";
|
import { addFindUserCommand } from "../logic/find_user.js";
|
||||||
@@ -29,6 +30,7 @@ const commandMap: Record<string, CommandFunction> = {
|
|||||||
"fetch-snippet-by-id": addFetchSnippetByIdCommand,
|
"fetch-snippet-by-id": addFetchSnippetByIdCommand,
|
||||||
zap: addZapCommand,
|
zap: addZapCommand,
|
||||||
"wallet-balance": addWalletBalanceCommand,
|
"wallet-balance": addWalletBalanceCommand,
|
||||||
|
deposit: addDepositCommand,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global server instance
|
// Global server instance
|
||||||
@@ -87,4 +89,5 @@ export function registerMcpCommands(server: McpServer) {
|
|||||||
addZapCommand(server);
|
addZapCommand(server);
|
||||||
addWalletBalanceCommand(server);
|
addWalletBalanceCommand(server);
|
||||||
}
|
}
|
||||||
|
addDepositCommand(server);
|
||||||
}
|
}
|
||||||
|
|||||||
3
index.ts
3
index.ts
@@ -2,9 +2,12 @@ import { initConfig, readConfig, writeConfig } from "./config.js";
|
|||||||
import { initNDK, ndk } from "./ndk.js";
|
import { initNDK, ndk } from "./ndk.js";
|
||||||
import "./db.js";
|
import "./db.js";
|
||||||
import { runCli } from "./commands/index.js";
|
import { runCli } from "./commands/index.js";
|
||||||
|
import { applyMigrations } from "./db.js";
|
||||||
import { log } from "./lib/utils/log.js";
|
import { log } from "./lib/utils/log.js";
|
||||||
import { runConfigWizard } from "./wizard";
|
import { runConfigWizard } from "./wizard";
|
||||||
|
|
||||||
|
await applyMigrations();
|
||||||
|
|
||||||
log("starting up...: args: " + process.argv.join(" "));
|
log("starting up...: args: " + process.argv.join(" "));
|
||||||
|
|
||||||
// Load config and ensure defaults
|
// Load config and ensure defaults
|
||||||
|
|||||||
85
lib/cache/wallets.ts
vendored
85
lib/cache/wallets.ts
vendored
@@ -1,5 +1,9 @@
|
|||||||
|
import {
|
||||||
|
NDKCashuMintList,
|
||||||
|
NDKPrivateKeySigner,
|
||||||
|
type NDKSigner,
|
||||||
|
} from "@nostr-dev-kit/ndk";
|
||||||
import { NDKCashuWallet, NDKNutzapMonitor } from "@nostr-dev-kit/ndk-wallet";
|
import { NDKCashuWallet, NDKNutzapMonitor } from "@nostr-dev-kit/ndk-wallet";
|
||||||
import { NDKCashuMintList, NDKPrivateKeySigner, type NDKSigner } from "@nostr-dev-kit/ndk";
|
|
||||||
import { ndk } from "../../ndk.js";
|
import { ndk } from "../../ndk.js";
|
||||||
import { log } from "../utils/log.js";
|
import { log } from "../utils/log.js";
|
||||||
|
|
||||||
@@ -15,7 +19,12 @@ export const walletsCache: Record<string, NDKCashuWallet> = {};
|
|||||||
* @param pubkey The public key to get the wallet for
|
* @param pubkey The public key to get the wallet for
|
||||||
* @returns The wallet (from cache or newly loaded)
|
* @returns The wallet (from cache or newly loaded)
|
||||||
*/
|
*/
|
||||||
export async function getWallet(pubkey: string, signer: NDKSigner): Promise<NDKCashuWallet | undefined> {
|
export async function getWallet(
|
||||||
|
pubkey: string,
|
||||||
|
signer: NDKSigner
|
||||||
|
): Promise<NDKCashuWallet | undefined> {
|
||||||
|
let newWallet = false;
|
||||||
|
|
||||||
// Return from cache if available
|
// Return from cache if available
|
||||||
if (walletsCache[pubkey]) {
|
if (walletsCache[pubkey]) {
|
||||||
console.log(`Returning cached wallet for ${pubkey}`);
|
console.log(`Returning cached wallet for ${pubkey}`);
|
||||||
@@ -23,45 +32,53 @@ export async function getWallet(pubkey: string, signer: NDKSigner): Promise<NDKC
|
|||||||
}
|
}
|
||||||
|
|
||||||
ndk.signer = signer;
|
ndk.signer = signer;
|
||||||
|
|
||||||
// Not in cache, fetch from Nostr
|
// Not in cache, fetch from Nostr
|
||||||
try {
|
try {
|
||||||
let wallet: NDKCashuWallet | undefined;
|
let wallet: NDKCashuWallet | undefined;
|
||||||
const user = ndk.getUser({pubkey});
|
const user = ndk.getUser({ pubkey });
|
||||||
const event = await ndk.fetchEvent({ kinds: [17375], authors: [pubkey] });
|
const event = await ndk.fetchEvent({
|
||||||
|
kinds: [17375],
|
||||||
|
authors: [pubkey],
|
||||||
|
});
|
||||||
|
|
||||||
// Use the existing wallet
|
// Use the existing wallet
|
||||||
if (event) {
|
if (event) {
|
||||||
console.log(`Found wallet event for ${pubkey}: ${event.id}`, event.inspect);
|
console.log(
|
||||||
|
`Found wallet event for ${pubkey}: ${event.id}`,
|
||||||
|
event.inspect
|
||||||
|
);
|
||||||
wallet = await NDKCashuWallet.from(event);
|
wallet = await NDKCashuWallet.from(event);
|
||||||
} else {
|
} else {
|
||||||
console.log('No wallet event found for', pubkey);
|
console.log("No wallet event found for", pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wallet) {
|
if (!wallet) {
|
||||||
|
newWallet = true;
|
||||||
wallet = new NDKCashuWallet(ndk);
|
wallet = new NDKCashuWallet(ndk);
|
||||||
wallet.mints = ["https://mint.coinos.io"];
|
wallet.mints = ["https://mint.coinos.io"];
|
||||||
|
|
||||||
// Generate a P2PK address for receiving nutzaps
|
// Generate a P2PK address for receiving nutzaps
|
||||||
await wallet.getP2pk();
|
await wallet.getP2pk();
|
||||||
log(`Generated P2PK address for ${pubkey}: ${wallet.p2pk}`);
|
log(`Generated P2PK address for ${pubkey}: ${wallet.p2pk}`);
|
||||||
|
|
||||||
// Publish the wallet info event (kind 17375)
|
// Publish the wallet info event (kind 17375)
|
||||||
await wallet.publish();
|
await wallet.publish();
|
||||||
log(`Published wallet info event for ${pubkey}`);
|
log(`Published wallet info event for ${pubkey}`);
|
||||||
|
|
||||||
// Set up the mint list for nutzap reception (kind 10019)
|
// Set up the mint list for nutzap reception (kind 10019)
|
||||||
const mintList = new NDKCashuMintList(ndk);
|
const mintList = new NDKCashuMintList(ndk);
|
||||||
mintList.mints = wallet.mints;
|
mintList.mints = wallet.mints;
|
||||||
mintList.relays = ['wss://relay.pri']
|
mintList.relays = ["wss://relay.primal.net"];
|
||||||
mintList.p2pk = wallet.p2pk;
|
mintList.p2pk = wallet.p2pk;
|
||||||
|
|
||||||
// Publish the mint list
|
// Publish the mint list
|
||||||
await mintList.publish();
|
await mintList.publish();
|
||||||
log(`Published mint list for ${pubkey} with mints: ${mintList.mints.join(', ')}`);
|
log(
|
||||||
|
`Published mint list for ${pubkey} with mints: ${mintList.mints.join(", ")}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Start wallet for monitoring balance and nutzaps
|
// Start wallet for monitoring balance and nutzaps
|
||||||
console.log(`Starting wallet for ${pubkey}`);
|
console.log(`Starting wallet for ${pubkey}`);
|
||||||
await wallet.start();
|
await wallet.start();
|
||||||
@@ -72,25 +89,45 @@ export async function getWallet(pubkey: string, signer: NDKSigner): Promise<NDKC
|
|||||||
const nutzapMonitor = new NDKNutzapMonitor(ndk, user, {});
|
const nutzapMonitor = new NDKNutzapMonitor(ndk, user, {});
|
||||||
nutzapMonitor.wallet = wallet;
|
nutzapMonitor.wallet = wallet;
|
||||||
nutzapMonitor.on("seen", () => {
|
nutzapMonitor.on("seen", () => {
|
||||||
log('seen nutzap');
|
log("seen nutzap");
|
||||||
});
|
});
|
||||||
nutzapMonitor.on("redeemed", (events) => {
|
nutzapMonitor.on("redeemed", (events) => {
|
||||||
log(`Nutzap redeemed for ${pubkey}: ${events.reduce((acc, event) => acc + event.amount, 0)} sats`);
|
log(
|
||||||
|
`Nutzap redeemed for ${pubkey}: ${events.reduce((acc, event) => acc + event.amount, 0)} sats`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
nutzapMonitor.start({});
|
nutzapMonitor.start({});
|
||||||
log(`Started nutzap monitor for ${pubkey}`);
|
log(`Started nutzap monitor for ${pubkey}`);
|
||||||
|
|
||||||
// Set up balance update listener
|
// Set up balance update listener
|
||||||
wallet.on('balance_updated', (newBalance) => {
|
wallet.on("balance_updated", (newBalance) => {
|
||||||
log(`Balance updated for ${pubkey}: ${newBalance?.amount || 0} sats`);
|
log(
|
||||||
|
`Balance updated for ${pubkey}: ${newBalance?.amount || 0} sats`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error starting nutzap monitor for ${pubkey}:`, error);
|
console.error(
|
||||||
|
`Error starting nutzap monitor for ${pubkey}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
walletsCache[pubkey] = wallet;
|
walletsCache[pubkey] = wallet;
|
||||||
|
|
||||||
// No wallet found
|
if (!newWallet) {
|
||||||
|
// Total hack, but we have a race condition getting the balance of the wallet,
|
||||||
|
// if we're starting the wallet with a get_balance command we'll always return zero
|
||||||
|
// in the first call, so let's give it some time to catch up. wallet.start() should
|
||||||
|
// have returned once it knows it has all the proofs
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(wallet);
|
||||||
|
}, 1000);
|
||||||
|
wallet.on("balance_updated", () => resolve(wallet));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// NKo wallet found
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching wallet for ${pubkey}:`, error);
|
console.error(`Error fetching wallet for ${pubkey}:`, error);
|
||||||
@@ -105,4 +142,4 @@ export function clearWalletsCache(): void {
|
|||||||
for (const key of Object.keys(walletsCache)) {
|
for (const key of Object.keys(walletsCache)) {
|
||||||
delete walletsCache[key];
|
delete walletsCache[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import type { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
|
import type { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
|
||||||
import { db } from "../../db.js";
|
import { db } from "../../db.js";
|
||||||
import { ndk } from "../../ndk.js";
|
import { ndk } from "../../ndk.js";
|
||||||
|
import {
|
||||||
|
formatPartialMatches,
|
||||||
|
formatSnippets,
|
||||||
|
toSnippet,
|
||||||
|
} from "../converters/index.js";
|
||||||
import type { CodeSnippet, FindSnippetsParams } from "../types/index.js";
|
import type { CodeSnippet, FindSnippetsParams } from "../types/index.js";
|
||||||
import { log } from "../utils/log.js";
|
import { log } from "../utils/log.js";
|
||||||
import { SNIPPET_KIND, identifierToPubkeys } from "./utils.js";
|
import { SNIPPET_KIND, identifierToPubkeys } from "./utils.js";
|
||||||
import { formatPartialMatches, formatSnippets, toSnippet } from "../converters/index.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get code snippets from Nostr events of kind 1337
|
* Get code snippets from Nostr events of kind 1337
|
||||||
@@ -54,6 +58,19 @@ export async function getSnippets(params: FindSnippetsParams = {}): Promise<{
|
|||||||
|
|
||||||
log(`Fetching snippets with filter: ${JSON.stringify(filter, null, 2)}`);
|
log(`Fetching snippets with filter: ${JSON.stringify(filter, null, 2)}`);
|
||||||
|
|
||||||
|
// ndk.subscribe(
|
||||||
|
// [filter],
|
||||||
|
// { closeOnEose: true },
|
||||||
|
// {
|
||||||
|
// onEvent: (event) => {
|
||||||
|
// log(`Received event: ${event.id}`);
|
||||||
|
// },
|
||||||
|
// onEose: () => {
|
||||||
|
// log("EOSE received.");
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
// Fetch events
|
// Fetch events
|
||||||
const events = await ndk.fetchEvents(filter);
|
const events = await ndk.fetchEvents(filter);
|
||||||
|
|
||||||
@@ -73,8 +90,11 @@ export async function getSnippets(params: FindSnippetsParams = {}): Promise<{
|
|||||||
.filter((t): t is string => t !== undefined); // Ensure tag value exists and narrow type
|
.filter((t): t is string => t !== undefined); // Ensure tag value exists and narrow type
|
||||||
|
|
||||||
// Count how many of the searched tags are present in the event's tags
|
// Count how many of the searched tags are present in the event's tags
|
||||||
return params.tags.filter((searchTag) =>
|
return params.tags.filter(
|
||||||
aTags.some((eventTag) => eventTag.match(new RegExp(searchTag, "i"))) // Case-insensitive tag matching
|
(searchTag) =>
|
||||||
|
aTags.some((eventTag) =>
|
||||||
|
eventTag.match(new RegExp(searchTag, "i"))
|
||||||
|
) // Case-insensitive tag matching
|
||||||
).length;
|
).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +118,6 @@ export async function getSnippets(params: FindSnippetsParams = {}): Promise<{
|
|||||||
const snippets = selectedEvents.map(toSnippet);
|
const snippets = selectedEvents.map(toSnippet);
|
||||||
const otherSnippets = notSelectedEvents.map(toSnippet);
|
const otherSnippets = notSelectedEvents.map(toSnippet);
|
||||||
|
|
||||||
|
|
||||||
// --- BEGIN DATABASE INSERTION ---
|
// --- BEGIN DATABASE INSERTION ---
|
||||||
const allSnippets = [...snippets, ...otherSnippets];
|
const allSnippets = [...snippets, ...otherSnippets];
|
||||||
if (allSnippets.length > 0) {
|
if (allSnippets.length > 0) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as fs from "node:fs";
|
import * as fs from "node:fs";
|
||||||
import { promises as fsPromises } from "node:fs";
|
|
||||||
import * as os from "node:os";
|
import * as os from "node:os";
|
||||||
import * as path from "node:path";
|
import * as path from "node:path";
|
||||||
|
|
||||||
|
const id = Math.floor(Math.random() * 1000000);
|
||||||
const timeZero = Date.now();
|
const timeZero = Date.now();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +21,7 @@ export function log(
|
|||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
const relativeTime = now.getTime() - timeZero;
|
const relativeTime = now.getTime() - timeZero;
|
||||||
const logMessage = `[${relativeTime}ms] ${timestamp} - ${message}\n`;
|
const logMessage = `[${id}] [${relativeTime}ms] ${timestamp} - ${message}\n`;
|
||||||
fs.appendFile(logFilePath, logMessage, (err) => {
|
fs.appendFile(logFilePath, logMessage, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Error writing to log file:", err);
|
console.error("Error writing to log file:", err);
|
||||||
|
|||||||
11
ndk.ts
11
ndk.ts
@@ -2,10 +2,12 @@ import NDK, {
|
|||||||
NDKPrivateKeySigner,
|
NDKPrivateKeySigner,
|
||||||
type NDKUser,
|
type NDKUser,
|
||||||
type NDKSigner,
|
type NDKSigner,
|
||||||
|
type NDKRelay,
|
||||||
} from "@nostr-dev-kit/ndk";
|
} from "@nostr-dev-kit/ndk";
|
||||||
import { NDKNip46Signer } from "@nostr-dev-kit/ndk";
|
import { NDKNip46Signer } from "@nostr-dev-kit/ndk";
|
||||||
import { type ConfigData, writeConfig } from "./config";
|
import { type ConfigData, writeConfig } from "./config";
|
||||||
import { updateFollowList } from "./update-follow-list";
|
import { updateFollowList } from "./update-follow-list";
|
||||||
|
import { log } from "./utils/log";
|
||||||
|
|
||||||
const DEFAULT_RELAYS = [
|
const DEFAULT_RELAYS = [
|
||||||
"wss://relay.primal.net",
|
"wss://relay.primal.net",
|
||||||
@@ -18,6 +20,13 @@ export const ndk = new NDK();
|
|||||||
|
|
||||||
export async function initNDK(config: ConfigData) {
|
export async function initNDK(config: ConfigData) {
|
||||||
ndk.explicitRelayUrls = config.relays || DEFAULT_RELAYS;
|
ndk.explicitRelayUrls = config.relays || DEFAULT_RELAYS;
|
||||||
|
ndk.pool.on("relay:connect", (r: NDKRelay) => log(`Connected to ${r.url}`));
|
||||||
|
ndk.pool.on("relay:disconnect", (r: NDKRelay) =>
|
||||||
|
log(`Disconnected from ${r.url}`)
|
||||||
|
);
|
||||||
|
ndk.pool.on("relay:connecting", (r: NDKRelay) =>
|
||||||
|
log(`Connecting to ${r.url}`)
|
||||||
|
);
|
||||||
await ndk.connect();
|
await ndk.connect();
|
||||||
|
|
||||||
let signer: NDKSigner;
|
let signer: NDKSigner;
|
||||||
@@ -53,5 +62,5 @@ export async function initNDK(config: ConfigData) {
|
|||||||
|
|
||||||
mainUser ??= await signer.user();
|
mainUser ??= await signer.user();
|
||||||
|
|
||||||
setTimeout(() => updateFollowList(mainUser), 1000);
|
// setTimeout(() => updateFollowList(mainUser), 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.7.0",
|
"@modelcontextprotocol/sdk": "^1.7.0",
|
||||||
"@nostr-dev-kit/ndk": "2.13.1-rc2",
|
"@nostr-dev-kit/ndk": "2.13.1-rc7",
|
||||||
"@nostr-dev-kit/ndk-wallet": "0.5.3-1",
|
"@nostr-dev-kit/ndk-wallet": "0.5.3-1",
|
||||||
"commander": "^13.1.0",
|
"commander": "^13.1.0",
|
||||||
"inquirer": "^12.5.0",
|
"inquirer": "^12.5.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user