npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ajax-16/vit

v0.1.1

Published

Interactive CLI to manage versions, changelogs and deployments — monorepo ready

Readme

VIT — Version It!

Interactive CLI tool to manage versions, changelogs and commits in single or multi-project repositories.

Installation

npm install -g @ajax-16/vit

Verify the installation:

vit

Quick start — vit init

The fastest way to configure VIT in a new project:

vit init

This creates two files in the current directory:

  • vit-config.json — ready-to-edit configuration with sensible defaults.
  • .vscode/settings.json — enables IntelliSense for vit-config.json in VS Code automatically.
  ✔  vit-config.json created.
  ✔  .vscode/settings.json created.

  VIT  Project initialized. Edit vit-config.json to configure.

If either file already exists, vit init skips it without overwriting anything.

VS Code IntelliSense

Once initialized, VS Code provides autocompletion, inline documentation and validation for every field in vit-config.json:

{
  "$schema": "https://raw.githubusercontent.com/Ajax-16/VIT/main/vit-config.schema.json",
  "changelog": { ... }
}

To enable it manually in an existing project, add this to your .vscode/settings.json:

{
  "json.schemas": [
    {
      "fileMatch": ["vit-config.json"],
      "url": "https://raw.githubusercontent.com/Ajax-16/VIT/main/vit-config.schema.json"
    }
  ]
}

Usage

Run vit at the root of your project. VIT will look for a vit-config.json file in the current directory.

  VIT   Version It!  v1.0.0

  VCS            : git
  Current branch : main
  Last tag       : v1.2.3

? Welcome. What do you want to do?
  🚀  Version it!  — bump + changelog + commit
  📋  Changelog    — add or edit entries
  💾  Commit       — commit and push without bump
  ⏫  Promote      — merge into main + stable release
  🔄  Sync         — sync prerelease branches with main
  ⏪  Rollback     — roll back to a tag
  ❌  Exit

Note: Promote and Sync only appear in the interactive menu when relevant (promote requires being on a prerelease branch).

Available actions

| Action | Description | | --------------- | -------------------------------------------------------- | | Version it! | Version bump + changelog + commit + tag + push | | Changelog | Add or edit changelog entries without bumping | | Commit | Commit and push without modifying versions | | Promote | Promote a prerelease branch into a stable release | | Sync | Sync prerelease branches that are behind their base | | Rollback | Revert the repository to a previous tag |


CLI Arguments

You can pass arguments directly when running vit to skip steps in the interactive flow.

vit [command] [options]

Commands

| Command | Alias | Description | | ----------- | ----- | -------------------------------------------------------------- | | release | r | Run the release flow | | commit | c | Run a commit without bumping | | changelog | cl | Open the changelog flow | | rollback | rb | Revert to a previous tag | | promote | pr | Promote prerelease branch into stable release | | sync | sy | Sync prerelease branches that are behind their release branch |

Options

| Option | Alias | Description | | ------------------ | ----- | ------------------------------------------------------------------------------- | | --bump <type> | -b | Bump type: patch, minor, major, prepatch, preminor, premajor | | --message <msg> | -m | Commit message | | --tag <tag> | -t | Target tag for rollback | | --projects <ids> | -p | Comma-separated project IDs (monorepo) | | --target <branch>| | Target release branch for promote (default: first in releaseBranches) | | --semantic | -s | Force semantic changelog mode for this run | | --yes | -y | Skip all prompts and confirmations, use defaults or provided flags | | --dry-run | -d | Simulate the operation without writing or pushing | | --version | -v | Show VIT version | | --help | -h | Show help |

Non-interactive mode (--yes)

--yes (or -y) skips all prompts and confirmations, using the values provided via flags or their defaults:

  • Confirms all actions automatically.
  • Selects all configured projects if --projects is not specified.
  • Uses the default commit message if --message is not provided.
  • In non-semantic mode, skips the changelog step silently.
  • In semantic mode, regenerates the changelog automatically from git tags.

Important: --yes does not guess required values. You must still provide --bump for release and --message for commit. Without them, VIT will exit with an error.

# ✅ Correct
vit release --bump patch --yes
vit commit --message "fix: typo" --yes

# ❌ Missing required flag
vit release --yes          # --bump is required
vit commit --yes           # --message is required

