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