11import * as p from "@clack/prompts" ;
2+ import { createRequire } from "module" ;
23import { resolveProvider , type ProviderName } from "./providers/index.js" ;
34import { generatePlan } from "./planner.js" ;
45import { runPlan } from "./runner.js" ;
6+ import { calculateCost , formatCost } from "./providers/pricing.js" ;
57import type { Step } from "./catalog.js" ;
68
79// ---------------------------------------------------------------------------
@@ -16,7 +18,8 @@ function showHelp(): void {
1618 --yes Skip confirmation prompt
1719 --dry-run Show plan without executing
1820 --debug Show system prompt and raw AI response
19- --help Show this help message` ,
21+ --help Show this help message
22+ --version, -v Show version` ,
2023 ) ;
2124 p . log . message (
2225 `Examples
@@ -45,6 +48,14 @@ function parseArgs(): {
4548 debug : boolean ;
4649} {
4750 const args = process . argv . slice ( 2 ) ;
51+ const require = createRequire ( import . meta. url ) ;
52+ const { version, name } = require ( "../package.json" ) ;
53+
54+ // show version
55+ if ( args . includes ( "--version" ) || args . includes ( "-v" ) ) {
56+ console . log ( `${ name } @${ version } ` ) ;
57+ process . exit ( 0 ) ;
58+ }
4859
4960 // show help if no args or --help flag
5061 if ( args . length === 0 || args . includes ( "--help" ) ) {
@@ -101,28 +112,28 @@ async function main() {
101112 const spinner = p . spinner ( ) ;
102113 spinner . start ( "Thinking..." ) ;
103114
104- let plan ;
115+ let planResult ;
105116 try {
106117 const provider = resolveProvider ( providerName ) ;
107- plan = await generatePlan ( prompt , provider , debug ) ;
108- spinner . stop ( "Plan ready" ) ;
118+ planResult = await generatePlan ( prompt , provider , debug ) ;
119+ spinner . stop ( debug ? "" : "Plan ready" ) ;
109120 } catch ( err ) {
110121 spinner . stop ( "Failed to generate plan" ) ;
111122 p . log . error ( err instanceof Error ? err . message : String ( err ) ) ;
112123 process . exit ( 1 ) ;
113124 }
114125
115126 // Step 2: Show plan
116- p . log . info ( `Goal: ${ plan . goal } \n` ) ;
117- plan . steps . forEach ( ( step , i ) => {
127+ p . log . info ( `Goal: ${ planResult . plan . goal } \n` ) ;
128+ planResult . plan . steps . forEach ( ( step , i ) => {
118129 const isShell = step . type === "shell" ;
119130 p . log . message (
120131 ` ${ i + 1 } . ${ formatStep ( step ) } ${ isShell ? " ⚠ shell" : "" } ` ,
121132 ) ;
122133 } ) ;
123134
124135 // Step 3: Extra warning if any shell steps
125- const hasShell = plan . steps . some ( ( s ) => s . type === "shell" ) ;
136+ const hasShell = planResult . plan . steps . some ( ( s ) => s . type === "shell" ) ;
126137 if ( hasShell ) {
127138 p . log . warn (
128139 "Plan contains shell commands — review carefully before proceeding." ,
@@ -131,38 +142,54 @@ async function main() {
131142
132143 // Step 4: Dry run — show plan and exit
133144 if ( dryRun ) {
134- p . outro ( "Dry run complete — no commands were executed." ) ;
135- setTimeout ( ( ) => process . exit ( 0 ) , 50 ) ;
136- return ;
145+ const { input, output } = planResult . usage ;
146+ const cost = calculateCost ( providerName , input , output ) ;
147+ const costStr = formatCost ( cost ) ;
148+ const usageStr =
149+ input > 0 || output > 0
150+ ? ` | tokens: ${ input } in / ${ output } out${ costStr ? ` | ${ costStr } ` : "" } `
151+ : "" ;
152+
153+ p . outro ( `Dry run complete — no commands were executed.${ usageStr } ` ) ;
154+ await new Promise ( ( r ) => setTimeout ( r , 100 ) ) ;
155+ process . exit ( 0 ) ;
137156 }
138157
139158 // Step 5: Confirm — skip if --yes
140159 if ( ! yes ) {
141160 const confirmed = await p . confirm ( { message : "Proceed?" } ) ;
142161 if ( p . isCancel ( confirmed ) || ! confirmed ) {
143162 p . cancel ( "Aborted." ) ;
144- setTimeout ( ( ) => process . exit ( 0 ) , 50 ) ;
145- return ;
163+ await new Promise ( ( r ) => setTimeout ( r , 100 ) ) ;
164+ process . exit ( 0 ) ;
146165 }
147166 } else {
148167 p . log . info ( "Skipping confirmation (--yes)" ) ;
149168 }
150169
151170 // Step 6: Execute
152171 console . log ( "" ) ;
153- const result = await runPlan ( plan , ( step , i , total ) => {
172+ const result = await runPlan ( planResult . plan , ( step , i , total ) => {
154173 p . log . step ( `Step ${ i + 1 } /${ total } : ${ formatStep ( step ) } ` ) ;
155174 } ) ;
156175
157176 // Step 7: Result
158177 if ( result . success ) {
159- p . outro ( "✅ All steps completed successfully." ) ;
178+ const { input, output } = planResult . usage ;
179+ const cost = calculateCost ( providerName , input , output ) ;
180+ const costStr = formatCost ( cost ) ;
181+ const usageStr =
182+ input > 0 || output > 0
183+ ? ` | tokens: ${ input } in / ${ output } out${ costStr ? ` | ${ costStr } ` : "" } `
184+ : "" ;
185+
186+ p . outro ( `✅ All steps completed successfully.${ usageStr } ` ) ;
160187 } else {
161188 p . log . error (
162189 `❌ Failed at step ${ result . failedStep ?. id } : ${ result . failedStep ?. description } \n${ result . error ?? "" } ` ,
163190 ) ;
164- setTimeout ( ( ) => process . exit ( 1 ) , 50 ) ;
165- return ;
191+ await new Promise ( ( r ) => setTimeout ( r , 100 ) ) ;
192+ process . exit ( 1 ) ;
166193 }
167194}
168195
0 commit comments