Behavior by level

| Command | What is skipped | What is still asked | | ------------------------------------------ | ---------------------------------------------------------------- | ------------------------------------------- | | vit release | Main menu | Bump type, changelog, message, confirmation | | vit release --bump patch | Menu + bump type | Changelog, message, confirmation | | vit release --bump patch --message "fix" | Menu + bump + message | Changelog, confirmation | | vit release --bump patch --yes | Everything | Nothing | | vit commit --message "fix" --yes | Everything | Nothing | | vit changelog --semantic --yes | Everything (regenerates full changelog from all tags) | Nothing | | vit rollback --tag v1.2.3 --yes | Everything | Nothing | | vit promote --yes | Everything (merges/promotes with defaults) | Nothing | | vit sync | Everything (always non-interactive) | Nothing |

Examples

# Interactive release from the menu
vit

# Release skipping the menu, asks the rest
vit release

# Release with fixed bump, still asks for changelog and confirmation
vit release --bump minor

# Fully non-interactive release
vit release --bump patch --yes

# Non-interactive commit with custom message
vit commit --message "fix: typo" --yes

# Rollback to a specific tag without confirmation
vit rollback --tag v1.2.3 --yes

# Simulate a release without writing anything
vit release --bump patch --dry-run

# Release in monorepo for backend only
vit release --bump patch --projects backend --yes

# Promote prerelease branch into main (merge strategy)
vit promote --yes

# Promote into a specific target branch
vit promote --target main --yes

# Sync prerelease branches
vit sync
vit sync --dry-run

Prerelease flow

VIT has native support for prerelease branches. When you run vit release from a branch listed in preReleaseBranches, VIT automatically switches into prerelease mode.

First prerelease bump

On the first release from a prerelease branch, VIT asks for the magnitude of the upcoming stable release:

? What magnitude will the final stable release be?
  prepatch  — anticipates a patch  (x.x.+1-alpha.0)
  preminor  — anticipates a minor  (x.+1.0-alpha.0)
  premajor  — anticipates a major  (+1.0.0-alpha.0)

Subsequent prerelease bumps

Once a prerelease version exists, subsequent bumps on the same branch automatically use prerelease, incrementing the counter (e.g. 1.1.0-alpha.01.1.0-alpha.1).

Prerelease changelog behaviour

Prerelease iterations (prepatch, preminor, premajor, prerelease) skip the changelog step entirely. The changelog is only generated when the stable version is published via promote.

In semantic mode, prerelease tags are not emitted as separate entries in the changelog. Their commits accumulate and are grouped under the next stable release entry.

Promote

When you are ready to publish the stable version, use promote from the prerelease branch:

vit promote
vit promote --yes
vit promote --target main --yes

Promote:

  1. Bumps all targets to the stable version (strips the prerelease suffix).
  2. Runs the changelog step (if semantic: true, regenerates the full changelog).
  3. Merges or opens a PR into the target release branch, depending on promoteStrategy.
  4. Creates the stable tag.

See git.promoteStrategy for merge vs PR configuration.

Sync

vit sync checks all branches listed in preReleaseBranches and merges any commits from their base release branch that are missing:

vit sync
vit sync --dry-run

This is useful to keep prerelease branches up to date with hotfixes or other changes landed on main.


Configuration — vit-config.json

Create a vit-config.json file at the root of your project or run vit init to generate one automatically:

{
  "$schema": "https://raw.githubusercontent.com/Ajax-16/VIT/main/vit-config.schema.json",
  "changelog": {
    "path": "./CHANGELOG.md",
    "title": "Changelog",
    "semantic": false
  },
  "git": {
    "defaultCommitMessage": "chore: update",
    "releaseCommitMessage": "chore: release",
    "changelogCommitMessage": "docs: update changelog",
    "strict": true,
    "releaseBranches": ["main"],
    "rollbackStrategy": "revert",
    "promoteStrategy": "merge",
    "preReleaseBranches": [
      { "id": "alpha", "name": "alpha" }
    ]
  },
  "vcs": {
    "provider": "git"
  },
  "envFile": ".env",
  "projects": [
    {
      "id": "my-project",
      "label": "My Project",
      "path": ".",
      "tagPrefix": "v"
    }
  ]
}

