import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import eu.svjatoslav.alyverkko_cli.Command;
-import eu.svjatoslav.alyverkko_cli.Utils;
import eu.svjatoslav.alyverkko_cli.configuration.Configuration;
+import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationModel;
import eu.svjatoslav.commons.cli_helper.CLIHelper;
import eu.svjatoslav.commons.cli_helper.parameter_parser.Parser;
import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.FileOption;
-import eu.svjatoslav.commons.cli_helper.parameter_parser.parameter.NullOption;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import static eu.svjatoslav.alyverkko_cli.Utils.printRedMessageToConsole;
import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.getConfigurationFile;
-import static eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper.loadConfiguration;
import static eu.svjatoslav.commons.cli_helper.CLIHelper.*;
-import static java.lang.Boolean.TRUE;
/**
* A single WizardCommand that:
public class WizardCommand implements Command {
// Command-line parser to handle wizard arguments
- private final Parser parser = new Parser();
-
- // If present, force overwriting existing config
- private final NullOption forceOverwriteOption = parser.add(new NullOption("Force overwrite existing configuration"))
- .addAliases("--force", "-f");
+ private final Parser cliParser = new Parser();
/**
* Optional CLI argument for specifying a configuration file path.
*/
- public FileOption configFileOption = parser.add(new FileOption("Configuration file path"))
+ public FileOption configFileOption = cliParser.add(new FileOption("Configuration file path"))
.addAliases("--config", "-c");
// The config object (loaded or newly created)
- private Configuration config;
+ private Configuration configuration;
+
+ private File configurationFile;
@Override
- public String getName() {
+ public String getCommandName() {
return "wizard";
}
@Override
- public void execute(String[] cliArguments) throws IOException {
- if (!parser.parse(cliArguments)) {
+ public void executeCommand(String[] cliArguments) throws IOException {
+ if (!cliParser.parse(cliArguments)) {
System.out.println("Failed to parse command-line arguments");
- parser.showHelp();
+ cliParser.showHelp();
return;
}
+ configurationFile = getConfigurationFile(configFileOption);
+ loadOrCreateConfiguration();
+
+ // TODO: ------- continue from here --------
- // 1. Load existing config if possible
- File configFile = loadOrCreateConfiguration();
// 2. Validate and fix each parameter
checkAndFixAllParameters();
fixModelEntries();
// 4. If the user is satisfied, attempt to save
- trySaveConfiguration(configFile);
+ trySaveConfiguration(this.configurationFile);
// 5. Final selftest pass
boolean finalOk = doFinalCheck();
} else {
System.out.println("\nSome checks did not pass, but we've saved the best config we could.");
System.out.println("You might want to run 'wizard' again or manually edit the YAML file:\n "
- + configFile.getAbsolutePath() + "\n");
+ + this.configurationFile.getAbsolutePath() + "\n");
}
}
- private File loadOrCreateConfiguration() throws IOException {
- File configFile = getConfigurationFile(configFileOption);
+ private void loadOrCreateConfiguration() throws IOException {
+ validateConfigurationFile();
- if (configFile.exists() && configFile.isFile()) {
- System.out.println("Found existing configuration at " + configFile.getAbsolutePath());
- System.out.println("I will check whether everything is valid, and if not, allow you to fix it.\n");
- config = loadConfiguration(configFile);
+ if (configurationFile.exists()) {
+ System.out.println("Found existing configuration at: \"" + configurationFile.getAbsolutePath() + "\"");
+ configuration = ConfigurationHelper.loadConfiguration(configurationFile);
} else {
// If no config found, create a fresh one
- System.out.println("No existing configuration found. Let's create one!\n");
- config = new Configuration();
+ System.out.println("Existing configuration not found at \""
+ + configurationFile.getAbsolutePath() + "\". Initializing new blank configuration.");
+ configuration = new Configuration();
+ }
+ }
+
+ private void validateConfigurationFile() {
+ if (!configurationFile.exists()) return; // No need to check further if it doesn't exist
+
+ if (configurationFile.isDirectory()) {
+ System.err.println("ERROR: Configuration file path incorrectly points to a directory: \"" + configurationFile.getAbsolutePath()
+ + "\". Please specify a file instead.");
+ System.exit(1);
+ }
+
+ if (!configurationFile.canRead()) {
+ System.err.println("ERROR: Cannot read configuration file: \"" + configurationFile.getAbsolutePath()
+ + "\". Please check permissions.");
+ System.exit(1);
+ }
+
+ if (!configurationFile.canWrite()) {
+ System.err.println("ERROR: Cannot write to configuration file: \"" + configurationFile.getAbsolutePath() +
+ "\". Please file check permissions.");
+ System.exit(1);
}
- return configFile;
}
/**
// 2.2 models_directory
while (true) {
- File modelsDir = config.getModelsDirectory();
+ File modelsDir = configuration.getModelsDirectory();
if (modelsDir == null || !modelsDir.isDirectory() || !modelsDir.exists()) {
System.out.println("Models directory is missing or invalid.");
String defaultVal = (modelsDir == null) ? "~/.config/alyverkko-cli/models" : modelsDir.getPath();
defaultVal
);
modelsDir = new File(userInput);
- config.setModelsDirectory(modelsDir);
+ configuration.setModelsDirectory(modelsDir);
// Attempt to create if not exist
if (!modelsDir.exists()) {
if (askBoolean("Models directory is: " + modelsDir.getAbsolutePath() + " . Is this OK?", true)) {
break;
}
- config.setModelsDirectory(null);
+ configuration.setModelsDirectory(null);
}
}
// 2.3 prompts_directory
while (true) {
- File promptsDir = config.getPromptsDirectory();
+ File promptsDir = configuration.getPromptsDirectory();
if (promptsDir == null || !promptsDir.isDirectory() || !promptsDir.exists()) {
System.out.println("Prompts directory is missing or invalid.");
String defaultVal = (promptsDir == null) ? "~/.config/alyverkko-cli/prompts" : promptsDir.getPath();
defaultVal
);
promptsDir = new File(userInput);
- config.setPromptsDirectory(promptsDir);
+ configuration.setPromptsDirectory(promptsDir);
// Attempt to create if not exist
if (!promptsDir.exists()) {
if (askBoolean("Prompts directory is: " + promptsDir.getAbsolutePath() + " . Is this OK?", true)) {
break;
}
- config.setPromptsDirectory(null);
+ configuration.setPromptsDirectory(null);
}
}
// 2.4 llama_cli_path
while (true) {
- File llamaCli = config.getLlamaCliPath();
+ File llamaCli = configuration.getLlamaCliPath();
boolean valid = (llamaCli != null && llamaCli.isFile() && llamaCli.exists());
if (!valid) {
System.out.println("The 'llama-cli' executable path is missing or invalid.");
defaultVal
);
llamaCli = new File(userInput);
- config.setLlamaCliPath(llamaCli);
+ configuration.setLlamaCliPath(llamaCli);
} else {
if (askBoolean("Llama-cli path is: " + llamaCli.getAbsolutePath() + " . Is this OK?", true)) {
break;
}
- config.setLlamaCliPath(null);
+ configuration.setLlamaCliPath(null);
}
}
// 2.5 default_temperature
- float oldTemp = config.getDefaultTemperature();
+ float oldTemp = configuration.getDefaultTemperature();
if (oldTemp < 0.0f || oldTemp > 3.0f) {
oldTemp = 0.7f;
}
);
- config.setDefaultTemperature(newTemp);
+ configuration.setDefaultTemperature(newTemp);
// 2.6 thread_count
- int oldThreadCount = config.getThreadCount();
+ int oldThreadCount = configuration.getThreadCount();
if (oldThreadCount < 1) {
oldThreadCount = 6;
}
oldThreadCount,
1, null, false
);
- config.setThreadCount(newThreadCount);
+ configuration.setThreadCount(newThreadCount);
// 2.7 batch_thread_count
- int oldBatchThreadCount = config.getBatchThreadCount();
+ int oldBatchThreadCount = configuration.getBatchThreadCount();
if (oldBatchThreadCount < 1) {
oldBatchThreadCount = 10;
}
oldBatchThreadCount,
1, null, false
);
- config.setBatchThreadCount(newBatchCount);
+ configuration.setBatchThreadCount(newBatchCount);
}
/**
private void checkMailDirectory() {
System.out.println("Älyverkko-cli uses a 'mail' directory to store and discover tasks that it has to solve. " +
"AI generated solutions are appended at the end of the task file. " +
- "It should be a directory that you can write to.\n\nCurrent mail directory is: " + describeValue(config.getMailDirectory()));
+ "It should be a directory that you can write to.\n\nCurrent mail directory is: " + describeValue(configuration.getMailDirectory()));
// 2.1 mail_directory
while (true) {
- File mailDir = config.getMailDirectory();
+ File mailDir = configuration.getMailDirectory();
if (mailDir == null) {
String userInput = askString(
"Enter the desired mail directory path",
, null, null, false);
mailDir = new File(userInput);
}
- config.setMailDirectory(mailDir);
+ configuration.setMailDirectory(mailDir);
// Attempt to create if not exist
if (!mailDir.exists()) {
* Then let user manually add more if desired.
*/
private void fixModelEntries() {
- if (config.getModels() == null) {
- config.setModels(new ArrayList<>());
+ if (configuration.getModels() == null) {
+ configuration.setModels(new ArrayList<>());
}
// Remove references to nonexistent model files
// Offer to autodiscover new model files
if (askBoolean("\nAttempt to autodiscover new .gguf model files in the models directory?", true)) {
- discoverAndSuggestNewModels(config.getModelsDirectory(), config.getModels());
+ discoverAndSuggestNewModels(configuration.getModelsDirectory(), configuration.getModels());
}
// Let user manually add new models
* let user decide whether to remove that model or keep it (perhaps to fix the path).
*/
private void removeDeadModelReferences() {
- Iterator<ConfigurationModel> it = config.getModels().iterator();
+ Iterator<ConfigurationModel> it = configuration.getModels().iterator();
while (it.hasNext()) {
ConfigurationModel cm = it.next();
- File f = new File(config.getModelsDirectory(), cm.getFilesystemPath());
+ File f = new File(configuration.getModelsDirectory(), cm.getFilesystemPath());
if (!f.exists()) {
System.out.println("\nModel with alias '" + cm.getAlias()
+ "' references missing file: " + f.getAbsolutePath());
);
// Check for duplicates
- boolean alreadyExists = config.getModels().stream()
+ boolean alreadyExists = configuration.getModels().stream()
.anyMatch(m -> m.getAlias().equals(alias));
if (alreadyExists) {
printRedMessageToConsole("Model with alias '" + alias + "' already exists! Skipping.");
model.setContextSizeTokens(contextSize);
model.setEndOfTextMarker(null);
- config.getModels().add(model);
+ configuration.getModels().add(model);
}
}
private void trySaveConfiguration(File configFile) {
boolean alreadyExists = Files.exists(configFile.toPath());
- if (alreadyExists && !forceOverwriteOption.isPresent()) {
- boolean userOk = askBoolean("\nConfiguration file already exists. Overwrite it?", true);
- if (!userOk) {
- System.out.println("Not overwriting. If you want to do so, run again with --force.");
- return;
- }
- }
-
try {
Files.createDirectories(configFile.toPath().getParent());
try (BufferedWriter writer = Files.newBufferedWriter(
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
)) {
- new ObjectMapper(new YAMLFactory()).writeValue(writer, config);
+ new ObjectMapper(new YAMLFactory()).writeValue(writer, configuration);
}
System.out.println("\nConfiguration saved to: " + configFile.toPath());
} catch (IOException e) {
boolean allOk = true;
// Check mail dir
- if (config.getMailDirectory() == null || !config.getMailDirectory().isDirectory()) {
- System.err.println("Mail directory is invalid: " + config.getMailDirectory());
+ if (configuration.getMailDirectory() == null || !configuration.getMailDirectory().isDirectory()) {
+ System.err.println("Mail directory is invalid: " + configuration.getMailDirectory());
allOk = false;
}
// Check llama-cli
- if (config.getLlamaCliPath() == null || !config.getLlamaCliPath().isFile()) {
- System.err.println("llama-cli path is invalid: " + config.getLlamaCliPath());
+ if (configuration.getLlamaCliPath() == null || !configuration.getLlamaCliPath().isFile()) {
+ System.err.println("llama-cli path is invalid: " + configuration.getLlamaCliPath());
allOk = false;
}
// Check prompts dir
- if (config.getPromptsDirectory() == null || !config.getPromptsDirectory().isDirectory()) {
- System.err.println("Prompts directory is invalid: " + config.getPromptsDirectory());
+ if (configuration.getPromptsDirectory() == null || !configuration.getPromptsDirectory().isDirectory()) {
+ System.err.println("Prompts directory is invalid: " + configuration.getPromptsDirectory());
allOk = false;
} else {
- File[] pFiles = config.getPromptsDirectory().listFiles();
+ File[] pFiles = configuration.getPromptsDirectory().listFiles();
if (pFiles == null || pFiles.length == 0) {
- System.out.println("Warning: No prompt files found in " + config.getPromptsDirectory());
+ System.out.println("Warning: No prompt files found in " + configuration.getPromptsDirectory());
// not necessarily fatal, so we won't mark allOk = false
}
}
// Check models
- if (config.getModels() == null || config.getModels().isEmpty()) {
+ if (configuration.getModels() == null || configuration.getModels().isEmpty()) {
System.err.println("No models are defined in the configuration.");
allOk = false;
} else {
// Check each model file
- for (ConfigurationModel m : config.getModels()) {
- File f = new File(config.getModelsDirectory(), m.getFilesystemPath());
+ for (ConfigurationModel m : configuration.getModels()) {
+ File f = new File(configuration.getModelsDirectory(), m.getFilesystemPath());
if (!f.exists()) {
System.err.println("Model alias '" + m.getAlias()
+ "' references missing file: " + f.getAbsolutePath());
}
// Check temperature
- if (config.getDefaultTemperature() < 0 || config.getDefaultTemperature() > 3) {
- System.err.println("Default temperature must be between 0 and 3. Found: " + config.getDefaultTemperature());
+ if (configuration.getDefaultTemperature() < 0 || configuration.getDefaultTemperature() > 3) {
+ System.err.println("Default temperature must be between 0 and 3. Found: " + configuration.getDefaultTemperature());
allOk = false;
}
- if (config.getThreadCount() < 1) {
- System.err.println("thread_count must be >= 1. Found: " + config.getThreadCount());
+ if (configuration.getThreadCount() < 1) {
+ System.err.println("thread_count must be >= 1. Found: " + configuration.getThreadCount());
allOk = false;
}
- if (config.getBatchThreadCount() < 1) {
- System.err.println("batch_thread_count must be >= 1. Found: " + config.getBatchThreadCount());
+ if (configuration.getBatchThreadCount() < 1) {
+ System.err.println("batch_thread_count must be >= 1. Found: " + configuration.getBatchThreadCount());
allOk = false;
}