11import { Command } from 'commander' ;
2- import { viewCommand } from './commands/view.js' ;
3- import { serveCommand } from './commands/serve.js' ;
4- import { stopCommand } from './commands/stop.js' ;
5- import { installCommand , installSkillHubCommand } from './commands/install.js' ;
6- import { uninstallCommand } from './commands/uninstall.js' ;
7- import { upgradeCommand } from './commands/upgrade.js' ;
8- import { listCommand } from './commands/list.js' ;
9- import { toolCommand } from './commands/tool.js' ;
10- import { sessionCommand } from './commands/session.js' ;
11- import { cliCommand } from './commands/cli.js' ;
12- import { memoryCommand } from './commands/memory.js' ;
13- import { coreMemoryCommand } from './commands/core-memory.js' ;
14- import { hookCommand } from './commands/hook.js' ;
15- import { specCommand } from './commands/spec.js' ;
16- import { issueCommand } from './commands/issue.js' ;
17- import { workflowCommand } from './commands/workflow.js' ;
18- import { loopCommand } from './commands/loop.js' ;
19- import { teamCommand } from './commands/team.js' ;
20- import { launcherCommand } from './commands/launcher.js' ;
21- import { chainLoaderCommand } from './commands/chain-loader.js' ;
222import { readFileSync , existsSync } from 'fs' ;
233import { fileURLToPath } from 'url' ;
244import { dirname , join } from 'path' ;
@@ -75,7 +55,22 @@ function loadPackageInfo(): PackageInfo {
7555
7656const pkg = loadPackageInfo ( ) ;
7757
78- export function run ( argv : string [ ] ) : void {
58+ type CommandHandler = ( ...args : any [ ] ) => void | Promise < void > ;
59+
60+ async function invokeNamedExport < TModule extends Record < string , unknown > > (
61+ loader : ( ) => Promise < TModule > ,
62+ exportName : string ,
63+ ...args : unknown [ ]
64+ ) : Promise < void > {
65+ const mod = await loader ( ) ;
66+ const handler = mod [ exportName ] ;
67+ if ( typeof handler !== 'function' ) {
68+ throw new Error ( `CCW CLI bootstrap error: ${ exportName } is not exported by the command module.` ) ;
69+ }
70+ await ( handler as CommandHandler ) ( ...args ) ;
71+ }
72+
73+ export async function run ( argv : string [ ] ) : Promise < void > {
7974 const program = new Command ( ) ;
8075
8176 program
@@ -91,7 +86,7 @@ export function run(argv: string[]): void {
9186 . option ( '--port <port>' , 'Server port' , '3456' )
9287 . option ( '--host <host>' , 'Server host to bind' , '127.0.0.1' )
9388 . option ( '--no-browser' , 'Start server without opening browser' )
94- . action ( viewCommand ) ;
89+ . action ( async ( options ) => invokeNamedExport ( ( ) => import ( './commands/view.js' ) , ' viewCommand' , options ) ) ;
9590
9691 // Serve command (alias for view)
9792 program
@@ -101,15 +96,15 @@ export function run(argv: string[]): void {
10196 . option ( '--port <port>' , 'Server port' , '3456' )
10297 . option ( '--host <host>' , 'Server host to bind' , '127.0.0.1' )
10398 . option ( '--no-browser' , 'Start server without opening browser' )
104- . action ( serveCommand ) ;
99+ . action ( async ( options ) => invokeNamedExport ( ( ) => import ( './commands/serve.js' ) , ' serveCommand' , options ) ) ;
105100
106101 // Stop command
107102 program
108103 . command ( 'stop' )
109104 . description ( 'Stop the running CCW dashboard server' )
110105 . option ( '--port <port>' , 'Server port' , '3456' )
111106 . option ( '-f, --force' , 'Force kill process on the port' )
112- . action ( stopCommand ) ;
107+ . action ( async ( options ) => invokeNamedExport ( ( ) => import ( './commands/stop.js' ) , ' stopCommand' , options ) ) ;
113108
114109 // Install command
115110 program
@@ -121,37 +116,38 @@ export function run(argv: string[]): void {
121116 . option ( '--skill-hub [skillId]' , 'Install skill from skill-hub (use --list to see available)' )
122117 . option ( '--cli <type>' , 'Target CLI for skill installation (claude or codex)' , 'claude' )
123118 . option ( '--list' , 'List available skills in skill-hub' )
124- . action ( ( options ) => {
119+ . action ( async ( options ) => {
120+ const installModule = await import ( './commands/install.js' ) ;
125121 // If skill-hub option is used, route to skill hub command
126122 if ( options . skillHub !== undefined || options . list ) {
127- return installSkillHubCommand ( {
123+ return installModule . installSkillHubCommand ( {
128124 skillId : typeof options . skillHub === 'string' ? options . skillHub : undefined ,
129125 cliType : options . cli ,
130126 list : options . list ,
131127 } ) ;
132128 }
133129 // Otherwise use normal install
134- return installCommand ( options ) ;
130+ return installModule . installCommand ( options ) ;
135131 } ) ;
136132
137133 // Uninstall command
138134 program
139135 . command ( 'uninstall' )
140136 . description ( 'Uninstall Claude Code Workflow' )
141- . action ( uninstallCommand ) ;
137+ . action ( async ( ) => invokeNamedExport ( ( ) => import ( './commands/uninstall.js' ) , ' uninstallCommand' ) ) ;
142138
143139 // Upgrade command
144140 program
145141 . command ( 'upgrade' )
146142 . description ( 'Upgrade Claude Code Workflow installations' )
147143 . option ( '-a, --all' , 'Upgrade all installations without prompting' )
148- . action ( upgradeCommand ) ;
144+ . action ( async ( options ) => invokeNamedExport ( ( ) => import ( './commands/upgrade.js' ) , ' upgradeCommand' , options ) ) ;
149145
150146 // List command
151147 program
152148 . command ( 'list' )
153149 . description ( 'List all installed Claude Code Workflow instances' )
154- . action ( listCommand ) ;
150+ . action ( async ( ) => invokeNamedExport ( ( ) => import ( './commands/list.js' ) , ' listCommand' ) ) ;
155151
156152 // Tool command
157153 program
@@ -166,7 +162,7 @@ export function run(argv: string[]): void {
166162 . option ( '--file <file>' , 'File path for symbol extraction (for codex_lens)' )
167163 . option ( '--files <files>' , 'Comma-separated file paths (for codex_lens update)' )
168164 . option ( '--languages <langs>' , 'Comma-separated languages (for codex_lens init)' )
169- . action ( ( subcommand , args , options ) => toolCommand ( subcommand , args , options ) ) ;
165+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/tool.js' ) , 'toolCommand' , subcommand , args , options ) ) ;
170166
171167 // Session command
172168 program
@@ -183,7 +179,7 @@ export function run(argv: string[]): void {
183179 . option ( '--raw' , 'Output raw content only' )
184180 . option ( '--no-metadata' , 'Exclude metadata from list' )
185181 . option ( '--no-update-status' , 'Skip status update on archive' )
186- . action ( ( subcommand , args , options ) => sessionCommand ( subcommand , args , options ) ) ;
182+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/session.js' ) , 'sessionCommand' , subcommand , args , options ) ) ;
187183
188184 // CLI command
189185 program
@@ -233,7 +229,7 @@ export function run(argv: string[]): void {
233229 . option ( '--timeout <seconds>' , 'Timeout for watch command' )
234230 . option ( '--all' , 'Show all executions in show command' )
235231 . option ( '--to-file <path>' , 'Save output to file' )
236- . action ( ( subcommand , args , options ) => cliCommand ( subcommand , args , options ) ) ;
232+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/cli.js' ) , 'cliCommand' , subcommand , args , options ) ) ;
237233
238234 // Memory command
239235 program
@@ -262,7 +258,7 @@ export function run(argv: string[]): void {
262258 . option ( '--path <path>' , 'Project path (pipeline commands)' )
263259 . option ( '--max-sessions <n>' , 'Max sessions to extract (extract)' )
264260 . option ( '--session-ids <ids>' , 'Comma-separated session IDs (extract)' )
265- . action ( ( subcommand , args , options ) => memoryCommand ( subcommand , args , options ) ) ;
261+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/memory.js' ) , 'memoryCommand' , subcommand , args , options ) ) ;
266262
267263 // Core Memory command
268264 program
@@ -294,7 +290,7 @@ export function run(argv: string[]): void {
294290 . option ( '--topK <n>' , 'Max results for unified search' , '20' )
295291 . option ( '--minScore <n>' , 'Min relevance score for unified search' , '0' )
296292 . option ( '--category <cat>' , 'Filter by category for unified search' )
297- . action ( ( subcommand , args , options ) => coreMemoryCommand ( subcommand , args , options ) ) ;
293+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/core-memory.js' ) , 'coreMemoryCommand' , subcommand , args , options ) ) ;
298294
299295 // Hook command - CLI endpoint for Claude Code hooks
300296 program
@@ -306,7 +302,7 @@ export function run(argv: string[]): void {
306302 . option ( '--type <type>' , 'Context type: session-start, context' )
307303 . option ( '--path <path>' , 'File or project path' )
308304 . option ( '--limit <n>' , 'Max entries to return (for project-state)' )
309- . action ( ( subcommand , args , options ) => hookCommand ( subcommand , args , options ) ) ;
305+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/hook.js' ) , 'hookCommand' , subcommand , args , options ) ) ;
310306
311307 // Spec command - Project spec management (load/list/rebuild/status/init)
312308 program
@@ -317,7 +313,7 @@ export function run(argv: string[]): void {
317313 . option ( '--keywords <text>' , 'Keywords for spec matching (CLI mode)' )
318314 . option ( '--stdin' , 'Read input from stdin (Hook mode)' )
319315 . option ( '--json' , 'Output as JSON' )
320- . action ( ( subcommand , args , options ) => specCommand ( subcommand , args , options ) ) ;
316+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/spec.js' ) , 'specCommand' , subcommand , args , options ) ) ;
321317
322318 // Issue command - Issue lifecycle management with JSONL task tracking
323319 program
@@ -350,14 +346,14 @@ export function run(argv: string[]): void {
350346 . option ( '--state <state>' , 'GitHub issue state: open, closed, or all' )
351347 . option ( '--limit <n>' , 'Maximum number of issues to pull from GitHub' )
352348 . option ( '--labels <labels>' , 'Filter by GitHub labels (comma-separated)' )
353- . action ( ( subcommand , args , options ) => issueCommand ( subcommand , args , options ) ) ;
349+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/issue.js' ) , 'issueCommand' , subcommand , args , options ) ) ;
354350
355351 // Loop command - Loop management for multi-CLI orchestration
356352 program
357353 . command ( 'loop [subcommand] [args...]' )
358354 . description ( 'Loop management for automated multi-CLI execution' )
359355 . option ( '--session <name>' , 'Specify workflow session' )
360- . action ( ( subcommand , args , options ) => loopCommand ( subcommand , args , options ) ) ;
356+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/loop.js' ) , 'loopCommand' , subcommand , args , options ) ) ;
361357
362358 // Team command - Team Message Bus CLI interface
363359 program
@@ -373,15 +369,15 @@ export function run(argv: string[]): void {
373369 . option ( '--last <n>' , 'Last N messages (for list)' )
374370 . option ( '--role <role>' , 'Role name (for get_state)' )
375371 . option ( '--json' , 'Output as JSON' )
376- . action ( ( subcommand , args , options ) => teamCommand ( subcommand , args , options ) ) ;
372+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/team.js' ) , 'teamCommand' , subcommand , args , options ) ) ;
377373
378374 // Workflow command - Workflow installation and management
379375 program
380376 . command ( 'workflow [subcommand] [args...]' )
381377 . description ( 'Workflow installation and management (install, list, sync)' )
382378 . option ( '-f, --force' , 'Force installation without prompts' )
383379 . option ( '--source <source>' , 'Install specific source only' )
384- . action ( ( subcommand , args , options ) => workflowCommand ( subcommand , args , options ) ) ;
380+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/workflow.js' ) , 'workflowCommand' , subcommand , args , options ) ) ;
385381
386382 // Launcher command - unified Claude Code launcher with workflow switching
387383 program
@@ -391,15 +387,15 @@ export function run(argv: string[]): void {
391387 . option ( '-s, --settings <name>' , 'Settings profile to use' )
392388 . option ( '--claude-md <path>' , 'Path to CLAUDE.md (for add-workflow)' )
393389 . option ( '--cli-tools <path>' , 'Path to cli-tools.json (for add-workflow)' )
394- . action ( ( subcommand , args , options ) => launcherCommand ( subcommand , args , options ) ) ;
390+ . action ( async ( subcommand , args , options ) => invokeNamedExport ( ( ) => import ( './commands/launcher.js' ) , 'launcherCommand' , subcommand , args , options ) ) ;
395391
396392 // Chain-loader command - progressive skill chain loader
397393 program
398394 . command ( 'chain-loader [json]' )
399395 . description ( 'Progressive skill chain loader (JSON params: cmd, skill, chain, session_id, choice, node, entry_name)' )
400- . action ( ( json ) => chainLoaderCommand ( json ) ) ;
396+ . action ( async ( json ) => invokeNamedExport ( ( ) => import ( './commands/chain-loader.js' ) , 'chainLoaderCommand' , json ) ) ;
401397
402- program . parse ( argv ) ;
398+ await program . parseAsync ( argv ) ;
403399}
404400
405401// Note: run() is called by bin/ccw.js entry point
0 commit comments