defineCheck
Defines a pre-flight check that validates preconditions before command execution.
Import
import { defineCheck } from '@pokit/core';Signature
function defineCheck(config: CheckConfig): CheckConfig;
type CheckConfig = {
label: string;
check: () => Promise<void> | void;
errorMessage?: string;
remediation?: string | string[];
documentationUrl?: string;
};Configuration
| Property | Type | Description |
|---|---|---|
label | string | Human-readable label for logging |
check | () => void | Promise<void> | Validation function that throws on failure |
errorMessage | string | Custom error message (replaces default thrown error) |
remediation | string | string[] | Fix instructions shown when check fails |
documentationUrl | string | Link to documentation for more information |
Examples
Basic Check
import { defineCheck } from '@pokit/core';
import { commandExists } from '@pokit/core';
export const dockerInstalled = defineCheck({
label: 'Docker installed',
check: async () => {
const exists = await commandExists('docker');
if (!exists) {
throw new Error('Docker is not installed. Please install Docker Desktop.');
}
},
});Check with Remediation Steps
import { defineCheck } from '@pokit/core';
import { $ } from 'bun';
export const dockerRunning = defineCheck({
label: 'Docker running',
check: async () => {
const result = await $`docker info`.nothrow().quiet();
if (result.exitCode !== 0) {
throw new Error('Docker is not running');
}
},
errorMessage: 'Docker daemon is not running',
remediation: [
'Start Docker Desktop, or',
"Run 'sudo systemctl start docker' (Linux)",
"Run 'open -a Docker' (macOS)",
],
documentationUrl: 'https://docs.docker.com/get-started/',
});Check with Single Remediation
import { defineCheck } from '@pokit/core';
export const dockerInstalled = defineCheck({
label: 'Docker installed',
check: async () => {
const exists = await commandExists('docker');
if (!exists) {
throw new Error('Docker not found');
}
},
errorMessage: 'Docker is not installed',
remediation: 'Install Docker from https://docs.docker.com/get-docker/',
documentationUrl: 'https://docs.docker.com/get-docker/',
});Check Node Version
import { defineCheck, getNodeMajorVersion } from '@pokit/core';
export const nodeVersion = defineCheck({
label: 'Node.js >= 18',
check: async () => {
const version = await getNodeMajorVersion();
if (version < 18) {
throw new Error(`Node.js 18+ required. Current: ${version}`);
}
},
});Check File Exists
import { defineCheck } from '@pokit/core';
import { exists } from 'fs/promises';
export const envFileExists = defineCheck({
label: '.env file exists',
check: async () => {
if (!(await exists('.env'))) {
throw new Error('.env file not found. Copy .env.example to .env and fill in values.');
}
},
});Using Checks
Static Checks
import { defineCommand } from '@pokit/core';
import { dockerRunning, nodeVersion } from './checks';
export const command = defineCommand({
label: 'Start development',
pre: [dockerRunning, nodeVersion],
run: async (r) => {
await r.exec('docker compose up');
},
});Single Check
export const command = defineCommand({
label: 'Build',
pre: nodeVersion, // Single check (not array)
run: async (r) => {
await r.exec('npm run build');
},
});Dynamic Checks (Hook Function)
Checks can depend on the resolved context:
import { defineCommand, defineCheck } from '@pokit/core';
import { z } from 'zod';
const prodConfirmation = defineCheck({
label: 'Production deployment confirmed',
check: async () => {
// In a real app, you might prompt for confirmation
const confirmed = process.env.CONFIRM_PROD === 'true';
if (!confirmed) {
throw new Error('Production deployment requires CONFIRM_PROD=true');
}
},
});
export const command = defineCommand({
label: 'Deploy',
context: {
env: {
from: 'flag',
schema: z.enum(['staging', 'prod']),
},
},
pre: (ctx) => {
// Only require confirmation for prod
if (ctx.env === 'prod') {
return [prodConfirmation];
}
return [];
},
run: async (r, ctx) => {
await r.exec(`deploy --env ${ctx.context.env}`);
},
});Returning Checks from Hook
The hook function can return:
void- No checksCheckConfig- Single checkCheckConfig[]- Multiple checksPromise<...>- Async versions of above
pre: async (ctx) => {
const checks: CheckConfig[] = [];
if (ctx.env === 'prod') {
checks.push(prodConfirmation);
}
if (ctx.useDocker) {
checks.push(dockerRunning);
}
return checks;
},Check Execution
When checks are executed:
- They run in a "Pre-flight Checks" group with visual spinners
- Each check's label is displayed with a spinner
- On success, a checkmark appears
- On failure, execution stops and the error message is shown
- If remediation steps are defined, they're displayed after the error
- If a documentation URL is provided, it's shown for more information
Basic Failure
┌ Pre-flight Checks
│
◇ Docker installed
│
■ Docker running
│
└ ✘ Failed
Error: Docker is not runningFailure with Remediation
┌ Pre-flight Checks
│
◇ Docker installed
│
■ Docker running
│ Docker daemon is not running
│
│ To fix:
│ - Start Docker Desktop, or
│ - Run 'sudo systemctl start docker' (Linux)
│
│ More info: https://docs.docker.com/get-started/
│
└ ✘ FailedDeduplication
When running all children of a parent command, checks are deduplicated by reference:
// Both commands use dockerRunning
// commands/dev.ts
pre: [dockerRunning, nodeVersion],
// commands/build.ts
pre: [dockerRunning],
// Running "all" only executes dockerRunning onceShell Utilities
pok exports utilities for common checks:
import {
commandExists, // Check if command is in PATH
getVersion, // Get version of a command
getNodeMajorVersion,
getPackageManager,
} from '@pokit/core';