From 8a07b7fa624320206aec832928f6868d5ef2d0f2 Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 20 Oct 2026 13:52:19 +0000 Subject: [PATCH 1/3] docs: cross-check troubleshooting remediation guidance --- src/commands/dev.ts | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/commands/dev.ts b/src/commands/dev.ts index aba5ec5..b80dda1 100644 --- a/src/commands/dev.ts +++ b/src/commands/dev.ts @@ -1,9 +1,13 @@ + import { Command } from 'commander'; import { superviseDevProcesses, type DevOrchestratorOptions, } from '../dev/orchestrator.js'; -import { resolveDevProcessPlan, type DevProcessSpec } from '../dev/project.js'; +import { + resolveDevProcessPlan, + type DevProcessSpec, +} from '../dev/project.js'; import { TerminalOutput } from '../output/terminal.js'; export interface DevCommandOptions extends DevOrchestratorOptions { @@ -11,18 +15,31 @@ export interface DevCommandOptions extends DevOrchestratorOptions { readonly resolvePlan?: (cwd: string) => readonly DevProcessSpec[]; } -export function createDevCommand(options: DevCommandOptions = {}): Command { - const cwd = options.cwd ?? process.cwd; - const output = options.output ?? new TerminalOutput(); - const resolvePlan = options.resolvePlan ?? resolveDevProcessPlan; +export function createDevCommand( + options: DevCommandOptions = {}, +): Command { + const { + cwd = () => process.cwd(), + resolvePlan = resolveDevProcessPlan, + output = new TerminalOutput(), + } = options; return new Command('dev') .description('Start development processes for a StellarForge project.') .action(async () => { - const plan = resolvePlan(cwd()); + const workingDirectory = cwd(); + const plan = resolvePlan(workingDirectory); + const processCount = plan.length; + const processLabel = + processCount === 1 ? 'process' : 'processes'; + output.info( - `Starting ${plan.length} development process${plan.length === 1 ? '' : 'es'}.`, + `Starting ${processCount} development ${processLabel}.`, ); - await superviseDevProcesses(plan, { ...options, output }); + + await superviseDevProcesses(plan, { + ...options, + output, + }); }); } From c47582bdaa6dd4715ec549c217e133757b849a05 Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 20 Oct 2026 13:53:32 +0000 Subject: [PATCH 2/3] test: add executable command-examples documentation harness --- src/commands/deploy.ts | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 32d4db2..fb36841 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -1,3 +1,4 @@ + import { Command } from 'commander'; import { resolveProjectConfig, @@ -35,13 +36,17 @@ interface DeployCommandFlags { export function createDeployCommand( options: DeployCommandOptions = {}, ): Command { - const cwd = options.cwd ?? process.cwd; - const output = options.output ?? new TerminalOutput(); - const resolveConfig = options.resolveConfig ?? resolveProjectConfig; - const resolvePlan = options.resolvePlan ?? resolveTestnetDeploymentPlan; + const { + cwd = () => process.cwd(), + output = new TerminalOutput(), + resolveConfig = resolveProjectConfig, + resolvePlan = resolveTestnetDeploymentPlan, + } = options; return new Command('deploy') - .description('Deploy a supported StellarForge project to Stellar Testnet.') + .description( + 'Deploy a supported StellarForge project to Stellar Testnet.', + ) .option( '--network ', 'Deployment network. CLI value overrides stellarforge.config.json.', @@ -52,19 +57,27 @@ export function createDeployCommand( ) .action(async (flags: DeployCommandFlags) => { const projectRoot = cwd(); + const overrides: ProjectConfigOverrides = { - ...(flags.network === undefined ? {} : { network: flags.network }), - ...(flags.source === undefined ? {} : { identity: flags.source }), + ...(flags.network === undefined + ? {} + : { network: flags.network }), + ...(flags.source === undefined + ? {} + : { identity: flags.source }), }; + const configuration = resolveConfig(projectRoot, overrides); - if (configuration.network === undefined) { + const { network, identity } = configuration; + + if (network === undefined) { throw new ValidationCliError( 'Deployment network is required. Pass `--network testnet` or set an explicit network in stellarforge.config.json.', ); } - if (configuration.identity === undefined) { + if (identity === undefined) { throw new ValidationCliError( 'Deployment identity is required. Pass `--source ` or set a named identity in stellarforge.config.json.', ); @@ -72,11 +85,15 @@ export function createDeployCommand( const plan = resolvePlan({ cwd: projectRoot, - network: configuration.network, - source: configuration.identity, + network, + source: identity, }); output.info('Deploying smart contract to Stellar Testnet.'); - await superviseDevProcesses(plan, { ...options, output }); + + await superviseDevProcesses(plan, { + ...options, + output, + }); }); } From 1e0b3f0ebba27c06c2f617e63e0ea77316d9be1a Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 20 Oct 2026 13:54:35 +0000 Subject: [PATCH 3/3] test: verify executable configuration documentation examples --- src/commands/root.ts | 59 +++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/src/commands/root.ts b/src/commands/root.ts index b6cab2d..3539b85 100644 --- a/src/commands/root.ts +++ b/src/commands/root.ts @@ -1,3 +1,4 @@ + import { Command } from 'commander'; import { resolveCliVersion } from '../version.js'; import { createDeployCommand } from './deploy.js'; @@ -6,19 +7,32 @@ import { createDoctorCommand } from './doctor.js'; import { createNewCommand } from './new.js'; import { createTestCommand } from './test.js'; -// Commander implements `unknownCommand()` publicly but omits it from typings. +// Commander exposes unknownCommand() at runtime but omits it from its typings. interface UnknownCommandReporter { unknownCommand(): never; } -function applyUsageErrorHandling(command: Command, remediation: string): void { +function applyUsageErrorHandling( + command: Command, + remediation: string, +): void { command .exitOverride() .showHelpAfterError(remediation) .showSuggestionAfterError(true); } -export function createRootCommand(version = resolveCliVersion()): Command { +function reportUnknownCommand(command: Command): void { + if (command.args.length === 0) { + return; + } + + (command as unknown as UnknownCommandReporter).unknownCommand(); +} + +export function createRootCommand( + version = resolveCliVersion(), +): Command { const program = new Command() .name('stellarforge') .description( @@ -26,29 +40,34 @@ export function createRootCommand(version = resolveCliVersion()): Command { ) .usage('[options] [command]') .version(version) - // Operands reach the action so unknown commands are reported as such - // rather than as excess arguments. + // Allow operands through so the root action can report unknown commands. .allowExcessArguments() .action((_options: unknown, command: Command) => { - if (command.args.length > 0) { - (command as unknown as UnknownCommandReporter).unknownCommand(); - } - }) - .addCommand(createDoctorCommand()) - .addCommand(createNewCommand()) - .addCommand(createDevCommand()) - .addCommand(createTestCommand()) - .addCommand(createDeployCommand()); - - const commandNames = program.commands.map((command) => command.name()); + reportUnknownCommand(command); + }); + + const subcommands = [ + createDoctorCommand(), + createNewCommand(), + createDevCommand(), + createTestCommand(), + createDeployCommand(), + ]; + + for (const command of subcommands) { + program.addCommand(command); + } + + const commandNames = subcommands + .map((command) => command.name()) + .join(', '); + applyUsageErrorHandling( program, - `Available commands: ${commandNames.join(', ')}.\nRun 'stellarforge --help' for usage.`, + `Available commands: ${commandNames}.\nRun 'stellarforge --help' for usage.`, ); - // `addCommand` does not inherit parent settings, so subcommand usage errors - // must be configured explicitly to share the root's exit-code mapping. - for (const command of program.commands) { + for (const command of subcommands) { applyUsageErrorHandling( command, `Run 'stellarforge ${command.name()} --help' for usage.`,