Skip to content

Add markpost --version / -v to print the installed CLI version - #154

Open
grimicorn-agent wants to merge 4 commits into
mainfrom
agent/cli-version-flag
Open

Add markpost --version / -v to print the installed CLI version#154
grimicorn-agent wants to merge 4 commits into
mainfrom
agent/cli-version-flag

Conversation

@grimicorn-agent

Copy link
Copy Markdown
Collaborator

What changed

Wires a top-level version flag into src/index.ts's dispatch so a globally-installed user can confirm which @markpost/cli version they're running:

  • markpost --version, markpost -v, and markpost version (added for symmetry with help/--help/-h — see HELP_COMMANDS) all print the installed version and exit 0.
  • Checked in the command position only, before the help check — a per-command sub-argument that happens to collide (e.g. markpost push -v) still reaches its handler untouched.
  • Extra arguments after the version token (e.g. markpost --version sync) are rejected with Unexpected arguments: ... + a usage line, exit 1 — a stray extra word is a usage mistake, not a request to version and run something else, mirroring the sync command's own unexpected-argument guard.
  • Reads packageJson.version via the same import ... from '../package.json' with { type: 'json' } pattern src/libs/config.ts already uses (this PR imports it directly in src/index.ts rather than routing through config.ts, since config.ts doesn't currently export it).
  • HELP_TEXT and the README's command table now mention --version/-v so the flag is discoverable.

Implementation decisions

  • Import path verified against the real build, not just typecheck. An independent reviewer round flagged (repeatedly, across all 3 rounds) that import ... from '../package.json' should fail TypeScript's rootDir/resolveJsonModule checks under tsconfig.json's "module": "NodeNext" + "rootDir": "./src". I verified directly: npm run build (tsc && tsc-alias), npx tsc -p tsconfig.json --listFiles, and running the emitted dist/index.js (node dist/index.js --version0.1.0) all succeed with zero errors. This matches the pre-existing, working precedent in src/libs/config.ts. I did not apply the reviewer's suggested createRequire rewrite since there is no actual reproducible failure — happy to revisit if CI proves otherwise.
  • Declined to add a package.json engines floor for Node 20.10+ (import-attribute syntax) — that's a pre-existing condition of the codebase's with { type: 'json' } usage in config.ts, not something this change introduces, and this PR was asked to avoid touching package.json (another open PR is mid-flight on it).

Testing

  • tests/index.test.ts: new cases for all three version tokens (happy path incl. semver-shape assertion, sub-argument pass-through, extra-argument rejection for each token).
  • Full suite: 845/845 passing. npm run typecheck, npm run build, npm run lint all clean.

Where to see it

  • src/index.ts (dispatch, runVersionCommand, VERSION_COMMANDS/VERSION_USAGE)
  • tests/index.test.ts
  • README.md command table

Closes #150

Wires a top-level version flag (--version, -v, and version for symmetry
with the existing help path) so a globally-installed user can confirm
which @markpost/cli version they're running. Reads the version the same
way libs/config.ts already imports package.json. Extra arguments after
the version token are rejected (fail loud), mirroring the sync command's
own unexpected-argument guard.

Closes #150
@grimicorn-agent

Copy link
Copy Markdown
Collaborator Author

Independent code review trail (3 rounds, opus)

Round 1

  • Flagged: HELP_TEXT/README don't mention --version; bare version word rejected as unknown command (asymmetric with help); sync sub-argument boundary untested; version-print assertion too loose (would pass even if extra output leaked).
  • Done: added --version mention to HELP_TEXT and the README table; added version to VERSION_COMMANDS; added a sync-sub-argument test (markpost sync --version still fails loud); tightened the assertion to toHaveBeenCalledTimes(1).
  • Skipped: none.
  • Also flagged (theoretical, TS rootDir/resolveJsonModule compile failure for import ... from '../package.json') — investigated below.

Round 2

  • Flagged: extra arguments after --version (e.g. markpost --version sync) silently printed the version and exited 0 instead of failing loud like sync's own guard; the version-string assertion was tautological (compares against the same package.json read the implementation uses, so it can't catch a blanked/malformed version field); -v colliding with the common "verbose" convention; bare version shadowing a hypothetical future COMMANDS entry.
  • Done: added a runVersionCommand guard that rejects extra arguments (fail loud, exit 1) and a semver-shape stringMatching assertion alongside the exact-value one.
  • Skipped: -v removal — the issue itself asks for -v explicitly, so keeping it is in scope, not a defect. Bare-version shadowing — same precedence tradeoff HELP_COMMANDS/help already makes in this file; noted in a comment, no code change since nothing currently collides.
  • Repeated (unchanged): the rootDir/resolveJsonModule compile claim.

