CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stricli--core

Build complex CLIs with type safety and no dependencies

Overview
Eval results
Files

configuration-and-context.mddocs/

Configuration and Context

Application configuration and context threading for custom data and behavior control.

Quick Reference

// Basic configuration
const app = buildApplication(command, {
  name: "myapp",
  versionInfo: { currentVersion: "1.0.0" }
})

// With custom settings
const app = buildApplication(command, {
  name: "myapp",
  versionInfo: { currentVersion: "1.0.0" },
  scanner: { caseStyle: "allow-kebab-for-camel", allowArgumentEscapeSequence: true },
  documentation: { useAliasInUsageLine: true, disableAnsiColor: false },
  determineExitCode: (exc) => exc instanceof MyError ? exc.code : 1
})

// Custom context
interface MyContext extends CommandContext {
  database: Database;
  logger: Logger;
}

await run(app, inputs, {
  process,
  async forCommand(info) {
    return { process, database: await connectDB(), logger: createLogger() };
  }
})

Configuration

PartialApplicationConfiguration

interface PartialApplicationConfiguration {
  name: string  // Required: application name
  versionInfo?: VersionInfo
  scanner?: Partial<ScannerConfiguration>
  documentation?: Partial<DocumentationConfiguration>
  completion?: Partial<CompletionConfiguration>
  localization?: Partial<LocalizationConfiguration>
  determineExitCode?: (exc: unknown) => number
}

Scanner Configuration

Controls command/argument scanning behavior.

scanner: {
  caseStyle: "original" | "allow-kebab-for-camel",  // default: "original"
  allowArgumentEscapeSequence: boolean,  // default: false (enables -- separator)
  distanceOptions: {  // "did you mean?" suggestions
    threshold: number,  // default: 7
    weights: {
      insertion: number,  // default: 1
      deletion: number,  // default: 3
      substitution: number,  // default: 2
      transposition: number  // default: 0
    }
  }
}

caseStyle:

  • "original": Exact match only (--myFlag)
  • "allow-kebab-for-camel": Accept both --myFlag and --my-flag

allowArgumentEscapeSequence: If true, -- marks end of flags (all subsequent inputs treated as arguments).

Documentation Configuration

Controls help text formatting.

documentation: {
  alwaysShowHelpAllFlag: boolean,  // default: false
  useAliasInUsageLine: boolean,  // default: false
  onlyRequiredInUsageLine: boolean,  // default: false
  caseStyle: "original" | "convert-camel-to-kebab",  // default: derived from scanner
  disableAnsiColor: boolean  // default: false
}

Version Info

versionInfo: {
  currentVersion: "1.0.0",  // Static version
  // OR
  getCurrentVersion: async function() { return "1.0.0" },  // Dynamic version
  
  // Optional:
  getLatestVersion: async function(currentVersion) { /* check registry */ },
  upgradeCommand: "npm install -g myapp@latest"
}

Custom Exit Codes

determineExitCode: (exc) => {
  if (exc instanceof BusinessError) return exc.exitCode;
  if (exc instanceof Error && exc.message.includes("timeout")) return 124;
  return 1;
}

Context

CommandContext

Base context interface with process streams.

interface CommandContext {
  process: {
    stdout: Writable;
    stderr: Writable;
  }
}

Custom Context

Extend CommandContext for application-specific data.

interface MyContext extends CommandContext {
  database: Database;
  logger: Logger;
  config: Config;
}

const command = buildCommand({
  func: async function(this: MyContext, flags) {
    await this.database.connect();
    this.logger.info("Connected");
    this.process.stdout.write("Done\n");
  },
  parameters: {},
  docs: { brief: "Command" }
});

Context Builder

Dynamic context creation per command.

await run(app, inputs, {
  process,
  locale: "en",
  async forCommand(info) {
    // info.prefix contains command route (e.g., ["myapp", "db", "migrate"])
    return {
      process,
      database: await connectDB(),
      logger: createLogger(info.prefix.join(" "))
    };
  }
});

Complete Example

import { buildApplication, run } from "@stricli/core";

interface AppContext extends CommandContext {
  database: Database;
  logger: Logger;
}

class AppError extends Error {
  constructor(message: string, public exitCode: number) {
    super(message);
  }
}

const app = buildApplication<AppContext>(command, {
  name: "myapp",
  versionInfo: {
    currentVersion: "2.1.0",
    async getLatestVersion() {
      const res = await fetch("https://api.example.com/version");
      return res.json().then(d => d.latest);
    },
    upgradeCommand: "npm install -g myapp@latest"
  },
  scanner: {
    caseStyle: "allow-kebab-for-camel",
    allowArgumentEscapeSequence: true
  },
  documentation: {
    useAliasInUsageLine: true,
    disableAnsiColor: false
  },
  determineExitCode: (exc) => {
    if (exc instanceof AppError) return exc.exitCode;
    return 1;
  }
});

await run(app, process.argv.slice(2), {
  process,
  locale: process.env.LANG,
  async forCommand(info) {
    return {
      process,
      database: await connectDB(),
      logger: createLogger(info.prefix.join(" "))
    };
  }
});

Environment Variables

  • STRICLI_SKIP_VERSION_CHECK=1: Skip automatic version checking
  • STRICLI_NO_COLOR=1: Disable ANSI color output

Related

  • Exit Codes
  • Text and Localization

Install with Tessl CLI

npx tessl i tessl/npm-stricli--core

docs

application.md

commands-and-routing.md

configuration-and-context.md

documentation-and-help.md

error-handling.md

exit-codes.md

flag-parameters.md

index.md

parameter-parsers.md

positional-parameters.md

text-and-localization.md

tile.json