Skip to content

feat(vscode): add commit message generation command#11017

Open
ddddddIl wants to merge 2 commits intocontinuedev:mainfrom
ddddddIl:pr/commit-message
Open

feat(vscode): add commit message generation command#11017
ddddddIl wants to merge 2 commits intocontinuedev:mainfrom
ddddddIl:pr/commit-message

Conversation

@ddddddIl
Copy link

@ddddddIl ddddddIl commented Mar 4, 2026

Summary

  • Add a VSCode command to generate commit messages from staged changes.
  • Introduce a commitMessage model role and wire it through config selection + YAML loading.
  • Add commit-message context collection + exclusion utilities with comprehensive Vitest coverage.

Notes

  • This PR is based on main and contains 2 commits.

Continue Tasks: 🔄 7 running — View all


Summary by cubic

Adds a VS Code command to generate a Conventional Commit message from staged, unstaged, or selected changes, powered by a new commitMessage model role. It builds a rich git context and writes the message to the Git input box.

  • New Features

    • VS Code: "Generate Commit Message" (palette + Git SCM title) auto-selects the right repo, shows Source Control progress, supports staged/unstaged/selected files, handles binaries/untracked files, and writes to the commit input.
    • Commit message generation: assembles diffs, a change summary, branch, recent commits, and selected-file count; excludes lockfiles, common dependency artifacts, and security-sensitive files; supports custom promptTemplates.commitMessage and enforces different wording on regenerate; cleans code fences/quotes.
    • Config: adds commitMessage to modelsByRole and selectedModelByRole in loaders/GUI defaults/YAML schema; schema accepts promptTemplates.commitMessage; tests cover change collection, context building, exclusions, and generator behavior.
  • Migration

    • Set selectedModelByRole.commitMessage in your config or assign the commitMessage role to a model; optionally define promptTemplates.commitMessage for custom prompting.

Written for commit 3c41094. Summary will update on new commits.

@ddddddIl ddddddIl requested a review from a team as a code owner March 4, 2026 08:28
@ddddddIl ddddddIl requested review from RomneyDa and removed request for a team March 4, 2026 08:28
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 4, 2026
@github-actions
Copy link

github-actions bot commented Mar 4, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

5 issues found across 19 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="extensions/vscode/src/commitMessage/collectCommitMessageChanges.vitest.ts">

<violation number="1" location="extensions/vscode/src/commitMessage/collectCommitMessageChanges.vitest.ts:278">
P2: Tests codify incorrect handling of Git rename/copy and quoted path formats, causing missing diffs for renamed or space-containing files. The implementation's `parseStagedNameStatus()` extracts file paths from Git `--name-status` output by taking everything after the first tab, which for rename lines (`R100\told-path\tnew-path`) produces an invalid path containing a tab character. Similarly, porcelain output containing rename arrows (`old.ts -> new.ts`) and quoted paths (`"has space.ts"`) are not parsed/decoded. The tests explicitly assert this broken behavior, verifying that filePaths contain raw tab-joined strings, arrows, and quotes, resulting in "diff unavailable" messages when Git cannot find these invalid paths. This degrades commit message quality for renamed files and files with spaces.</violation>
</file>

<file name="extensions/vscode/src/commitMessage/commitMessageContext.vitest.ts">

<violation number="1" location="extensions/vscode/src/commitMessage/commitMessageContext.vitest.ts:63">
P2: The ordering assertion for sampleDiffs can produce false positives because it doesn't verify both entries exist before comparing indices.</violation>
</file>

<file name="extensions/vscode/src/commitMessage/collectCommitMessageChanges.ts">

<violation number="1" location="extensions/vscode/src/commitMessage/collectCommitMessageChanges.ts:60">
P1: Rename/copy entries from `git diff --name-status --cached` are parsed as single-path records, producing invalid file paths. For rename lines like `R100\told\tnew`, the parser stores `old\tnew` as the file path, which fails when later used in git diff commands.</violation>

<violation number="2" location="extensions/vscode/src/commitMessage/collectCommitMessageChanges.ts:90">
P1: Rename/copy entries from `git status --porcelain` are parsed as single-path records. For rename lines like `R  old -> new`, the parser stores `old -> new` as the file path, including the arrow notation, which is not a valid filesystem path.</violation>
</file>

<file name="extensions/vscode/src/commitMessage/commitMessageContext.ts">

<violation number="1" location="extensions/vscode/src/commitMessage/commitMessageContext.ts:32">
P2: Code-fence construction does not handle embedded triple-backticks in content, which can break markdown context boundaries when diffs or commit messages contain markdown code blocks.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

return [];
}

const filePath = line.substring(2).trim();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P1: Rename/copy entries from git status --porcelain are parsed as single-path records. For rename lines like R old -> new, the parser stores old -> new as the file path, including the arrow notation, which is not a valid filesystem path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/vscode/src/commitMessage/collectCommitMessageChanges.ts, line 90:

<comment>Rename/copy entries from `git status --porcelain` are parsed as single-path records. For rename lines like `R  old -> new`, the parser stores `old -> new` as the file path, including the arrow notation, which is not a valid filesystem path.</comment>

<file context>
@@ -0,0 +1,526 @@
+      return [];
+    }
+
+    const filePath = line.substring(2).trim();
+    if (!filePath) {
+      return [];
</file context>
Fix with Cubic

}

