The system SHALL implement the public orodc CLI as a TypeScript application using oclif command modules.
- WHEN user runs
orodc --helpafter installation - THEN the installed command SHALL execute the compiled TypeScript CLI
- AND help output SHALL be displayed without requiring Bash command modules under
libexec/orodc
- WHEN a maintainer runs the CLI from a source checkout
- THEN the CLI SHALL resolve project assets from the checkout path
- AND command behavior SHALL match the installed Homebrew package for the same inputs
- WHEN a public command exists in the supported command surface
- THEN the command SHALL be implemented as an oclif command class or explicit alias route
- AND command-specific logic SHALL NOT be added to a monolithic dispatcher
The system SHALL preserve the existing public orodc command surface during the rewrite.
- WHEN user runs
orodc up,orodc down,orodc ps,orodc logs,orodc start,orodc stop, ororodc restart - THEN the CLI SHALL route to the same behavior as the corresponding compose operation
- AND remaining arguments SHALL be passed through unchanged
- WHEN user runs
orodc database <subcommand>,orodc tests <subcommand>,orodc proxy <subcommand>, ororodc image <subcommand> - THEN the CLI SHALL route to the matching command group implementation
- AND unknown subcommands SHALL produce a helpful error with exit code 1
- WHEN user runs
orodc mysql,orodc psql, ororodc cli - THEN the CLI SHALL execute behavior equivalent to
orodc database mysql,orodc database psql, ororodc database cli
- WHEN user runs
orodc --version,orodc -r <code>,orodc script.php,orodc bin/console <args>, ororodc bin/magento <args> - THEN the CLI SHALL route the command to the configured CLI container using the same PHP command detection rules as the current implementation
- WHEN user runs
orodc db <subcommand> - THEN the CLI SHALL route to the same behavior as
orodc database <subcommand>
- WHEN user runs
orodc vororodc verbose - THEN the CLI SHALL toggle verbose mode and report the new state
- AND the command SHALL exit immediately without initializing project context
- WHEN the interactive menu selects a different environment and re-invokes the CLI with
DC_ORO_SELECTED_ENV_NAME,DC_ORO_SELECTED_ENV_PATH, andDC_ORO_SELECTED_ENV_CONFIG - THEN the CLI SHALL resolve the project name, app directory, and config directory from those values when the current directory matches the selected path
The system SHALL preserve pattern-matched command spellings accepted by the current router.
- WHEN user runs a recognized variant such as
orodc importdb,orodc dbimport,orodc databaseimport,orodc exportdb, ororodc dbexport - THEN the CLI SHALL route to the matching database import or export behavior
- WHEN user runs a recognized variant such as
orodc platformupdate,orodc updateplatform, or acache:*console command - THEN the CLI SHALL route to the platform update or cache behavior used by the current implementation
The system SHALL assemble the Docker Compose -f file stack from runtime context as the current CLI does.
- WHEN compose configuration is generated or compose commands run
- THEN the stack SHALL include the base compose file
- AND include
docker-compose-default.ymlonly indefaultsync mode - AND include
docker-compose-pgsql.ymlordocker-compose-mysql.ymlaccording to the detected or persisted database schema - AND include
docker-compose-oro.ymlonly for Oro projects - AND include the CMS-matching cron compose file when applicable
- WHEN
~/.orodc/<project>/already contains a database-specific compose file - THEN the CLI SHALL keep using the matching database schema instead of re-deriving it from project files
The system SHALL forward Composer authentication into containers and SSH sessions.
- WHEN neither
DC_ORO_COMPOSER_AUTHnorCOMPOSER_AUTHis set and~/.composer/auth.jsonexists - THEN the CLI SHALL export its compacted JSON content as
COMPOSER_AUTHfor container execution and SSHSendEnv
The system SHALL preserve the existing source-code sync modes and their default selection.
- WHEN
DC_ORO_MODEis not set - THEN the CLI SHALL default to
mutagenon macOS - AND the CLI SHALL default to
defaulton Linux and WSL2
- WHEN
DC_ORO_MODEismutagenand the project is valid - THEN the CLI SHALL ensure the
<project>_appcodeDocker volume exists - AND create the mutagen sync session against the running
sshservice if it does not already exist - AND wait until the session reaches a watching state before continuing
- AND avoid creating duplicate sessions when one already exists
- WHEN
DC_ORO_MODEisssh - THEN the CLI SHALL ensure the
<project>_appcodeDocker volume exists - AND perform an initial rsync of the project source into the running
sshservice, excludingvar/cache,vendor, andnode_modules
- WHEN
DC_ORO_MODEisdefault - THEN the CLI SHALL not create a mutagen session or appcode rsync sync
- AND the project directory SHALL be mounted directly
The system SHALL resolve host ports for each service using the project port prefix with free-port fallback.
- WHEN service ports are not explicitly overridden
- THEN the CLI SHALL derive nginx, database, search, message queue, redis, mail, ssh, gotenberg, and profiler ports from
DC_ORO_PORT_PREFIX
- WHEN a per-service port variable such as
DC_ORO_PORT_NGINXis set - THEN the CLI SHALL use the explicit value instead of the prefix-derived value
- WHEN a derived or requested host port is unavailable
- THEN the CLI SHALL allocate an available free port for that service
- AND expose the resolved ports for compose generation
The system SHALL load project and OroDC configuration files with the same precedence as the current CLI.
- WHEN a project contains
.env,.env-app, and.env-app.local - THEN the CLI SHALL load these files before OroDC-specific config
- AND exported database, search, queue, and Redis URLs SHALL be available to later compose generation
- WHEN both
~/.orodc/<project>/.env.orodcand<project>/.env.orodcexist - THEN the CLI SHALL load the global config first
- AND the local project config SHALL override matching values from the global config
- WHEN the CLI reads or writes OroDC-managed configuration
- THEN project configuration SHALL remain in
.env.orodc - AND global project configuration SHALL remain in
~/.orodc/<project>/.env.orodc - AND generated compose output SHALL remain in
~/.orodc/<project>/compose.yml
- WHEN
~/.orodc/<project>.env.orodcexists and~/.orodc/<project>/.env.orodcdoes not exist - THEN the CLI SHALL migrate the old file to the directory-based location
- AND subsequent loads SHALL use
~/.orodc/<project>/.env.orodc
- WHEN loaded environment files provide database, search, message queue, or Redis connection URIs
- THEN the CLI SHALL parse each URI into normalized host, port, user, password, and database/path components
- AND expose them as the same
DC_ORO_*values the current CLI derives for compose generation
The system SHALL preserve project-scoped runtime state managed by the current CLI between invocations.
- WHEN the user changes the Xdebug mode
- THEN the CLI SHALL persist
XDEBUG_MODE*values in the project configuration - AND restore them on subsequent command invocations
- WHEN compose profiles are selected for a project
- THEN the CLI SHALL cache the selection
- AND reuse the cached profiles on subsequent compose invocations until they are changed
- WHEN up or proxy workflows require TLS for project domains
- THEN the CLI SHALL set up project certificates using the mkcert-based flow of the current implementation
- AND store them where the proxy and compose configuration expect them
The system SHALL resolve static OroDC assets consistently in development and installed environments.
- WHEN the CLI is installed through Homebrew
- THEN compose YAML files, Dockerfiles, doctor configs, agent docs, and static scripts SHALL be resolved from the installed package asset directory
- WHEN the CLI is executed from a repository checkout
- THEN assets SHALL be resolved from the checkout
compose/and related project directories
- WHEN a required asset file cannot be found
- THEN the CLI SHALL display the searched paths
- AND exit with a non-zero status code
- AND avoid generating partial configuration from missing assets
The system SHALL execute external commands through a shared process runner that preserves exit codes, TTY behavior, and output mode.
- WHEN a command requires an interactive terminal
- THEN the process runner SHALL attach stdio to the current terminal
- AND user input SHALL reach the child process
- WHEN a long-running command is executed in normal mode with spinner feedback
- THEN the process runner SHALL capture command output to a log file
- AND display concise progress output
- AND show captured error output when the command fails
- WHEN an external command exits with a non-zero code
- THEN
orodcSHALL exit with the same code unless a command-specific compatibility rule explicitly handles that code
- WHEN user sends an interrupt or termination signal to
orodc - THEN the CLI SHALL forward the signal to the active child process
- AND clean up any spinner or temporary terminal state
The system SHALL construct Docker Compose invocations from parsed arguments without unsafe shell string evaluation.
- WHEN user runs
orodc compose <command> <flags> <services> - THEN the CLI SHALL pass supported left-side and right-side Docker Compose flags to
docker compose - AND service names and remaining arguments SHALL preserve ordering
- WHEN a command requires generated compose configuration
- THEN the CLI SHALL generate or refresh
compose.ymlbefore executing Docker Compose - AND the environment registry SHALL be updated after successful generation
- WHEN the CLI executes Docker, Docker Compose, rsync, mutagen, Homebrew, or PHP-related external commands
- THEN the command SHALL be invoked with an argument array
- AND shell execution SHALL be used only for documented cases that require shell semantics
The system SHALL install the rewritten CLI and required assets through the Homebrew formula.
- WHEN user installs the formula
- THEN Homebrew SHALL install the compiled CLI entry point
- AND
orodcSHALL be available on PATH - AND required runtime dependencies SHALL be installed or bundled
- WHEN the formula installs OroDC
- THEN
compose/assets and other runtime data files SHALL be copied to the installed package location - AND the CLI SHALL locate those assets without relying on the source tap checkout
- WHEN the formula installs OroDC
- THEN free-port discovery SHALL be provided by the TypeScript ports service with Docker-aware collision checks
- AND the formula SHALL NOT install
orodc-find_free_portororodc-sync - AND the vendored osync script (
bin/orodc-sync) SHALL be removed from the repository
- WHEN Homebrew runs the formula test
- THEN the test SHALL execute a non-Docker command such as
orodc --help - AND the command SHALL complete successfully
- WHEN changes to the formula or CLI are proposed
- THEN CI SHALL install the formula from the tap checkout on Linux and macOS
- AND run
brew testand a non-Dockerorodccommand - AND fail the build if installation or the smoke command fails
The system SHALL include tests that verify the rewritten CLI preserves current public behavior.
- WHEN tests run for help, version, routing errors, deprecated syntax errors, and common aliases
- THEN the rewritten CLI output SHALL match approved golden fixtures or documented intentional changes
- WHEN tests run against fixture projects with
.env,.env-app,.env-app.local, global.env.orodc, and local.env.orodc - THEN the computed runtime environment SHALL match expected precedence and normalized values
- WHEN tests run for compose, PHP, Composer, database, proxy, image, and tests commands
- THEN generated external command argv arrays SHALL match expected commands
- AND no Docker daemon SHALL be required for these unit tests
- WHEN integration tests run in an environment with Docker available
- THEN representative
init,config,up,ps,down, database, and proxy workflows SHALL be validated against real Docker Compose execution