Contributing
September 18, 2026 ยท View on GitHub
Thanks for helping improve jev-cli. Issues and pull requests are welcome.
Setup
git clone https://github.com/Nasrallah-AL/jev-cli
cd jev-cli
npm install
npm run check
Node.js 20.12 or newer. No API key is needed for npm run check.
Workflow
npm run dev -- <args>runs the CLI from source with tsx.npm run typecheck,npm run lint,npm testare what CI runs.npm run checkruns all three.npm run lint:fixapplies Biome formatting and safe fixes.npm run test:e2eruns live tests against the TypeSafe API and needsTYPESAFE_API_KEY.
Layout
src/
cli.ts commander program, global flags, error handling, exit codes
context.ts resolves config + output options + provider for a command
config.ts config file, env, and flag resolution (zod)
provider.ts TypeSafe / OpenRouter / Cloudflare transports -> AskFn
input.ts @file, stdin, JSON list/item parsing
output.ts tables, colors, JSON emit
lib.ts pure helpers shared by commands (ids, thresholds, ranking)
core/ one file per judgment; pure functions that take an AskFn
commands/ flag parsing and text rendering per command
test/
commands/<name>.test.ts one file per command: "<name>: core" (pure logic with a fake AskFn)
and "<name>: cli" (spawns dist/cli.js against the fake API)
cli-global.test.ts help, version, errors, credentials, models, config
lib/config/input/provider.test.ts shared modules
helpers/fake-api.ts local stand-in for api.typesafe.ai
helpers/fake-ask.ts in-process fake provider for core tests
helpers/cli.ts cliHarness(): spawn runner + hooks
e2e.test.ts live API, skipped without a key
Adding a command: src/core/<name>.ts (pure, takes AskFn), src/commands/<name>.ts (flags, rendering, and a
prepare<Name>Batch if it takes one text input), register it in src/cli.ts and BATCHABLE in
src/commands/batch.ts, export from src/index.ts, add test/commands/<name>.test.ts with both describes,
add docs/<name>.md, a row in the README command table, and a section in plugin/skills/jev/SKILL.md.
Keep question design (instructions and criteria) in src/core/. Keep policy (thresholds, exit codes) in code, not in prompts. Anything a script may depend on, such as JSON field names and exit codes, is a public contract: note changes in CHANGELOG.md.
Vendored code
src/vendor/compaction/ is fast-jev-compaction (MIT), lightly adapted (import paths only). It is excluded
from Biome formatting so diffs against upstream stay readable. The plugin needs its own copy at
plugin/hooks/compaction/ because a plugin folder cannot import from outside itself; npm run sync:hooks
refreshes it and npm run check fails on drift. npm run typecheck:hooks checks the hook against the Claude
Code function-hook type reference in plugin/hooks/types/.
Pull requests
- One change per PR, with tests. CLI-visible changes get a case in the command's
test/commands/<name>.test.ts. - Docs: each command has one page in
docs/<command>.mdwith the same sections (synopsis, when to use, options, output, example). Update it for new flags or output fields; keepREADME.mdto the command index and conventions. Add an entry underUnreleasedinCHANGELOG.md. - CI must pass: typecheck, lint, tests on Node 20 and 22.
Releasing
Maintainers: bump the version in package.json, move Unreleased notes to a new version heading in CHANGELOG.md, commit, then tag vX.Y.Z and push the tag. The release workflow publishes to npm via Trusted Publishing (GitHub OIDC, no stored token) with provenance, and creates a GitHub release from the CHANGELOG section.