Skip to content

fix: make -c/--context, -y/--yes, and --fgm flags actually work#549

Open
SOV710 wants to merge 7 commits intodi-sukharev:masterfrom
SOV710:fix-cli-flags
Open

fix: make -c/--context, -y/--yes, and --fgm flags actually work#549
SOV710 wants to merge 7 commits intodi-sukharev:masterfrom
SOV710:fix-cli-flags

Conversation

@SOV710
Copy link
Copy Markdown

@SOV710 SOV710 commented Apr 5, 2026

Summary

This PR fixes three CLI flags that were silently broken or no-ops in the current oco release: -c/--context, -y/--yes, and --fgm. None of them caused a visible error — they just silently did the wrong thing, so users got plain conventional-commit output without ever realizing their flags were dropped (or, in the -c case, got a cryptic git commit hang/failure).

Each bug is fixed in its own atomic commit so the history is bisectable.

What was broken & why

1. -c/--context — completely non-functional

extraArgs = process.argv.slice(2) contained the raw ['-c', 'my context'] tokens, which commit() then forwarded verbatim to the internal git commit -m "…" -c "my context" call. git interprets its own -c as "reuse commit message from <commit>" and fails/hangs looking for a commit named "my context". (Primary, visible bug.)

But -c had two additional latent bugs that would have broken it even after the extraArgs fix:

  • Large-diff chunking path (getCommitMsgsPromisesFromFileDiffsgetMessagesPromisesByChangesInFilegenerateCommitMessageChatCompletionPrompt) threaded fullGitMojiSpec but never context, so -c silently disappeared for any diff large enough to trigger chunking.
  • Regenerate path — when the user answers "No" and regenerates, the recursive call forwarded only diff, extraArgs, and fullGitMojiSpec, dropping both context and skipCommitConfirmation. So -c (and -y) worked on attempt 1 and were lost on attempt 2+.

2. -y/--yes and --fgm — same extraArgs leak as -c

