Class Ghostwriter

java.lang.Object
org.machanism.machai.gw.processor.Ghostwriter

public final class Ghostwriter extends Object
Command-line entry point for the Ghostwriter application.

Ghostwriter scans a project's files or directories and processes them with GenAI guidance. It supports two processing modes:

  • Guidance mode (default) — processes files using inline guidance comments found in the scanned content, via GuidanceProcessor.
  • Act mode (enabled with --act) — runs a predefined, possibly interactive, prompt ("act") against the project, via ActProcessor.

Runtime behavior can be configured through command-line options, a persisted properties file (see PropertiesConfigurator), or a combination of both, with command-line options taking precedence. This class is responsible for parsing CLI arguments, resolving effective settings, wiring up the appropriate processor, and mapping processing outcomes to JVM exit codes.

This class is not intended to be instantiated; it exposes only a static main(String[]) entry point.

  • Field Details

  • Constructor Details

    • Ghostwriter

      private Ghostwriter()
  • Method Details

    • main

      public static void main(String[] args) throws IOException, org.apache.commons.cli.ParseException
      Starts the Ghostwriter CLI.

      Parses command-line arguments, loads configuration, resolves runtime settings, and delegates to the appropriate processor. If --help is specified, prints usage information and returns without processing anything.

      Parameters:
      args - command-line arguments
      Throws:
      IOException - if configuration or processing fails with an I/O error
      org.apache.commons.cli.ParseException - if command-line parsing fails
    • createOptions

      private static org.apache.commons.cli.Options createOptions()
      Creates the supported CLI option definitions.
      Returns:
      configured options describing every flag accepted by the CLI
    • printHelp

      private static void printHelp(org.apache.commons.cli.Options options) throws IOException
      Prints CLI help text, including usage syntax, all available options, and example invocations, to standard output.
      Parameters:
      options - available command-line options
      Throws:
      IOException
    • logVersion

      private static void logVersion()
      Logs the application version when available from package metadata. If no implementation version is present (e.g., when running from an IDE without a packaged manifest), no log entry is produced.
    • initializeConfiguration

      private static void initializeConfiguration(org.apache.commons.cli.CommandLine cmd, String projectDir, PropertiesConfigurator config) throws IOException
      Loads the external configuration properties file when present, using either the GWConstants.CONFIG_PROP_NAME system property or the default Ghostwriter properties file name, resolved relative to the home directory.

      Failures to locate or load the file are tolerated: a missing file is silently ignored, while unexpected runtime errors are logged as warnings so startup can continue.

      Parameters:
      config - configuration source to populate
      projectDir -
      Throws:
      IOException
    • loadRuntimeSettings

      private static Ghostwriter.RuntimeSettings loadRuntimeSettings(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config, Scanner scanner)
      Resolves runtime settings from CLI arguments and persisted configuration.

      For every setting, an explicit command-line value takes precedence over the corresponding value from config, which in turn takes precedence over any built-in default.

      Parameters:
      cmd - parsed command line
      config - configuration source
      scanner - console scanner used for optional interactive prompts
      Returns:
      populated runtime settings ready to be applied to a processor
    • resolveGenai

      private static String resolveGenai(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config)
      Resolves the configured AI provider/model, preferring the --model command-line option over the corresponding configuration value.
      Parameters:
      cmd - parsed command line
      config - configuration source
      Returns:
      provider/model identifier (e.g. "OpenAI:gpt-5.1"), or null if not configured
    • resolveInstructions

      private static String resolveInstructions(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config, Scanner scanner)
      Resolves the system instruction text from CLI input or configuration.

      If the --instructions option is present without a value, the user is interactively prompted (via scanner) to enter the instruction text.

      Parameters:
      cmd - parsed command line
      config - configuration source
      scanner - console scanner used for prompting when no value is supplied
      Returns:
      resolved instruction text, or null if not configured
    • resolveExcludes

      private static String[] resolveExcludes(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config)
      Resolves the exclude list from the --excludes command-line option or configuration, splitting the comma-separated value into individual patterns.
      Parameters:
      cmd - parsed command line
      config - configuration source
      Returns:
      exclude patterns split by comma, or null if not configured
    • resolveMultiThread

      private static String resolveMultiThread(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config)
      Resolves the concurrency (thread count) setting from the --threads command-line option or configuration.
      Parameters:
      cmd - parsed command line
      config - configuration source
      Returns:
      configured thread count as text, or null if not configured
    • resolveProjectDir

      private static File resolveProjectDir(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config)
      Resolves the project directory from the -d command-line option or configuration.
      Parameters:
      cmd - parsed command line
      config - configuration source
      Returns:
      project directory; falls back to the current user directory when not explicitly configured
    • resolvePaths

      private static String[] resolvePaths(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config)
      Resolves the scan directories or patterns to process, in order of precedence: positional command-line arguments, then the configured path property, then the current directory (".") as a final fallback.
      Parameters:
      cmd - parsed command line
      config - configuration source
      Returns:
      scan path(s) or pattern(s) to process; never null or empty
    • promptForValue

      private static String promptForValue(Scanner scanner, String prompt)
      Prompts the user for a single (possibly multi-line) piece of input on standard input, printing the prompt via Console when available or plain System.out otherwise.

      Lines ending with GWConstants.MULTIPLE_LINES_BREAKER are treated as continued: the breaker is stripped and a line separator is appended, and reading continues on the next line. Reading stops at the first line that does not end with the breaker. After input is collected, a right-aligned signature footer with the current user name is printed.

      Parameters:
      scanner - scanner reading standard input
      prompt - prompt text to display before reading
      Returns:
      the entered value, with continuation markers removed and multiple lines joined by the platform line separator
    • logStartup

      private static void logStartup(File projectDir)
      Logs basic startup path information at INFO level: the resolved Ghostwriter home directory and the resolved project directory.
      Parameters:
      projectDir - project directory
    • execute

      private static void execute(Scanner scanner, PropertiesConfigurator config, org.apache.commons.cli.CommandLine cmd, Ghostwriter.RuntimeSettings settings) throws IOException
      Creates and runs the selected processor (guidance or act mode) against the resolved scan paths, then applies the resulting exit code.

      Recognized failures are logged and translated into a non-zero exit code via handleExitCode(int) rather than propagating as uncaught exceptions, except for I/O errors during processor creation, which are rethrown.

      Parameters:
      scanner - console scanner
      config - configuration source
      cmd - parsed command line
      settings - resolved runtime settings
      Throws:
      IOException - if processor creation fails with an I/O error
    • handleExitCode

      private static void handleExitCode(int exitCode)
      Terminates the JVM with the given exit code when it is non-zero. A zero exit code is treated as success and does not trigger System.exit(int).
      Parameters:
      exitCode - exit code to apply
    • createProcessor

      private static AIFileProcessor createProcessor(Scanner scanner, PropertiesConfigurator config, org.apache.commons.cli.CommandLine cmd, Ghostwriter.RuntimeSettings settings) throws IOException
      Creates either a GuidanceProcessor (default mode) or an ActProcessor (when --act is specified), fully configured for the current run.
      Parameters:
      scanner - console scanner
      config - configuration source
      cmd - parsed command line
      settings - resolved runtime settings
      Returns:
      configured processor ready for use
      Throws:
      IOException - if act initialization fails
    • createActProcessor

      private static ActProcessor createActProcessor(Scanner scanner, PropertiesConfigurator config, Ghostwriter.RuntimeSettings settings)
      Creates an ActProcessor with console-backed interactive input, overriding AIFileProcessor.input() to read from the CLI scanner instead of the default input source. Logs the resolved AI model, if any, at INFO level.
      Parameters:
      scanner - console scanner
      config - configuration source
      settings - resolved runtime settings
      Returns:
      act processor configured for CLI-driven interactive input
    • readActInput

      private static String readActInput(Scanner scanner)
      Reads possibly multi-line interactive act input from standard input, printing the USER_INPUT_PREFIX prompt before each line and supporting the same continuation-marker convention as promptForValue(Scanner, String).
      Parameters:
      scanner - scanner reading standard input
      Returns:
      collected input text, with continuation markers removed and multiple lines joined by the platform line separator
    • formatConsole

      private static void formatConsole(Console console, String message)
      Writes a prompt message to the console when available. If no Console is attached (e.g., input is redirected), no output is produced.
      Parameters:
      console - console instance, may be null
      message - message to print, followed by ": "
    • appendContinuedLine

      private static void appendContinuedLine(StringBuilder sb, String nextLine)
      Appends a continued input line to the buffer, stripping the trailing continuation marker and replacing it with the platform line separator.
      Parameters:
      sb - buffer receiving the line
      nextLine - line that ends with the continuation marker
    • configureActsLocation

      private static void configureActsLocation(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config, ActProcessor actProcessor)
      Configures a custom acts location on the given processor when one is provided via the --acts command-line option or configuration. Leaves the processor's default acts location unchanged if none is configured.
      Parameters:
      cmd - parsed command line
      config - configuration source
      actProcessor - act processor to configure
    • configureDefaultAct

      private static void configureDefaultAct(org.apache.commons.cli.CommandLine cmd, PropertiesConfigurator config, Scanner scanner, ActProcessor actProcessor) throws IOException
      Configures the default act to run when act mode is enabled.

      The act name/prompt is resolved from the --act command-line option value or configuration. If --act is present without a value, the user is interactively prompted (via scanner) to enter the act name.

      Parameters:
      cmd - parsed command line
      config - configuration source
      scanner - scanner used for prompting when no value is supplied
      actProcessor - act processor to configure
      Throws:
      IOException - if act loading fails
    • applyCommonSettings

      private static void applyCommonSettings(AIFileProcessor processor, Ghostwriter.RuntimeSettings settings)
      Applies shared processor settings — instructions, excludes, and concurrency — to the given processor, skipping any setting that was not resolved.
      Parameters:
      processor - processor to configure
      settings - resolved runtime settings
    • applyInstructions

      private static void applyInstructions(AIFileProcessor processor, String instructions)
      Applies custom instructions to the processor when present, logging an abbreviated version of the text at INFO level.
      Parameters:
      processor - processor to configure
      instructions - instruction text, or null to leave unset
    • applyExcludes

      private static void applyExcludes(AIFileProcessor processor, String[] excludes)
      Applies exclude patterns to the processor when configured, logging the full list at INFO level.
      Parameters:
      processor - processor to configure
      excludes - exclude patterns, or null to leave unset
    • applyConcurrency

      private static void applyConcurrency(AIFileProcessor processor, String threads)
      Applies the configured concurrency (thread count) setting to the processor when present, logging the resolved value at INFO level.
      Parameters:
      processor - processor to configure
      threads - thread count as text, or null to leave unset; parsed with Integer.parseInt(String)
    • logAbbreviatedMessage

      private static void logAbbreviatedMessage(String label, String value)
      Logs an abbreviated value at INFO level, skipping the abbreviation work entirely when INFO logging is disabled.
      Parameters:
      label - message label
      value - message value
    • processPathectories

      private static int processPathectories(AIFileProcessor processor, String[] paths, File projectDir)
      Processes all requested scan paths using the given processor, converting recognized failures into an appropriate exit code instead of propagating them further, and always logging usage statistics and completion.
      Parameters:
      processor - configured processor
      paths - scan directories or patterns to process, in order
      projectDir - project directory
      Returns:
      0 on success; the termination exception's exit code if processing was explicitly terminated; EXIT_CODE_ERROR for any other handled failure
    • handleProcessTermination

      private static int handleProcessTermination(ProcessTerminationException exception)
      Handles an explicit process termination request raised by a processor or tool, logging the termination message and reason before returning the exit code requested by the exception.
      Parameters:
      exception - termination exception carrying the requested exit code
      Returns:
      exit code to use, as specified by exception
    • handleProcessingFailure

      private static int handleProcessingFailure(String message, Exception exception)
      Logs a processing failure with the given message prefix and returns the generic error exit code.
      Parameters:
      message - log prefix describing the failure category
      exception - failure that occurred during processing
      Returns:
      EXIT_CODE_ERROR