{"id":51109305,"url":"https://github.com/mooxphp/prompts","last_synced_at":"2026-06-24T16:01:59.980Z","repository":{"id":339606566,"uuid":"1103840132","full_name":"mooxphp/prompts","owner":"mooxphp","description":" Prompts is a package that provides CLI-compatible prompts for Laravel Artisan Commands with identical API to Laravel Prompts. Supports all prompt types","archived":false,"fork":false,"pushed_at":"2026-02-20T14:55:32.000Z","size":431,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-04T17:09:46.534Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mooxphp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-25T12:04:00.000Z","updated_at":"2026-02-20T14:55:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mooxphp/prompts","commit_stats":null,"previous_names":["mooxphp/prompts"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mooxphp/prompts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mooxphp%2Fprompts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mooxphp%2Fprompts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mooxphp%2Fprompts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mooxphp%2Fprompts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mooxphp","download_url":"https://codeload.github.com/mooxphp/prompts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mooxphp%2Fprompts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34739426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-24T16:01:57.746Z","updated_at":"2026-06-24T16:01:59.966Z","avatar_url":"https://github.com/mooxphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Moox Prompts\n\nCLI- and Web-compatible prompts for Laravel Artisan commands – with a flow that can continue step-by-step in the browser.\n\n## What does a Flow Command look like?\n\nTo make a command work as a flow in both CLI and Web, you only need to follow these rules:\n\n- **Extend `FlowCommand`**  \n\n  ```php\n  use Moox\\Prompts\\Support\\FlowCommand;\n  use function Moox\\Prompts\\text;\n  use function Moox\\Prompts\\select;\n  ```\n\n  ```php\n  class ProjectSetupCommand extends FlowCommand\n  {\n      protected $signature = 'prompts:project-setup';\n      protected $description = 'Project setup wizard (CLI \u0026 Web)';\n  ```\n\n- **Store state as public properties**  \n  (they are automatically persisted between steps in the web flow)\n\n  ```php\n      public ?string $environment = null;\n      public ?string $projectName = null;\n  ```\n\n- **Define steps via `promptFlowSteps()`** – the array order **is the flow order**\n\n  ```php\n      public function promptFlowSteps(): array\n      {\n          return [\n              'stepIntro',\n              'stepEnvironment',\n              'stepProjectName',\n              'stepSummary',\n          ];\n      }\n  ```\n\n- **Each step is a `public function stepXyz(): void`** – ideally **one prompt per step**\n\n  ```php\n      public function stepIntro(): void\n      {\n          $this-\u003einfo('=== Project Setup ===');\n      }\n\n      public function stepEnvironment(): void\n      {\n          $this-\u003eenvironment = select(\n              label: 'Which environment do you want to configure?',\n              options: [\n                  'local' =\u003e 'Local',\n                  'staging' =\u003e 'Staging',\n                  'production' =\u003e 'Production',\n              ],\n              default: 'local',\n          );\n      }\n\n      public function stepProjectName(): void\n      {\n          $this-\u003eprojectName = text(\n              label: 'What is your project name?',\n              placeholder: 'e.g. MyCoolApp',\n              validate: 'required|min:3',\n              required: true,\n          );\n      }\n\n      public function stepSummary(): void\n      {\n          $this-\u003einfo('--- Summary ---');\n          $this-\u003eline('Project: '.$this-\u003eprojectName);\n          $this-\u003eline('Environment: '.$this-\u003eenvironment);\n      }\n  }\n  ```\n\n- **Optional steps** can simply be skipped with a guard at the beginning:\n\n  ```php\n  public array $features = [];\n\n  public function stepLoggingLevel(): void\n  {\n      if (! in_array('logging', $this-\u003efeatures, true)) {\n          return; // skip step\n      }\n\n      // Prompt …\n  }\n  ```\n\n- **Calling other Artisan commands** – in a flow, always use `$this-\u003ecall()` instead of `Artisan::call()`, so the output is also visible in the web UI:\n\n  ```php\n  public function stepPublishConfig(): void\n  {\n      $shouldPublish = confirm(\n          label: 'Publish the config now?',\n          default: true,\n      );\n\n      if (! $shouldPublish) {\n          return;\n      }\n\n      $this-\u003ecall('vendor:publish', [\n          '--tag' =\u003e 'moox-prompts-config',\n      ]);\n  }\n  ```\n\nThat’s all you need in the command – no special flow methods, no custom persistence.  \nEverything else (CLI/Web differences, state, web UI) is handled by the package.\n\n## Running flows in the browser (Filament)\n\nOnce you’ve created a flow command, you can run it in both CLI and browser.\n\n### CLI\n\n```bash\nphp artisan prompts:project-setup\n```\n\nThe command behaves like a normal Laravel Artisan command – all prompts are shown in the terminal.\n\n### Web\n\n1. Open the Filament page **“Run Command”** (automatically added to navigation)\n2. Select your flow command from the list\n3. Click **“Start command”**\n4. The flow runs step by step in the browser:\n   - Every step shows a prompt (text, select, multiselect, confirm, etc.)\n   - After each step you see the step’s output\n   - You can cancel any time with “Back to command selection”\n   - After a successful run the button switches to “Start new command”\n\n**Note:** All commands executed via the web UI are automatically logged in the database (see [Command Execution Logging](#command-execution-logging)).\n\n## How and why reflection is used\n\nIf you’re just writing commands, you don’t need to care about reflection.  \nTo understand what happens under the hood, here’s a short overview.\n\n- **Problem 1: Setting arguments \u0026 options in the web flow**  \n  Laravel stores arguments/options internally on a protected `$input` property of your command.  \n  In CLI mode the Artisan kernel takes care of this.  \n  In the web flow, we create fresh command instances – and need to set `$input` ourselves.  \n  That’s what `PromptFlowRunner::setCommandInput()` does via reflection:\n  - finds the `input` property on your command object,\n  - temporarily makes it accessible,\n  - assigns the current `ArrayInput` instance.  \n  **Result:** In flow commands you can keep using `argument()` and `option()` normally – both in CLI and in the browser.\n\n- **Problem 2: Remembering command state between web requests**  \n  In the web flow, your command runs across multiple HTTP requests. Without extra logic, properties like `$environment`, `$features`, `$projectName` would be lost between steps.  \n  `PromptFlowRunner` handles this with two internal methods:\n  - `captureCommandContext($command, $state)`  \n    - uses reflection to read all non-static properties of your concrete command class  \n    - stores simple values (scalars, arrays, `null`) into `PromptFlowState::$context`\n  - `restoreCommandContext($command, $state)`  \n    - restores all stored values back onto the new command instance on the next request  \n  **Result:** For your code it feels like the same command instance keeps running – you don’t need your own persistence layer (cache, DB, session, …).\n\n- **Problem 3: Initializing package tools in the web context**  \n  Many packages using `Spatie\\LaravelPackageTools` only register publishable resources (config, views, migrations, assets, …) in CLI context.  \n  `WebCommandRunner` uses reflection to access the internal `package` object and replay `publishes(...)` registrations for the web context.  \n  **Result:** Commands like `vendor:publish` work just as well in the browser as in CLI, even though Laravel is not running in console mode there.\n\n**Important:**  \nReflection is only used inside the package internals, not in your flow commands.  \nYour commands remain normal Laravel commands – you only need to:\n\n- extend `FlowCommand`,\n- define properties for your state,\n- list steps in `promptFlowSteps()`,\n- implement `step*` methods (ideally one prompt per step).\n\nThe package takes care of the rest (reflection, state, web flow).\n\n### Are there alternatives without reflection?\n\nYes – technically we could avoid reflection, but it would degrade the DX:\n\n- For **arguments \u0026 options** we’d need a custom API instead of `argument()/option()`, or force you to manage everything via properties/arrays. That’s less “Laravel-ish” and harder to learn.\n- For **state between steps** we could ask you to manually list all properties to persist (e.g. `flowContextKeys()`), or manage cache/DB/session yourself. That’s more boilerplate and error-prone.\n- For **Spatie Package Tools in the web** we’d either need changes in the Spatie package or manual configuration of all publishable paths – both would make setup more complex.\n\nThat’s why we intentionally keep reflection encapsulated in the package and keep your command API as simple as possible.\n\n## Command Execution Logging\n\nAll commands executed via the web interface are automatically logged in the database.  \nYou can inspect them via the Filament resource **“Command Executions”**.\n\n### Status\n\nEach execution has one of the following statuses:\n\n- **`running`**: The command is currently running\n- **`completed`**: The command finished successfully\n- **`failed`**: The command failed with an error\n- **`cancelled`**: The command was cancelled by the user or aborted mid-flow\n\n### Stored information\n\nFor each execution we store:\n\n- **Basic information**: command name, description, status, timestamps\n- **Steps**: ordered list of all defined steps\n- **Step outputs**: output of each step (JSON)\n- **Context**: all command properties (e.g. `$environment`, `$projectName`, `$features`, …)\n- **Failure details**: for `failed` status – the error message and the step where it occurred (`failed_at_step`)\n- **Cancellation details**: for `cancelled` status – the step where cancellation happened (`cancelled_at_step`)\n- **User**: polymorphic relation to the user who started the command (`created_by`)\n\n### Important: `step_outputs` vs `context`\n\nIt’s important to understand the difference between these two fields:\n\n- **`step_outputs`**  \n  - Contains the **console output** of each step.  \n  - This is everything you print via `$this-\u003einfo()`, `$this-\u003eline()`, `$this-\u003ewarn()`, etc.  \n  - Example:\n\n    ```php\n    public function stepEnvironment(): void\n    {\n        $this-\u003eenvironment = select(...);\n        $this-\u003einfo(\"✅ Environment: {$this-\u003eenvironment}\");\n    }\n    ```\n\n    will result in e.g.:\n\n    ```json\n    \"stepEnvironment\": \"✅ Environment: production\\n\"\n    ```\n\n- **`context`**  \n  - Contains the **raw state** of your command – all public, non-static properties from your concrete command class.  \n  - This includes values returned from `text()`, `select()`, `multiselect()`, `confirm()`, etc.\n  - Example:\n\n    ```php\n    public ?bool $publishConfig = null;\n\n    public function stepPublishConfigConfirm(): void\n    {\n        $this-\u003epublishConfig = confirm(\n            label: 'Publish the config now?',\n            default: true,\n        );\n    }\n    ```\n\n    will store in `context` something like:\n\n    ```json\n    {\n      \"publishConfig\": true\n    }\n    ```\n\n    but `step_outputs[\"stepPublishConfigConfirm\"]` will be an **empty string**, because `confirm()` itself doesn’t print anything.\n\nIf you want to see the user’s choice in the **step output** as well, you can explicitly print it:\n\n```php\npublic function stepPublishConfigConfirm(): void\n{\n    $this-\u003epublishConfig = confirm(\n        label: 'Publish the config now?',\n        default: true,\n    );\n\n    $this-\u003einfo('✅ Publish config: ' . ($this-\u003epublishConfig ? 'yes' : 'no'));\n}\n```\n\nThis way you have:\n\n- the decision in `context.publishConfig`, and\n- a readable line in `step_outputs.stepPublishConfigConfirm` for the history/inspector UI.\n\n### Running the migration\n\nTo enable logging, run:\n\n```bash\nphp artisan migrate\n```\n\nThis creates the `command_executions` table with all necessary fields.\n\n### Filament resource\n\nThe Filament resource **“Command Executions”** is automatically available in the Filament navigation (if enabled). There you can:\n\n- inspect all past command executions,\n- filter by status,\n- see details per execution (steps, outputs, context, errors),\n- analyze failed or cancelled commands.\n\nThe resource also shows which step a command **failed** on (`failed_at_step`) or where it was **cancelled** (`cancelled_at_step`).\n\n## License\n\nSee [LICENSE.md](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmooxphp%2Fprompts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmooxphp%2Fprompts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmooxphp%2Fprompts/lists"}