open source is social v-it.org
0
fork

Configure Feed

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

fix: CLI surface polish — bug fix, empty states, operator terminology

Fix undefined beacon variable in vouch.js cap vouch record (ship-blocker).
Enrich all empty-state messages with contextual guidance and next steps.
Replace "user" with "operator" in all agent-facing console output.
Only show skim hint/separator when there are actual results.
Add not-found hints with follow/explore guidance in vet, remix, vouch, learn.

Implements cpo/specs/in-flight/vit-cli-surface-polish.md — all 15 acceptance
criteria passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+99 -31
+2 -1
src/cmd/beacon.js
··· 52 52 if (beacon) { 53 53 console.log(`${mark} beacon: lit ${beacon}`); 54 54 } else { 55 - console.log(`${mark} beacon: unlit`); 55 + console.log(`${mark} beacon: unlit — this repo hasn't initialized vit yet.`); 56 + console.log("the maintainer can light the beacon by running 'vit init' inside the repo."); 56 57 } 57 58 } catch (err) { 58 59 console.error(err instanceof Error ? err.message : String(err));
+6 -1
src/cmd/config.js
··· 23 23 // Default to list when no action given 24 24 if (!action || action === 'list') { 25 25 const config = loadConfig(); 26 - for (const [k, v] of getScalars(config)) { 26 + const scalars = [...getScalars(config)]; 27 + if (scalars.length === 0) { 28 + console.log("no configuration set. run 'vit login <handle>' to get started."); 29 + return; 30 + } 31 + for (const [k, v] of scalars) { 27 32 console.log(`${k}=${v}`); 28 33 } 29 34 return;
+1 -1
src/cmd/doctor.js
··· 88 88 if (projConfig.beacon) { 89 89 if (!opts.json) console.log(`${mark} beacon: ${projConfig.beacon}`); 90 90 } else { 91 - if (!opts.json) console.log(`${mark} beacon: not set`); 91 + if (!opts.json) console.log(`${mark} beacon: not set (run vit init)`); 92 92 } 93 93 94 94 const skillPath = join(process.cwd(), '.claude', 'skills', 'using-vit', 'SKILL.md');
+4
src/cmd/explore.js
··· 255 255 console.log(`${brand} explore caps`); 256 256 if (!data.caps?.length) { 257 257 console.log('no caps found.'); 258 + console.log('the network is just getting started. ship a cap or skill to be one of the first.'); 259 + console.log("try 'vit scan' for real-time discovery — the explore index may still be catching up."); 258 260 return; 259 261 } 260 262 ··· 310 312 console.log(`${brand} explore skills`); 311 313 if (!data.skills?.length) { 312 314 console.log('no skills found.'); 315 + console.log('the network is just getting started. ship a cap or skill to be one of the first.'); 313 316 return; 314 317 } 315 318 ··· 357 360 console.log(`${brand} explore beacons`); 358 361 if (!data.beacons?.length) { 359 362 console.log('no beacons found.'); 363 + console.log('the network is just getting started. ship a cap or skill to be one of the first.'); 360 364 return; 361 365 } 362 366
+5 -2
src/cmd/follow.js
··· 117 117 const list = readFollowing(); 118 118 if (list.length === 0) { 119 119 if (opts.json) { 120 - jsonOk({ following: [] }); 120 + jsonOk({ following: [], hint: "run 'vit follow <handle>' to add accounts" }); 121 121 return; 122 122 } 123 - console.log('no followings'); 123 + console.log('not following anyone yet.'); 124 + console.log(''); 125 + console.log("run 'vit follow <handle>' to start seeing what people are shipping."); 126 + console.log("try 'vit scan' to discover active publishers on the network."); 124 127 return; 125 128 } 126 129 if (opts.json) {
+6 -2
src/cmd/learn.js
··· 78 78 return; 79 79 } 80 80 console.error(`skill '${ref}' is not yet vetted. user-wide install requires vetting.`); 81 - console.error(`ask the user to vet it first:`); 81 + console.error(`tell your operator to vet it first:`); 82 82 console.error(''); 83 83 console.error(` vit vet ${ref}`); 84 84 console.error(''); ··· 98 98 return; 99 99 } 100 100 console.error(`skill '${ref}' is not yet vetted.`); 101 - console.error(`ask the user to vet it first:`); 101 + console.error(`tell your operator to vet it first:`); 102 102 console.error(''); 103 103 console.error(` vit vet ${ref}`); 104 104 console.error(''); ··· 158 158 return; 159 159 } 160 160 console.error(`no skill found with ref '${ref}' from followed accounts.`); 161 + console.error(''); 162 + console.error('hint: skills appear from accounts you follow and your own.'); 163 + console.error(` vit following check who you're following`); 164 + console.error(` vit explore skills browse skills network-wide`); 161 165 process.exitCode = 1; 162 166 return; 163 167 }
+6 -2
src/cmd/remix.js
··· 74 74 const trustGate = shouldBypassVet(); 75 75 if (!trustGate.bypass) { 76 76 if (opts.json) { 77 - jsonError(`cap '${ref}' is not trusted`, `ask user to run 'vit vet ${ref} --trust'`); 77 + jsonError(`cap '${ref}' is not trusted`, `tell your operator to run 'vit vet ${ref} --trust'`); 78 78 return; 79 79 } 80 - console.error(`cap '${ref}' is not trusted. ask the user to vet it first:`); 80 + console.error(`cap '${ref}' is not trusted. tell your operator to vet it first:`); 81 81 console.error(''); 82 82 console.error(` vit vet ${ref}`); 83 83 console.error(''); ··· 129 129 return; 130 130 } 131 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`); 132 136 process.exitCode = 1; 133 137 return; 134 138 }
+2
src/cmd/scan.js
··· 162 162 return; 163 163 } 164 164 console.log(`no ${scanType} publishers found in this time window.`); 165 + console.log('the network is young — be an early publisher.'); 166 + console.log("ship a cap with 'vit ship' or a skill with 'vit ship --skill' to get things started."); 165 167 return; 166 168 } 167 169
+2 -2
src/cmd/ship.js
··· 200 200 jsonError('session expired or invalid', "run 'vit login <handle>'"); 201 201 return; 202 202 } 203 - console.error(`session expired or invalid. tell your user to run '${name} login <handle>'.`); 203 + console.error(`session expired or invalid. tell your operator to run '${name} login <handle>'.`); 204 204 process.exitCode = 1; 205 205 return; 206 206 } ··· 416 416 jsonError('session expired or invalid', "run 'vit login <handle>'"); 417 417 return; 418 418 } 419 - console.error(`session expired or invalid. tell your user to run '${name} login <handle>'.`); 419 + console.error(`session expired or invalid. tell your operator to run '${name} login <handle>'.`); 420 420 process.exitCode = 1; 421 421 return; 422 422 }
+35 -7
src/cmd/skim.js
··· 135 135 const capped = allItems.slice(0, limit); 136 136 137 137 if (opts.json) { 138 - console.log(JSON.stringify(capped, null, 2)); 138 + if (capped.length === 0) { 139 + const following = readFollowing(); 140 + let hint; 141 + if (skillsOnly) { 142 + hint = "no skills found — try 'vit explore skills' or ship your own with 'vit ship --skill'"; 143 + } else if (following.length === 0) { 144 + hint = "not following anyone — run 'vit follow <handle>'"; 145 + } else { 146 + hint = "no matching caps — try 'vit explore caps' or 'vit ship'"; 147 + } 148 + console.log(JSON.stringify({ ok: true, items: [], hint }, null, 2)); 149 + } else { 150 + console.log(JSON.stringify(capped, null, 2)); 151 + } 139 152 } else { 140 153 if (capped.length === 0) { 141 154 if (skillsOnly) { 142 - console.log('no skills found.'); 143 - } else if (opts.caps) { 144 - console.log('no caps found for this beacon.'); 155 + console.log('no skills found from followed accounts.'); 156 + console.log(''); 157 + console.log("try 'vit explore skills' to discover skills network-wide, or ship your own with 'vit ship --skill'."); 145 158 } else { 146 - console.log('no caps or skills found.'); 159 + const following = readFollowing(); 160 + if (following.length === 0) { 161 + console.log("no caps or skills found. you're not following anyone yet and haven't shipped any caps for this beacon."); 162 + console.log(''); 163 + console.log('next steps:'); 164 + console.log(' vit scan discover active publishers on the network'); 165 + console.log(' vit follow <handle> start following someone to see their caps'); 166 + console.log(' vit ship publish a cap to seed the network'); 167 + } else { 168 + console.log('no caps found for this beacon from your followed accounts.'); 169 + console.log(''); 170 + console.log("the network grows when people ship. publish a cap with 'vit ship' to get things started for this project."); 171 + console.log("try 'vit explore caps' for network-wide discovery."); 172 + } 147 173 } 148 174 } 149 175 for (const rec of capped) { ··· 172 198 console.log(); 173 199 } 174 200 } 175 - console.log('---'); 176 - console.log(`hint: tell your user to run '${name} vet <ref>' in another terminal for any item they want to review.`); 201 + if (capped.length > 0) { 202 + console.log('---'); 203 + console.log(`hint: tell your operator to run '${name} vet <ref>' in another terminal for any item they want to review.`); 204 + } 177 205 } 178 206 } catch (err) { 179 207 console.error(err instanceof Error ? err.message : String(err));
+11 -3
src/cmd/vet.js
··· 179 179 console.log(' caps and skills in this project.'); 180 180 console.log(''); 181 181 console.log(' any agent running in this project can remix caps and learn skills'); 182 - console.log(' without human review. only do this if you trust the agent\'s judgment'); 182 + console.log(' without operator review. only do this if you trust the agent\'s judgment'); 183 183 console.log(' and the network sources you follow.'); 184 184 console.log(''); 185 185 console.log(' to proceed, confirm: vit vet --dangerous-accept --confirm'); ··· 230 230 // Sandboxed sub-agent pattern — allow it 231 231 } else { 232 232 if (opts.json) { 233 - jsonError('vit vet is for human review', 'use --trust --confirm to bypass'); 233 + jsonError('vit vet is for operator review', 'use --trust --confirm to bypass'); 234 234 return; 235 235 } 236 - console.error('vit vet is for human review. agents should not vet directly.'); 236 + console.error('vit vet is for operator review. agents should not vet directly.'); 237 237 console.error(''); 238 238 console.error('if you are a sandboxed sub-agent specifically tasked with vetting,'); 239 239 console.error('you can bypass this gate:'); ··· 305 305 return; 306 306 } 307 307 console.error(`no cap found with ref '${ref}' for this beacon.`); 308 + console.error(''); 309 + console.error('hint: caps only appear from accounts you follow and your own.'); 310 + console.error(` vit following check who you're following`); 311 + console.error(` vit explore cap ${ref} search the network-wide index`); 308 312 process.exitCode = 1; 309 313 return; 310 314 } ··· 448 452 return; 449 453 } 450 454 console.error(`no skill found with ref '${ref}' from followed accounts.`); 455 + console.error(''); 456 + console.error('hint: skills appear from accounts you follow and your own.'); 457 + console.error(` vit following check who you're following`); 458 + console.error(` vit explore skills browse skills network-wide`); 451 459 process.exitCode = 1; 452 460 return; 453 461 }
+11 -2
src/cmd/vouch.js
··· 111 111 return; 112 112 } 113 113 console.error(`no skill found with ref '${ref}' from followed accounts.`); 114 + console.error(''); 115 + console.error('hint: skills appear from accounts you follow and your own.'); 116 + console.error(` vit following check who you're following`); 117 + console.error(` vit explore skills browse skills network-wide`); 114 118 process.exitCode = 1; 115 119 return; 116 120 } ··· 219 223 return; 220 224 } 221 225 console.error(`no cap found with ref '${ref}' for this beacon.`); 226 + console.error(''); 227 + console.error('hint: caps only appear from accounts you follow and your own.'); 228 + console.error(` vit following check who you're following`); 229 + console.error(` vit explore cap ${ref} search the network-wide index`); 222 230 process.exitCode = 1; 223 231 return; 224 232 } 225 233 226 234 const now = new Date().toISOString(); 235 + const projBeacon = [...beaconSet][0]; 227 236 const vouchRecord = { 228 237 $type: VOUCH_COLLECTION, 229 238 subject: { ··· 232 241 }, 233 242 createdAt: now, 234 243 ref, 235 - beacon, 244 + beacon: projBeacon, 236 245 }; 237 246 if (verbose) vlog(`[verbose] creating vouch for ${match.uri}`); 238 247 const rkey = TID.nextStr(); ··· 250 259 uri: match.uri, 251 260 cid: match.cid, 252 261 vouchUri: res.data.uri, 253 - beacon, 262 + beacon: projBeacon, 254 263 ts: now, 255 264 }); 256 265 } catch (logErr) {
+1 -1
test/follow.test.js
··· 90 90 test('shows message when no followings', () => { 91 91 const result = run('following', tmpDir); 92 92 expect(result.exitCode).toBe(0); 93 - expect(result.stdout).toContain('no followings'); 93 + expect(result.stdout).toContain('not following anyone yet'); 94 94 }); 95 95 });
+1 -1
test/vet-skill.test.js
··· 16 16 test('rejects when run inside a coding agent (skill ref)', () => { 17 17 const result = run('vet skill-agent-test', undefined, { CLAUDECODE: '1' }); 18 18 expect(result.exitCode).toBe(1); 19 - expect(result.stderr).toContain('vit vet is for human review'); 19 + expect(result.stderr).toContain('vit vet is for operator review'); 20 20 expect(result.stderr).toContain('vit vet skill-agent-test'); 21 21 expect(result.stderr).toContain('--trust --confirm'); 22 22 });
+6 -6
test/vet.test.js
··· 94 94 test('agent without flags: error with sandboxed sub-agent hint', () => { 95 95 const result = run('vet fast-cache-invalidation', undefined, agentEnv); 96 96 expect(result.exitCode).toBe(1); 97 - expect(result.stderr).toContain('vit vet is for human review'); 97 + expect(result.stderr).toContain('vit vet is for operator review'); 98 98 expect(result.stderr).toContain('--trust --confirm'); 99 99 expect(result.stderr).toContain('sandboxed sub-agent'); 100 100 }); ··· 102 102 test('agent with --trust but no --confirm: error', () => { 103 103 const result = run('vet fast-cache-invalidation --trust', undefined, agentEnv); 104 104 expect(result.exitCode).toBe(1); 105 - expect(result.stderr).toContain('vit vet is for human review'); 105 + expect(result.stderr).toContain('vit vet is for operator review'); 106 106 expect(result.stderr).toContain('--trust --confirm'); 107 107 }); 108 108 109 109 test('agent with --confirm but no --trust: error', () => { 110 110 const result = run('vet fast-cache-invalidation --confirm', undefined, agentEnv); 111 111 expect(result.exitCode).toBe(1); 112 - expect(result.stderr).toContain('vit vet is for human review'); 112 + expect(result.stderr).toContain('vit vet is for operator review'); 113 113 }); 114 114 115 115 test('agent with --trust --confirm: passes agent gate (fails at DID)', () => { ··· 118 118 mkdirSync(configHome, { recursive: true }); 119 119 const result = run('vet fast-cache-invalidation --trust --confirm', undefined, { ...agentEnv, XDG_CONFIG_HOME: configHome }); 120 120 // Should NOT contain the agent gate error 121 - expect(result.stderr).not.toContain('vit vet is for human review'); 121 + expect(result.stderr).not.toContain('vit vet is for operator review'); 122 122 rmSync(configHome, { recursive: true, force: true }); 123 123 }); 124 124 ··· 127 127 mkdirSync(configHome, { recursive: true }); 128 128 const result = run('vet fast-cache-invalidation --trust --confirm', undefined, { ...noAgentEnv, XDG_CONFIG_HOME: configHome }); 129 129 // Should NOT contain the agent gate error 130 - expect(result.stderr).not.toContain('vit vet is for human review'); 130 + expect(result.stderr).not.toContain('vit vet is for operator review'); 131 131 rmSync(configHome, { recursive: true, force: true }); 132 132 }); 133 133 }); ··· 186 186 mkdirSync(configHome, { recursive: true }); 187 187 const result = run('vet fast-cache-invalidation --sandbox claude', undefined, { ...agentEnv, XDG_CONFIG_HOME: configHome }); 188 188 // Should NOT contain the agent gate error 189 - expect(result.stderr).not.toContain('vit vet is for human review'); 189 + expect(result.stderr).not.toContain('vit vet is for operator review'); 190 190 rmSync(configHome, { recursive: true, force: true }); 191 191 }); 192 192