open source is social v-it.org
0
fork

Configure Feed

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

at main 144 lines 4.9 kB view raw
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4import { requireDid, loadConfig } from '../lib/config.js'; 5import { restoreAgent } from '../lib/oauth.js'; 6import { readFollowing, writeFollowing } from '../lib/vit-dir.js'; 7import { mark } from '../lib/brand.js'; 8import { jsonOk, jsonError } from '../lib/json-output.js'; 9import { formatError } from '../lib/error-format.js'; 10 11export default function register(program) { 12 program 13 .command('follow') 14 .argument('<handle>', 'Handle to follow (e.g. alice.bsky.social)') 15 .description('Add an account to this project\'s following list') 16 .option('-v, --verbose', 'Show step-by-step details') 17 .option('--json', 'Output as JSON') 18 .option('--did <did>', 'DID to use for handle resolution') 19 .action(async (handle, opts) => { 20 try { 21 const { verbose } = opts; 22 const vlog = opts.json ? (...a) => console.error(...a) : console.log; 23 handle = handle.replace(/^@/, ''); 24 25 if (opts.json && !(opts.did || loadConfig().did)) { 26 jsonError('no DID configured', "run 'vit login <handle>' first"); 27 return; 28 } 29 const did = requireDid(opts); 30 if (!did) return; 31 if (verbose) vlog(`[verbose] DID: ${did}`); 32 33 const list = readFollowing(); 34 if (list.some(e => e.handle === handle)) { 35 if (opts.json) { 36 jsonError(`already following ${handle}`); 37 return; 38 } 39 console.error(`already following ${handle}`); 40 process.exitCode = 1; 41 return; 42 } 43 44 const { agent } = await restoreAgent(did); 45 if (verbose) vlog('[verbose] session restored'); 46 47 const resolved = await agent.resolveHandle({ handle }); 48 const targetDid = resolved.data.did; 49 if (verbose) vlog(`[verbose] resolved ${handle} to ${targetDid}`); 50 51 list.push({ handle, did: targetDid, followedAt: new Date().toISOString() }); 52 writeFollowing(list); 53 if (opts.json) { 54 jsonOk({ handle, did: targetDid, followedAt: list[list.length - 1].followedAt }); 55 return; 56 } 57 console.log(`${mark} following ${handle} (${targetDid})`); 58 } catch (err) { 59 if (opts.json) { 60 jsonError(err); 61 return; 62 } 63 console.error(formatError(err, { verbose: opts.verbose })); 64 process.exitCode = 1; 65 } 66 }); 67 68 program 69 .command('unfollow') 70 .argument('<handle>', 'Handle to unfollow (e.g. alice.bsky.social)') 71 .description('Remove an account from this project\'s following list') 72 .option('-v, --verbose', 'Show step-by-step details') 73 .option('--json', 'Output as JSON') 74 .action(async (handle, opts) => { 75 try { 76 const { verbose } = opts; 77 const vlog = opts.json ? (...a) => console.error(...a) : console.log; 78 handle = handle.replace(/^@/, ''); 79 80 const list = readFollowing(); 81 const filtered = list.filter(e => e.handle !== handle); 82 if (filtered.length === list.length) { 83 if (opts.json) { 84 jsonError(`not following ${handle}`); 85 return; 86 } 87 console.error(`not following ${handle}`); 88 process.exitCode = 1; 89 return; 90 } 91 92 writeFollowing(filtered); 93 if (verbose) vlog(`[verbose] removed ${handle} from following list`); 94 if (opts.json) { 95 jsonOk({ handle }); 96 return; 97 } 98 console.log(`${mark} unfollowed ${handle}`); 99 } catch (err) { 100 if (opts.json) { 101 jsonError(err); 102 return; 103 } 104 console.error(formatError(err, { verbose: opts.verbose })); 105 process.exitCode = 1; 106 } 107 }); 108 109 program 110 .command('following') 111 .description('List accounts in this project\'s following list') 112 .option('-v, --verbose', 'Show step-by-step details') 113 .option('--json', 'Output as JSON') 114 .action(async (opts) => { 115 try { 116 const list = readFollowing(); 117 if (list.length === 0) { 118 if (opts.json) { 119 jsonOk({ following: [], hint: "run 'vit follow <handle>' to add accounts" }); 120 return; 121 } 122 console.log('not following anyone yet.'); 123 console.log(''); 124 console.log("run 'vit follow <handle>' to start seeing what people are shipping."); 125 console.log("try 'vit scan' to discover active publishers on the network."); 126 return; 127 } 128 if (opts.json) { 129 jsonOk({ following: list }); 130 return; 131 } 132 for (const e of list) { 133 console.log(`${e.handle} (${e.did})`); 134 } 135 } catch (err) { 136 if (opts.json) { 137 jsonError(err); 138 return; 139 } 140 console.error(formatError(err, { verbose: opts.verbose })); 141 process.exitCode = 1; 142 } 143 }); 144}