@hyperfrontend/features/cliCLI
Programmatic entry point for the hyperfrontend features CLI — the init, build, and dev commands behind the hf bin.
import { runFeaturesCli } from '@hyperfrontend/features/cli'
const code = await runFeaturesCli({
argv: process.argv.slice(2),
cwd: process.cwd(),
stdout: process.stdout,
stderr: process.stderr,
})
Commands
| Command | Purpose |
|---|---|
init | Scaffolds the hostee glue module and wires a marker-guarded import into the app entry file. |
build | Resolves feature.config.*, generates the host connector, bundles it, and packs a publishable tarball. |
dev | Resolves hf-dev.config.* and starts the dev server — one static server per app plus the debug UI. |
Config resolution
feature.config.* (and hf-dev.config.*) resolve through one tiered loader: .json via
@hyperfrontend/project-scope, and .js/.cjs/.mjs/.ts/.cts/.mts via native await import().
Every config key has a matching flag (--name, --version, --protocol, --out, --url), objects are
passed as path strings (--contract, --config), precedence is defaults < config file < flags, and
--ci/--yes run headlessly (erroring on any unresolved required key).
API Reference
ƒ Functions
<baseName>.<ext> config file directly under a directory. Extensions are probed in the loader's documented order (JSON, then JS, then TS) so a single project never has its format silently chosen at random.
Parameters
Returns
stringnull when none exists.Example
Discovering a feature config in the current directory
const path = discoverConfigFile(process.cwd(), FEATURE_CONFIG_BASENAME)feature.config. / hf-dev.config. / .contract. file regardless of source format. JSON files parse through
@hyperfrontend/project-scope; .js/.cjs/.mjs and .ts/.cts/.mts resolve through native await import() (Node strips TypeScript types on supported runtimes), returning the module's default export when present. The caller is responsible for validating the shape.Parameters
| Name | Type | Description |
|---|---|---|
§absolutePath | string | Absolute path to the config or contract file. |
Returns
Promise<unknown>Example
Loading a TypeScript feature config
const config = await loadModuleFile('/abs/feature.config.ts')Parameters
| Name | Type | Description |
|---|---|---|
§argv | unknown | Argument list following the bin name (usually process.argv.slice(2)). |
Returns
ParsedArgsExample
Parsing a build invocation
parseCliArgs(['build', '--protocol', 'v2', '--out', './dist'])
// => { command: 'build', flags: { protocol: 'v2', out: './dist', ci: false, ... } }feature.config.* into a ResolvedFeatureConfig and its contract, applying defaults < config file < flags precedence where a flag replaces its whole top-level key (no deep merge).Parameters
| Name | Type | Description |
|---|---|---|
§options | ResolveBuildConfigOptions | The working directory and parsed flags. |
Returns
Promise<ResolvedBuildBundle>Example
Resolving from a discovered config plus a flag override
const { config, contract } = await resolveBuildConfig({ cwd: process.cwd(), flags })--out. A v1/v2 security protocol is required for production output, and the temp dir is always removed.Parameters
| Name | Type | Description |
|---|---|---|
§options | RunBuildOptions | Flags, working directory, output sinks, and injectable deps. |
Returns
Promise<number>Example
Building a feature into ./dist
const code = await runBuild({ flags, cwd: process.cwd(), stdout: process.stdout, stderr: process.stderr })hf-dev.config.* through the shared tiered loader and starts the dev server: one static server per app plus the debug UI. The returned promise resolves once the servers are listening; the process stays alive serving them.Parameters
| Name | Type | Description |
|---|---|---|
§options | RunDevOptions | Flags, working directory, output sinks, and injectable deps. |
Returns
Promise<number>Example
Starting the dev server in the current directory
const code = await runDev({ flags, cwd: process.cwd(), stdout: process.stdout, stderr: process.stderr })init, build, or dev. --help (and a missing command) print usage; an unknown command or flag fails with usage. The returned exit code is mapped to process.exit by the bin bootstrap.Parameters
| Name | Type | Description |
|---|---|---|
§options | RunFeaturesCliOptions | argv, working directory, and output sinks. |
Returns
Promise<number>Example
Running the build command programmatically
const code = await runFeaturesCli({ argv: ['build', '--protocol', 'v2'], cwd: process.cwd(), stdout: process.stdout, stderr: process.stderr })feature.config.json, and wires a marker-guarded import into the resolved entry file. Discovery, prompting, and insertion live here; the glue source comes from the pure feature-module generator. Honors --dry-run, and --ci/--yes require every value to come from flags.Parameters
| Name | Type | Description |
|---|---|---|
§options | RunInitOptions | Flags, working directory, output sinks, and injectable deps. |
Returns
Promise<number>Example
Scaffolding a feature non-interactively
const code = await runInit({
flags: { name: 'clock', contract: './clock.contract.json', entry: './src/main.ts', ci: true, yes: false, dryRun: false, help: false },
cwd: process.cwd(),
stdout: process.stdout,
stderr: process.stderr,
})◈ Interfaces
runBuild, defaulted for production and overridden in tests.--ci/--yes and --dry-run are the headless and preview toggles.Properties
readonly apps?:string— --apps); the object key passed as a path.readonly config?:string— --config); the path-flag for the config itself.readonly protocol?:string— --protocol): none, v1, or v2.runDev, defaulted for production and overridden in tests.Properties
runInit, defaulted for production and overridden in tests.Properties
readonly commit?:(tree: Tree, options?: CommitOptions) => CommitResult— readonly createTreeFn?:(root: string, options?: CreateTreeOptions) => Tree— readonly discoverEntries?:(directory: string) => unknown— readonly loadContract?:(absolutePath: string) => Promise<FeatureContract>— readonly promptEntry?:(candidates: unknown) => Promise<string>— Properties
readonly contract:FeatureContract— build invocation.dev invocation.Properties
Properties
init invocation.Properties
readonly commit?:(tree: Tree, options?: CommitOptions) => CommitResult— readonly createTreeFn?:(root: string, options?: CreateTreeOptions) => Tree— readonly discoverEntries?:(directory: string) => unknown— readonly loadContract?:(absolutePath: string) => Promise<FeatureContract>— readonly promptEntry?:(candidates: unknown) => Promise<string>— ● Variables
--help and on an unknown command. Documents the three commands and the shared flag surface so the headless (
--ci) path is discoverable without reading the docs.