@@ -4,16 +4,57 @@ import { generatePlan } from "./planner.js";
44import { runPlan } from "./runner.js" ;
55import type { Step } from "./catalog.js" ;
66
7+ // ---------------------------------------------------------------------------
8+ // Help
9+ // ---------------------------------------------------------------------------
10+ function showHelp ( ) : void {
11+ p . intro ( "json-cli — AI-powered CLI task runner" ) ;
12+ p . log . message ( `Usage\n json-cli "<your goal>" [options]\n` ) ;
13+ p . log . message (
14+ `Options
15+ --provider <name> AI provider: claude | openai | ollama (default: claude)
16+ --yes Skip confirmation prompt
17+ --dry-run Show plan without executing
18+ --help Show this help message` ,
19+ ) ;
20+ p . log . message (
21+ `Examples
22+ json-cli "please run tests"
23+ json-cli "run tests and build"
24+ json-cli "run tests and build" --yes
25+ json-cli "git add, commit with message 'fix: bug', push"
26+ json-cli "clone https://github.com/user/repo, install deps, run dev"
27+ json-cli "run tests and publish" --provider openai
28+ json-cli "run tests" --dry-run` ,
29+ ) ;
30+ p . outro ( "Docs: https://github.com/ekaone/json-cli" ) ;
31+ }
32+
733// ---------------------------------------------------------------------------
834// Parse CLI args
9- // e.g. json-cli "run tests" --provider claude
35+ // e.g. json-cli "run tests" --provider claude --yes --dry-run
1036// ---------------------------------------------------------------------------
11- function parseArgs ( ) : { prompt : string ; provider : ProviderName } {
37+ function parseArgs ( ) : {
38+ prompt : string ;
39+ provider : ProviderName ;
40+ yes : boolean ;
41+ dryRun : boolean ;
42+ } {
1243 const args = process . argv . slice ( 2 ) ;
44+
45+ // show help if no args or --help flag
46+ if ( args . length === 0 || args . includes ( "--help" ) ) {
47+ showHelp ( ) ;
48+ process . exit ( 0 ) ;
49+ }
50+
1351 const providerFlag = args . indexOf ( "--provider" ) ;
1452 const provider : ProviderName =
1553 providerFlag !== - 1 ? ( args [ providerFlag + 1 ] as ProviderName ) : "claude" ;
1654
55+ const yes = args . includes ( "--yes" ) ;
56+ const dryRun = args . includes ( "--dry-run" ) ;
57+
1758 const prompt = args
1859 . filter (
1960 ( a , i ) =>
@@ -22,13 +63,11 @@ function parseArgs(): { prompt: string; provider: ProviderName } {
2263 . join ( " " ) ;
2364
2465 if ( ! prompt ) {
25- console . error (
26- 'Usage: json-cli "<your goal>" [--provider claude|openai|ollama]' ,
27- ) ;
28- process . exit ( 1 ) ;
66+ showHelp ( ) ;
67+ process . exit ( 0 ) ;
2968 }
3069
31- return { prompt, provider } ;
70+ return { prompt, provider, yes , dryRun } ;
3271}
3372
3473// ---------------------------------------------------------------------------
@@ -46,9 +85,11 @@ function formatStep(step: Step): string {
4685// Main
4786// ---------------------------------------------------------------------------
4887async function main ( ) {
49- const { prompt, provider : providerName } = parseArgs ( ) ;
88+ const { prompt, provider : providerName , yes , dryRun } = parseArgs ( ) ;
5089
51- p . intro ( `json-cli — powered by ${ providerName } ` ) ;
90+ p . intro (
91+ `json-cli — powered by ${ providerName } ${ dryRun ? " (dry run)" : "" } ` ,
92+ ) ;
5293
5394 // Step 1: Generate plan
5495 const spinner = p . spinner ( ) ;
@@ -82,27 +123,37 @@ async function main() {
82123 ) ;
83124 }
84125
85- // Step 4: Confirm
86- const confirmed = await p . confirm ( { message : "Proceed?" } ) ;
87- if ( p . isCancel ( confirmed ) || ! confirmed ) {
88- p . cancel ( "Aborted." ) ;
89- process . exit ( 0 ) ;
126+ // Step 4: Dry run — show plan and exit
127+ if ( dryRun ) {
128+ p . outro ( "Dry run complete — no commands were executed." ) ;
129+ setTimeout ( ( ) => process . exit ( 0 ) , 50 ) ;
90130 }
91131
92- // Step 5: Execute
132+ // Step 5: Confirm — skip if --yes
133+ if ( ! yes ) {
134+ const confirmed = await p . confirm ( { message : "Proceed?" } ) ;
135+ if ( p . isCancel ( confirmed ) || ! confirmed ) {
136+ p . cancel ( "Aborted." ) ;
137+ setTimeout ( ( ) => process . exit ( 0 ) , 50 ) ;
138+ }
139+ } else {
140+ p . log . info ( "Skipping confirmation (--yes)" ) ;
141+ }
142+
143+ // Step 6: Execute
93144 console . log ( "" ) ;
94145 const result = await runPlan ( plan , ( step , i , total ) => {
95146 p . log . step ( `Step ${ i + 1 } /${ total } : ${ formatStep ( step ) } ` ) ;
96147 } ) ;
97148
98- // Step 6 : Result
149+ // Step 7 : Result
99150 if ( result . success ) {
100151 p . outro ( "✅ All steps completed successfully." ) ;
101152 } else {
102153 p . log . error (
103154 `❌ Failed at step ${ result . failedStep ?. id } : ${ result . failedStep ?. description } \n${ result . error ?? "" } ` ,
104155 ) ;
105- process . exit ( 1 ) ;
156+ setTimeout ( ( ) => process . exit ( 1 ) , 50 ) ;
106157 }
107158}
108159
0 commit comments