diff --git a/cli/repo_wizard.php b/cli/repo_wizard.php index 5dc612d..9268f48 100644 --- a/cli/repo_wizard.php +++ b/cli/repo_wizard.php @@ -47,6 +47,9 @@ class RepoWizard extends CliFramework /** Collected wizard answers. */ private array $answers = []; + /** When true, skip all interactive prompts and use defaults. */ + private bool $nonInteractive = false; + protected function configure(): void { $this->setDescription('Interactive configuration wizard for new repositories'); @@ -57,16 +60,25 @@ class RepoWizard extends CliFramework protected function run(): int { - $targetPath = realpath($this->getArgument('--path', '.')) ?: $this->getArgument('--path', '.'); + $rawPath = $this->getArgument('--path', '.'); + $targetPath = realpath($rawPath) ?: $rawPath; + $this->nonInteractive = (bool) $this->getArgument('--non-interactive', false); + + // Validate target path + if (!is_dir($targetPath) && !@mkdir($targetPath, 0755, true)) { + $this->log('ERROR', "Target path does not exist and cannot be created: {$targetPath}"); + return self::EXIT_USAGE; + } + $targetPath = realpath($targetPath) ?: $targetPath; $this->section('MokoCli Repository Wizard'); // ── Gather info ────────────────────────────────────────────── - $this->answers['name'] = $this->input('Repository name', basename($targetPath)); - $this->answers['platform'] = $this->menu('Platform type', self::PLATFORMS, 'generic'); - $this->answers['org'] = $this->input('Organization', 'MokoConsulting'); - $this->answers['description'] = $this->input('Description', ''); - $this->answers['license'] = $this->menu('License', self::LICENSES, 'GPL-3.0-or-later'); + $this->answers['name'] = $this->ask('Repository name', basename($targetPath)); + $this->answers['platform'] = $this->choose('Platform type', self::PLATFORMS, 'generic'); + $this->answers['org'] = $this->ask('Organization', 'MokoConsulting'); + $this->answers['description'] = $this->ask('Description', ''); + $this->answers['license'] = $this->choose('License', self::LICENSES, 'GPL-3.0-or-later'); // ── Confirm ────────────────────────────────────────────────── $this->section('Configuration Summary'); @@ -94,7 +106,7 @@ class RepoWizard extends CliFramework } $this->log('INFO', ''); - $this->log('INFO', "Generated {$this->count($generated)} files in {$targetPath}"); + $this->log('INFO', 'Generated ' . count($generated) . " files in {$targetPath}"); $this->log('INFO', 'Next: git init && git add -A && git commit -m "chore: initial scaffold"'); return 0; @@ -209,7 +221,31 @@ class RepoWizard extends CliFramework } } - private function count(array $arr): int { return \count($arr); } + // ── Interactive helpers (respect --non-interactive) ───────────── + + private function ask(string $prompt, string $default): string + { + if ($this->nonInteractive) { + return $default; + } + return $this->input($prompt, $default); + } + + private function choose(string $prompt, array $options, string $default): string + { + if ($this->nonInteractive) { + return $default; + } + $keys = array_keys($options); + $labels = []; + foreach ($options as $key => $desc) { + $labels[] = "{$key} — {$desc}"; + } + $chosen = $this->select($prompt, $labels); + // Extract the key from "key — description" + $chosenKey = explode(' — ', $chosen, 2)[0] ?? $default; + return in_array($chosenKey, $keys, true) ? $chosenKey : $default; + } // ── Template content ───────────────────────────────────────────── @@ -266,24 +302,15 @@ MD; private function composerJson(): string { - $name = strtolower($this->answers['name']); - $desc = $this->answers['description'] ?: $this->answers['name']; - $license = $this->answers['license']; - - return <<=8.1" - }, - "autoload": { - "psr-4": {} - } -} -JSON; + $data = [ + 'name' => 'mokoconsulting/' . strtolower($this->answers['name']), + 'description' => $this->answers['description'] ?: $this->answers['name'], + 'type' => 'library', + 'license' => $this->answers['license'], + 'require' => ['php' => '>=8.1'], + 'autoload' => ['psr-4' => new \stdClass()], + ]; + return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; } private function phpcsXml(): string @@ -310,24 +337,15 @@ NEON; private function packageJson(): string { - $name = strtolower($this->answers['name']); - $desc = $this->answers['description'] ?: $this->answers['name']; - - return << '@mokoconsulting/' . strtolower($this->answers['name']), + 'version' => '0.1.0', + 'description' => $this->answers['description'] ?: $this->answers['name'], + 'type' => 'module', + 'scripts' => ['build' => 'tsc', 'start' => 'node dist/index.js'], + 'devDependencies' => ['typescript' => '^5.0'], + ]; + return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; } private function tsconfigJson(): string @@ -363,7 +381,7 @@ JSON; private function pyprojectToml(): string { $name = strtolower($this->answers['name']); - $desc = $this->answers['description'] ?: $this->answers['name']; + $desc = str_replace(['\\', '"'], ['\\\\', '\\"'], $this->answers['description'] ?: $this->answers['name']); return <<execute());