Development guide for the pharn-cli package. This is the full guide; the root CONTRIBUTING.md is the quick-start pointer.
cd pharn-cli
npm install| Script | Purpose |
|---|---|
npm run dev |
Run CLI via tsx, e.g. npm run dev -- init |
npm run build |
Compile src/ to dist/ |
npm run build:install-local |
Build and symlink pharn into the local test-app/node_modules (no-op if test-app/ is absent) |
npm run test |
Vitest (single run) |
npm run test:watch |
Vitest watch mode |
npm run test:coverage |
Coverage report |
npm run typecheck |
tsc for src and tests |
npm run lint |
ESLint on src/ |
npm run format |
Prettier write |
npm run format:check |
Prettier check (CI-friendly) |
From the test-app/ directory (which needs its own package.json) after build:install-local:
npx pharn initPublished package pharn-cli exposes both pharn and pharn-cli bins (see package.json).
CI (.github/workflows/ci.yml) runs these gates on every push and PR — all must pass:
npm run format:check
npm run lint
npm run lint:md # markdownlint-cli2 over docs/ and root *.md
npm run typecheck
npm run test:coverage # vitest with enforced coverage thresholdsnpm run check runs format:check + lint + typecheck + test as a single local pre-push command.
A separate CodeQL workflow analyzes the JavaScript/TypeScript surface on PRs, pushes to main, and weekly.
- Branch with a
feat/…,fix/…, ordocs/…prefix. - Commit in Conventional Commits style, one logical change per commit.
- Open an issue first for any non-trivial change — PHARN is small-surface on purpose.
pharn-cli/
src/
index.ts CLI entry, command routing
commands/ init, add, update
steps/ wizard steps (prereqs, fresh-check, mode-select, wizard-questions, module/stackpack/constitution select, vendor-consent, summary, install)
lib/ manifest, wizard, repo, installer, install-modules, pharn-config, validate, constants, banner, confirm, format
types.ts Manifest / ModuleManifest / WizardConfig / PharnConfig
tests/ vitest specs
docs/ user + maintainer documentation
scripts/install-local.mjs
See CLAUDE.md for the architecture in depth (the init step pipeline, dependency resolution, and the security-sensitive libs).
lib/validate.ts, lib/manifest.ts, and lib/install-modules.ts handle all remote input (manifest, module names, install/skill paths, wizard values). Preserve their invariants when editing:
- Strict regex allowlists (
MODULE_NAME_RE,VERSION_RE,INSTALL_PATH_RE,WIZARD_VALUE_RE),..rejection, and control-char rejection. - Every copy — modules and skills — is guarded by
safeJoinso nothing escapes its base directory. - Remote fetches use
redirect: 'error', an 8s timeout, and a 256KB body cap. - The manifest
schemaVersionmust be exactly1or2— anything else hard-fails by design so old CLIs don't guess at a new schema.
| Test file | Behavior covered |
|---|---|
manifest.test.ts / manifest-v2.test.ts |
v1 parse/validate of manifest + module.json, dependency resolution, exclusivity, categorization; parseManifest schemaVersion routing + wizard block validation |
wizard.test.ts |
matchCondition and the pure rule engine / answer resolver (lib/wizard.ts) |
wizard-questions.test.ts |
runWizardQuestions Custom-mode rendering (hide / relabel / coming-soon / warn rules) |
mode-select.test.ts |
Default vs Custom stack mode select |
vendor-consent.test.ts |
runVendorConsent consent recording |
install-modules.test.ts / install-skills.test.ts |
Copy installs maps, materialize memory-bank + constitution; selective installSkills; path-escape guards |
installer.test.ts / install.test.ts |
fetchAndInstall shared core; runInstall step |
init.test.ts / init-v2.test.ts |
v1 and v2 init pipelines end to end |
add.test.ts / update.test.ts |
runAdd (module + category:skill) and runUpdate re-resolution |
validate.test.ts |
assertSafeString allowlists, .. and control-char rejection |
pharn-config.test.ts |
Read/write/round-trip pharn.config.json, incl. v2 additive fields |
prereqs.test.ts |
Next.js and git checks |
fresh-check.test.ts |
Commit counts, custom file heuristic |
confirm.test.ts |
Cancel and warn helpers |
repo.test.ts / banner.test.ts / format.test.ts |
degit clone wrapper; banner; format helpers |
When changing behavior, add or update tests before docs.
Keep docs/ aligned with code when you change:
| Code change | Update docs |
|---|---|
| Install output or config shape | reference/pharn-config.md |
| Wizard steps or resolution | commands/init.md, getting-started.md |
| New validation or warning | troubleshooting.md |
| New command or behavior | commands/*.md, roadmap.md |
CLI --help text |
commands/init.md, README.md |
Do not document behavior that is not implemented without marking Coming soon or referencing roadmap.md.
PHARN_DEBUG=1 enables full error output for catalog fetch and install failures. Document new debug surfaces in troubleshooting.md.
By contributing, you agree your contributions are licensed under the repository's Apache 2.0 license.