mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-17 19:07:06 +02:00
feat(chat): add NIP-22 comment adapter as wildcard chat for all events
Implements a NIP-22 adapter that enables comments (kind 1111) on any Nostr event or external resource. This acts as the catch-all wildcard for events not handled by NIP-10 (kind 1 threads) or NIP-53 (live activities). All events now show a "Comments" option in context menus. - Create Nip22Adapter using applesauce CommentBlueprint for proper NIP-22 tag structure (uppercase root/lowercase parent convention) - Support event pointers (nevent), address pointers (naddr), and external identifiers (NIP-73) as comment roots - Add CommentIdentifier, CommentAddressIdentifier, and CommentExternalIdentifier types to chat.ts - Update chat-parser to route NIP-22 as wildcard after NIP-10/29/53 - Wire NIP-22 into ChatViewer (getAdapter, getChatIdentifier, getConversationRelays) - Update BaseEventRenderer to show Chat/Comments for all event kinds with kind-aware protocol routing (getChatPropsForEvent helper) - Update man.ts command docs and CLAUDE.md chat system docs https://claude.ai/code/session_01PsevnSkZf2Pn1yhc1Rinc3
This commit is contained in:
23
CLAUDE.md
23
CLAUDE.md
@@ -377,12 +377,22 @@ This allows `applyTheme()` to switch themes at runtime.
|
||||
|
||||
## Chat System
|
||||
|
||||
**Current Status**: Only NIP-29 (relay-based groups) is supported. Other protocols are planned for future releases.
|
||||
**Current Status**: NIP-29 (relay-based groups), NIP-10 (kind 1 threads), NIP-53 (live activity chat), and NIP-22 (comments on any event) are supported. NIP-17 (encrypted DMs) and NIP-28 (channels) are planned.
|
||||
|
||||
**Architecture**: Protocol adapter pattern for supporting multiple Nostr messaging protocols:
|
||||
- `src/lib/chat/adapters/base-adapter.ts` - Base interface all adapters implement
|
||||
- `src/lib/chat/adapters/nip-29-adapter.ts` - NIP-29 relay groups (currently enabled)
|
||||
- Other adapters (NIP-C7, NIP-17, NIP-28, NIP-53) are implemented but commented out
|
||||
- `src/lib/chat/adapters/nip-10-adapter.ts` - NIP-10 kind 1 thread chat
|
||||
- `src/lib/chat/adapters/nip-22-adapter.ts` - NIP-22 comments on any event (wildcard)
|
||||
- `src/lib/chat/adapters/nip-29-adapter.ts` - NIP-29 relay groups
|
||||
- `src/lib/chat/adapters/nip-53-adapter.ts` - NIP-53 live activity chat
|
||||
- Other adapters (NIP-17, NIP-28) planned for future releases
|
||||
|
||||
**NIP-22 Comments (Wildcard)**: Comments on any event not handled by NIP-10 or NIP-53
|
||||
- Accepts `nevent1...` (any kind except 1) or `naddr1...` (addressable events)
|
||||
- Uses kind 1111 comment events with uppercase (root) and lowercase (parent) tag convention
|
||||
- Also supports external identifiers (NIP-73: URLs, ISBNs, DOIs, etc.)
|
||||
- Uses applesauce `CommentBlueprint` for proper tag construction
|
||||
- All events now show a "Comments" option in context menus
|
||||
|
||||
**NIP-29 Group Format**: `relay'group-id` (wss:// prefix optional)
|
||||
- Examples: `relay.example.com'bitcoin-dev`, `wss://nos.lol'welcome`
|
||||
@@ -392,11 +402,14 @@ This allows `applyTheme()` to switch themes at runtime.
|
||||
**Key Components**:
|
||||
- `src/components/ChatViewer.tsx` - Main chat interface (protocol-agnostic)
|
||||
- `src/components/chat/ReplyPreview.tsx` - Shows reply context with scroll-to functionality
|
||||
- `src/lib/chat-parser.ts` - Auto-detects protocol from identifier format
|
||||
- `src/lib/chat-parser.ts` - Auto-detects protocol from identifier format (NIP-22 is the wildcard catch-all)
|
||||
- `src/types/chat.ts` - Protocol-agnostic types (Conversation, Message, etc.)
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
chat nevent1... # Comments on any event (NIP-22)
|
||||
chat naddr1...30023... # Comments on an article (NIP-22)
|
||||
chat note1abc... # Thread chat on kind 1 note (NIP-10)
|
||||
chat relay.example.com'bitcoin-dev # Join NIP-29 group
|
||||
chat wss://nos.lol'welcome # Join with explicit wss:// prefix
|
||||
```
|
||||
@@ -404,7 +417,7 @@ chat wss://nos.lol'welcome # Join with explicit wss:// prefix
|
||||
**Adding New Protocols** (for future work):
|
||||
1. Create new adapter extending `ChatProtocolAdapter` in `src/lib/chat/adapters/`
|
||||
2. Implement all required methods (parseIdentifier, resolveConversation, loadMessages, sendMessage)
|
||||
3. Uncomment adapter registration in `src/lib/chat-parser.ts` and `src/components/ChatViewer.tsx`
|
||||
3. Register adapter in `src/lib/chat-parser.ts` and `src/components/ChatViewer.tsx`
|
||||
4. Update command docs in `src/types/man.ts` if needed
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -27,6 +27,7 @@ import type {
|
||||
} from "@/types/chat";
|
||||
import { CHAT_KINDS } from "@/types/chat";
|
||||
import { Nip10Adapter } from "@/lib/chat/adapters/nip-10-adapter";
|
||||
import { Nip22Adapter } from "@/lib/chat/adapters/nip-22-adapter";
|
||||
import { Nip29Adapter } from "@/lib/chat/adapters/nip-29-adapter";
|
||||
import { Nip53Adapter } from "@/lib/chat/adapters/nip-53-adapter";
|
||||
import type { ChatProtocolAdapter } from "@/lib/chat/adapters/base-adapter";
|
||||
@@ -157,6 +158,11 @@ function getConversationRelays(conversation: Conversation): string[] {
|
||||
}
|
||||
}
|
||||
|
||||
// NIP-22 comments: Use relays from metadata
|
||||
if (conversation.protocol === "nip-22") {
|
||||
return conversation.metadata?.relays || [];
|
||||
}
|
||||
|
||||
// NIP-29 groups and fallback: Use single relay URL
|
||||
const relayUrl = conversation.metadata?.relayUrl;
|
||||
return relayUrl ? [relayUrl] : [];
|
||||
@@ -168,6 +174,7 @@ function getConversationRelays(conversation: Conversation): string[] {
|
||||
*
|
||||
* For NIP-29 groups: relay'group-id (without wss:// prefix)
|
||||
* For NIP-53 live activities: naddr1... encoding
|
||||
* For NIP-22 comments: nevent1.../naddr1... encoding
|
||||
*/
|
||||
function getChatIdentifier(conversation: Conversation): string | null {
|
||||
if (conversation.protocol === "nip-29") {
|
||||
@@ -196,6 +203,30 @@ function getChatIdentifier(conversation: Conversation): string | null {
|
||||
});
|
||||
}
|
||||
|
||||
if (conversation.protocol === "nip-22") {
|
||||
const relays = (conversation.metadata?.relays || []).slice(0, 3);
|
||||
|
||||
// Addressable event — encode as naddr
|
||||
if (conversation.metadata?.rootAddress) {
|
||||
const parts = conversation.metadata.rootAddress.split(":");
|
||||
const kind = parseInt(parts[0]);
|
||||
const pubkey = parts[1];
|
||||
const identifier = parts.slice(2).join(":");
|
||||
return nip19.naddrEncode({ kind, pubkey, identifier, relays });
|
||||
}
|
||||
|
||||
// Regular event — encode as nevent
|
||||
if (conversation.metadata?.rootEventId) {
|
||||
return nip19.neventEncode({
|
||||
id: conversation.metadata.rootEventId,
|
||||
relays,
|
||||
kind: conversation.metadata.rootEventKind,
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1250,13 +1281,14 @@ export function ChatViewer({
|
||||
|
||||
/**
|
||||
* Get the appropriate adapter for a protocol
|
||||
* Currently NIP-10 (thread chat), NIP-29 (relay-based groups) and NIP-53 (live activity chat) are supported
|
||||
* Other protocols will be enabled in future phases
|
||||
* Supported: NIP-10 (threads), NIP-22 (comments), NIP-29 (groups), NIP-53 (live activity)
|
||||
*/
|
||||
function getAdapter(protocol: ChatProtocol): ChatProtocolAdapter {
|
||||
switch (protocol) {
|
||||
case "nip-10":
|
||||
return new Nip10Adapter();
|
||||
case "nip-22":
|
||||
return new Nip22Adapter();
|
||||
case "nip-29":
|
||||
return new Nip29Adapter();
|
||||
// case "nip-17": // Phase 2 - Encrypted DMs (coming soon)
|
||||
|
||||
@@ -40,12 +40,90 @@ import { EventFooter } from "@/components/EventFooter";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { isAddressableKind } from "@/lib/nostr-kinds";
|
||||
import { getSemanticAuthor } from "@/lib/semantic-author";
|
||||
import type { ChatProtocol, ProtocolIdentifier } from "@/types/chat";
|
||||
import { EventFactory } from "applesauce-core/event-factory";
|
||||
import { ReactionBlueprint } from "applesauce-common/blueprints";
|
||||
import { publishEventToRelays } from "@/services/hub";
|
||||
import { selectRelaysForInteraction } from "@/services/relay-selection";
|
||||
import type { EmojiTag } from "@/lib/emoji-helpers";
|
||||
|
||||
/**
|
||||
* Determine the chat protocol and identifier for any event.
|
||||
* - Kind 1 → NIP-10 thread
|
||||
* - Kind 30311 → NIP-53 live activity
|
||||
* - Everything else → NIP-22 comments (wildcard)
|
||||
*/
|
||||
function getChatPropsForEvent(
|
||||
event: NostrEvent,
|
||||
relays: string[],
|
||||
): { protocol: ChatProtocol; identifier: ProtocolIdentifier } {
|
||||
// Kind 1: NIP-10 thread
|
||||
if (event.kind === 1) {
|
||||
return {
|
||||
protocol: "nip-10",
|
||||
identifier: {
|
||||
type: "thread",
|
||||
value: {
|
||||
id: event.id,
|
||||
relays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Kind 30311: NIP-53 live activity
|
||||
if (event.kind === 30311) {
|
||||
const dTag = getTagValue(event, "d") || "";
|
||||
return {
|
||||
protocol: "nip-53",
|
||||
identifier: {
|
||||
type: "live-activity",
|
||||
value: {
|
||||
kind: 30311 as const,
|
||||
pubkey: event.pubkey,
|
||||
identifier: dTag,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Addressable events (kinds 10000-19999, 30000-39999): NIP-22 comment-address
|
||||
if (isAddressableKind(event.kind)) {
|
||||
const dTag = getTagValue(event, "d") || "";
|
||||
return {
|
||||
protocol: "nip-22",
|
||||
identifier: {
|
||||
type: "comment-address",
|
||||
value: {
|
||||
kind: event.kind,
|
||||
pubkey: event.pubkey,
|
||||
identifier: dTag,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// All other events: NIP-22 comment by event ID
|
||||
return {
|
||||
protocol: "nip-22",
|
||||
identifier: {
|
||||
type: "comment",
|
||||
value: {
|
||||
id: event.id,
|
||||
kind: event.kind,
|
||||
pubkey: event.pubkey,
|
||||
relay: relays[0],
|
||||
},
|
||||
relays,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Universal event properties and utilities shared across all kind renderers
|
||||
*/
|
||||
@@ -214,26 +292,10 @@ export function EventMenu({
|
||||
};
|
||||
|
||||
const openChatWindow = () => {
|
||||
// Only kind 1 notes support NIP-10 thread chat
|
||||
if (event.kind === 1) {
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
// Open chat with NIP-10 thread protocol
|
||||
addWindow("chat", {
|
||||
protocol: "nip-10",
|
||||
identifier: {
|
||||
type: "thread",
|
||||
value: {
|
||||
id: event.id,
|
||||
relays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
});
|
||||
}
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
const { protocol, identifier } = getChatPropsForEvent(event, relays);
|
||||
addWindow("chat", { protocol, identifier });
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -252,12 +314,10 @@ export function EventMenu({
|
||||
<Zap className="size-4 mr-2 text-yellow-500" />
|
||||
Zap
|
||||
</DropdownMenuItem>
|
||||
{event.kind === 1 && (
|
||||
<DropdownMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
{event.kind === 1 ? "Chat" : "Comments"}
|
||||
</DropdownMenuItem>
|
||||
{canSign && onReactClick && (
|
||||
<DropdownMenuItem onClick={onReactClick}>
|
||||
<SmilePlus className="size-4 mr-2" />
|
||||
@@ -384,26 +444,10 @@ export function EventContextMenu({
|
||||
};
|
||||
|
||||
const openChatWindow = () => {
|
||||
// Only kind 1 notes support NIP-10 thread chat
|
||||
if (event.kind === 1) {
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
|
||||
// Open chat with NIP-10 thread protocol
|
||||
addWindow("chat", {
|
||||
protocol: "nip-10",
|
||||
identifier: {
|
||||
type: "thread",
|
||||
value: {
|
||||
id: event.id,
|
||||
relays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind,
|
||||
},
|
||||
relays,
|
||||
},
|
||||
});
|
||||
}
|
||||
const seenRelaysSet = getSeenRelays(event);
|
||||
const relays = seenRelaysSet ? Array.from(seenRelaysSet) : [];
|
||||
const { protocol, identifier } = getChatPropsForEvent(event, relays);
|
||||
addWindow("chat", { protocol, identifier });
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -418,12 +462,10 @@ export function EventContextMenu({
|
||||
<Zap className="size-4 mr-2 text-yellow-500" />
|
||||
Zap
|
||||
</ContextMenuItem>
|
||||
{event.kind === 1 && (
|
||||
<ContextMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
Chat
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
<ContextMenuItem onClick={openChatWindow}>
|
||||
<MessageSquare className="size-4 mr-2" />
|
||||
{event.kind === 1 ? "Chat" : "Comments"}
|
||||
</ContextMenuItem>
|
||||
{canSign && onReactClick && (
|
||||
<ContextMenuItem onClick={onReactClick}>
|
||||
<SmilePlus className="size-4 mr-2" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ChatCommandResult, GroupListIdentifier } from "@/types/chat";
|
||||
import { Nip10Adapter } from "./chat/adapters/nip-10-adapter";
|
||||
import { Nip22Adapter } from "./chat/adapters/nip-22-adapter";
|
||||
import { Nip29Adapter } from "./chat/adapters/nip-29-adapter";
|
||||
import { Nip53Adapter } from "./chat/adapters/nip-53-adapter";
|
||||
import { nip19 } from "nostr-tools";
|
||||
@@ -16,6 +17,7 @@ import { nip19 } from "nostr-tools";
|
||||
* 3. NIP-28 (channels) - specific event format (kind 40)
|
||||
* 4. NIP-29 (groups) - specific group ID format
|
||||
* 5. NIP-53 (live chat) - specific addressable format (kind 30311)
|
||||
* 6. NIP-22 (comments) - wildcard for all other events/addresses
|
||||
*
|
||||
* @param args - Command arguments (first arg is the identifier)
|
||||
* @returns Parsed result with protocol and identifier
|
||||
@@ -61,12 +63,14 @@ export function parseChatCommand(args: string[]): ChatCommandResult {
|
||||
}
|
||||
|
||||
// Try each adapter in priority order
|
||||
// NIP-22 is last — it's the wildcard catch-all for events not claimed by specific adapters
|
||||
const adapters = [
|
||||
new Nip10Adapter(), // NIP-10 - Thread chat (nevent/note)
|
||||
new Nip10Adapter(), // NIP-10 - Thread chat (nevent/note, kind 1 only)
|
||||
// new Nip17Adapter(), // Phase 2
|
||||
// new Nip28Adapter(), // Phase 3
|
||||
new Nip29Adapter(), // NIP-29 - Relay groups
|
||||
new Nip53Adapter(), // NIP-53 - Live activity chat
|
||||
new Nip53Adapter(), // NIP-53 - Live activity chat (kind 30311)
|
||||
new Nip22Adapter(), // NIP-22 - Comments on any event (wildcard)
|
||||
];
|
||||
|
||||
for (const adapter of adapters) {
|
||||
@@ -84,20 +88,18 @@ export function parseChatCommand(args: string[]): ChatCommandResult {
|
||||
`Unable to determine chat protocol from identifier: ${identifier}
|
||||
|
||||
Currently supported formats:
|
||||
- nevent1.../note1... (NIP-10 thread chat, kind 1 notes)
|
||||
- nevent1... (NIP-22 comments on any event, or NIP-10 thread for kind 1)
|
||||
Examples:
|
||||
chat nevent1qqsxyz... (thread with relay hints)
|
||||
chat note1abc... (thread with event ID only)
|
||||
chat nevent1qqsxyz... (comments/thread with relay hints)
|
||||
chat note1abc... (kind 1 thread with event ID only)
|
||||
- naddr1... (NIP-22 comments on addressable events, NIP-53 for kind 30311)
|
||||
Examples:
|
||||
chat naddr1... (article, repo, wiki, etc.)
|
||||
chat naddr1... (live stream address → NIP-53)
|
||||
- relay.com'group-id (NIP-29 relay group, wss:// prefix optional)
|
||||
Examples:
|
||||
chat relay.example.com'bitcoin-dev
|
||||
chat wss://relay.example.com'nostr-dev
|
||||
- naddr1... (NIP-29 group metadata, kind 39000)
|
||||
Example:
|
||||
chat naddr1qqxnzdesxqmnxvpexqmny...
|
||||
- naddr1... (NIP-53 live activity chat, kind 30311)
|
||||
Example:
|
||||
chat naddr1... (live stream address)
|
||||
- naddr1... (Multi-room group list, kind 10009)
|
||||
Example:
|
||||
chat naddr1... (group list address)
|
||||
|
||||
1041
src/lib/chat/adapters/nip-22-adapter.ts
Normal file
1041
src/lib/chat/adapters/nip-22-adapter.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ import type { EventPointer, AddressPointer } from "nostr-tools/nip19";
|
||||
export const CHAT_KINDS = [
|
||||
9, // NIP-29: Group chat messages
|
||||
9321, // NIP-61: Nutzaps (ecash zaps in groups/live chats)
|
||||
1111, // NIP-22: Comments on any event
|
||||
1311, // NIP-53: Live chat messages
|
||||
9735, // NIP-57: Zap receipts (part of chat context)
|
||||
] as const;
|
||||
@@ -15,12 +16,23 @@ export const CHAT_KINDS = [
|
||||
/**
|
||||
* Chat protocol identifier
|
||||
*/
|
||||
export type ChatProtocol = "nip-17" | "nip-28" | "nip-29" | "nip-53" | "nip-10";
|
||||
export type ChatProtocol =
|
||||
| "nip-17"
|
||||
| "nip-28"
|
||||
| "nip-29"
|
||||
| "nip-53"
|
||||
| "nip-10"
|
||||
| "nip-22";
|
||||
|
||||
/**
|
||||
* Conversation type
|
||||
*/
|
||||
export type ConversationType = "dm" | "channel" | "group" | "live-chat";
|
||||
export type ConversationType =
|
||||
| "dm"
|
||||
| "channel"
|
||||
| "group"
|
||||
| "live-chat"
|
||||
| "comments";
|
||||
|
||||
/**
|
||||
* Participant role in a conversation
|
||||
@@ -83,6 +95,12 @@ export interface ConversationMetadata {
|
||||
providedEventId?: string; // Original event from nevent (may be reply)
|
||||
threadDepth?: number; // Approximate depth of thread
|
||||
relays?: string[]; // Relays for this conversation
|
||||
|
||||
// NIP-22 comments
|
||||
rootEventKind?: number; // Kind of the root event being commented on
|
||||
rootAddress?: string; // "kind:pubkey:d-tag" for addressable root events
|
||||
externalId?: string; // External identifier (NIP-73) for external root scope
|
||||
externalKind?: string; // External identifier type (e.g., "web", "isbn")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,6 +247,51 @@ export interface ThreadIdentifier {
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-22 comment identifier - comments on any event or external resource
|
||||
* Acts as a wildcard for events not handled by NIP-10 or NIP-53
|
||||
*/
|
||||
export interface CommentIdentifier {
|
||||
type: "comment";
|
||||
/** Event pointer (for regular events) */
|
||||
value: {
|
||||
id: string;
|
||||
kind: number;
|
||||
pubkey?: string;
|
||||
relay?: string;
|
||||
};
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-22 comment on an addressable event
|
||||
*/
|
||||
export interface CommentAddressIdentifier {
|
||||
type: "comment-address";
|
||||
/** Address pointer for the root event */
|
||||
value: {
|
||||
kind: number;
|
||||
pubkey: string;
|
||||
identifier: string;
|
||||
};
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* NIP-22 comment on an external resource (NIP-73)
|
||||
*/
|
||||
export interface CommentExternalIdentifier {
|
||||
type: "comment-external";
|
||||
/** External identifier value (URL, ISBN, DOI, etc.) */
|
||||
value: string;
|
||||
/** External identifier type (e.g., "web", "isbn", "doi") */
|
||||
externalKind: string;
|
||||
/** Relay hints */
|
||||
relays?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol-specific identifier - discriminated union
|
||||
* Returned by adapter parseIdentifier()
|
||||
@@ -240,7 +303,10 @@ export type ProtocolIdentifier =
|
||||
| NIP05Identifier
|
||||
| ChannelIdentifier
|
||||
| GroupListIdentifier
|
||||
| ThreadIdentifier;
|
||||
| ThreadIdentifier
|
||||
| CommentIdentifier
|
||||
| CommentAddressIdentifier
|
||||
| CommentExternalIdentifier;
|
||||
|
||||
/**
|
||||
* Chat command parsing result
|
||||
|
||||
@@ -578,15 +578,18 @@ export const manPages: Record<string, ManPageEntry> = {
|
||||
section: "1",
|
||||
synopsis: "chat <identifier>",
|
||||
description:
|
||||
"Join and participate in Nostr chat conversations. Supports NIP-29 relay-based groups, NIP-53 live activity chat, and multi-room group list interface. For NIP-29 groups, use format 'relay'group-id' where relay is the WebSocket URL (wss:// prefix optional). For NIP-53 live activities, pass the naddr of a kind 30311 live event. For multi-room interface, pass the naddr of a kind 10009 group list event.",
|
||||
"Join and participate in Nostr chat conversations. Supports NIP-22 comments on any event, NIP-10 kind 1 threads, NIP-29 relay-based groups, NIP-53 live activity chat, and multi-room group list interface. Pass any nevent or naddr to open a comments view (NIP-22). For kind 1 events, NIP-10 threading is used automatically. For NIP-29 groups, use format 'relay'group-id'. For NIP-53 live activities, pass the naddr of a kind 30311 live event.",
|
||||
options: [
|
||||
{
|
||||
flag: "<identifier>",
|
||||
description:
|
||||
"NIP-29 group (relay'group-id), NIP-53 live activity (naddr1... kind 30311), or group list (naddr1... kind 10009)",
|
||||
"nevent1.../naddr1... (comments/thread), relay'group-id (NIP-29 group), or naddr1... kind 10009 (group list)",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
"chat nevent1... Comments on any event (NIP-22)",
|
||||
"chat naddr1...30023... Comments on an article (NIP-22)",
|
||||
"chat note1... Thread chat on kind 1 note (NIP-10)",
|
||||
"chat relay.example.com'bitcoin-dev Join NIP-29 relay group",
|
||||
"chat wss://nos.lol'welcome Join NIP-29 group with explicit protocol",
|
||||
"chat naddr1...30311... Join NIP-53 live activity chat",
|
||||
|
||||
Reference in New Issue
Block a user