# `suaveplan-hash-password` bin entry _(no submodules)_ ## Purpose This file is the platform-runtime entry for the `suaveplan-hash-password` binary shipped by `@suaveplan/crypto-bin`. It is intentionally a minimal shim: it constructs an `HashPasswordCliEnv` adapter from `process.stdout` and `process.stderr`, then delegates to the testable `main()` function in `../hash-password/hash-password.ts`. All argument parsing, algorithm dispatch, and exit-code logic live in that pure core so they can be unit tested by direct invocation rather than by spawning a subprocess. The shim exists so the package can publish a Node-style `bin` entry under `./dist/bin/hash-password.js` (with the `#!/usr/bin/env node` shebang preserved by Vite) without coupling the testable core to `process.*` globals. Anything that touches `process.argv` / `process.exit` / `process.stdout` is confined to this module. ## Features - Forwards `process.argv.slice(2)` into `main()` and exits with the returned numeric code. - Wires `process.stdout.write` / `process.stderr.write` into the `HashPasswordCliEnv` adapter — the core never references `process` directly. - Auto-exec guard: only runs `main()` when invoked as the top-level module (`process.argv[1]` ends with `hash-password.js`). Importing this module from a test or another script does not trigger an exit. - Coverage-excluded by design — this module is exercised end-to-end via the bin install path; the logic it wraps is fully covered by `../hash-password/hash-password.test.ts`. - Shebang line emitted verbatim into the dist bundle so the file is directly executable once symlinked by `bun install` / `npm install`. ## Usage: Basic Example ```bash # Once installed, the bin is on PATH via the package.json `bin` map $ suaveplan-hash-password --password "correct horse battery staple" $argon2id$v=19$m=65536,t=3,p=1$$ $ echo $? 0 ``` ## Usage: Advanced Example ```bash # Pipe-friendly verify (exit 0 = match, 1 = mismatch, 3+ = error) $ STORED='$argon2id$v=19$m=65536,t=3,p=1$$' $ if suaveplan-hash-password --password "$PW" --verify "$STORED"; then > echo "login ok" > else > case $? in > 1) echo "wrong password" ;; > 3) echo "stored hash has unrecognised algorithm" ;; > 4) echo "stored hash is corrupt" ;; > *) echo "argument error" ;; > esac > fi ``` For programmatic invocation that does not spawn a process, import the testable core directly instead of this shim: ```ts import { main } from "@suaveplan/crypto-bin"; const code = main(["--password", "pw"], { write: (s) => process.stdout.write(s), writeError: (s) => process.stderr.write(s), }); ``` ## API Reference This module has no public exports — it is a side-effect entry point. Behaviour: - On import, registers the auto-exec guard and (if invoked as the top-level script) calls `main(argv, env)` and exits with its return value. - `argv`: `process.argv.slice(2)` — same shape `main()` accepts. - `env.write(s)`: forwards `s` to `process.stdout.write` synchronously. - `env.writeError(s)`: forwards `s` to `process.stderr.write` synchronously. For the contract of `main()` itself (exit codes, accepted flags, error classes) see `../hash-password/hash-password.md`. ## Implementation Notes The auto-exec guard checks `process.argv[1]?.endsWith("hash-password.js")` rather than `import.meta.url === ...` so the same module survives Vite's ES-module bundling without ESM-vs-CJS surprises in older Node hosts. The guard string matches the bundled filename (`hash-password.js`) deliberately — the source is `.ts` and is never executed directly in production. `/* istanbul ignore */` markers wrap the guard and the `process.exit` call because the test suite invokes `main()` directly with a captured env adapter (see `../hash-password/hash-password.test.ts`). Spawning a subprocess to cover this two-line wrapper would add filesystem and Node runtime coupling to the test suite without exercising any logic that is not already covered. The `vitest.config.ts` coverage `exclude` list documents this decision in a sibling comment so future readers do not mistake the exclusion for an oversight.