{"version":3,"file":"interactive-shell.mjs","names":[],"sources":["../../src/lib/interactive-shell.ts"],"sourcesContent":["import { readline, execSync, spawnSync } from './node-shell-deps';\nimport type { Interface as ReadlineInterface } from 'readline';\nimport { stringToArgs } from './utils';\nimport { AnyInternalCLI } from './internal-cli';\nimport { getBin } from '@cli-forge/parser';\n\nexport interface InteractiveShellOptions {\n  prompt?: string;\n  prependArgs?: string[];\n}\n\ntype NormalizedInteractiveShellOptions = Required<InteractiveShellOptions>;\n\nfunction normalizeShellOptions(\n  cli: AnyInternalCLI,\n  options?: InteractiveShellOptions\n): NormalizedInteractiveShellOptions {\n  return {\n    prompt:\n      options?.prompt ??\n      (() => {\n        const chain = [cli.name];\n        if (cli.commandChain.length > 2) {\n          chain.push('...', ...cli.commandChain[cli.command.length - 1]);\n        } else {\n          chain.push(...cli.commandChain);\n        }\n        return chain.join(' ') + ' > ';\n      })(),\n    prependArgs: options?.prependArgs ?? [],\n  };\n}\n\nexport let INTERACTIVE_SHELL: InteractiveShell | undefined;\n\nexport class InteractiveShell {\n  private readonly rl: ReadlineInterface;\n  private listeners: any[] = [];\n\n  constructor(cli: AnyInternalCLI, opts?: InteractiveShellOptions) {\n    if (INTERACTIVE_SHELL) {\n      throw new Error(\n        'Only one interactive shell can be created at a time. Make sure the other instance is closed.'\n      );\n    }\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    INTERACTIVE_SHELL = this;\n\n    const { prompt, prependArgs } = normalizeShellOptions(cli, opts);\n\n    this.rl = readline\n      .createInterface({\n        input: process.stdin,\n        output: process.stdout,\n        prompt: prompt,\n      })\n      .once('SIGINT', () => {\n        process.emit('SIGINT');\n      });\n\n    // Show the cursor (in case it was hidden)\n    process.stdout.write('\\x1b[?25h');\n    this.rl.prompt();\n\n    this.registerLineListener(async (line) => {\n      const nextArgs = stringToArgs(line);\n      let currentCommand = cli;\n      for (const subcommand of cli.commandChain) {\n        currentCommand = currentCommand.registeredCommands[subcommand];\n      }\n      if (currentCommand.registeredCommands[nextArgs[0]]) {\n        spawnSync(\n          process.execPath,\n          [\n            ...process.execArgv,\n            getBin(process.argv),\n            ...prependArgs,\n            ...nextArgs,\n          ],\n          { stdio: 'inherit' }\n        );\n      } else if (nextArgs[0] === 'help') {\n        currentCommand.clone().printHelp();\n      } else if (nextArgs[0] === 'exit') {\n        this.close();\n        return true;\n      } else if (line.trim()) {\n        try {\n          execSync(line, { stdio: 'inherit' });\n        } catch {\n          // ignore\n        }\n      }\n      return false;\n    });\n  }\n\n  registerLineListener(callback: (line: string) => Promise<boolean | void>) {\n    const wrapped = async (line: string) => {\n      this.rl.pause();\n      const shouldHalt = await callback(line);\n      if (!shouldHalt) this.rl.prompt();\n    };\n    this.listeners.push(wrapped);\n    this.rl.on('line', wrapped);\n  }\n\n  close() {\n    this.listeners.forEach((listener) => this.rl.off('line', listener));\n    this.rl.close();\n    readline.moveCursor(process.stdout, -1 * this.rl.getCursorPos().cols, 0);\n    readline.clearScreenDown(process.stdout);\n    if (INTERACTIVE_SHELL === this) {\n      INTERACTIVE_SHELL = undefined;\n    }\n  }\n}\n"],"mappings":";;;;AAaA,SAAS,sBACP,KACA,SACmC;AACnC,QAAO;EACL,QACE,SAAS,iBACF;GACL,MAAM,QAAQ,CAAC,IAAI,KAAK;AACxB,OAAI,IAAI,aAAa,SAAS,EAC5B,OAAM,KAAK,OAAO,GAAG,IAAI,aAAa,IAAI,QAAQ,SAAS,GAAG;OAE9D,OAAM,KAAK,GAAG,IAAI,aAAa;AAEjC,UAAO,MAAM,KAAK,IAAI,GAAG;MACvB;EACN,aAAa,SAAS,eAAe,EAAE;EACxC;;AAGH,IAAW;AAEX,IAAa,mBAAb,MAA8B;CAC5B;CACA,YAA2B,EAAE;CAE7B,YAAY,KAAqB,MAAgC;AAC/D,MAAI,kBACF,OAAM,IAAI,MACR,+FACD;AAGH,sBAAoB;EAEpB,MAAM,EAAE,QAAQ,gBAAgB,sBAAsB,KAAK,KAAK;AAEhE,OAAK,KAAK,SACP,gBAAgB;GACf,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACR;GACT,CAAC,CACD,KAAK,gBAAgB;AACpB,WAAQ,KAAK,SAAS;IACtB;AAGJ,UAAQ,OAAO,MAAM,YAAY;AACjC,OAAK,GAAG,QAAQ;AAEhB,OAAK,qBAAqB,OAAO,SAAS;GACxC,MAAM,WAAW,aAAa,KAAK;GACnC,IAAI,iBAAiB;AACrB,QAAK,MAAM,cAAc,IAAI,aAC3B,kBAAiB,eAAe,mBAAmB;AAErD,OAAI,eAAe,mBAAmB,SAAS,IAC7C,WACE,QAAQ,UACR;IACE,GAAG,QAAQ;IACX,OAAO,QAAQ,KAAK;IACpB,GAAG;IACH,GAAG;IACJ,EACD,EAAE,OAAO,WAAW,CACrB;YACQ,SAAS,OAAO,OACzB,gBAAe,OAAO,CAAC,WAAW;YACzB,SAAS,OAAO,QAAQ;AACjC,SAAK,OAAO;AACZ,WAAO;cACE,KAAK,MAAM,CACpB,KAAI;AACF,aAAS,MAAM,EAAE,OAAO,WAAW,CAAC;WAC9B;AAIV,UAAO;IACP;;CAGJ,qBAAqB,UAAqD;EACxE,MAAM,UAAU,OAAO,SAAiB;AACtC,QAAK,GAAG,OAAO;AAEf,OAAI,CADe,MAAM,SAAS,KAAK,CACtB,MAAK,GAAG,QAAQ;;AAEnC,OAAK,UAAU,KAAK,QAAQ;AAC5B,OAAK,GAAG,GAAG,QAAQ,QAAQ;;CAG7B,QAAQ;AACN,OAAK,UAAU,SAAS,aAAa,KAAK,GAAG,IAAI,QAAQ,SAAS,CAAC;AACnE,OAAK,GAAG,OAAO;AACf,WAAS,WAAW,QAAQ,QAAQ,KAAK,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE;AACxE,WAAS,gBAAgB,QAAQ,OAAO;AACxC,MAAI,sBAAsB,KACxB,qBAAoB,KAAA"}