@sherwoodagent/cli 0.29.1 → 0.38.3

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.
Files changed (57) hide show
  1. package/dist/{addresses-NOWMJT4H.js → addresses-6GJP2WAY.js} +4 -4
  2. package/dist/{agent-U6OFXITU.js → agent-TB7VNLFH.js} +1085 -296
  3. package/dist/agent-TB7VNLFH.js.map +1 -0
  4. package/dist/{chat-SIB6GCJF.js → chat-36TB53HK.js} +9 -9
  5. package/dist/{chunk-7W6U6ZC6.js → chunk-4EG4TSRE.js} +6 -6
  6. package/dist/{chunk-UW6P2PMP.js → chunk-6SKMCZ7I.js} +6 -6
  7. package/dist/{chunk-EYI6JORK.js → chunk-B4AH26UI.js} +2 -2
  8. package/dist/{chunk-H32QA3NV.js → chunk-IJG4CTOI.js} +2 -2
  9. package/dist/{chunk-N2547R2L.js → chunk-OFR3LCYE.js} +3 -3
  10. package/dist/{chunk-7PDRYBHD.js → chunk-OPKMVIYJ.js} +4 -4
  11. package/dist/{chunk-7PDRYBHD.js.map → chunk-OPKMVIYJ.js.map} +1 -1
  12. package/dist/{chunk-PQ5ZX6ZT.js → chunk-OQUGUIYM.js} +14 -1
  13. package/dist/{chunk-PQ5ZX6ZT.js.map → chunk-OQUGUIYM.js.map} +1 -1
  14. package/dist/{chunk-OD5JECOR.js → chunk-PNUBECG2.js} +5 -5
  15. package/dist/{chunk-BVL3O7UH.js → chunk-SP2SI63D.js} +5 -5
  16. package/dist/{chunk-RGOTBJIN.js → chunk-WCBG44IQ.js} +9 -1
  17. package/dist/chunk-WCBG44IQ.js.map +1 -0
  18. package/dist/{chunk-C4SYHSY2.js → chunk-XKDB5D4E.js} +5 -5
  19. package/dist/{client-66VTYDRS.js → client-HKAG55PQ.js} +4 -4
  20. package/dist/{config-YXZKPSZB.js → config-LS7FKZL5.js} +4 -2
  21. package/dist/{eas-YTMCD3UN.js → eas-XNLD5PTV.js} +7 -7
  22. package/dist/{governor-2N3CPFOP.js → governor-ZOIXGEVS.js} +7 -7
  23. package/dist/index.js +67 -48
  24. package/dist/index.js.map +1 -1
  25. package/dist/{network-GJA2ZN3O.js → network-KSMKPKNL.js} +3 -3
  26. package/dist/{price-HGBIMFYN.js → price-WGV6NYK3.js} +6 -6
  27. package/dist/research-662HNMOG.js +14 -0
  28. package/dist/{research-ECOWBTFP.js → research-AYT6QDJP.js} +9 -9
  29. package/dist/{session-RTCMOPAQ.js → session-46SXKEKP.js} +11 -11
  30. package/dist/{trade-3HVCELTB.js → trade-LIRSGOV7.js} +17 -17
  31. package/dist/{xmtp-5FPJN5WE.js → xmtp-XQGWSO72.js} +21 -16
  32. package/dist/xmtp-XQGWSO72.js.map +1 -0
  33. package/package.json +7 -5
  34. package/dist/agent-U6OFXITU.js.map +0 -1
  35. package/dist/chunk-RGOTBJIN.js.map +0 -1
  36. package/dist/research-3GNTDKY4.js +0 -14
  37. package/dist/xmtp-5FPJN5WE.js.map +0 -1
  38. /package/dist/{addresses-NOWMJT4H.js.map → addresses-6GJP2WAY.js.map} +0 -0
  39. /package/dist/{chat-SIB6GCJF.js.map → chat-36TB53HK.js.map} +0 -0
  40. /package/dist/{chunk-7W6U6ZC6.js.map → chunk-4EG4TSRE.js.map} +0 -0
  41. /package/dist/{chunk-UW6P2PMP.js.map → chunk-6SKMCZ7I.js.map} +0 -0
  42. /package/dist/{chunk-EYI6JORK.js.map → chunk-B4AH26UI.js.map} +0 -0
  43. /package/dist/{chunk-H32QA3NV.js.map → chunk-IJG4CTOI.js.map} +0 -0
  44. /package/dist/{chunk-N2547R2L.js.map → chunk-OFR3LCYE.js.map} +0 -0
  45. /package/dist/{chunk-OD5JECOR.js.map → chunk-PNUBECG2.js.map} +0 -0
  46. /package/dist/{chunk-BVL3O7UH.js.map → chunk-SP2SI63D.js.map} +0 -0
  47. /package/dist/{chunk-C4SYHSY2.js.map → chunk-XKDB5D4E.js.map} +0 -0
  48. /package/dist/{client-66VTYDRS.js.map → client-HKAG55PQ.js.map} +0 -0
  49. /package/dist/{config-YXZKPSZB.js.map → config-LS7FKZL5.js.map} +0 -0
  50. /package/dist/{eas-YTMCD3UN.js.map → eas-XNLD5PTV.js.map} +0 -0
  51. /package/dist/{governor-2N3CPFOP.js.map → governor-ZOIXGEVS.js.map} +0 -0
  52. /package/dist/{network-GJA2ZN3O.js.map → network-KSMKPKNL.js.map} +0 -0
  53. /package/dist/{price-HGBIMFYN.js.map → price-WGV6NYK3.js.map} +0 -0
  54. /package/dist/{research-3GNTDKY4.js.map → research-662HNMOG.js.map} +0 -0
  55. /package/dist/{research-ECOWBTFP.js.map → research-AYT6QDJP.js.map} +0 -0
  56. /package/dist/{session-RTCMOPAQ.js.map → session-46SXKEKP.js.map} +0 -0
  57. /package/dist/{trade-3HVCELTB.js.map → trade-LIRSGOV7.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["/**\n * Local config management — ~/.sherwood/config.json\n *\n * Stores group ID cache, per-chain contract addresses, and wallet config.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".sherwood\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\n/** Per-chain user-specific addresses (stored by chainId). */\nexport interface ChainContracts {\n vault?: string; // user's default vault address\n}\n\n/** A syndicate the agent belongs to (creator or member). */\nexport interface SyndicateMembership {\n subdomain: string;\n vault: string;\n role: \"creator\" | \"agent\";\n}\n\nexport interface SherwoodConfig {\n dbEncryptionKey?: string; // legacy — no longer used, XMTP CLI manages its own DB\n privateKey?: string; // wallet private key (0x-prefixed)\n xmtpInboxId?: string;\n groupCache: Record<string, string>; // subdomain → XMTP group ID\n veniceApiKey?: string; // Venice AI inference API key\n agentId?: number; // ERC-8004 identity token ID\n contracts?: Record<string, ChainContracts>; // chainId → user addresses\n syndicates?: Record<string, SyndicateMembership[]>; // chainId → syndicate memberships\n primarySyndicate?: Record<string, string>; // chainId → subdomain of the active syndicate\n rpc?: Record<string, string>; // network name → custom RPC URL\n notifyTo?: string; // destination for cron summaries (Telegram chat ID, phone, etc.)\n uniswapApiKey?: string; // Uniswap Trading API key (from developers.uniswap.org)\n positions?: unknown[]; // open trade positions (typed in positions.ts)\n closedPositions?: unknown[]; // historical closed positions\n _xmtpMigrated?: boolean; // one-time flag: revoked stale installations from ~/.xmtp/ era\n /** Cached swap routes per chain: chainId → { tokenPair → SwapRoute } */\n swapRoutes?: Record<string, Record<string, SwapRoute>>;\n}\n\n/** Persisted swap route detected by the CLI during portfolio strategy proposal. */\nexport interface SwapRoute {\n mode: \"direct\" | \"multi-hop\";\n feeTier: number; // direct pool fee tier\n hop?: { via: string; feeIn: number; feeOut: number }; // multi-hop details\n detectedAt: number; // unix timestamp\n}\n\nexport function loadConfig(): SherwoodConfig {\n if (fs.existsSync(CONFIG_PATH)) {\n const config = JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n if (!config.groupCache) config.groupCache = {};\n return config;\n }\n\n return { groupCache: {} };\n}\n\nexport function saveConfig(config: SherwoodConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n}\n\nexport function cacheGroupId(subdomain: string, groupId: string): void {\n const config = loadConfig();\n config.groupCache[subdomain] = groupId;\n saveConfig(config);\n}\n\nexport function getCachedGroupId(subdomain: string): string | undefined {\n const config = loadConfig();\n return config.groupCache[subdomain];\n}\n\nexport function setVeniceApiKey(apiKey: string): void {\n const config = loadConfig();\n config.veniceApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getVeniceApiKey(): string | undefined {\n return loadConfig().veniceApiKey ?? process.env.VENICE_API_KEY;\n}\n\nexport function setAgentId(agentId: number): void {\n const config = loadConfig();\n config.agentId = agentId;\n saveConfig(config);\n}\n\nexport function getAgentId(): number | undefined {\n return loadConfig().agentId;\n}\n\nexport function setPrivateKey(key: string): void {\n const config = loadConfig();\n config.privateKey = key.startsWith(\"0x\") ? key : `0x${key}`;\n saveConfig(config);\n}\n\nexport function getPrivateKey(): string | undefined {\n return loadConfig().privateKey;\n}\n\n// ── Uniswap Trading API Key ──\n\nexport function setUniswapApiKey(apiKey: string): void {\n const config = loadConfig();\n config.uniswapApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getUniswapApiKey(): string | undefined {\n return loadConfig().uniswapApiKey ?? process.env.UNISWAP_API_KEY;\n}\n\n// ── Per-network RPC URLs ──\n\nexport function getConfigRpcUrl(network: string): string | undefined {\n return loadConfig().rpc?.[network];\n}\n\nexport function setConfigRpcUrl(network: string, url: string): void {\n const config = loadConfig();\n if (!config.rpc) config.rpc = {};\n config.rpc[network] = url;\n saveConfig(config);\n}\n\n// ── Per-chain contract addresses ──\n\nexport function getChainContracts(chainId: number): ChainContracts {\n const config = loadConfig();\n return config.contracts?.[String(chainId)] ?? {};\n}\n\nexport function getNotifyTo(): string | undefined {\n return loadConfig().notifyTo;\n}\n\nexport function setNotifyTo(id: string): void {\n const config = loadConfig();\n config.notifyTo = id;\n saveConfig(config);\n}\n\nexport function setChainContract(\n chainId: number,\n key: keyof ChainContracts,\n value: string,\n): void {\n const config = loadConfig();\n if (!config.contracts) config.contracts = {};\n const cid = String(chainId);\n if (!config.contracts[cid]) config.contracts[cid] = {};\n config.contracts[cid][key] = value;\n saveConfig(config);\n}\n\n// ── Syndicate Membership ──\n\n/**\n * Add (or update) a syndicate membership. Deduplicates by subdomain.\n * Automatically sets it as primary if it's the first syndicate on this chain.\n */\nexport function addSyndicate(\n chainId: number,\n membership: SyndicateMembership,\n): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.syndicates) config.syndicates = {};\n if (!config.syndicates[cid]) config.syndicates[cid] = [];\n\n // Upsert — replace existing entry with same subdomain\n const idx = config.syndicates[cid].findIndex(\n (s) => s.subdomain === membership.subdomain,\n );\n if (idx >= 0) {\n config.syndicates[cid][idx] = membership;\n } else {\n config.syndicates[cid].push(membership);\n }\n\n // Auto-set as primary if it's the first syndicate (or no primary set)\n if (!config.primarySyndicate) config.primarySyndicate = {};\n if (!config.primarySyndicate[cid]) {\n config.primarySyndicate[cid] = membership.subdomain;\n }\n\n saveConfig(config);\n}\n\n/** Get all syndicate memberships for a chain. */\nexport function getSyndicates(chainId: number): SyndicateMembership[] {\n const config = loadConfig();\n return config.syndicates?.[String(chainId)] ?? [];\n}\n\n/** Set which syndicate is the active/primary one for CLI commands. */\nexport function setPrimarySyndicate(\n chainId: number,\n subdomain: string,\n): void {\n const config = loadConfig();\n if (!config.primarySyndicate) config.primarySyndicate = {};\n config.primarySyndicate[String(chainId)] = subdomain;\n saveConfig(config);\n}\n\n/**\n * Get the primary syndicate for this chain.\n * Falls back to ChainContracts.vault for backwards compat with older configs.\n */\nexport function getPrimarySyndicate(\n chainId: number,\n): SyndicateMembership | undefined {\n const config = loadConfig();\n const cid = String(chainId);\n\n // Check new syndicates store first\n const primarySubdomain = config.primarySyndicate?.[cid];\n if (primarySubdomain && config.syndicates?.[cid]) {\n const found = config.syndicates[cid].find(\n (s) => s.subdomain === primarySubdomain,\n );\n if (found) return found;\n }\n\n // Backwards compat: if syndicates list has entries but no primary, use the first one\n if (config.syndicates?.[cid]?.length) {\n return config.syndicates[cid][0];\n }\n\n // Legacy fallback: config only has a vault address, no subdomain\n const vault = config.contracts?.[cid]?.vault;\n if (vault) {\n return { subdomain: \"\", vault, role: \"creator\" };\n }\n\n return undefined;\n}\n\n// ── Swap Route Cache ──\n\nfunction swapRouteKey(asset: string, token: string): string {\n return `${asset.toLowerCase()}→${token.toLowerCase()}`;\n}\n\n/** Get a cached swap route for a token pair on a chain. */\nexport function getCachedSwapRoute(chainId: number, asset: string, token: string): SwapRoute | undefined {\n const config = loadConfig();\n return config.swapRoutes?.[String(chainId)]?.[swapRouteKey(asset, token)];\n}\n\n/** Save a detected swap route to the config cache. */\nexport function cacheSwapRoute(chainId: number, asset: string, token: string, route: SwapRoute): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.swapRoutes) config.swapRoutes = {};\n if (!config.swapRoutes[cid]) config.swapRoutes[cid] = {};\n config.swapRoutes[cid][swapRouteKey(asset, token)] = route;\n saveConfig(config);\n}\n\n/** Clear all cached swap routes for a chain (e.g. after pool migration). */\nexport function clearSwapRoutes(chainId: number): void {\n const config = loadConfig();\n delete config.swapRoutes?.[String(chainId)];\n saveConfig(config);\n}\n"],"mappings":"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","names":[]}
@@ -1,14 +0,0 @@
1
- import {
2
- MessariProvider,
3
- NansenProvider,
4
- getResearchProvider
5
- } from "./chunk-EYI6JORK.js";
6
- import "./chunk-N2547R2L.js";
7
- import "./chunk-H32QA3NV.js";
8
- import "./chunk-RGOTBJIN.js";
9
- export {
10
- MessariProvider,
11
- NansenProvider,
12
- getResearchProvider
13
- };
14
- //# sourceMappingURL=research-3GNTDKY4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/xmtp.ts"],"sourcesContent":["/**\n * XMTP client and group operations for syndicate chat.\n *\n * Uses @xmtp/node-sdk directly with a singleton Client instance.\n * Deterministic DB path (~/.sherwood/xmtp/) and encryption key derived\n * from the sherwood private key via keccak256.\n *\n * This replaces the previous @xmtp/cli subprocess architecture which\n * caused stale MLS installations (issue #110).\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { homedir } from \"node:os\";\nimport {\n Client,\n ConsentState,\n Group,\n GroupPermissionsOptions,\n IdentifierKind,\n type CreateGroupOptions,\n type DecodedMessage,\n type Identifier,\n type NetworkOptions,\n type Signer,\n type XmtpEnv,\n} from \"@xmtp/node-sdk\";\nimport { keccak256, toBytes } from \"viem\";\nimport {\n loadConfig,\n saveConfig,\n cacheGroupId,\n getCachedGroupId,\n} from \"./config.js\";\nimport { getTextRecord } from \"./ens.js\";\nimport { getChainConfig } from \"./network.js\";\nimport type { ChatEnvelope } from \"./types.js\";\nimport { getAccount } from \"./client.js\";\n\n// ── Types ──\n\nexport interface XmtpMessage {\n id: string;\n conversationId: string;\n senderInboxId: string;\n contentType: string;\n content: string;\n sentAt: Date;\n}\n\nexport interface XmtpMember {\n inboxId: string;\n permissionLevel: string;\n}\n\n// ── Internal helpers ──\n\nlet _client: Client | null = null;\n\nfunction getXmtpEnv(): string {\n return getChainConfig().xmtpEnv;\n}\n\nfunction getDbEncryptionKey(privateKey: string): Uint8Array {\n const hash = keccak256(toBytes(privateKey + \"xmtp-db-key\"));\n return toBytes(hash);\n}\n\nfunction getDbPath(): string {\n const dir = path.join(homedir(), \".sherwood\", \"xmtp\");\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n return path.join(dir, \"xmtp.db3\");\n}\n\nfunction ethIdentifier(address: string): Identifier {\n return {\n identifier: address.toLowerCase(),\n identifierKind: IdentifierKind.Ethereum,\n };\n}\n\nasync function getOrCreateClient(): Promise<Client> {\n if (_client) return _client;\n\n const config = loadConfig();\n if (!config.privateKey) {\n throw new Error(\n 'No private key configured. Run \"sherwood config set --private-key 0x...\"',\n );\n }\n\n const account = getAccount();\n\n const signer: Signer = {\n type: \"EOA\",\n getIdentifier: () => ({\n identifier: account.address.toLowerCase(),\n identifierKind: IdentifierKind.Ethereum,\n }),\n signMessage: async (message: string) => {\n const signature = await account.signMessage({ message });\n return toBytes(signature);\n },\n };\n\n const clientOptions: NetworkOptions = {\n env: getXmtpEnv() as XmtpEnv,\n };\n _client = await Client.create(signer, {\n ...clientOptions,\n dbEncryptionKey: getDbEncryptionKey(config.privateKey),\n dbPath: getDbPath(),\n });\n\n // Sync all conversations on first connect (processes MLS welcome messages)\n await _client.conversations.syncAll([ConsentState.Allowed]);\n\n // One-time migration: revoke stale installations from the old ~/.xmtp/ era\n if (!config._xmtpMigrated) {\n try {\n await _client.revokeAllOtherInstallations();\n } catch {\n // Non-fatal — stale installations are a UX issue, not a blocker\n }\n config._xmtpMigrated = true;\n saveConfig(config);\n }\n\n return _client;\n}\n\n// ── Client ──\n\nexport async function getXmtpClient(): Promise<string> {\n const client = await getOrCreateClient();\n\n // Cache inbox ID\n const config = loadConfig();\n if (!config.xmtpInboxId && client.inboxId) {\n config.xmtpInboxId = client.inboxId;\n saveConfig(config);\n }\n\n return client.inboxId;\n}\n\n// ── Group Creation ──\n\nexport async function createSyndicateGroup(\n _client: string,\n subdomain: string,\n isPublic: boolean = false,\n): Promise<string> {\n const client = await getOrCreateClient();\n\n const group = await client.conversations.createGroup([], {\n name: subdomain,\n description: `Sherwood syndicate: ${subdomain}.sherwoodagent.eth`,\n permissionLevel: GroupPermissionsOptions.AdminOnly,\n } as CreateGroupOptions);\n\n const groupId = group.id;\n if (!groupId) {\n throw new Error(\"Failed to create XMTP group — no group ID returned\");\n }\n\n // Add spectator if requested — enables dashboard live feed\n const SPECTATOR_ADDRESS =\n process.env.DASHBOARD_SPECTATOR_ADDRESS ||\n \"0x9f6518e69a62c526ead155ad2661f5957b6b2fc3\";\n if (isPublic) {\n await addMember(groupId, SPECTATOR_ADDRESS);\n }\n\n // Cache locally\n cacheGroupId(subdomain, groupId);\n\n return groupId;\n}\n\n// ── Group Lookup ──\n\nexport async function getGroup(\n _client: string,\n subdomain: string,\n): Promise<string> {\n const client = await getOrCreateClient();\n\n // Sync to get latest conversations (including MLS welcome messages)\n await client.conversations.syncAll([ConsentState.Allowed]);\n\n // Try local cache\n let groupId: string | undefined = getCachedGroupId(subdomain);\n\n // Validate cached ID actually exists in the local DB\n if (groupId) {\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) {\n cacheGroupId(subdomain, \"\"); // invalidate stale entry\n groupId = undefined;\n }\n }\n\n // Fall back to on-chain ENS text record\n if (!groupId) {\n const ensId = await getTextRecord(subdomain, \"xmtpGroupId\");\n if (ensId) {\n const conv = await client.conversations.getConversationById(ensId);\n if (conv) {\n groupId = ensId;\n cacheGroupId(subdomain, groupId);\n }\n }\n }\n\n // Last resort: search synced conversations by name\n if (!groupId) {\n const groups = client.conversations.listGroups();\n const match = groups.find(\n (g) =>\n g.name === subdomain ||\n g.description?.includes(`${subdomain}.sherwoodagent.eth`),\n );\n if (match) {\n groupId = match.id;\n cacheGroupId(subdomain, groupId);\n }\n }\n\n if (!groupId) {\n throw new Error(\n `No XMTP group found for syndicate \"${subdomain}\". Run \"sherwood chat ${subdomain} init\" to create one.`,\n );\n }\n\n return groupId;\n}\n\n// ── Member Management ──\n\nexport async function addMember(\n groupId: string,\n address: string,\n): Promise<void> {\n const client = await getOrCreateClient();\n\n // Verify the target has an active XMTP identity before adding\n const reachable = await client.canMessage([ethIdentifier(address)]);\n // Try both original and lowercased as map key\n const isReachable =\n reachable.get(address) ?? reachable.get(address.toLowerCase()) ?? false;\n if (!isReachable) {\n throw new Error(\n `${address} is not reachable on XMTP. They need to initialize their client first.`,\n );\n }\n\n await client.conversations.syncAll([ConsentState.Allowed]);\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) throw new Error(`Conversation ${groupId} not found`);\n\n // Cast to Group — we know syndicate conversations are always groups\n const group = conv as Group;\n await group.addMembersByIdentifiers([ethIdentifier(address)]);\n\n // Set consent to \"allowed\" so subsequent operations don't skip this conversation\n try {\n group.updateConsentState(ConsentState.Allowed);\n } catch {\n // Non-fatal — consent state is a filtering concern, not a blocker\n }\n}\n\nexport async function removeMember(\n groupId: string,\n address: string,\n): Promise<void> {\n const client = await getOrCreateClient();\n await client.conversations.syncAll([ConsentState.Allowed]);\n\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) throw new Error(`Conversation ${groupId} not found`);\n\n // Cast to Group — we know syndicate conversations are always groups\n const group = conv as Group;\n await group.removeMembersByIdentifiers([ethIdentifier(address)]);\n}\n\n// ── Messaging ──\n\nexport async function sendEnvelope(\n groupId: string,\n envelope: ChatEnvelope,\n): Promise<void> {\n const client = await getOrCreateClient();\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) throw new Error(`Conversation ${groupId} not found`);\n\n const text = JSON.stringify(envelope);\n await conv.sendText(text);\n}\n\nexport async function sendMarkdown(\n groupId: string,\n markdown: string,\n): Promise<void> {\n const envelope: ChatEnvelope = {\n type: \"MESSAGE\",\n from: getAccount().address,\n text: markdown,\n data: { format: \"markdown\" },\n timestamp: Math.floor(Date.now() / 1000),\n };\n await sendEnvelope(groupId, envelope);\n}\n\nexport async function sendReaction(\n groupId: string,\n messageId: string,\n emoji: string,\n): Promise<void> {\n const envelope: ChatEnvelope = {\n type: \"REACTION\",\n from: getAccount().address,\n data: { reference: messageId, emoji },\n timestamp: Math.floor(Date.now() / 1000),\n };\n await sendEnvelope(groupId, envelope);\n}\n\n// ── Streaming ──\n\nexport async function streamMessages(\n groupId: string,\n onMessage: (msg: XmtpMessage) => void,\n): Promise<() => void> {\n const client = await getOrCreateClient();\n\n const stream = await client.conversations.streamAllMessages({\n consentStates: [ConsentState.Allowed],\n });\n\n let stopped = false;\n\n // Consume stream in background\n (async () => {\n try {\n for await (const message of stream) {\n if (stopped) break;\n // Filter to our group\n if (message.conversationId !== groupId) continue;\n\n onMessage({\n id: message.id || \"\",\n conversationId: message.conversationId || \"\",\n senderInboxId: message.senderInboxId || \"\",\n contentType:\n typeof message.contentType === \"object\"\n ? (message.contentType as { typeId?: string })?.typeId || \"text\"\n : String(message.contentType || \"text\"),\n content:\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content),\n sentAt: message.sentAt || new Date(),\n });\n }\n } catch {\n // Stream ended or errored — expected on cleanup\n }\n })();\n\n // Return cleanup function\n return () => {\n stopped = true;\n try {\n // AsyncStreamProxy exposes end() to terminate the stream\n if (typeof (stream as any).end === \"function\") {\n (stream as any).end();\n } else if (typeof (stream as any).return === \"function\") {\n (stream as any).return();\n }\n } catch {\n // Best-effort cleanup\n }\n };\n}\n\n// ── Message History ──\n\nexport async function getRecentMessages(\n groupId: string,\n limit: number = 20,\n): Promise<XmtpMessage[]> {\n const client = await getOrCreateClient();\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) throw new Error(`Conversation ${groupId} not found`);\n\n // Sync to get latest messages\n await conv.sync();\n\n const rawMessages = await conv.messages({ limit });\n\n return rawMessages.map((m) => ({\n id: m.id || \"\",\n conversationId: m.conversationId || \"\",\n senderInboxId: m.senderInboxId || \"\",\n contentType:\n typeof m.contentType === \"object\"\n ? (m.contentType as { typeId?: string })?.typeId || \"text\"\n : String(m.contentType || \"text\"),\n content:\n typeof m.content === \"string\"\n ? m.content\n : JSON.stringify(m.content),\n sentAt: m.sentAt || new Date(),\n }));\n}\n\n// ── Members ──\n\nexport async function getMembers(\n groupId: string,\n): Promise<XmtpMember[]> {\n const client = await getOrCreateClient();\n const conv = await client.conversations.getConversationById(groupId);\n if (!conv) throw new Error(`Conversation ${groupId} not found`);\n\n const members = await conv.members();\n\n return (Array.isArray(members) ? members : []).map((m: any) => ({\n inboxId: String(m.inboxId || \"\"),\n permissionLevel:\n m.permissionLevel === 2\n ? \"super_admin\"\n : m.permissionLevel === 1\n ? \"admin\"\n : \"member\",\n }));\n}\n"],"mappings":"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","names":["_client"]}