const status = line.slice(0, tabIndex).trim();
const filePath = line.slice(tabIndex + 1).trim();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P1: Rename/copy entries from git diff --name-status --cached are parsed as single-path records, producing invalid file paths. For rename lines like R100\told\tnew, the parser stores old\tnew as the file path, which fails when later used in git diff commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/vscode/src/commitMessage/collectCommitMessageChanges.ts, line 60:

<comment>Rename/copy entries from `git diff --name-status --cached` are parsed as single-path records, producing invalid file paths. For rename lines like `R100\told\tnew`, the parser stores `old\tnew` as the file path, which fails when later used in git diff commands.</comment>

<file context>
@@ -0,0 +1,526 @@
+    }
+
+    const status = line.slice(0, tabIndex).trim();
+    const filePath = line.slice(tabIndex + 1).trim();
+
+    if (!status || !filePath) {
</file context>
Fix with Cubic


expect(result.mode).toBe("staged");
expect(result.changes).toHaveLength(1);
expect(result.changes[0].filePath).toBe(rawPath);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P2: Tests codify incorrect handling of Git rename/copy and quoted path formats, causing missing diffs for renamed or space-containing files. The implementation's parseStagedNameStatus() extracts file paths from Git --name-status output by taking everything after the first tab, which for rename lines (R100\told-path\tnew-path) produces an invalid path containing a tab character. Similarly, porcelain output containing rename arrows (old.ts -> new.ts) and quoted paths ("has space.ts") are not parsed/decoded. The tests explicitly assert this broken behavior, verifying that filePaths contain raw tab-joined strings, arrows, and quotes, resulting in "diff unavailable" messages when Git cannot find these invalid paths. This degrades commit message quality for renamed files and files with spaces.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/vscode/src/commitMessage/collectCommitMessageChanges.vitest.ts, line 278:

<comment>Tests codify incorrect handling of Git rename/copy and quoted path formats, causing missing diffs for renamed or space-containing files. The implementation's `parseStagedNameStatus()` extracts file paths from Git `--name-status` output by taking everything after the first tab, which for rename lines (`R100\told-path\tnew-path`) produces an invalid path containing a tab character. Similarly, porcelain output containing rename arrows (`old.ts -> new.ts`) and quoted paths (`"has space.ts"`) are not parsed/decoded. The tests explicitly assert this broken behavior, verifying that filePaths contain raw tab-joined strings, arrows, and quotes, resulting in "diff unavailable" messages when Git cannot find these invalid paths. This degrades commit message quality for renamed files and files with spaces.</comment>

<file context>
@@ -0,0 +1,506 @@
+
+    expect(result.mode).toBe("staged");
+    expect(result.changes).toHaveLength(1);
+    expect(result.changes[0].filePath).toBe(rawPath);
+    expect(result.changes[0].absPath).toBe(rawAbsPath);
+    expect(result.diffs[0]).toContain(`File ${rawAbsPath} - diff unavailable`);
</file context>
Fix with Cubic

Comment on lines +63 to +65
expect(diffSection.indexOf(sampleDiffs[0].trim())).toBeLessThan(
diffSection.indexOf(sampleDiffs[1].trim()),
);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P2: The ordering assertion for sampleDiffs can produce false positives because it doesn't verify both entries exist before comparing indices.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/vscode/src/commitMessage/commitMessageContext.vitest.ts, line 63:

<comment>The ordering assertion for sampleDiffs can produce false positives because it doesn't verify both entries exist before comparing indices.</comment>

<file context>
@@ -0,0 +1,121 @@
+
+    const diffSection = context.slice(diffIndex, summaryIndex);
+    expect(diffSection).toContain("```diff");
+    expect(diffSection.indexOf(sampleDiffs[0].trim())).toBeLessThan(
+      diffSection.indexOf(sampleDiffs[1].trim()),
+    );
</file context>
Suggested change
expect(diffSection.indexOf(sampleDiffs[0].trim())).toBeLessThan(
diffSection.indexOf(sampleDiffs[1].trim()),
);
expect(diffSection).toContain(sampleDiffs[0].trim());
expect(diffSection).toContain(sampleDiffs[1].trim());
expect(diffSection.indexOf(sampleDiffs[0].trim())).toBeLessThan(
diffSection.indexOf(sampleDiffs[1].trim()),
);
Fix with Cubic

return MODE_LABELS[mode] ?? MODE_LABELS.selected;
}

function createFencedBlock(body: string, language?: string): string {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P2: Code-fence construction does not handle embedded triple-backticks in content, which can break markdown context boundaries when diffs or commit messages contain markdown code blocks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/vscode/src/commitMessage/commitMessageContext.ts, line 32:

<comment>Code-fence construction does not handle embedded triple-backticks in content, which can break markdown context boundaries when diffs or commit messages contain markdown code blocks.</comment>

<file context>
@@ -0,0 +1,168 @@
+  return MODE_LABELS[mode] ?? MODE_LABELS.selected;
+}
+
+function createFencedBlock(body: string, language?: string): string {
+  const payload = body ? `${body}\n` : "";
+  const fence = language ? "```" + language : "```";
</file context>
Fix with Cubic

@ddddddIl
Copy link
Author

ddddddIl commented Mar 4, 2026

I have read the CLA Document and I hereby sign the CLA

@ddddddIl ddddddIl force-pushed the pr/commit-message branch from da68d37 to 3c41094 Compare March 4, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant