Skip to content

Commit f6d35db

Browse files
committed
chore: wip
1 parent 2f7f895 commit f6d35db

29 files changed

+373
-276
lines changed

packages/launchpad/bin/cli.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const cli = new CAC('launchpad')
2525
cli.version(version)
2626
cli.help()
2727

28+
//
29+
2830
// Config command - show resolved user configuration
2931
cli
3032
.command('config', 'Show current Launchpad configuration')
@@ -49,6 +51,8 @@ cli
4951
}
5052
})
5153

54+
// (parse moved to end)
55+
5256
// Main installation command
5357
cli
5458
.command('install [packages...]', 'Install packages or set up development environment')
@@ -1377,19 +1381,10 @@ cli
13771381
json?: boolean
13781382
}) => {
13791383
try {
1380-
const argv: string[] = []
1381-
if (options?.iterations)
1382-
argv.push('--iterations', String(options.iterations))
1383-
if (options?.depths)
1384-
argv.push('--depths', options.depths)
1385-
if (options?.verbose)
1386-
argv.push('--verbose')
1387-
if (options?.json)
1388-
argv.push('--json')
13891384
const cmd = await resolveCommand('benchmark:file-detection')
13901385
if (!cmd)
13911386
return
1392-
const code = await cmd.run({ argv, env: process.env })
1387+
const code = await cmd.run({ argv: [], options, env: process.env })
13931388
if (typeof code === 'number' && code !== 0)
13941389
process.exit(code)
13951390
}
@@ -1399,16 +1394,7 @@ cli
13991394
}
14001395
})
14011396

1402-
// Parse CLI arguments
1403-
try {
1404-
cli.version(version)
1405-
cli.help()
1406-
cli.parse()
1407-
}
1408-
catch (error) {
1409-
console.error('CLI error:', error instanceof Error ? error.message : String(error))
1410-
process.exit(1)
1411-
}
1397+
// NOTE: cli.parse() moved to the end of the file to ensure all commands are registered
14121398

14131399
// Database management commands
14141400
cli
@@ -1431,23 +1417,10 @@ cli
14311417
password?: string
14321418
}) => {
14331419
try {
1434-
const argv: string[] = []
1435-
if (options?.name)
1436-
argv.push('--name', options.name)
1437-
if (options?.type)
1438-
argv.push('--type', options.type)
1439-
if (options?.host)
1440-
argv.push('--host', options.host)
1441-
if (options?.port)
1442-
argv.push('--port', String(options.port))
1443-
if (options?.user)
1444-
argv.push('--user', options.user)
1445-
if (options?.password)
1446-
argv.push('--password', options.password)
14471420
const cmd = await resolveCommand('db:create')
14481421
if (!cmd)
14491422
return
1450-
const code = await cmd.run({ argv, env: process.env })
1423+
const code = await cmd.run({ argv: [], options, env: process.env })
14511424
if (typeof code === 'number' && code !== 0)
14521425
process.exit(code)
14531426
}
@@ -1456,3 +1429,12 @@ cli
14561429
process.exit(1)
14571430
}
14581431
})
1432+
1433+
// Parse CLI arguments (must be last)
1434+
try {
1435+
cli.parse()
1436+
}
1437+
catch (error) {
1438+
console.error('CLI error:', error instanceof Error ? error.message : String(error))
1439+
process.exit(1)
1440+
}

packages/launchpad/src/cli/types.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
export interface CommandContext {
2+
// Backward-compat: most commands expect argv to exist
23
argv: string[]
4+
// Preferred: structured options parsed by the CLI
5+
options?: Record<string, any>
36
env: NodeJS.ProcessEnv
47
}
58

@@ -8,7 +11,7 @@ export interface Command {
811
aliases?: string[]
912
description?: string
1013
help?: string
11-
run(ctx: CommandContext): Promise<number> | number
14+
run: (ctx: CommandContext) => Promise<number> | number
1215
}
1316

