11import process from 'node:process' ;
2- import { jack } from 'jackspeak' ;
3- import { render } from 'ink' ;
2+ import { jack } from 'jackspeak' ;
3+ import { render } from 'ink' ;
44import React from 'react' ;
5- import { FetchCommand } from './commands/fetch.js' ;
5+ import { FetchCommand } from './commands/fetch.js' ;
6+ import { BatchCommand } from './commands/batch.js' ;
7+ import { VerifyCommand } from './commands/verify.js' ;
8+ import { PinCommand } from './commands/pin.js' ;
9+ import { OutdatedCommand } from './commands/outdated.js' ;
10+ import { DiffCommand } from './commands/diff.js' ;
11+ import { ScanCommand } from './commands/scan.js' ;
12+ import { CatalogCommand } from './commands/catalog.js' ;
13+ import { PRESETS } from './presets.js' ;
614
715const j = jack ( {
8- usage : 'vlurp [source] [options]'
16+ usage : 'vlurp [command] [ source] [options]'
917} )
1018 . description ( 'A fun CLI tool to quickly fetch GitHub repositories and gists' )
1119 . opt ( {
1220 d : {
1321 description : 'Root directory for vlurping' ,
1422 short : 'd'
23+ } ,
24+ preset : {
25+ description : 'Use a preset filter configuration (claude, skills, agents, docs, all-md, minimal)' ,
26+ hint : 'name'
27+ } ,
28+ ref : {
29+ description : 'Pin fetch to a specific git ref (commit SHA, tag, or branch)' ,
30+ hint : 'sha|tag|branch'
31+ } ,
32+ as : {
33+ description : 'Override output directory name (flatten path structure)' ,
34+ hint : 'name'
1535 }
1636 } )
1737 . optList ( {
@@ -25,28 +45,73 @@ const j = jack({
2545 description : 'Show this help message' ,
2646 short : 'h'
2747 } ,
48+ auto : {
49+ description : 'Auto-detect repository structure and apply appropriate filters' ,
50+ short : 'a'
51+ } ,
52+ 'dry-run' : {
53+ description : 'Preview what would be fetched without actually fetching' ,
54+ short : 'n'
55+ } ,
56+ quiet : {
57+ description : 'Suppress non-essential output' ,
58+ short : 'q'
59+ } ,
2860 force : {
2961 description : 'Force overwrite existing directories without prompting' ,
3062 short : 'f'
3163 }
3264 } ) ;
3365
34- const { values, positionals } = j . parse ( ) ;
66+ const { values, positionals} = j . parse ( ) ;
3567
3668if ( values . help ) {
3769 console . log ( `vlurp - A fun CLI tool to quickly fetch GitHub repositories and gists
3870
71+ Commands:
72+ vlurp <source> Fetch a single repository
73+ vlurp batch <file> Process a .vlurpfile
74+ vlurp verify <path> Verify file integrity against lineage records
75+ vlurp pin [source] Pin unpinned sources to current upstream HEAD
76+ vlurp outdated [file] Check for upstream changes
77+ vlurp diff <source> Show content diff against upstream
78+ vlurp scan <path> Analyze content for injection/escalation patterns
79+ vlurp catalog <path> Generate catalog.json of indexed skills
80+
3981Usage:
40- vlurp <user>/<repo> Fetch to ./<user>/<repo>
41- vlurp <user>/<repo> -d <root> Fetch to <root>/<user>/<repo>
42- vlurp <url> Fetch GitHub/Gist URL to ./<user>/<repo>
43- vlurp <url> -d <root> Fetch to <root>/<user>/<repo>
82+ vlurp <user>/<repo> Fetch to ./<user>/<repo>
83+ vlurp <user>/<repo> --ref <sha> Fetch pinned to commit
84+ vlurp <user>/<repo> --as <name> -d ./skills Fetch to ./skills/<name>
85+ vlurp <url> -d <root> Fetch to <root>/<user>/<repo>
86+ vlurp batch <vlurpfile> Process batch file
87+ vlurp verify ./skills Check files against .vlurp.jsonl
88+ vlurp pin Pin all unpinned in .vlurpfile
89+ vlurp outdated .vlurpfile Check what has changed upstream
90+ vlurp diff user/repo -d ./skills Show diff against upstream
91+
92+ Presets:
93+ ${ Object . entries ( PRESETS ) . map ( ( [ name , config ] ) =>
94+ ` ${ name . padEnd ( 10 ) } ${ config . description } ` ) . join ( '\n' ) }
4495
4596Examples:
46- vlurp facebook/react Fetch with default filters
47- vlurp nodejs/node --filter "*.js" Fetch only JavaScript files
48- vlurp user/repo --filter "src/**" Fetch src folder
49- vlurp user/repo --force Force overwrite existing directory
97+ vlurp user/repo --ref abc1234 Fetch pinned to commit
98+ vlurp user/repo --as myskill -d ./sk Fetch to ./sk/myskill
99+ vlurp user/repo --preset claude Use claude preset filters
100+ vlurp user/repo --auto Auto-detect structure
101+ vlurp batch .vlurpfile Process batch file
102+ vlurp batch .vlurpfile --dry-run Preview batch operations
103+ vlurp verify skills/ Verify integrity
104+ vlurp pin Pin all sources
105+ vlurp outdated .vlurpfile Check upstream
106+ vlurp diff user/repo -d ./skills Content diff
107+ vlurp scan skills/ Scan for threats
108+ vlurp catalog skills/ Build catalog
109+
110+ .vlurpfile Format:
111+ # Comments start with #
112+ vlurp user/repo -d ./vlurp --ref abc1234
113+ vlurp user/repo -d ./vlurp --filter "claude/**" --as myname
114+ vlurp user/repo --preset skills
50115
51116Options:
52117${ j . usage ( ) } `) ;
@@ -58,11 +123,100 @@ if (positionals.length === 0) {
58123 process . exit ( 1 ) ;
59124}
60125
61- const source = positionals [ 0 ] ;
126+ const command = positionals [ 0 ] ;
62127const rootDir = values . d ;
63- const filters = values . filter ;
64- const { force} = values ;
128+ const { force, auto, preset, quiet} = values ;
129+ const { ref} = values ;
130+ const asName = values . as ;
131+ const dryRun = values [ 'dry-run' ] ;
132+
133+ // Handle subcommands
134+ switch ( command ) {
135+ case 'batch' : {
136+ const vlurpfile = positionals [ 1 ] ;
137+ if ( ! vlurpfile ) {
138+ console . error ( 'Error: batch command requires a .vlurpfile path' ) ;
139+ console . error ( 'Usage: vlurp batch <vlurpfile>' ) ;
140+ process . exit ( 1 ) ;
141+ }
142+
143+ render ( React . createElement ( BatchCommand , {
144+ vlurpfile, dryRun, force, quiet
145+ } ) ) ;
146+
147+ break ;
148+ }
149+
150+ case 'verify' : {
151+ const targetPath = positionals [ 1 ] || '.' ;
152+ render ( React . createElement ( VerifyCommand , { targetPath} ) ) ;
153+
154+ break ;
155+ }
156+
157+ case 'pin' : {
158+ const source = positionals [ 1 ] || null ;
159+ const vlurpfilePath = positionals [ 2 ] || null ;
160+ render ( React . createElement ( PinCommand , { source, vlurpfilePath} ) ) ;
65161
66- render ( React . createElement ( FetchCommand , {
67- source, rootDir, filters, force
68- } ) ) ;
162+ break ;
163+ }
164+
165+ case 'outdated' : {
166+ const vlurpfileArg = positionals [ 1 ] || null ;
167+ render ( React . createElement ( OutdatedCommand , { vlurpfilePath : vlurpfileArg } ) ) ;
168+
169+ break ;
170+ }
171+
172+ case 'scan' : {
173+ const scanPath = positionals [ 1 ] || '.' ;
174+ render ( React . createElement ( ScanCommand , { targetPath : scanPath } ) ) ;
175+
176+ break ;
177+ }
178+
179+ case 'catalog' : {
180+ const catalogPath = positionals [ 1 ] || '.' ;
181+ render ( React . createElement ( CatalogCommand , { targetPath : catalogPath } ) ) ;
182+
183+ break ;
184+ }
185+
186+ case 'diff' : {
187+ const diffSource = positionals [ 1 ] ;
188+ if ( ! diffSource ) {
189+ console . error ( 'Error: diff command requires a source' ) ;
190+ console . error ( 'Usage: vlurp diff <user/repo> [-d <root>]' ) ;
191+ process . exit ( 1 ) ;
192+ }
193+
194+ render ( React . createElement ( DiffCommand , { source : diffSource , rootDir} ) ) ;
195+
196+ break ;
197+ }
198+
199+ default : {
200+ // Regular fetch command
201+ const source = command ;
202+
203+ // Resolve filters from preset or explicit filters
204+ let filters = values . filter ;
205+ if ( preset && PRESETS [ preset ] ) {
206+ filters = PRESETS [ preset ] . filters ;
207+ }
208+
209+ render ( React . createElement ( FetchCommand , {
210+ source,
211+ rootDir,
212+ filters,
213+ force,
214+ auto,
215+ dryRun,
216+ quiet,
217+ ref,
218+ asName,
219+ preset
220+ } ) ) ;
221+ }
222+ }
0 commit comments