changelog

| Field | Type | Default | Description | | ---------- | --------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | path | string | ./CHANGELOG.md | Path to the changelog file | | title | string | Changelog | Changelog title | | semantic | boolean | false | If true, the changelog is automatically generated from commits using Conventional Commits |

Semantic changelog

When semantic: true, VIT analyzes the commit history since the last tag and automatically generates the changelog by grouping commits by type (feat, fix, refactor…). The expected commit message format is:

<type>(<optional scope>): <description>

Valid examples:

feat: new login screen
fix(api): correct timeout on slow requests
refactor(auth): extract validation logic

Commits that don't follow this format are automatically ignored.

Interactive flow — VIT shows the detected commits, lets you deselect the ones you don't want to include, and optionally asks for an introductory text before saving.

With --yes — the changelog is silently regenerated without prompts.

You can also force semantic mode for a single run without changing vit-config.json using the --semantic flag:

vit changelog --semantic --yes
vit release --bump minor --semantic --yes
"changelog": {
  "path": "./CHANGELOG.md",
  "title": "Changelog",
  "semantic": true
}

git

| Field | Type | Default | Description | | ------------------------ | ---------- | ------------------------ | -------------------------------------------------------------------- | | defaultCommitMessage | string | chore: update | Default message for commits without bump | | releaseCommitMessage | string | chore: version bump | Default message for release commits | | changelogCommitMessage | string | docs: update changelog | Default message for changelog commits | | releaseBranches | string[] | [] | Branches from which stable releases are allowed | | strict | boolean | false | If true, blocks the release when on a non-allowed branch | | rollbackStrategy | string | "revert" | Rollback strategy: "revert" (default) or "reset" | | promoteStrategy | string | "merge" | Promote strategy: "merge" (local merge) or "pr" (GitHub PR) | | preReleaseBranches | array | [] | Branches treated as prerelease (see Prerelease flow) |

Branch control for releases

You can restrict which branches can run a release using releaseBranches and strict.

Warning mode (strict: false, default)

If you are on a non-allowed branch, VIT shows a warning and asks if you want to continue anyway:

  WARNING   You are on branch "feat/my-feature", not on a release branch.
  Configured release branches: main

? Continue anyway? (y/N)

With --yes, the warning is automatically accepted and the release continues.

Strict mode (strict: true)

If you are on a non-allowed branch, the release is blocked:

  BLOCKED   Releases are not allowed from branch "feat/my-feature".
  Allowed branches: main

In --dry-run mode, strict blocking is ignored to allow simulations from any branch.

git.promoteStrategy

Controls how vit promote integrates the prerelease branch into the target release branch.

| Value | Behaviour | | --------- | ---------------------------------------------------------------------------------------------- | | "merge" | Merges the prerelease branch locally into the target branch and pushes. (default) | | "pr" | Opens a GitHub Pull Request from the prerelease branch into the target branch via the API. |

When "pr" is selected and a PR already exists for the same head/base pair, VIT reuses it (updates title and body) instead of creating a duplicate.

The GitHub token must be available as GITHUB_TOKEN in the environment or via envFile:

"git": {
  "promoteStrategy": "pr"
},
"envFile": ".env"
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

git.preReleaseBranches

List of branches that VIT treats as prerelease. Accepts strings or objects:

"preReleaseBranches": [
  "alpha",
  { "id": "beta", "name": "beta" }
]
  • When on one of these branches, vit release automatically enters prerelease mode.
  • The promote command is only available from these branches.
  • Prerelease tags (e.g. v1.1.0-alpha.0) are excluded as standalone entries in the semantic changelog.

Rollback strategy

rollbackStrategy controls how VIT undoes changes when rolling back to a previous tag.

Before executing, VIT always shows a preview of the affected commits and the active strategy:

  Commits that will be rolled back:  (strategy: revert)
  ─────────────────────────────────────────────────────
  · feat: new login screen
  · fix: fix bug in the form
  · chore: release v1.1.0

  Strategy  : revert — creates a new commit, history preserved
  Target tag: v1.0.0 (3 commit(s) affected)

"revert" (default) — creates a new commit that undoes the changes. History intact, normal push possible.