These also leaked into the git commit invocation. Less destructive than -c (they're not git flags with meaning), but still noise that could interact with repo hooks or aliases.

3. --fgm — no-op even after extraArgs fix

getCommitConvention gated the entire GitMoji branch on config.OCO_EMOJI:

config.OCO_EMOJI ? (fullGitMojiSpec ? FULL_GITMOJI_SPEC : GITMOJI_HELP)
                 : CONVENTIONAL_COMMIT_KEYWORDS

Since OCO_EMOJI defaults to false, --fgm was silently ignored unless the user had previously run oco config set OCO_EMOJI true. CLI flags should override config, not be subordinate to it. Restructured so --fgm forces FULL_GITMOJI_SPEC unconditionally.

Commits (in bisect order)

# Commit What
1 fix(cli): strip -c/--context from extraArgs to prevent git commit conflict Add stripOcoFlags with -c/--context handling; feed raw argv to cleye but stripped argv to git commit.
2 fix(cli): strip -y/--fgm from extraArgs to prevent git commit conflict Extend the stripper to -y/--yes/--fgm.
3 fix(commit): preserve context and skip-confirm flag across regenerate Forward context + skipCommitConfirmation through the recursive regenerate call.
4 fix(generate): forward context through chunked large-diff prompt path Thread context through getCommitMsgsPromisesFromFileDiffs / getMessagesPromisesByChangesInFile / generateCommitMessageChatCompletionPrompt.
5 fix(prompts): make --fgm override OCO_EMOJI config Restructure getCommitConvention so --fgm wins over OCO_EMOJI.
6 refactor(prompts): null-safe, trim-aware user context handling Harden userInputCodeContext against whitespace-only and null/undefined input; inline the INIT_MAIN_PROMPT IIFE for clarity. Behavior unchanged.
7 build Recompile out/cli.cjs.

Behavior matrix — --fgm × OCO_EMOJI

--fgm OCO_EMOJI Convention used Change
absent false (default) CONVENTIONAL_COMMIT_KEYWORDS unchanged
absent true GITMOJI_HELP unchanged
present false FULL_GITMOJI_SPEC fixed (was no-op)
present true FULL_GITMOJI_SPEC unchanged

Test plan

  • pnpm run build — clean
  • pnpm test — all 36 existing unit tests pass
  • oco -c "add retry logic" on a small diff → context appears in generated message, no git commit hang
  • oco -c "…" on a large diff that triggers chunking → context still appears in each sub-prompt
  • Generate → answer "No" → regenerate → context still honored on the second attempt
  • oco --fgm with default config (OCO_EMOJI=false) → message prefixed with an emoji from the 81-item full spec (e.g. 🎨, ⚡️)
  • oco (no flags) with OCO_EMOJI=false → plain conventional commit, unchanged
  • oco (no flags) with OCO_EMOJI=true → 10-item GITMOJI_HELP subset, unchanged
  • oco -y --fgm -c "…" → all three flags honored, none leak into git commit

SOV710 added 7 commits April 5, 2026 03:58
…flict

cleye's ignoreArgv passes unconsumed flags and arguments through to
the internal `git commit` execa call. Although -c/--context is
defined as a known cleye flag, a defensive guard is needed to strip
it from extraArgs in case it leaks through, which would conflict
with git's own handling.

Add a sanitization step at the entry of commit() that filters -c,
--context, and their values from extraArgs before they are forwarded
to the git commit invocation.
Same class of bug as the -c/--context fix: these flags could leak
into extraArgs and be forwarded to the internal `git commit` call,
causing unexpected behavior.

Extend the extraArgs sanitization to also strip -y, --yes, --fgm,
and their values.
When the user answers "No" at the confirmation prompt and chooses to
regenerate, the recursive call to generateCommitMessageFromGitDiff
forwarded only `diff`, `extraArgs`, and `fullGitMojiSpec`. Both
`context` and `skipCommitConfirmation` were silently dropped, so:

- `-c/--context` was honored only on the first attempt and lost on
  every regeneration;
- `-y/--yes` was honored only on the first attempt, forcing a manual
  confirmation after regeneration.

Forward both fields through the recursive call so the user's flags
are respected for the full lifetime of the commit() invocation.
When a staged diff exceeds MAX_REQUEST_TOKENS, generateCommitMessageByDiff
routes through getCommitMsgsPromisesFromFileDiffs →
getMessagesPromisesByChangesInFile → generateCommitMessageChatCompletionPrompt
to produce one sub-prompt per chunk. That entire chain was threading
`fullGitMojiSpec` but never `context`, so `-c/--context` was silently
dropped for any diff large enough to trigger chunking, even though
the simple (non-chunked) path forwarded it correctly.

Add a `context` parameter to each of the three helpers and thread it
through to generateCommitMessageChatCompletionPrompt so the user's
context is present in every sub-prompt.
getCommitConvention gated the entire GitMoji branch on
config.OCO_EMOJI, so --fgm was silently ignored unless the user had
previously run `oco config set OCO_EMOJI true`. Since OCO_EMOJI
defaults to false, --fgm was a no-op for most users.

This violates the standard CLI convention that command-line flags
should override configuration. Restructure getCommitConvention so
that --fgm forces FULL_GITMOJI_SPEC regardless of OCO_EMOJI:

  --fgm=true                    → FULL_GITMOJI_SPEC
  --fgm=false + OCO_EMOJI=true  → GITMOJI_HELP (unchanged)
  --fgm=false + OCO_EMOJI=false → CONVENTIONAL_COMMIT_KEYWORDS (unchanged)

No other files need changes — the fgm flag was already threaded
correctly through cli.ts → commit.ts → generateCommitMessageByDiff
→ getMainCommitPrompt → getCommitConvention.
The previous userInputCodeContext only skipped the context block
when context was exactly '' or ' '. Anything else (e.g. a string of
whitespace, null, undefined) would inject an empty or
whitespace-only <context>…</context> tag into the system prompt.

Trim the input and guard against null/undefined:
  - accept string | undefined | null
  - normalize via `(context ?? '').trim()`
  - skip the injection whenever the trimmed value is empty

Also inline the INIT_MAIN_PROMPT IIFE into a normal function body
and introduce a `content` local, removing a layer of nesting that
obscured the prompt assembly. Behavior is unchanged.
@SOV710
Copy link
Copy Markdown
Author

SOV710 commented Apr 5, 2026

Hi @di-sukharev, could you please take a look when you have time? Thanks!

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.

1 participant