14-
export type CommandModule = { default: Command }
17+
export interface CommandModule { default: Command }

packages/launchpad/src/commands/benchmark/file-detection.ts

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,23 @@
11
import type { Command } from '../../cli/types'
22

3-
function parseArgs(argv: string[]): { depths?: number[], iterations?: number, verbose?: boolean, json?: boolean } {
4-
const result: { depths?: number[], iterations?: number, verbose?: boolean, json?: boolean } = {}
5-
for (let i = 0; i < argv.length; i++) {
6-
const a = argv[i]
7-
if (a === '--verbose') {
8-
result.verbose = true
9-
}
10-
else if (a === '--json') {
11-
result.json = true
12-
}
13-
else if (a === '--iterations' && i + 1 < argv.length) {
14-
const v = Number.parseInt(argv[++i], 10)
15-
if (!Number.isNaN(v))
16-
result.iterations = v
17-
}
18-
else if (a === '--depths' && i + 1 < argv.length) {
19-
const v = String(argv[++i])
20-
const depths = v.split(',').map(d => Number.parseInt(d.trim(), 10)).filter(d => !Number.isNaN(d))
21-
if (depths.length > 0)
22-
result.depths = depths
23-
}
24-
}
25-
return result
26-
}
27-
283
const command: Command = {
294
name: 'benchmark:file-detection',
305
description: 'Benchmark file detection performance (shell vs Bun)',
31-
async run({ argv }) {
6+
async run({ options }) {
327
const { runFileDetectionBenchmark } = await import('../../dev/benchmark')
33-
const opts = parseArgs(argv)
8+
const depths = typeof options?.depths === 'string'
9+
? options.depths.split(',').map((d: string) => Number.parseInt(d.trim(), 10)).filter((d: number) => !Number.isNaN(d))
10+
: undefined
11+
const iterations = typeof options?.iterations === 'string'
12+
? Number.parseInt(options.iterations, 10)
13+
: typeof options?.iterations === 'number'
14+
? options.iterations
15+
: undefined
3416
await runFileDetectionBenchmark({
35-
depths: opts.depths,
36-
iterations: opts.iterations,
37-
verbose: opts.verbose,
38-
json: opts.json,
17+
depths,
18+
iterations,
19+
verbose: Boolean(options?.verbose),
20+
json: Boolean(options?.json),
3921
})
4022
return 0
4123
},

packages/launchpad/src/commands/cache/clean.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@ import type { Command } from '../../cli/types'
33
const cmd: Command = {
44
name: 'cache:clean',
55
description: 'Clean up old cached packages based on age and size limits',
6-
async run({ argv }) {
6+
async run({ argv, options }) {
77
const { getCacheStats, cleanupCache } = await import('../../cache')
88

9+
// Strongly type options
10+
interface Opts { maxAge?: number | string; maxSize?: number | string; dryRun?: boolean }
11+
const opts = (options ?? {}) as Opts
12+
913
const getArgValue = (flag: string): string | undefined => {
1014
const idx = argv.indexOf(flag)
1115
if (idx !== -1 && idx + 1 < argv.length) return argv[idx + 1]
1216
return undefined
1317
}
1418

15-
const maxAge = getArgValue('--max-age')
16-
const maxSize = getArgValue('--max-size')
17-
const dryRun = argv.includes('--dry-run')
19+
const maxAge = typeof opts.maxAge === 'number' ? String(opts.maxAge)
20+
: typeof opts.maxAge === 'string' ? opts.maxAge
21+
: getArgValue('--max-age')
22+
const maxSize = typeof opts.maxSize === 'number' ? String(opts.maxSize)
23+
: typeof opts.maxSize === 'string' ? opts.maxSize
24+
: getArgValue('--max-size')
25+
const dryRun = typeof opts.dryRun === 'boolean' ? opts.dryRun : argv.includes('--dry-run')
1826

1927
const maxAgeDays = maxAge ? Number.parseInt(maxAge, 10) : 30
2028
const maxSizeGB = maxSize ? Number.parseFloat(maxSize) : 5

packages/launchpad/src/commands/cache/clear.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1+
/* eslint-disable no-console */
12
import type { Command } from '../../cli/types'
23

34
const cmd: Command = {
45
name: 'cache:clear',
56
description: 'Clear all cached packages and downloads',
6-
async run({ argv }) {
7+
async run({ argv, options }) {
78
const fs = await import('node:fs')
89
const path = await import('node:path')
910
const os = await import('node:os')
1011
const { config } = await import('../../config')
1112

12-
const verbose = argv.includes('--verbose')
13-
const force = argv.includes('--force')
14-
const dryRun = argv.includes('--dry-run')
13+
// Strongly type options
14+
interface Opts { verbose?: boolean, force?: boolean, dryRun?: boolean }
15+
const opts = (options ?? {}) as Opts
1516

16-
if (verbose) config.verbose = true
17+
const verbose = typeof opts.verbose === 'boolean' ? opts.verbose : argv.includes('--verbose')
18+
const force = typeof opts.force === 'boolean' ? opts.force : argv.includes('--force')
19+
const dryRun = typeof opts.dryRun === 'boolean' ? opts.dryRun : argv.includes('--dry-run')
20+
21+
if (verbose)
22+
config.verbose = true
1723

1824
const homeDir = os.homedir()
1925
const cacheDir = path.join(homeDir, '.cache', 'launchpad')
@@ -35,7 +41,8 @@ const cmd: Command = {
3541
let fileCount = 0
3642

3743
const calculateCacheStats = (dir: string) => {
38-
if (!fs.existsSync(dir)) return
44+
if (!fs.existsSync(dir))
45+
return
3946
try {
4047
const stack = [dir]
4148
while (stack.length > 0) {
@@ -63,7 +70,8 @@ const cmd: Command = {
6370
catch { /* ignore */ }
6471
}
6572

66-
if (fs.existsSync(cacheDir)) calculateCacheStats(cacheDir)
73+
if (fs.existsSync(cacheDir))
74+
calculateCacheStats(cacheDir)
6775

6876
const formatSize = (bytes: number): string => {
6977
const units = ['B', 'KB', 'MB', 'GB']
@@ -84,8 +92,10 @@ const cmd: Command = {
8492
console.log(` • Cache directory: ${cacheDir}`)
8593
console.log('')
8694
console.log('Would remove:')
87-
if (fs.existsSync(bunCacheDir)) console.log(` • Bun cache: ${bunCacheDir}`)
88-
if (fs.existsSync(packageCacheDir)) console.log(` • Package cache: ${packageCacheDir}`)
95+
if (fs.existsSync(bunCacheDir))
96+
console.log(` • Bun cache: ${bunCacheDir}`)
97+
if (fs.existsSync(packageCacheDir))
98+
console.log(` • Package cache: ${packageCacheDir}`)
8999
}
90100
else {
91101
console.log('📭 No cache found - nothing to clear')

packages/launchpad/src/commands/dev/check-updates.ts renamed to packages/launchpad/src/commands/check-updates.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import type { Command } from '../../cli/types'
1+
import type { Command } from '../cli/types'
22

33
const cmd: Command = {
4-
name: 'dev:check-updates',
4+
name: 'check-updates',
55
aliases: [],
66
description: 'Check global dependencies for updates (TTL-based); auto-update if enabled',
77
async run({ argv, env }) {
8-
const { checkAndMaybeUpdate } = await import('../../dev/update-check')
8+
const { checkAndMaybeUpdate } = await import('../dev/update-check')
99

1010
// Flags (optional): --dry-run to skip network, --auto-update to force on
1111
const dryRun = argv.includes('--dry-run') || env.LAUNCHPAD_SKIP_NETWORK === '1'

0 commit comments

Comments
 (0)