This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Improve island not-found message with suggestions

When an island ID is not found, suggest similar IDs or tell user
to list available islands.

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta Code <noreply@letta.com>

author
nandi
co-author
Letta Code
date (May 15, 2026, 6:45 AM UTC) commit 5c14f630 parent f346b26e
+19 -12
+19 -12
src/island-discover.ts
··· 17 17 import { createHash } from 'node:crypto'; 18 18 import { Database } from 'bun:sqlite'; 19 19 import { loadDotEnv } from './cli-utils.js'; 20 - import { islandId, domainFromUrl } from './island-shared.js'; 20 + import { islandId, domainFromUrl, computeCentroid, type Component } from './island-shared.js'; 21 21 22 22 const __dirname = dirname(fileURLToPath(import.meta.url)); 23 23 await loadDotEnv(resolve(__dirname, '..', '.env')); ··· 27 27 const DB_PATH = process.env.ISLAND_DETECT_DB ?? resolve(CARRY_DIR, '.island-detect.db'); 28 28 const COLLECTION = 'network.cosmik.connection'; 29 29 const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour 30 - 31 - interface Component { 32 - nodes: Set<string>; 33 - dids: Set<string>; 34 - lexmin: string; 35 - islandId: string; 36 - } 37 30 38 31 // --- SQLite --- 39 32 ··· 203 196 } 204 197 } 205 198 const lexmin = [...compNodes].sort()[0]; 206 - components.push({ nodes: compNodes, dids: compDids, lexmin, islandId: islandId(lexmin) }); 199 + const centroid = computeCentroid(adj, compNodes); 200 + components.push({ nodes: compNodes, dids: compDids, lexmin, centroid, islandId: islandId(centroid) }); 207 201 } 208 202 209 203 return components.sort((a, b) => b.nodes.size - a.nodes.size); ··· 261 255 // Show a specific island by ID 262 256 if (targetId) { 263 257 const comp = components.find((c) => c.islandId === targetId); 264 - if (!comp) { console.error(`Island ${targetId} not found`); process.exit(1); } 258 + if (!comp) { 259 + console.error(`Island ${targetId} not found.`); 260 + // Suggest similar IDs 261 + const similar = filtered.filter((c) => c.islandId.startsWith(targetId.slice(0, 4))); 262 + if (similar.length > 0) { 263 + console.error(`Similar IDs:`); 264 + for (const s of similar.slice(0, 5)) console.error(` ${s.islandId} ${s.nodes.size} nodes ${domainFromUrl(s.centroid ?? s.lexmin)}`); 265 + } else { 266 + console.error(`Run without args to list available islands.`); 267 + } 268 + process.exit(1); 269 + } 265 270 const didPlaceholders = [...comp.dids].map(() => '?').join(','); 266 271 const didRows = db.query(`SELECT did, handle, edge_count FROM dids WHERE did IN (${didPlaceholders})`).all(...comp.dids) as Array<{ did: string; handle: string | null; edge_count: number }>; 267 272 if (wantJson) { 268 273 console.log(JSON.stringify({ 269 274 id: comp.islandId, 275 + centroid: comp.centroid, 270 276 lexmin: comp.lexmin, 271 277 nodeCount: comp.nodes.size, 272 278 didCount: comp.dids.size, ··· 275 281 }, null, 2)); 276 282 } else { 277 283 console.log(`Island ${comp.islandId}: ${comp.nodes.size} nodes, ${comp.dids.size} DIDs`); 278 - console.log(`Lexmin: ${comp.lexmin}`); 284 + console.log(`Centroid: ${comp.centroid}`); 279 285 console.log('\nNodes:'); 280 286 for (const url of [...comp.nodes].sort()) console.log(` ${url}`); 281 287 console.log('\nDIDs:'); ··· 293 299 componentCount: filtered.length, 294 300 components: filtered.map((c) => ({ 295 301 id: c.islandId, 302 + centroid: c.centroid, 296 303 lexmin: c.lexmin, 297 304 nodeCount: c.nodes.size, 298 305 didCount: c.dids.size, ··· 308 315 console.log(`Connected components (>= ${minSize} nodes): ${filtered.length}\n`); 309 316 310 317 for (const comp of filtered.slice(0, 30)) { 311 - const domain = domainFromUrl(comp.lexmin); 318 + const domain = domainFromUrl(comp.centroid); 312 319 console.log(`${comp.islandId} ${comp.nodes.size} nodes, ${comp.dids.size} DIDs ${domain}`); 313 320 } 314 321