"reset" — moves HEAD to the target tag, rewriting history. Requires git push --force.

With reset, VIT also offers to delete tags that were above the target tag.

vcs

| Field | Type | Default | Description | | ---------- | -------- | ------- | ---------------------------------------- | | provider | string | git | VCS provider. Currently supported: git |

projects

Array of projects to manage. Useful for monorepos.

| Field | Type | Description | | ----------- | -------- | -------------------------------------------------------------- | | id | string | Unique project identifier | | label | string | Human-readable project name | | path | string | Relative path to the project directory | | tagPrefix | string | Prefix for git tags (vv1.2.3, vbackvback1.2.3) |

Monorepo example:

"projects": [
  { "id": "backend",  "label": "Backend",  "path": "./Backend",  "tagPrefix": "vback" },
  { "id": "frontend", "label": "Frontend", "path": "./Frontend", "tagPrefix": "vfront" }
]

types (optional)

Customize the commit types available in the changelog.

"types": [
  { "value": "feat",   "label": "🚀 Features",     "choiceLabel": "🚀 feat     — New feature" },
  { "value": "fix",    "label": "🐛 Bug Fixes",     "choiceLabel": "🐛 fix      — Bug fix" },
  { "value": "chore",  "label": "🔧 Maintenance",   "choiceLabel": "🔧 chore    — Maintenance" },
  { "value": "deploy", "label": "🌍 Deployment",    "choiceLabel": "🌍 deploy   — Deployment / infra" }
]

Default types included: feat, fix, refactor, perf, revert, docs, style.

envFile (optional)

Path to a global .env file whose variables will be available in all actions.

{
  "envFile": ".env"
}

Variable interpolation — ${VAR}

VIT supports ${VAR} placeholder interpolation across all string values in vit-config.json. Variables are resolved from:

  1. process.env (environment variables already in scope)
  2. The global envFile (loaded before interpolation)

This makes it easy to inject secrets, tokens or dynamic values without hardcoding them:

{
  "envFile": ".env",
  "postActions": [
    {
      "id": "deploy",
      "command": "scp ./dist ${DEPLOY_USER}@${SERVER_HOST}:/var/www"
    }
  ]
}
DEPLOY_USER=deploy-bot
SERVER_HOST=production.myserver.com
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

Built-in VIT variables

VIT exposes a set of built-in variables automatically available in any config string:

| Variable | Value | | --------------------- | ------------------------------------------ | | ${branch} | Current git branch | | ${last_tag} | Last git tag | | ${version} | current project version |


Pre-actions and Post-actions

VIT allows you to run commands automatically before (preActions) and after (postActions) each operation.

{
  "preActions": [...],
  "postActions": [...]
}

Action structure

{
  "id": "my-action",
  "label": "Visible description",
  "on": ["release", "commit"],
  "cwd": "./Backend",
  "continueOnError": false,
  "showOutput": true,
  "timeoutMs": 30000,
  "envFile": ".env.production",
  "env": {
    "NODE_ENV": "production"
  },
  "promptEnv": [
    { "name": "SSH_PASS", "message": "SSH password:" }
  ],
  "pipeline": [...],
  "command": "npm test"
}

| Field | Type | Default | Description | | ----------------- | ---------- | ------------- | -------------------------------------------------------------------------------- | | id | string | auto | Unique identifier | | label | string | command | Text shown in the spinner | | on | string[] | ["release"] | Triggers: release, commit, changelog, prerelease | | cwd | string | . | Working directory for the command | | continueOnError | boolean | false | If true, an error doesn't stop execution | | showOutput | boolean | true | Show stdout/stderr in real time | | timeoutMs | number | null | Timeout in ms. null = no limit | | envFile | string | null | Path to a .env specific to this action (higher priority than global envFile) | | env | object | {} | Static environment variables (higher priority than envFile) | | promptEnv | array | [] | Variables asked interactively before running (highest priority) | | pipeline | array | [] | Previous steps that enrich the command's environment | | command | string | — | Main command to execute |

Available triggers

| Trigger | When it runs | | ----------- | -------------------------------------- | | release | When bumping the version | | prerelease| When bumping the a prerelease version | | commit | When committing without bump | | changelog | When committing a changelog |

promptEnv

