open source is social v-it.org
at main 185 lines 7.3 kB view raw
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4import { requireDid } from '../lib/config.js'; 5import { CAP_COLLECTION } from '../lib/constants.js'; 6import { restoreAgent } from '../lib/oauth.js'; 7import { readBeaconSet, readFollowing, readLog } from '../lib/vit-dir.js'; 8import { requireAgent, detectCodingAgent } from '../lib/agent.js'; 9import { shouldBypassVet } from '../lib/trust-gate.js'; 10import { resolveRef, REF_PATTERN } from '../lib/cap-ref.js'; 11import { brand, name } from '../lib/brand.js'; 12import { resolvePds, listRecordsFromPds, batchQuery } from '../lib/pds.js'; 13import { loadConfig } from '../lib/config.js'; 14import { jsonOk, jsonError } from '../lib/json-output.js'; 15 16export default function register(program) { 17 program 18 .command('remix') 19 .argument('<ref>', 'Three-word cap reference (e.g. fast-cache-invalidation)') 20 .description('Derive a vetted cap into the local codebase') 21 .option('--did <did>', 'DID to use') 22 .option('--json', 'Output as JSON') 23 .option('-v, --verbose', 'Show step-by-step details') 24 .action(async (ref, opts) => { 25 try { 26 const gate = requireAgent(); 27 if (!gate.ok) { 28 if (opts.json) { 29 jsonError('agent required', 'run vit remix from a coding agent'); 30 return; 31 } 32 console.error(`${name} remix should be run by a coding agent (e.g. claude code, gemini cli).`); 33 console.error(`open your agent and ask it to run '${name} remix' for you.`); 34 process.exitCode = 1; 35 return; 36 } 37 38 const { verbose } = opts; 39 const vlog = opts.json ? (...a) => console.error(...a) : console.log; 40 41 if (!REF_PATTERN.test(ref)) { 42 if (opts.json) { 43 jsonError('invalid ref', 'expected three lowercase words with dashes'); 44 return; 45 } 46 console.error('invalid ref. expected three lowercase words with dashes (e.g. fast-cache-invalidation)'); 47 process.exitCode = 1; 48 return; 49 } 50 51 if (opts.json && !(opts.did || loadConfig().did)) { 52 jsonError('no DID configured', "run 'vit login <handle>' first"); 53 return; 54 } 55 const did = requireDid(opts); 56 if (!did) return; 57 if (verbose) vlog(`[verbose] DID: ${did}`); 58 59 const beaconSet = readBeaconSet(); 60 if (beaconSet.size === 0) { 61 if (opts.json) { 62 jsonError('no beacon set', "run 'vit init' first"); 63 return; 64 } 65 console.error(`no beacon set. run '${name} init' in a project directory first.`); 66 process.exitCode = 1; 67 return; 68 } 69 if (verbose) vlog(`[verbose] beacons: ${[...beaconSet].join(', ')}`); 70 71 const trusted = readLog('trusted.jsonl'); 72 const trustedEntry = trusted.find(e => e.ref === ref); 73 if (!trustedEntry) { 74 const trustGate = shouldBypassVet(); 75 if (!trustGate.bypass) { 76 if (opts.json) { 77 jsonError(`cap '${ref}' is not trusted`, `tell your operator to run 'vit vet ${ref} --trust'`); 78 return; 79 } 80 console.error(`cap '${ref}' is not trusted. tell your operator to vet it first:`); 81 console.error(''); 82 console.error(` vit vet ${ref}`); 83 console.error(''); 84 console.error('after reviewing, they can trust it with:'); 85 console.error(''); 86 console.error(` vit vet ${ref} --trust`); 87 if (detectCodingAgent()) { 88 console.error(''); 89 console.error('or, to trust all items without review:'); 90 console.error(''); 91 console.error(' vit vet --dangerous-accept --confirm'); 92 } 93 process.exitCode = 1; 94 return; 95 } 96 if (verbose) vlog(`[verbose] vet gate bypassed: ${trustGate.reason}`); 97 } 98 if (verbose && trustedEntry) vlog(`[verbose] trusted entry found, uri: ${trustedEntry.uri}`); 99 100 const { agent } = await restoreAgent(did); 101 if (verbose) vlog('[verbose] session restored'); 102 103 const following = readFollowing(); 104 const dids = following.map(e => e.did); 105 dids.push(did); 106 107 const allRecords = await batchQuery(dids, async (repoDid) => { 108 const pds = await resolvePds(repoDid); 109 if (verbose) vlog(`[verbose] ${repoDid}: resolved PDS ${pds}`); 110 return (await listRecordsFromPds(pds, repoDid, CAP_COLLECTION, 50)).records; 111 }, { verbose }); 112 113 let match = null; 114 for (const records of allRecords) { 115 for (const rec of records) { 116 if (!beaconSet.has(rec.value.beacon)) continue; 117 const recRef = resolveRef(rec.value, rec.cid); 118 if (recRef === ref) { 119 if (!match || (rec.value.createdAt || '') > (match.value.createdAt || '')) { 120 match = rec; 121 } 122 } 123 } 124 } 125 126 if (!match) { 127 if (opts.json) { 128 jsonError(`no cap found with ref '${ref}' for this beacon`); 129 return; 130 } 131 console.error(`no cap found with ref '${ref}' for this beacon.`); 132 console.error(''); 133 console.error('hint: caps only appear from accounts you follow and your own.'); 134 console.error(` vit following check who you're following`); 135 console.error(` vit explore cap ${ref} search the network-wide index`); 136 process.exitCode = 1; 137 return; 138 } 139 140 const record = match.value; 141 const author = match.uri.split('/')[2]; 142 const title = record.title || ref; 143 const description = record.description || ''; 144 const text = record.text || ''; 145 146 if (opts.json) { 147 jsonOk({ ref, author, title, description, text }); 148 return; 149 } 150 151 console.log(`# ${brand} remix: ${title}`); 152 console.log(''); 153 console.log(`ref: ${ref}`); 154 console.log(`author: ${author}`); 155 if (description) console.log(`description: ${description}`); 156 console.log(''); 157 console.log('---'); 158 console.log(''); 159 console.log('you are remixing a vetted cap into the current codebase.'); 160 console.log('create a thorough implementation plan that:'); 161 console.log(''); 162 console.log('1. adapts the cap to this repo\'s architecture, conventions, and existing code'); 163 console.log('2. follows local guidelines (CLAUDE.md, project conventions, coding standards)'); 164 console.log('3. identifies all files to create or modify'); 165 console.log('4. specifies tests to add or update'); 166 console.log('5. notes any dependencies or migrations needed'); 167 console.log(''); 168 console.log('do not apply the cap blindly. produce a well-researched plan first.'); 169 console.log(''); 170 console.log('---'); 171 console.log(''); 172 console.log('## cap content'); 173 console.log(''); 174 console.log(text); 175 } catch (err) { 176 const msg = err instanceof Error ? err.message : String(err); 177 if (opts.json) { 178 jsonError(msg); 179 return; 180 } 181 console.error(msg); 182 process.exitCode = 1; 183 } 184 }); 185}