open source is social v-it.org
0
fork

Configure Feed

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

add vit remix command

Add a new agent-only vit remix <ref> command that derives vetted caps
into the local codebase. The command outputs a pretext block plus cap
content to stdout so the calling agent can produce a thorough
implementation plan.

Add readLog(filename) to src/lib/vit-dir.js for reading append-only
JSONL logs such as .vit/trusted.jsonl.

Tests cover agent gate, ref validation, missing DID, and missing beacon.

+200
+7
skills/vit/SKILL.md
··· 45 45 - Output: prefer `--json` (JSON array of ATProto records); text mode prints `ref`, `title`, and `description` per cap. 46 46 - Common errors: no DID, no beacon, no following, session expired. 47 47 48 + ### `vit remix <ref>` 49 + - Description: Derive a vetted cap into the current codebase and output an implementation plan. 50 + - Usage: `vit remix <ref>` 51 + - Key flags: `--did <did>`, `--verbose` 52 + - Output: text pretext block with cap content to stdout (consumed by the calling agent). 53 + - Common errors: not running inside agent, invalid ref, no DID, no beacon, cap not trusted, cap not found. 54 + 48 55 ### Agent-usable commands 49 56 50 57 ### `vit doctor`
+2
src/cli.js
··· 9 9 import registerInit from './cmd/init.js'; 10 10 import registerLogin from './cmd/login.js'; 11 11 import registerFirehose from './cmd/firehose.js'; 12 + import registerRemix from './cmd/remix.js'; 12 13 import registerShip from './cmd/ship.js'; 13 14 import registerSkim from './cmd/skim.js'; 14 15 import registerVet from './cmd/vet.js'; ··· 30 31 registerFirehose(program); 31 32 registerShip(program); 32 33 registerSkim(program); 34 + registerRemix(program); 33 35 registerVet(program); 34 36 registerFollow(program); 35 37 registerSetup(program);
+135
src/cmd/remix.js
··· 1 + // SPDX-License-Identifier: AGPL-3.0-only 2 + // Copyright (c) 2026 sol pbc 3 + 4 + import { requireDid } from '../lib/config.js'; 5 + import { CAP_COLLECTION } from '../lib/constants.js'; 6 + import { restoreAgent } from '../lib/oauth.js'; 7 + import { readProjectConfig, readFollowing, readLog } from '../lib/vit-dir.js'; 8 + import { requireAgent } from '../lib/agent.js'; 9 + import { resolveRef, REF_PATTERN } from '../lib/cap-ref.js'; 10 + 11 + export default function register(program) { 12 + program 13 + .command('remix') 14 + .argument('<ref>', 'Three-word cap reference (e.g. fast-cache-invalidation)') 15 + .description('Derive a vetted cap into the local codebase') 16 + .option('--did <did>', 'DID to use') 17 + .option('-v, --verbose', 'Show step-by-step details') 18 + .action(async (ref, opts) => { 19 + try { 20 + const gate = requireAgent(); 21 + if (!gate.ok) { 22 + console.error('vit remix should be run by a coding agent (e.g. claude code, gemini cli).'); 23 + console.error("open your agent and ask it to run 'vit remix' for you."); 24 + process.exitCode = 1; 25 + return; 26 + } 27 + 28 + const { verbose } = opts; 29 + 30 + if (!REF_PATTERN.test(ref)) { 31 + console.error('invalid ref. expected three lowercase words with dashes (e.g. fast-cache-invalidation)'); 32 + process.exitCode = 1; 33 + return; 34 + } 35 + 36 + const did = requireDid(opts); 37 + if (!did) return; 38 + if (verbose) console.log(`[verbose] DID: ${did}`); 39 + 40 + const projectConfig = readProjectConfig(); 41 + const beacon = projectConfig.beacon; 42 + if (!beacon) { 43 + console.error("no beacon set. run 'vit init' in a project directory first."); 44 + process.exitCode = 1; 45 + return; 46 + } 47 + if (verbose) console.log(`[verbose] beacon: ${beacon}`); 48 + 49 + const trusted = readLog('trusted.jsonl'); 50 + const trustedEntry = trusted.find(e => e.ref === ref); 51 + if (!trustedEntry) { 52 + console.error(`cap '${ref}' is not trusted. ask the user to vet it first:`); 53 + console.error(''); 54 + console.error(` vit vet ${ref}`); 55 + console.error(''); 56 + console.error('after reviewing, they can trust it with:'); 57 + console.error(''); 58 + console.error(` vit vet ${ref} --trust`); 59 + process.exitCode = 1; 60 + return; 61 + } 62 + if (verbose) console.log(`[verbose] trusted entry found, uri: ${trustedEntry.uri}`); 63 + 64 + const { agent } = await restoreAgent(did); 65 + if (verbose) console.log('[verbose] session restored'); 66 + 67 + const following = readFollowing(); 68 + const dids = following.map(e => e.did); 69 + dids.push(did); 70 + if (verbose) console.log(`[verbose] querying ${dids.length} accounts`); 71 + 72 + let match = null; 73 + for (const repoDid of dids) { 74 + try { 75 + const res = await agent.com.atproto.repo.listRecords({ 76 + repo: repoDid, 77 + collection: CAP_COLLECTION, 78 + limit: 50, 79 + }); 80 + for (const rec of res.data.records) { 81 + if (rec.value.beacon !== beacon) continue; 82 + const recRef = resolveRef(rec.value, rec.cid); 83 + if (recRef === ref) { 84 + if (!match || (rec.value.createdAt || '') > (match.value.createdAt || '')) { 85 + match = rec; 86 + } 87 + } 88 + } 89 + } catch (err) { 90 + if (verbose) console.log(`[verbose] ${repoDid}: error fetching caps: ${err.message}`); 91 + } 92 + } 93 + 94 + if (!match) { 95 + console.error(`no cap found with ref '${ref}' for this beacon.`); 96 + process.exitCode = 1; 97 + return; 98 + } 99 + 100 + const record = match.value; 101 + const author = match.uri.split('/')[2]; 102 + const title = record.title || ref; 103 + const description = record.description || ''; 104 + const text = record.text || ''; 105 + 106 + console.log(`# remix: ${title}`); 107 + console.log(''); 108 + console.log(`ref: ${ref}`); 109 + console.log(`author: ${author}`); 110 + if (description) console.log(`description: ${description}`); 111 + console.log(''); 112 + console.log('---'); 113 + console.log(''); 114 + console.log('you are remixing a vetted cap into the current codebase.'); 115 + console.log('create a thorough implementation plan that:'); 116 + console.log(''); 117 + console.log('1. adapts the cap to this repo\'s architecture, conventions, and existing code'); 118 + console.log('2. follows local guidelines (CLAUDE.md, project conventions, coding standards)'); 119 + console.log('3. identifies all files to create or modify'); 120 + console.log('4. specifies tests to add or update'); 121 + console.log('5. notes any dependencies or migrations needed'); 122 + console.log(''); 123 + console.log('do not apply the cap blindly. produce a well-researched plan first.'); 124 + console.log(''); 125 + console.log('---'); 126 + console.log(''); 127 + console.log('## cap content'); 128 + console.log(''); 129 + console.log(text); 130 + } catch (err) { 131 + console.error(err.message); 132 + process.exitCode = 1; 133 + } 134 + }); 135 + }
+14
src/lib/vit-dir.js
··· 30 30 appendFileSync(join(dir, filename), JSON.stringify(record) + '\n'); 31 31 } 32 32 33 + export function readLog(filename) { 34 + const p = join(vitDir(), filename); 35 + if (!existsSync(p)) return []; 36 + try { 37 + return readFileSync(p, 'utf-8') 38 + .split('\n') 39 + .filter(line => line.trim()) 40 + .map(line => { try { return JSON.parse(line); } catch { return null; } }) 41 + .filter(Boolean); 42 + } catch { 43 + return []; 44 + } 45 + } 46 + 33 47 export function readFollowing() { 34 48 const p = join(vitDir(), 'following.json'); 35 49 if (!existsSync(p)) return [];
+42
test/remix.test.js
··· 1 + // SPDX-License-Identifier: AGPL-3.0-only 2 + // Copyright (c) 2026 sol pbc 3 + 4 + import { describe, test, expect } from 'bun:test'; 5 + import { run } from './helpers.js'; 6 + import { mkdirSync, rmSync } from 'node:fs'; 7 + import { tmpdir } from 'node:os'; 8 + import { join } from 'node:path'; 9 + 10 + describe('vit remix', () => { 11 + test('rejects when run outside a coding agent', () => { 12 + const result = run('remix fast-cache-invalidation', '/tmp', { CLAUDECODE: '', GEMINI_CLI: '', CODEX_CI: '' }); 13 + expect(result.exitCode).not.toBe(0); 14 + expect(result.stderr).toContain('should be run by a coding agent'); 15 + }); 16 + 17 + test('fails with no arguments', () => { 18 + const result = run('remix', '/tmp', { CLAUDECODE: '1' }); 19 + expect(result.exitCode).not.toBe(0); 20 + }); 21 + 22 + test('rejects invalid ref format', () => { 23 + const result = run('remix not-valid', '/tmp', { CLAUDECODE: '1' }); 24 + expect(result.exitCode).not.toBe(0); 25 + expect(result.stderr).toContain('invalid ref'); 26 + }); 27 + 28 + test('errors when no DID configured', () => { 29 + const configHome = join(tmpdir(), '.test-remix-config-' + Math.random().toString(36).slice(2)); 30 + mkdirSync(configHome, { recursive: true }); 31 + const result = run('remix fast-cache-invalidation', '/tmp', { CLAUDECODE: '1', XDG_CONFIG_HOME: configHome }); 32 + expect(result.exitCode).not.toBe(0); 33 + expect(result.stderr).toContain('no DID configured'); 34 + rmSync(configHome, { recursive: true, force: true }); 35 + }); 36 + 37 + test('errors when no beacon is set', () => { 38 + const result = run('remix fast-cache-invalidation --did did:plc:test123', '/tmp', { CLAUDECODE: '1' }); 39 + expect(result.exitCode).not.toBe(0); 40 + expect(result.stderr).toContain('no beacon set'); 41 + }); 42 + });