@titannio/webtoolkit-cli
v1.3.14
Published
Portable CLI tools for TypeScript monorepos and web projects.
Maintainers
Readme
@titannio/webtoolkit-cli
Portable CLI tools for TypeScript monorepos and web projects.
Installation
npm install -D @titannio/webtoolkit-cliCommands
webtoolkit clean --level cache --dry-run
webtoolkit clean --level deep
webtoolkit clean --level nuclear --no-store-prune --reinstall=never
webtoolkit architecture-map
webtoolkit check
webtoolkit build
webtoolkit test --filter backend
webtoolkit test-coverage
webtoolkit test-e2e -- --grep "checkout"
webtoolkit release-gate
webtoolkit validate
webtoolkit jsdoc-report
webtoolkit upgrade --verbose
webtoolkit performance-bundle-audit
webtoolkit dev-watch --apps=user,admin
webtoolkit dev-grid --dry-run
webtoolkit wait-service --url=http://localhost:3001
webtoolkit env-bootstrap
webtoolkit env-doctor
webtoolkit config --help documentation
webtoolkit config --help guards
webtoolkit config --json
webtoolkit config --json guards
webtoolkit guard documentation
webtoolkit guard repository-hygiene
webtoolkit guard package-surface
webtoolkit run:customTaskCleanup levels:
empty: remove empty directories only.cache: remove cache and temporary artifacts.deep: remove cache and build artifacts withoutnode_modules.nuclear: remove cache, build artifacts,node_modules, then optionally run package-manager cleanup/reinstall.
Project Config
Create .webtoolkit-cli/config.json in the consuming project root when defaults need project-specific paths, package-manager behavior, or configured task recipes. The file must be valid JSON: no comments and no trailing commas.
Start with the smallest config that describes what is local to your project:
{
"packageManager": "pnpm",
"cleaner": {
"workspaceRootNames": ["apps", "packages"],
"protectedRootNames": ["apps", "scripts"],
"levels": {
"deep": {
"removableSpecificFiles": ["apps/frontend-user/src/setup-env.js"]
},
"nuclear": {
"removableSpecificFiles": ["apps/frontend-user/src/setup-env.js"]
}
}
},
"tasks": {
"check": {
"title": "Project checks",
"steps": [
{
"label": "TypeScript",
"command": "pnpm",
"args": ["exec", "tsc", "--noEmit"]
}
]
}
}
}The config file is discovered by walking upward from the current working directory.
The CLI also exposes its complete configuration reference without requiring a config file:
webtoolkit config
webtoolkit config --help documentation
webtoolkit config --help guards
webtoolkit config --json
webtoolkit config --json documentation
webtoolkit config --json guards--json emits JSON Schema for tools that need a machine-readable list of supported fields.
Every discovered config is validated before a configured command or guard
starts. Unknown fields, invalid regular expressions, paths that escape the
project, empty required scopes, unknown builtin names, and steps that define
both or neither command and builtinGuard are rejected with config paths in
the error. Configured scan directories must exist, be directories, and contain
at least one eligible file; this prevents a missing scope from producing a
false successful check.
Config Reference
Top-level fields:
packageManager: command used for package-manager operations and task steps, usuallypnpm,npm, oryarn.cleaner: optional cleanup behavior overrides.tasks: named recipes used by generic task commands such aswebtoolkit check,webtoolkit build, andwebtoolkit run:<name>.architectureMap: source paths and output directory used bywebtoolkit architecture-map.guards: consumer-owned paths, targets, rules, and allowlists for configurable builtin guards.documentation: declarative Markdown, collection, paired-document, and coverage-inventory checks.repoCheck: repository quality check steps used bywebtoolkit check.workspaceTests: workspace targets used bywebtoolkit test,webtoolkit test-coverage, andwebtoolkit workspace-test.e2eTests: Playwright runner, browser preflight, and managed service definitions used bywebtoolkit test-e2e.releaseGate: named critical stages used bywebtoolkit release-gate.validate: ordered validation steps used bywebtoolkit validate.jsdocReport: paths and rules used bywebtoolkit jsdoc-report.bundleAudit: frontend build directories, diagnostic thresholds, and blocking asset budgets used bywebtoolkit performance-bundle-audit.upgrade: dependency upgrade policy used bywebtoolkit upgrade.devWatch: dev app ports and package filters used bywebtoolkit dev-watch.devGrid: terminal row layout used bywebtoolkit dev-grid.environment: Node/Corepack/package-manager policy used bywebtoolkit env-bootstrapandwebtoolkit env-doctor.
Documentation fields:
files: required glob patterns selecting Markdown files to inspect.excludeDirectories: optional directory names omitted from repository scanning.checks: optionalsingleH1,headingOrder,localLinks, and reachability rules. The first three default totrue.requiredFiles: exact repository-relative files that must exist.collections: document globs with optional index, metadata, and paired-document rules.inventories: inventory documents and source globs that must be listed as inline-code paths.- Paths and globs are repository-relative. Paired-document targets support
{basename}and{stem}. - Run
webtoolkit config --help documentationorwebtoolkit config --json documentationfor the complete nested reference.
Cleaner fields:
workspaceRootNames: directory names whose direct children are package/app roots. With["apps", "packages"], paths likeapps/apiandpackages/coreare workspace roots.protectedRootNames: top-level directories that must not be removed just because they are empty.skipEmptyDirNames: directory names skipped while removing empty directories.skipArtifactDirNames: directory names skipped while walking for artifacts.levels: per-cleanup-level overrides forempty,cache,deep, andnuclear.
Cleanup level fields:
label: text printed in the summary.removeEmptyDirs: whether this level removes empty directories.removableDirNames: artifact directory names removable only at the repo root or workspace root.removableFileNames: exact file names to remove.removableFileSuffixes: file suffixes to remove.removableFilePrefixes: file prefixes to remove.removableFilePatterns: regex strings matched against file names.removableSpecificFiles: project-relative files to remove exactly.
Task fields:
title: heading printed before the task runs.failFast: defaults totrue; when enabled, later steps are skipped after a failure.steps: ordered commands to run.
Task step fields:
label: human-readable step name.builtinGuard: optional builtin guard name forrepoChecksteps. When present,commandis not required.command: executable to spawn, such aspnpm,node, ornpm.args: argument array; keep each shell token as a separate string.cwd: optional project-relative working directory for the step.env: optional environment variables for the step.appendArgs: whentrue, extra CLI arguments are appended to this step.outputMode:inheritby default; usebufferedto print captured output only on failure.
Repo check fields:
title: optional heading printed before checks run.failFast: defaults tofalse, so every independent check runs and all failures appear in one summary. Set it totrueto mark later checks asSKIPafter the first failure.steps: ordered task steps. The engine prints each step, tracks duration, and renders a final ASCII summary table.
Builtin guards:
anyassert-no-tests-in-distcode-patterndal-service-repositorydependency-cruiserdocumentationinternal-linkmojibakepackage-surfacerebuild-preflightrepository-hygieneschemasingleton-depstsconfigworkspace-manifest
Configurable guard policy:
any: source directories and additional exclusion regexes for AST-based TypeScriptanykeyword detection. Comments, strings, property names, and words merely containinganyare not violations.internalLink: source directories and additional exclusion regexes.schema: central schema directory, scanned directories, configured Zod builders, and additional exclusions. Builder calls are recognized through direct and fluent chains.rebuildPreflight: named targets with warning text, Turbo filters, and relevant build packages.repositoryHygiene: forbidden and explicitly allowed regexes matched against normalized Git-tracked paths.packageSurface: post-build package directories and regexes forbidden in the npm dry-run inventory.tsconfig: package scope, config files, required includes, compiler options, public aliases, and literal forbidden text. Compiler options and aliases are checked after resolvingextends.workspaceManifest: workspace package roots, internal workspace protocol policy, valid dependency ranges, exclusive runtime dependency sections, unique package names, and explicit provider/consumer peer requirements.dalServiceRepository: source root, tsconfig, layer classification, and forbidden layer dependencies.codePattern: tsconfig, model directory, and enabled rule scopes/allowlists.- These guards fail clearly when their corresponding
guardsblock is absent. There are no project-specific builtin profiles. - Configured exclusions extend the safe CLI base. They do not replace dependency/build exclusions or common test patterns.
- Defining
guards.<name>configures policy but does not execute the guard. Add the builtin torepoCheck, callwebtoolkit guard <name>directly, or place build-dependent checks inreleaseGate. - Run
webtoolkit config --json guardsfor the complete nested schema, including required fields and accepted value types.
Safe scan defaults:
- Source extensions:
.cjs,.cts,.js,.jsx,.mjs,.mts,.ts, and.tsx. - Artifact directories:
node_modules,dist,build, andcoverage. - Source-policy exclusions:
*.test.*,*.test-*, theirspecequivalents,test/,tests/,__tests__/, and*.stories.*.
Complete guard wiring example:
{
"guards": {
"any": {
"includePaths": ["apps", "packages"]
},
"internalLink": {
"includePaths": ["apps/web/src"]
},
"repositoryHygiene": {
"forbiddenPathPatterns": ["(^|/)\\.env($|\\.)", "\\.(pem|key|p12)$"],
"allowedPathPatterns": ["(^|/)\\.env\\.example$"]
},
"packageSurface": {
"packageDirectories": ["packages/library"],
"forbiddenPublishedPatterns": ["(^|/)__tests__/", "\\.(test|spec)\\."]
},
"schema": {
"centralDirectory": "packages/contracts/src/schemas",
"includePaths": ["apps/api/src", "apps/web/src"],
"builders": ["object", "enum", "array", "nativeEnum"]
},
"tsconfig": {
"packageScope": "@acme",
"configs": [
{
"path": "tsconfig.json",
"compilerOptions": {
"strict": true
},
"publicAliases": ["@acme/library"]
}
]
},
"workspaceManifest": {
"packageRoots": ["apps", "packages"],
"requireWorkspaceProtocol": true,
"peerRequirements": [
{
"dependency": "example-runtime",
"providers": ["packages/shared-ui"],
"consumers": ["apps/web"]
}
]
}
},
"repoCheck": {
"title": "Repository checks",
"failFast": false,
"steps": [
{
"label": "Repository hygiene",
"builtinGuard": "repository-hygiene"
},
{
"label": "TypeScript any",
"builtinGuard": "any"
},
{
"label": "Schema ownership",
"builtinGuard": "schema"
},
{
"label": "TSConfig policy",
"builtinGuard": "tsconfig"
},
{
"label": "Workspace manifests",
"builtinGuard": "workspace-manifest"
}
]
},
"releaseGate": {
"stages": [
{
"name": "package-surface",
"command": "webtoolkit",
"args": ["guard", "package-surface"]
}
]
}
}workspaceManifest.packageRoots are container directories. Their direct
children containing package.json are treated as workspace packages.
peerDependencies plus devDependencies is allowed for provider development;
providers must not keep the configured peer in runtime dependencies, consumers
must declare it in a runtime dependency section, and runtime dependency
sections remain mutually exclusive.
repository-hygiene reads only git ls-files; it does not inspect file
contents or consider ignored local files. Explicit allowedPathPatterns take
precedence over forbidden patterns. Use a dedicated consumer-owned secret
scanner when content scanning is required. Run it inside a Git worktree with
at least one tracked file.
package-surface validates main, module, types, typings, string/object
bin, and every file target under exports. It verifies both the built file
and its presence in the JSON inventory from
npm pack --dry-run --json --ignore-scripts, then rejects published paths that
match forbiddenPublishedPatterns. It does not build or publish. Build every
configured package first and keep this guard outside repoCheck. Wildcard or
unsupported export targets fail with their exact manifest field; null export
targets are intentionally ignored:
webtoolkit check
pnpm run build
webtoolkit release-gate package-surfaceWorkspace test fields:
workspaces: array of{ "name", "package", "path" }.packageis the package-manager filter name;pathis project-relative.executionMode: optional runner mode.turbois the default;package-localruns each workspace's package scripts from its own directory.errorLogFile: optional consolidated failure log path. Defaults totests_output_errors.log.testFilePattern: optional regex string for test files. Defaults to\\.(test|spec)\\.(ts|tsx|js|jsx)$.ignoreDirNames: optional directory names skipped while counting test files.maxFailureExcerptLines: optional maximum number of lines written per failed workspace.
E2E test fields:
playwrightPackage: consumer-installed Playwright package used for browser preflight.testDirectoryandtestFilePattern: Playwright spec discovery inputs.browser: installed Playwright browser required before the suite starts.playwright.config: JSON-compatibledefineConfigoptions. The CLI generates and removes the Playwright config file for each run;testDiris always the configuredtestDirectory.playwright.ciConfig: optional top-level Playwright option overrides whenCIis set.runner: command and argument array that runs Playwright; additionaltest-e2earguments are forwarded to it.servers: managed process definitions with command arguments, optional working directory/environment, exact readiness URL, and timeout in milliseconds.- The CLI starts all configured servers, waits for their readiness URLs, and always stops their process trees after Playwright exits.
Release gate fields:
stages: ordered stages. Each stage needsnameand eithercommand/args,package/script, orpackage/files.packageplusscriptrunspackageManager --filter <package> run <script>.packageplusfilesrunspackageManager --filter <package> exec vitest run <files...>.
Validation fields:
steps: ordered task steps.postSteps: optional ordered task steps run after the main validation steps.
JSDoc report fields:
includePaths: project-relative directories scanned by default.excludePatterns: regex strings skipped during scanning.reportFile: Markdown output path used with--write,--report, or an interactive confirmation.maxLineLength: maximum accepted JSDoc line length.JSDOC_MAX_LINE_LENGTHoverrides this at runtime.promptForReport: whentrue, interactive terminals are asked before writing the Markdown report.
Bundle audit fields:
appDirs: project-relative frontend app directories. Each app is expected to havedist/assets.top: number of largest assets printed by default.rawWarningBytes: raw byte threshold for warning markers.
Upgrade fields:
defaultCooldownDays: release-age cooldown used unless--no-cooldownor--days=Nis passed.protectedOverridesFile: project-relative YAML file with top-leveloverrides, usuallypnpm-workspace.yaml.protectedDependencyUpstreamHints: map of protected package names to upstream packages that should be reviewed before isolated upgrades.singletonGuardCommand: optional task step run after protected singleton upgrades.- Interactive terminals use arrow keys, Space, and Enter to select update types and cooldowns. The default is minor and patch updates; protected singleton upgrades default to
Yes. Choosing Major first shows its candidate table, then opens a separate package selector with nothing preselected, including fromAll. Cooldown-held packages are shown before their exception selector; protected packages declined by the user are never offered as exceptions. --types=major,minor,patchselects exact SemVer categories,--types=allselects every category, and--major/--latestremain compatibility aliases for all categories. With--yes, those major flags explicitly authorize unattended major updates. Unknown, duplicate value, and contradictory options fail instead of silently changing the selected policy.--dry-runrenders the preview without changing manifests, overrides, or lockfiles. Interactive dry runs also walk through cooldown exceptions and show their resulting preview before exiting;--yesremains unattended. No selector or apply confirmation appears when no update can be applied.- Upgrade previews and final reports group major, minor, and patch changes separately. Repeated package, change, and release values are shown once per consecutive workspace group. Final reports always include skipped updates and their reason, including after selecting cooldown exceptions.
Dev watch fields:
apps: map of app keys to{ "displayName", "port", "filter", "color" }.filteris required for watch mode.defaultApps: app keys used when--appsis omitted.backendApp: optional app key used by--include-backend.host: optional host used for port checks. Defaults to127.0.0.1.backendPortCleanupGraceMs: optional wait after killing a stale backend listener.
Dev grid fields:
layout.rows: ordered terminal rows from top to bottom.- each row requires
panes, ordered from left to right. Panes in the same row receive equal widths, and rows receive equal heights. - each pane requires
titleandcommand, and can optionally define:silentCommand: command used bywebtoolkit dev-grid --silent.fontSize: positive integer font size applied through a temporary Windows Terminal fragment profile.
fallbackScriptandsilentFallbackScript: package scripts used when Windows Terminal is unavailable.preflightCommand: optional task step run before opening the grid.layout.rowsis mandatory. The former flatpanes,maxPanels, and per-panefullWidthfields are not accepted.
Environment fields:
requiredNodeMajor: expected Node major version.corepackHome: project-relative Corepack home directory.
Common Config Patterns
Minimal project with only cleaner defaults:
{
"packageManager": "pnpm"
}Monorepo with apps and packages:
{
"packageManager": "pnpm",
"cleaner": {
"workspaceRootNames": ["apps", "packages"],
"protectedRootNames": ["apps", "packages", "scripts"]
}
}Project-specific generated files:
{
"cleaner": {
"levels": {
"deep": {
"removableSpecificFiles": ["src/generated/env.d.ts"]
},
"nuclear": {
"removableSpecificFiles": ["src/generated/env.d.ts"]
}
}
}
}Task that forwards extra arguments:
{
"tasks": {
"test": {
"title": "Project tests",
"steps": [
{
"label": "Vitest",
"command": "pnpm",
"args": ["exec", "vitest", "run"],
"appendArgs": true
}
]
}
}
}Then run:
webtoolkit test -- --filter authThe separator -- is optional but recommended when forwarding arguments through package scripts.
Repo check engine:
{
"repoCheck": {
"title": "Project quality checks",
"failFast": false,
"steps": [
{
"label": "TypeScript Guard",
"builtinGuard": "tsconfig"
},
{
"label": "Architecture Lint",
"builtinGuard": "dependency-cruiser",
"args": ["src", "--config", ".dependency-cruiser.cjs"]
}
]
}
}Workspace test engine:
{
"workspaceTests": {
"executionMode": "package-local",
"errorLogFile": "tests_output_errors.log",
"workspaces": [
{ "name": "Core", "package": "@acme/core", "path": "packages/core" },
{ "name": "Backend", "package": "@acme/backend", "path": "apps/backend" }
]
}
}For package-local, define package scripts inside each workspace:
{
"scripts": {
"test": "webtoolkit workspace-test test",
"test:coverage": "webtoolkit workspace-test test:coverage"
}
}Release gate engine:
{
"releaseGate": {
"stages": [
{ "name": "core-contracts", "package": "@acme/core", "script": "test:coverage" },
{
"name": "backend-critical",
"package": "@acme/backend",
"files": ["tests/integration/auth.spec.ts"]
}
]
}
}Architecture map engine:
{
"architectureMap": {
"includePaths": ["apps", "packages", "scripts"],
"outputDirectory": "docs/generated",
"dependencyCruiserConfig": ".webtoolkit-cli/dependency-cruiser.cjs",
"initialExpandedDepth": 1
}
}outputDirectory may be absolute or relative to the project. The command includes production code, tests, and scripts under includePaths, excludes dependencies and generated artifacts, and writes a self-contained YYYY-MM-DD_architecture-map.html. The HTML uses a graph-first interface with a collapsible hierarchy, aggregated import edges, search, pan/zoom, critical-path highlighting, and node details. Running it again on the same day replaces that day's map. initialExpandedDepth defaults to 1: 0 opens the repository, 1 also opens workspace roots, 2 also opens packages, and higher values open successive package descendants. dependencyCruiserConfig is optional; without it, dependency-cruiser runs with --no-config.
JSDoc, bundle audit, and upgrade engines:
{
"jsdocReport": {
"includePaths": ["apps/backend", "packages/core"],
"excludePatterns": ["node_modules", "dist", "\\.test\\.", "\\.spec\\."],
"reportFile": "temp_jsdocs_check.md",
"maxLineLength": 250,
"promptForReport": true
},
"bundleAudit": {
"appDirs": ["apps/frontend"],
"top": 20,
"rawWarningBytes": 1000000,
"budgets": [
{
"appDir": "apps/frontend",
"label": "main bundle",
"pattern": "^index-.*\\.js$",
"maxRawBytes": 500000,
"required": true
}
],
"entryBudgets": [
{
"appDir": "apps/frontend",
"label": "initial entrypoint",
"maxBrotliBytes": 150000
}
]
},
"upgrade": {
"defaultCooldownDays": 7,
"protectedOverridesFile": "pnpm-workspace.yaml",
"protectedDependencyUpstreamHints": {
"zod": ["@acme/shared-utils"]
},
"singletonGuardCommand": {
"label": "Singleton Guard",
"command": "pnpm",
"args": ["exec", "tsx", "scripts/guards/singleton-deps.ts"]
}
}
}entryBudgets reads each app's built dist/index.html, deduplicates the local
JavaScript and CSS referenced by scripts, stylesheets, and module preloads, and
enforces their aggregate Brotli size. External URLs are ignored. A missing
entrypoint or referenced local asset fails the audit.
Dev and environment engines:
{
"devWatch": {
"host": "127.0.0.1",
"backendApp": "backend",
"defaultApps": ["user"],
"apps": {
"backend": { "displayName": "Backend", "port": 3001 },
"user": {
"displayName": "Frontend User",
"filter": "@acme/frontend-user",
"port": 3002
}
}
},
"devGrid": {
"fallbackScript": "dev:concurrent",
"silentFallbackScript": "dev:concurrent:silent",
"preflightCommand": {
"label": "DEV port preflight",
"command": "webtoolkit",
"args": ["dev-watch", "--check-only", "--include-backend"]
},
"layout": {
"rows": [
{
"panes": [
{
"title": "FRONTEND USER",
"command": "pnpm run dev:frontend-user",
"silentCommand": "pnpm run dev:frontend-user:silent",
"fontSize": 15
}
]
},
{
"panes": [
{
"title": "BACKEND",
"command": "pnpm run dev:backend"
}
]
}
]
}
},
"environment": {
"requiredNodeMajor": 26,
"corepackHome": ".corepack"
}
}Command resolution:
When a native top-level config block exists, the matching command uses the CLI engine:
repoCheckforcheck;workspaceTestsfortest,test-coverage, andworkspace-test;releaseGateforrelease-gate;validateforvalidate;jsdocReportforjsdoc-report;bundleAuditforperformance-bundle-audit;upgradeforupgrade;devWatchfordev-watch;devGridfordev-grid;environmentforenv-bootstrapandenv-doctor.Without the native block, public task commands fall back to configured task names:
webtoolkit build->tasks.buildwebtoolkit test->tasks.testwebtoolkit test-coverage->tasks.testCoveragewebtoolkit release-gate->tasks.releaseGatewebtoolkit validate->tasks.validatewebtoolkit jsdoc-report->tasks.jsdocReportwebtoolkit upgrade->tasks.upgradewebtoolkit performance-bundle-audit->tasks.performanceBundleAuditwebtoolkit run:<name>->tasks.<name>
Avoiding Config Mistakes
- Use JSON arrays for
args; do not write a whole command line as one string. - Use project-relative paths in config. Absolute paths make the config machine-specific.
- Put generated-file cleanup in both
deepandnuclearif both levels should remove it. - Only override
removableDirNameswhen you want to replace the default artifact directory list. - Prefer
webtoolkit <task> --helpbefore running a newly configured task; it prints the resolved step list. - Always test cleanup with
--dry-runbefore running a destructive level.