Round 3

  • Flagged: the extra-argument rejection printed no usage hint (inconsistent with runSyncCommand, which prints SYNC_USAGE after its error); the extra-argument test only covered the --version token, not -v/version; a Node engines floor for with { type: 'json' } syntax; the rootDir claim again.
  • Done: added a VERSION_USAGE line printed alongside the error; converted the extra-argument test to it.each covering all three tokens.
  • Skipped: engines floor — pre-existing condition of config.ts's identical with { type: 'json' } usage, not introduced by this change, and this task was explicitly scoped away from touching package.json (another PR is mid-flight on it).

Unresolved / investigated and not applied: all three rounds flagged that import packageJson from '../package.json' with { type: 'json' } in src/index.ts should fail TypeScript's rootDir check (tsconfig.json: "module": "NodeNext", "rootDir": "./src") with TS6059, and that the resulting build would be broken. I verified this concretely rather than taking it on faith:

  • npm run build (tsc && tsc-alias) — exit 0, no diagnostics.
  • npx tsc -p tsconfig.json --listFilespackage.json is included in the program and compiles clean.
  • node dist/index.js --version / -v / version — all print 0.1.0 correctly from the real emitted output.
  • This mirrors the pre-existing, already-working import packageJson from './../../package.json' with { type: 'json' } in src/libs/config.ts.

Given the reproducible, passing build/typecheck/runtime evidence against a theoretical claim repeated without new evidence across all 3 rounds, I did not apply the suggested createRequire-based rewrite. Flagging here for a human to double-check if CI disagrees.

@grimicorn grimicorn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix conflicts and pull in main for the CI fix

@grimicorn-agent

Copy link
Copy Markdown
Collaborator Author

Merge + independent code review trail

Merged origin/main into this branch. One real conflict, in README.md (the commands table): resolved by taking main's reformatted/padded table (it also added detail to the sources row) and adding this PR's --version row into it. All other conflicting-looking files (package.json, package-lock.json, src/commands/sources.ts, tests/commands/sources.test.ts, tests/package.test.ts) auto-merged cleanly — they were main-only additions with no overlapping edits from this branch.

After the merge: npm run lint, npm run build (tsc + tsc-alias), and npm run test:ci (858 tests, later 860) all green.

Round 1

  • Finding: console.log(packageJson.version) prints the literal string undefined and exits 0 if the manifest's version field is ever blank — violates fail-loud. Fixed: added a guard that fails loud (stderr + exit 1) instead.
  • Finding: markpost help version fell through to the full HELP_TEXT instead of VERSION_USAGE, contradicting the line HELP_TEXT itself prints about markpost --version. Fixed: printHelp now special-cases VERSION_COMMANDS topics.
  • Finding (skipped): claimed the static import packageJson from '../package.json' with { type: 'json' } violates tsconfig.json's rootDir: "./src" and breaks the dist bin layout. Verified empirically instead of taking on faith: npx tsc --noEmit exits 0, npm run build produces dist/index.js with the import intact, and node dist/index.js --version prints the correct version directly. tests/package.test.ts (from main) also runs a real npm pack --dry-run against the built output and passed. Not reproducible in this repo's actual config — false positive.
  • Finding (skipped): Node engines/import-attributes compatibility concern. This repo has no stated minimum Node version either way; out of scope for a conflict-resolution PR, and the CI runner + local repro both execute this import fine.

Round 2

  • Finding: --version sub-argument spellings partially documented — considered, but VERSION_USAGE matches the existing minimalist pattern (HELP_TEXT's own footer line omits -h too). Skipped as consistent with an existing convention, not a new inconsistency.
  • Finding: version command not listed in the Commands: block of HELP_TEXT. Skipped — same treatment help itself already gets (trailing prose, not a COMMANDS entry); not a new inconsistency introduced by this PR.
  • Repeated the round-1 rootDir/dist-layout claim — re-verified with the same empirical checks, still not reproducible.

Round 3

  • Finding: runVersionCommand bypassed the centralized per-command --help/-h handling in dispatch because it returns early before that check runs, so markpost version --help fell into the unexpected-arguments guard instead of printing usage like every other command's --help. Fixed: added the same HELP_FLAG_ARGS check inside runVersionCommand.
  • Finding (skipped): the new help-flag check uses args.some(...) rather than an exact args.length === 1 match, so e.g. --version sync --help would print usage instead of failing loud. This mirrors the existing commandArgs.some((arg) => HELP_FLAG_ARGS.has(arg)) check already used for every other command in dispatch (line ~269) — tightening only the version path would blend two conflicting help-handling behaviors in the same file. Left consistent with the established pattern; out of scope for this PR to redesign help-arg handling CLI-wide.
  • Repeated the !packageJson.version "dead code" claim (true in a narrow TS-literal-type sense for the current committed file, but the value is genuinely read from disk at runtime, not inlined) and the rootDir claim once more — no new evidence, left as-is per the round-1/2 verification.

3 rounds run per policy; stopping here. Re-requesting @grimicorn's review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add markpost --version / -v to print the installed CLI version

2 participants