Allows asking for sensitive values (passwords, tokens) right before running the action, without storing them anywhere.

"promptEnv": [
  { "name": "SSH_PASS",     "message": "SSH password:" },
  { "name": "DEPLOY_TOKEN", "message": "Deploy token:" }
]

Note: promptEnv has the highest priority in VIT. Even when running with --yes, the process will pause until it receives user input for any promptEnv variables.


Environment variables and envFile

VIT supports loading environment variables from .env files at two levels: global (for all actions) and per action (only for that action).

Priority order (lower → higher)

process.env  →  global envFile  →  action envFile  →  action.env  →  promptEnv

Global envFile

Defined at the root of vit-config.json. Its variables are available in all actions and in ${VAR} interpolation.

{
  "envFile": ".env",
  "preActions": [...]
}

Per-action envFile

Defined inside a specific action. Overrides variables from the global envFile with the same name.

{
  "id": "deploy",
  "envFile": ".env.production",
  "command": "scp ./dist ${DEPLOY_USER}@${SERVER_HOST}:/var/www"
}

Note: .env files are parsed internally without needing dotenv. Comments (# comment), blank lines and quoted values are supported.


Step pipeline

The pipeline of an action is a list of commands that run before the main command. Each step can capture its stdout as an environment variable available to subsequent steps and the final command via ${VAR} interpolation.

"pipeline": [
  {
    "id": "node-version",
    "command": "node -e \"process.stdout.write(process.versions.node)\"",
    "captureAs": "NODE_VERSION"
  },
  {
    "id": "git-branch",
    "command": "git rev-parse --abbrev-ref HEAD",
    "captureAs": "GIT_BRANCH"
  }
],
"command": "node -e \"console.log('Node: ${NODE_VERSION} — Branch: ${GIT_BRANCH}')\""

Pipeline step fields

| Field | Type | Default | Description | | ----------------- | --------- | --------------- | --------------------------------------------------- | | id | string | auto | Unique identifier | | label | string | command | Text shown in the spinner | | command | string | — | Command to execute | | captureAs | string | null | Variable to store stdout in | | cwd | string | process.cwd() | Working directory | | continueOnError | boolean | false | If true, an error doesn't stop the pipeline | | showOutput | boolean | false | Show stdout (usually unnecessary in pipeline steps) | | timeoutMs | number | null | Timeout in ms |


Pipeline vs. multiple actions

Pipeline — steps inside an action

  • All steps share the same accumulated environment.
  • Their purpose is to prepare dynamic data to build the main command.
  • They have no on, promptEnv or env of their own.

Multiple actions — independent tasks

  • Each action has its own on, cwd, env, envFile, promptEnv, showOutput and timeoutMs.
  • Each one appears as a separate block with its own spinner in the UI.
  • They do not share variables between them.

Practical rule

| Situation | Use | | ------------------------------------------------------------------ | ---------------- | | I need the result of step A to build command B | pipeline | | They are independent tasks that could run separately | separate actions | | I want each task to have its own clearly visible label and spinner | separate actions | | I want to prepare context before a complex command | pipeline |


Advanced examples

Docker build with automatic version tag

{
  "id": "docker-build",
  "label": "Build Docker",
  "on": ["release"],
  "showOutput": true,
  "pipeline": [
    {
      "command": "node -e \"process.stdout.write(require('./package.json').version)\"",
      "captureAs": "VERSION"
    },
    {
      "command": "node -e \"process.stdout.write(require('./package.json').name)\"",
      "captureAs": "APP_NAME"
    }
  ],
  "command": "docker build -t ${APP_NAME}:${VERSION} -t ${APP_NAME}:latest ."
}

SCP deploy with password asked at runtime

{
  "id": "deploy-production",
  "label": "Deploy to production",
  "on": ["release"],
  "showOutput": true,
  "promptEnv": [
    { "name": "SSH_PASS", "message": "Production server SSH password:" }
  ],
  "pipeline": [
    {
      "command": "node -e \"process.stdout.write(require('./package.json').version)\"",
      "captureAs": "VERSION"
    },
    {
      "command": "node -e \"process.stdout.write(new Date().toISOString().slice(0,10).replace(/-/g,''))\"",
      "captureAs": "DATE"
    }
  ],
  "command": "sshpass -p ${SSH_PASS} scp -r ./dist [email protected]:/var/www/releases/${VERSION}-${DATE}"
}

Publish to npm only if the version doesn't exist yet

{
  "id": "npm-publish",
  "label": "Publish to npm",
  "on": ["release"],
  "showOutput": true,
  "pipeline": [
    {
      "command": "node -e \"process.stdout.write(require('./package.json').version)\"",
      "captureAs": "VERSION"
    },
    {
      "command": "node -e \"process.stdout.write(require('./package.json').name)\"",
      "captureAs": "PKG_NAME"
    },
    {
      "id": "check-published",
      "command": "npm view ${PKG_NAME}@${VERSION} version",
      "captureAs": "PUBLISHED_VERSION",
      "continueOnError": true
    }
  ],
  "command": "node -e \"if ('${PUBLISHED_VERSION}' === '${VERSION}') { console.log('Version ${VERSION} already published, skipping.'); process.exit(0); } require('child_process').execSync('npm publish', { stdio: 'inherit' });\""
}

Slack notification on release

{
  "id": "notify-slack",
  "label": "Notify Slack",
  "on": ["release"],
  "continueOnError": true,
  "showOutput": false,
  "promptEnv": [{ "name": "SLACK_WEBHOOK", "message": "Slack Webhook URL:" }],
  "pipeline": [
    {
      "command": "node -e \"process.stdout.write(require('./package.json').version)\"",
      "captureAs": "VERSION"
    },
    {
      "command": "git rev-parse --abbrev-ref HEAD",
      "captureAs": "BRANCH"
    },
    {
      "command": "node -e \"process.stdout.write(new Date().toISOString().slice(0,16).replace('T',' '))\"",
      "captureAs": "DATE"
    }
  ],
  "command": "curl -s -X POST ${SLACK_WEBHOOK} -H 'Content-type: application/json' --data '{\"text\":\"🚀 *Release v${VERSION}* published from `${BRANCH}` on ${DATE}\"}'"
}

Full monorepo: preflight + tests + build + deploy + summary

{
  "git": {
    "strict": true,
    "releaseBranches": ["main"],
    "promoteStrategy": "merge",
    "preReleaseBranches": [
      { "id": "alpha", "name": "alpha" }
    ]
  },
  "envFile": ".env",
  "projects": [
    { "id": "backend",  "label": "Backend",  "path": "./Backend",  "tagPrefix": "vback" },
    { "id": "frontend", "label": "Frontend", "path": "./Frontend", "tagPrefix": "vfront" }
  ],
  "preActions": [
    {
      "id": "test-backend",
      "label": "Backend tests",
      "on": ["release"],
      "cwd": "./Backend",
      "showOutput": true,
      "command": "npm test"
    },
    {
      "id": "build-frontend",
      "label": "Frontend build",
      "on": ["release"],
      "cwd": "./Frontend",
      "showOutput": true,
      "command": "npm run build"
    }
  ],
  "postActions": [
    {
      "id": "deploy",
      "label": "Deploy to production",
      "on": ["release"],
      "showOutput": true,
      "envFile": ".env.production",
      "promptEnv": [{ "name": "SSH_PASS", "message": "SSH password:" }],
      "pipeline": [
        {
          "command": "node -e \"process.stdout.write(require('./Backend/package.json').version)\"",
          "captureAs": "BACK_VERSION"
        },
        {
          "command": "node -e \"process.stdout.write(require('./Frontend/package.json').version)\"",
          "captureAs": "FRONT_VERSION"
        }
      ],
      "command": "sshpass -p ${SSH_PASS} ssh ${DEPLOY_USER}@${SERVER_HOST} \"cd /var/www && ./deploy.sh ${BACK_VERSION} ${FRONT_VERSION}\""
    }
  ]
}

Error handling

When a command fails, VIT shows a clean message and saves the full stack trace to a temporary log file:

  ERROR   "Tests" failed (exit 1)

  Log saved to:
  C:\Users\user\AppData\Local\Temp\vit-logs\vit-error-1745678912345.log

Logs are saved in {tmpdir}/vit-logs/ with the format vit-error-{timestamp}.log.


Requirements

  • Node.js >= 18
  • Git installed and configured

License

MIT