The CLI command layer exposes the stackctl executable interface. It builds the Cliffy command
tree, maps command-line options and positional arguments into typed operation inputs, invokes the
domain modules, formats human-readable or JSON output, and translates validation, dependency, and
unexpected failures into process exit codes.
- Command registration is centralized in
buildCli(), which creates the rootCommand, attaches global metadata and options, then registers each top-level command and nested command in one command tree. - Each command action is a thin adapter. It extracts options from
Record<string, unknown>, casts Cliffy parsed values to local types, normalizes comma-separated lists, resolves the active working directory withDeno.cwd(), and delegates work to a module function. - Runner injection is explicit at Docker and secrets boundaries. Command actions instantiate
RealProcessRunner, passingdryRunwhere supported, then provide that runner to Docker and secrets operations instead of invoking external tools directly. - Exit handling uses the shared
ExitCodeenum for semantic results. Many command actions set the module-levelexitCodeand return, while some deeper asynchronous paths callDeno.exit()for immediate termination. - Output handling stays in the CLI layer. Domain results return structured data, warnings, errors, and generated content. The CLI decides whether to print tables, diffs, YAML, JSON, warnings, or status lines.
main(args)callsbuildCli().parse(args)and returns the accumulatedexitCode. Parse errors or uncaught exceptions are converted to exit code1.buildCli()registers root options such as--debugand--config, a default help action, and commands for initialization, generation, rendering, stack lifecycle, health checks, reload, secrets, environment files, planning, and shell completions.- Command actions parse Cliffy options, including boolean flags, required string options,
positional arguments, and comma-separated lists such as
--stacks,--override, and--paths. - Most commands resolve configuration with
resolveConfig({ profile, cwd }), deriverepoRoot, then pass normalized inputs to config, compose, render, docker, env, or secrets functions. - Compose workflows commonly discover stack names, generate stack YAML in memory, parse generated YAML, render variables, optionally write files, and then deploy, reload, compare, or report.
- Docker-backed commands create a
RealProcessRunnerand delegate Docker CLI interaction to docker wrapper functions. Dry-run commands use a dry-run runner or skip mutation and print intended actions. - Result objects drive final control flow. Errors and drift set
ExitCode.DriftOrValidation, user configuration errors setExitCode.UserConfigError, missing external tooling setsExitCode.MissingDependency, and uncaught command exceptions setExitCode.UnexpectedError.
config:initConfig()creates.stackctlfiles.resolveConfig()loads active configuration for profile-aware commands.ExitCodesupplies shared numeric exit semantics.compose:generateStacks()builds canonical stack YAML,discoverComposeFiles()discovers stack names,syncValidation()checks generated output against committed stack files,reloadStacks()performs config-first reloads, andplanOperation()produces deterministic operation plans.render:renderStack()resolves${VAR}placeholders in generated Compose data and reports unresolved variables and warnings.docker: Docker wrapper functions perform Swarm and Compose operations through the injected runner, including stack deploy, removal, service listing, task listing, logs, Compose config validation, Docker info, and Swarm status checks.env: Environment commands delegate discovery, creation, diffing, materialization, status listing, and audit behavior todiscoverEnvExamples(),batchCreateEnvs(),diffEnvFiles(),materializeEnvFromProfile(),getEnvStatusList(), andenvDoctor().secrets: Secrets commands delegate SOPS and age workflows toensureTooling(),checkTooling(),findEncryptedEnvFiles(),encryptEnvFile(),decryptEnvFile(),cleanDecryptedEnvFiles(), anddeployPipeline().process:RealProcessRunneris the runtime adapter for external process execution and dry-run behavior.- Deno and standard library APIs provide filesystem writes, temporary files, directory creation, YAML parsing and serialization, path operations, prompts, and completion command support.