@hyperfrontend/versioning/flowflow/
Composable versioning workflow system for orchestrating release operations.
Overview
This module provides a declarative flow execution engine for versioning workflows. Flows are sequences of steps that perform operations like fetching registry versions, analyzing commits, calculating bumps, generating changelogs, and creating git commits/tags.
Architecture
Execution Options
FlowExecutionOptions
| Option | Default | Description |
|---|---|---|
showDiff |
false |
Preview changes before committing to VFS |
diffFormat |
'unified' |
Diff format: 'unified' or 'simple' |
rollbackOnFailure |
false |
Discard all VFS changes if any step fails |
WriteChangelogStepOptions
| Option | Default | Description |
|---|---|---|
backupChangelog |
false |
Backup existing changelog before writing (uses tree.rename()) |
Usage
Basic Execution
import { createConventionalFlow, executeFlow } from '@hyperfrontend/versioning/flow'
const flow = createConventionalFlow({ dryRun: true })
const result = await executeFlow(flow, 'lib-utils', '/workspace')
console.log(result.summary)
// "Flow success in 234ms: 8 completed, 0 skipped, 0 failed. Version: 1.2.3 → 1.3.0"
Custom Flow
import {
createFlow,
createFetchRegistryStep,
createAnalyzeCommitsStep,
createCalculateBumpStep,
executeFlow,
} from '@hyperfrontend/versioning/flow'
const minimalFlow = createFlow('minimal', 'Minimal Flow', [
createFetchRegistryStep(),
createAnalyzeCommitsStep(),
createCalculateBumpStep(),
])
const result = await executeFlow(minimalFlow, 'lib-utils', '/workspace', {
dryRun: true,
})
Custom Step
import { createStep, addStep, createConventionalFlow } from '@hyperfrontend/versioning/flow'
const notifyStep = createStep(
'notify',
'Send Notification',
async (ctx) => {
const { state } = ctx
console.log(`Released ${state.nextVersion}`)
return { status: 'success', message: 'Notification sent' }
},
{ dependsOn: ['create-commit'] }
)
let flow = createConventionalFlow()
flow = addStep(flow, notifyStep)
Flow Execution Lifecycle
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
preset |
string |
'conventional' |
Flow preset name |
releaseTypes |
string[] |
['feat', 'fix', 'perf', 'revert'] |
Types that trigger releases |
minorTypes |
string[] |
['feat'] |
Types that trigger minor bumps |
patchTypes |
string[] |
['fix', 'perf', 'revert'] |
Types that trigger patch bumps |
skipGit |
boolean |
false |
Skip git operations |
skipTag |
boolean |
true |
Skip tag creation |
skipChangelog |
boolean |
false |
Skip changelog update |
dryRun |
boolean |
false |
Preview without changes |
commitMessage |
string |
'chore(${projectName}): release...' |
Commit message template |
tagFormat |
string |
'${projectName}@${version}' |
Tag name template |
trackDeps |
boolean |
false |
Track dependency bumps |
releaseBranch |
string |
'main' |
Allowed release branch |
firstReleaseVersion |
string |
'0.1.0' |
Initial version for new packages |
releaseAs |
string |
undefined |
Force bump type: 'major', 'minor', or 'patch' |
maxCommitFallback |
number |
500 |
Max commits to analyze when no base available |
repository |
* |
undefined |
Repository config for compare URLs (see below) |
changelogFileName |
string |
'CHANGELOG.md' |
Custom changelog filename |
commitTypeToSection |
object |
undefined |
Custom commit type → section mapping (see below) |
Repository Configuration
The repository option controls compare URL generation in changelog entries:
// Auto-detect from package.json or git remote
createVersionFlow('conventional', { repository: 'inferred' })
// Disable compare URLs
createVersionFlow('conventional', { repository: 'disabled' })
// Explicit configuration
createVersionFlow('conventional', {
repository: {
mode: 'explicit',
repository: {
platform: 'github',
baseUrl: 'https://github.com/owner/repo',
},
},
})
// Inferred with custom order
createVersionFlow('conventional', {
repository: {
mode: 'inferred',
inferenceOrder: ['git-remote', 'package-json'], // Try git first
},
})
When repository is resolved, changelog entries include compare URLs:
## [1.2.0](https://github.com/owner/repo/compare/v1.1.0...v1.2.0) - 2026-03-17
Commit Type to Section Mapping
The commitTypeToSection option customizes how commit types map to changelog sections:
createVersionFlow('conventional', {
commitTypeToSection: {
// Override default mapping
chore: 'other',
// Add custom commit type
wip: 'other',
// Exclude type from changelog
docs: null,
},
})
Default mapping:
| Commit Type | Section |
|---|---|
feat |
features |
fix |
fixes |
perf |
performance |
docs |
documentation |
refactor |
refactoring |
revert |
other |
build |
build |
ci |
ci |
test |
tests |
chore |
chores |
style |
other |
Unmapped types fall back to chores. Use null to exclude a type entirely.
Step Dependencies
Steps can declare dependencies using dependsOn:
const tagStep = createStep('create-tag', 'Create Tag', execute, {
dependsOn: ['create-commit'], // Only runs after create-commit succeeds
})
The executor respects dependencies and skips steps when dependencies fail.
Error Handling
Steps can use continueOnError to allow the flow to continue:
const optionalStep = createStep('optional', 'Optional Step', execute, {
continueOnError: true, // Flow continues even if this fails
})
Flow results include detailed step-by-step outcomes:
const result = await executeFlow(flow, project, root)
for (const step of result.steps) {
console.log(`${step.stepName}: ${step.status}`)
if (step.error) {
console.error(step.error.message)
}
}
See Also
- commits/ — Commit parsing for analyze-commits step
- semver/ — Version bumping for calculate-bump step
- changelog/ — Changelog generation step
- git/ — Git operations for commit/tag steps
- registry/ — Registry queries for fetch-registry step
- workspace/ — Workspace operations for batch flows
- Main README — Package overview and quick start
- ARCHITECTURE.md — Design principles and data flow
API Reference
ƒ Functions
This step resolves repository configuration for compare URL generation. It supports multiple resolution modes:
undefinedor'disabled': No-op, backward compatible default'inferred': Auto-detect from package.json or git remoteRepositoryConfig: Direct repository configuration providedRepositoryResolution: Fine-grained control with mode and options
- repositoryConfig: Resolved repository configuration (if successful)
Returns
FlowStepExample
Configuring repository resolution modes
// Auto-detect repository
const flow = createFlow({
repository: 'inferred'
})
// Explicit repository
const flow = createFlow({
repository: {
platform: 'github',
baseUrl: 'https://github.com/owner/repo'
}
})Returns
VersionFlowExample
Adding a custom step to a flow
import { addStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const extended = addStep(flow, createNoopStep('custom', 'Custom Step'))
console.log(extended.steps.length)
// => original steps + 1This step:
- Uses publishedCommit from npm registry (set by fetch-registry step)
- Verifies the commit is reachable from current HEAD
- Gets all commits since that commit (or recent commits if first release/fallback)
- Parses each commit using conventional commit format
- Classifies commits based on scope filtering strategy
- Filters to only release-worthy commits that belong to this project
- effectiveBaseCommit: The verified base commit (null if fallback was used)
- commits: Array of parsed conventional commits (for backward compatibility)
- classificationResult: Full classification result with source attribution
Returns
FlowStepExample
Analyzing commits since last release
import { createAnalyzeCommitsStep, executeStep } from '@hyperfrontend/versioning'
const step = createAnalyzeCommitsStep()
const result = await executeStep(step, context)
// Access analyzed commits
console.log(result.stateUpdates?.commits)
// => [{ type: 'feat', subject: 'add feature' }, ...]This is a variant that skips commit/tag creation, intended to be used when releasing multiple packages in sequence with a single commit at the end.
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Releasing multiple packages in batch
import { createBatchReleaseFlow, executeFlow } from '@hyperfrontend/versioning'
// Release multiple packages without individual commits
for (const pkg of ['lib-a', 'lib-b', 'lib-c']) {
await executeFlow(createBatchReleaseFlow(), pkg, '/workspace')
}
// Then create a single combined commitThis step:
- Analyzes commit types and breaking changes
- Determines the appropriate bump level
- Calculates the next version
- bumpType: 'major' | 'minor' | 'patch' | 'none'
- nextVersion: Calculated next version string
Returns
FlowStepExample
Running the calculate-bump step
import { createCalculateBumpStep, executeStep } from '@hyperfrontend/versioning'
const step = createCalculateBumpStep()
const result = await executeStep(step, context)
// Get the calculated bump
console.log(result.stateUpdates?.bumpType)
// => 'minor'
console.log(result.stateUpdates?.nextVersion)
// => '1.2.0'This step cascades version updates to packages that depend on the updated package.
Returns
FlowStepExample
Updating dependent packages in a monorepo
import { createCascadeDependenciesStep, executeStep } from '@hyperfrontend/versioning'
const step = createCascadeDependenciesStep()
const result = await executeStep(step, contextWithTrackDeps)
// Dependent packages are updated
console.log(result.message)Only generates changelog, no version bumps or git operations.
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Creating a changelog-only flow
import { createChangelogOnlyFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createChangelogOnlyFlow()
const result = await executeFlow(flow, 'my-lib', '/workspace')
// Only changelog is updated, no version bump
console.log(result.state.changelogEntry)In independent versioning, when a dependency is bumped, dependents may also need version bumps.
Returns
FlowStepExample
Checking if dependent packages need bumps
import { createCheckDependentBumpsStep, executeStep } from '@hyperfrontend/versioning'
const step = createCheckDependentBumpsStep()
const result = await executeStep(step, contextWithTrackDeps)
// Result indicates if any dependents need bumps
console.log(result.message)This step prevents redundant releases by checking if the calculated version is already published.
Returns
FlowStepExample
Preventing duplicate releases
import { createCheckIdempotencyStep, executeStep } from '@hyperfrontend/versioning'
const step = createCheckIdempotencyStep()
const result = await executeStep(step, context)
// If version already published, step skips with bumpType: 'none'
if (result.status === 'skipped') {
console.log('Version already published')
}Returns
FlowStepExample
Generating a combined changelog for all packages
import { createCombinedChangelogStep, executeStep } from '@hyperfrontend/versioning'
const step = createCombinedChangelogStep()
const result = await executeStep(step, context)
// Single changelog for all packages
console.log(result.message)This flow follows the standard conventional commits workflow:
- Fetch published version from registry
- Resolve repository configuration (for compare URLs)
- Analyze commits since last release
- Calculate version bump based on commit types
- Check if version already published (idempotency)
- Generate changelog entry (with compare URL if repository resolved)
- Update package.json version
- Write changelog to file
- Create git commit (optional)
- Create git tag (optional, typically after publish)
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Creating a conventional versioning flow
import { createConventionalFlow, executeFlow } from '@hyperfrontend/versioning'
// Use defaults
const flow = createConventionalFlow()
// With overrides
const customFlow = createConventionalFlow({
skipTag: false,
releaseTypes: ['feat', 'fix'],
})
const result = await executeFlow(flow, 'lib-utils', '/workspace')Convenience function that creates a flow with dryRun enabled.
Parameters
Returns
VersionFlowExample
Creating a dry-run flow for preview
import { createDryRunFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createDryRunFlow('conventional')
const result = await executeFlow(flow, 'my-lib', '/workspace')
// Preview changes without modifying files
console.log('Would release:', result.state.nextVersion)Parameters
Returns
FlowStepResultExample
Handling step execution errors
import { createFailedResult } from '@hyperfrontend/versioning'
// In a step handler:
try {
await doOperation()
} catch (err) {
return createFailedResult(err as Error, 'Operation failed')
}This step:
- Queries the registry for the latest published version
- Reads the current version from package.json
- Determines if this is a first release
- publishedVersion: Latest version on registry (null if not published)
- currentVersion: Version from local package.json
- isFirstRelease: True if never published
Returns
FlowStepExample
Fetching published version from registry
import { createFetchRegistryStep, executeStep } from '@hyperfrontend/versioning'
const step = createFetchRegistryStep()
const result = await executeStep(step, context)
// Check if first release
if (result.stateUpdates?.isFirstRelease) {
console.log('First release detected')
}Similar to synced, but uses a fixed version scheme where the version is explicitly provided rather than calculated from commits.
Parameters
Returns
VersionFlowExample
Creating a fixed version release flow
import { createFixedVersionFlow, executeFlow } from '@hyperfrontend/versioning'
// Release with explicit version, ignoring commit analysis
const flow = createFixedVersionFlow('2.0.0')
const result = await executeFlow(flow, 'workspace', '/workspace')
console.log(result.state.nextVersion)
// => '2.0.0'createFlow(id: string, name: string, steps: unknown, options: CreateFlowOptions): VersionFlow
Parameters
Returns
VersionFlowExample
Creating a custom flow
const myFlow = createFlow(
'custom',
'Custom Release Flow',
[fetchStep, analyzeStep, bumpStep],
{ description: 'My custom versioning workflow' }
)This step:
- Groups commits by type/section
- Creates changelog items from commits
- Assembles a complete changelog entry
- changelogEntry: The generated ChangelogEntry
Returns
FlowStepExample
Generating a changelog entry from commits
import { createGenerateChangelogStep, executeStep } from '@hyperfrontend/versioning'
const step = createGenerateChangelogStep()
const result = await executeStep(step, context)
// Access the generated changelog entry
const entry = result.stateUpdates?.changelogEntry
console.log(entry?.version, entry?.sections.length)
// => '1.2.0', 3This step:
- Stages modified files
- Creates a commit with the configured message
- commitHash: Hash of the created commit
Returns
FlowStepExample
Creating and staging a release commit
import { createGitCommitStep, executeStep } from '@hyperfrontend/versioning'
const step = createGitCommitStep()
const result = await executeStep(step, context)
// Get the created commit hash
console.log(result.stateUpdates?.commitHash)
// => 'a1b2c3d4e5f6...'This flow is designed for monorepos where each package is versioned independently:
- Fetch published version from registry
- Analyze commits since last release
- Calculate version bump based on commit types
- Check for dependent package bumps (cascade)
- Check if version already published (idempotency)
- Generate changelog entry
- Update package.json version
- Cascade dependency updates
- Write changelog to file
- Create git commit
- Create git tag
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Creating an independent versioning flow
import { createIndependentFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createIndependentFlow()
const result = await executeFlow(flow, 'lib-utils', '/workspace')
// Check which dependents were bumped
console.log(result.state.cascadedBumps)Skips changelog and tag creation.
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Creating a minimal release flow
import { createMinimalFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createMinimalFlow()
const result = await executeFlow(flow, 'my-lib', '/workspace')
// Quick release without changelog or tags
console.log('Released:', result.state.nextVersion)Parameters
Returns
FlowStepExample
Creating a placeholder step
import { createNoopStep, executeStep } from '@hyperfrontend/versioning'
const step = createNoopStep('placeholder', 'Placeholder Step')
const result = await executeStep(step, context)
console.log(result.status)
// => 'success'Returns
FlowStepExample
Pushing the tag to remote
import { createPushTagStep, executeStep } from '@hyperfrontend/versioning'
const step = createPushTagStep()
const result = await executeStep(step, context)
// Tag is pushed to remote
console.log(result.message)
// => 'Pushed tag: my-lib@1.2.0'Parameters
| Name | Type | Description |
|---|---|---|
§message | string | Explanation for why the step was skipped |
Returns
FlowStepResultExample
Skipping a step conditionally
import { createSkippedResult } from '@hyperfrontend/versioning'
// In a step handler:
if (!config.enabled) {
return createSkippedResult('Feature disabled in config')
}createStep(id: string, name: string, execute: StepExecutor, options: CreateStepOptions): FlowStep
Parameters
Returns
FlowStepExample
Creating a custom fetch step
const fetchStep = createStep(
'fetch-registry',
'Fetch Registry Version',
async (ctx) => {
const version = await ctx.registry.getLatestVersion(ctx.packageName)
return {
status: 'success',
stateUpdates: { publishedVersion: version },
message: `Found published version: ${version}`
}
}
)Parameters
Returns
FlowStepResultExample
Returning a success result with state updates
import { createSuccessResult } from '@hyperfrontend/versioning'
// In a step handler:
return createSuccessResult('Updated 3 files', {
modifiedFiles: ['/path/a.ts', '/path/b.ts', '/path/c.ts']
})Returns
FlowStepExample
Syncing all packages to the same version
import { createSyncAllPackagesStep, executeStep } from '@hyperfrontend/versioning'
const step = createSyncAllPackagesStep()
const result = await executeStep(step, context)
// All packages updated to same version
console.log(result.stateUpdates?.modifiedFiles)This flow maintains the same version across all packages in a monorepo. When any package changes, all packages get the same new version.
Flow steps:
- Fetch published version from registry
- Analyze commits across all packages
- Calculate version bump (highest needed)
- Check if version already published
- Sync all package versions
- Generate combined changelog
- Write changelog to root
- Create git commit
- Create single git tag
Parameters
| Name | Type | Description |
|---|---|---|
§config? | Partial<FlowConfig> | Optional configuration overrides |
Returns
VersionFlowExample
Creating a synced versioning flow
import { createSyncedFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createSyncedFlow()
const result = await executeFlow(flow, 'workspace', '/workspace')
// All packages now share the same version
console.log(`Released v${result.state.nextVersion}`)This step:
- Creates an annotated git tag
- Uses the configured tag format
- tagName: Name of the created tag
Returns
FlowStepExample
Creating an annotated version tag
import { createTagStep, executeStep } from '@hyperfrontend/versioning'
const step = createTagStep()
const result = await executeStep(step, context)
// Get the created tag name
console.log(result.stateUpdates?.tagName)
// => 'my-lib@1.2.0'This step:
- Updates the version field in package.json
- Tracks the modified files
- modifiedFiles: Adds package.json to list
Returns
FlowStepExample
Updating the package.json version field
import { createUpdatePackageStep, executeStep } from '@hyperfrontend/versioning'
const step = createUpdatePackageStep()
const result = await executeStep(step, context)
// package.json version field is updated
console.log(result.stateUpdates?.modifiedFiles)
// => ['/workspace/libs/my-lib/package.json']This is the main factory function for creating flows. Use this when you want to create a flow based on a standard preset with optional customization.
Parameters
Returns
VersionFlowExample
Creating flows from presets
import { createVersionFlow, executeFlow } from '@hyperfrontend/versioning'
// Create a conventional flow
const flow = createVersionFlow('conventional')
// Create an independent flow with custom config
const customFlow = createVersionFlow('independent', {
skipTag: true,
trackDeps: true,
})
const result = await executeFlow(flow, 'lib-utils', '/workspace')This step writes the generated changelog entry to CHANGELOG.md.
Returns
FlowStepExample
Writing the changelog entry to CHANGELOG.md
import { createWriteChangelogStep, executeStep } from '@hyperfrontend/versioning'
const step = createWriteChangelogStep()
const result = await executeStep(step, context)
// CHANGELOG.md is updated with the new entry
console.log(result.message)
// => 'Updated CHANGELOG.md with version 1.2.0'dryRun(flow: VersionFlow, projectName: string, workspaceRoot: string, options: Omit<ExecuteOptions, "dryRun">): Promise<FlowResult>
Convenience wrapper that sets dryRun: true.
Parameters
Returns
Promise<FlowResult>Example
Previewing version changes without modifying files
import { dryRun, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const result = await dryRun(flow, 'my-lib', '/workspace')
// Preview what would happen
console.log('Would bump to:', result.state.nextVersion)
// No files modified, no git operations performedexecuteFlow(flow: VersionFlow, projectName: string, workspaceRoot: string, options: ExecuteOptions): Promise<FlowResult>
This is the main entry point for running a versioning workflow. Steps are executed in order, with state accumulated between steps.
Parameters
Returns
Promise<FlowResult>Example
Executing a conventional version flow
import { createConventionalFlow, executeFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow({ dryRun: true })
const result = await executeFlow(flow, 'lib-utils', '/path/to/workspace')
console.log(result.summary)
// "Flow success in 234ms: 8 completed, 0 skipped, 0 failed. Version: 1.2.3 → 1.3.0"Returns
unknownExample
Listing available presets
import { getAvailablePresets } from '@hyperfrontend/versioning'
const presets = getAvailablePresets()
// => ['conventional', 'independent', 'synced']Parameters
| Name | Type | Description |
|---|---|---|
§preset | FlowPreset | The preset name |
Returns
stringExample
Getting a preset description
import { getPresetDescription } from '@hyperfrontend/versioning'
console.log(getPresetDescription('independent'))
// => 'Version packages independently with dependency tracking'Returns
FlowStepExample
Getting a step by ID
import { getStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const step = getStep(flow, 'analyze-commits')
console.log(step?.name)
// => 'Analyze Commits'Returns
booleanExample
Checking if a flow has a step
import { hasStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
console.log(hasStep(flow, 'create-commit'))
// => true
console.log(hasStep(flow, 'custom-step'))
// => falseParameters
Returns
VersionFlowExample
Inserting a step at a specific position
import { insertStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStep(flow, createNoopStep('early', 'Early Step'), 0)
console.log(modified.steps[0].id)
// => 'early'Parameters
Returns
VersionFlowExample
Inserting a step after another step
import { insertStepAfter, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStepAfter(flow, createNoopStep('validate', 'Validate'), 'analyze-commits'))
// 'validate' step now follows 'analyze-commits'Parameters
Returns
VersionFlowExample
Inserting a step before another step
import { insertStepBefore, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStepBefore(flow, createNoopStep('prep', 'Prepare'), 'create-commit'))
// 'prep' step now runs before 'create-commit'Parameters
Returns
VersionFlowExample
Removing a step from a flow
import { removeStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const minimal = removeStep(flow, 'generate-changelog')
// Flow no longer has changelog step
console.log(minimal.steps.find(s => s.id === 'generate-changelog'))
// => undefinedParameters
Returns
VersionFlowExample
Replacing a step with a custom implementation
import { replaceStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = replaceStep(flow, 'create-tag', createNoopStep('create-tag', 'Custom Tag'))
// 'create-tag' now uses custom implementationChecks for:
- Duplicate step IDs
- Invalid dependency references
- Circular dependencies
Parameters
| Name | Type | Description |
|---|---|---|
§flow | VersionFlow | The flow to validate |
Returns
unknownExample
Validating a flow before execution
import { validateFlow, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const errors = validateFlow(flow)
if (errors.length > 0) {
console.error('Invalid flow:', errors)
}
// => []Parameters
Returns
VersionFlowExample
Updating flow configuration
import { withConfig, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const dryRunFlow = withConfig(flow, { dryRun: true })
// Flow now runs in dry-run mode◈ Interfaces
Properties
projectRoot?:string— rollbackOnFailure?:boolean— When true (default), pending VFS changes are discarded when a step fails and
continueOnError is false. This ensures no partial state remains.Properties
readonly backupChangelog?:boolean— When enabled:
- Existing
CHANGELOG.mdis renamed toCHANGELOG.backup.md - New changelog is written
- Backup is deleted on success
readonly commitTypeToSection?:Partial<Record<string, ChangelogSectionType | null>>— null to exclude a type from changelog.readonly maxCommitFallback?:number— Set higher if you expect >500 commits between releases.
readonly releaseAs?:"minor" | "patch" | "major"— readonly repository?:RepositoryConfig | "inferred" | "disabled" | RepositoryResolution— Controls how repository information is resolved:
'disabled': No compare URLs generated (default, backward compatible)'inferred': Auto-detect from package.json or git remoteRepositoryResolution: Fine-grained control with explicit mode and optionsRepositoryConfig: Direct repository configuration
readonly scopeFiltering?:ScopeFilteringConfig— By default, hybrid filtering ensures commits are included based on conventional commit scope OR file changes within the project.
Note:
state is mutable within context to allow accumulation, but individual FlowState objects are immutable.Properties
Properties
readonly diffs?:unknown— showDiff: true is passed to executeFlow. Provides unified diff format for programmatic access.Properties
readonly classificationResult?:ClassificationResult— readonly effectiveBaseCommit?:string— publishedCommit if that commit is reachable from HEAD, or null if a fallback was used (e.g., history was rewritten). When null, compare URLs are omitted from the changelog.
readonly isPendingPublication?:boolean— - nextVersion is calculated from publishedVersion (not currentVersion)
- Changelog entries > publishedVersion should be cleaned up
- The correct changelog entry replaces any stacked ones
Steps are pure functions that:
- Read from context (state, config, services)
- Perform work (possibly with side effects via services)
- Return state updates
Properties
Properties
Properties
Flows are immutable configurations that define:
- What steps to execute
- In what order
- With what configuration
◆ Types
type FlowStatus = "success" | "partial" | "failed" | "skipped"type StepCondition = (context: FlowContext) => booleantype StepExecutor = (context: FlowContext) => Promise<FlowStepResult>