@nomad-e/bluma-cli 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/skills/git-commit/LICENSE.txt +18 -0
- package/dist/config/skills/git-commit/SKILL.md +258 -0
- package/dist/config/skills/git-commit/references/REFERENCE.md +249 -0
- package/dist/config/skills/git-commit/scripts/validate_commit_msg.py +163 -0
- package/dist/config/skills/git-pr/LICENSE.txt +18 -0
- package/dist/config/skills/git-pr/SKILL.md +293 -0
- package/dist/config/skills/git-pr/references/REFERENCE.md +256 -0
- package/dist/config/skills/git-pr/scripts/validate_commits.py +112 -0
- package/dist/config/skills/pdf/LICENSE.txt +26 -0
- package/dist/config/skills/pdf/SKILL.md +327 -0
- package/dist/config/skills/pdf/references/FORMS.md +69 -0
- package/dist/config/skills/pdf/references/REFERENCE.md +52 -0
- package/dist/config/skills/pdf/scripts/create_report.py +59 -0
- package/dist/config/skills/pdf/scripts/merge_pdfs.py +39 -0
- package/dist/config/skills/skill-creator/LICENSE.txt +26 -0
- package/dist/config/skills/skill-creator/SKILL.md +229 -0
- package/dist/config/skills/xlsx/LICENSE.txt +18 -0
- package/dist/config/skills/xlsx/SKILL.md +298 -0
- package/dist/config/skills/xlsx/references/REFERENCE.md +337 -0
- package/dist/config/skills/xlsx/scripts/office/__init__.py +2 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/pack.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/soffice.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/unpack.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/__pycache__/validate.cpython-312.pyc +0 -0
- package/dist/config/skills/xlsx/scripts/office/pack.py +58 -0
- package/dist/config/skills/xlsx/scripts/office/soffice.py +180 -0
- package/dist/config/skills/xlsx/scripts/office/unpack.py +63 -0
- package/dist/config/skills/xlsx/scripts/office/validate.py +122 -0
- package/dist/config/skills/xlsx/scripts/recalc.py +143 -0
- package/dist/main.js +201 -50
- package/package.json +1 -1
- package/dist/config/example.bluma-mcp.json.txt +0 -14
- package/dist/config/models_config.json +0 -78
- package/dist/skills/git-conventional/LICENSE.txt +0 -3
- package/dist/skills/git-conventional/SKILL.md +0 -83
- package/dist/skills/skill-creator/SKILL.md +0 -495
- package/dist/skills/testing/LICENSE.txt +0 -3
- package/dist/skills/testing/SKILL.md +0 -114
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
BluMa — Base Language Unit · Model Agent
|
|
2
|
+
Proprietary License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-2026 BluMa Contributors
|
|
5
|
+
|
|
6
|
+
This skill is part of the BluMa CLI distribution.
|
|
7
|
+
It is provided as a bundled native skill and may not be
|
|
8
|
+
redistributed, modified, or used outside of the BluMa agent
|
|
9
|
+
framework without prior written permission.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
12
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
13
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
14
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
15
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
16
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
17
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
18
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-commit
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill whenever the user asks to commit code, stage changes, write
|
|
5
|
+
a commit message, or finalize work. Triggers: "commit", "commit my changes",
|
|
6
|
+
"stage and commit", "save my work", "git commit", "write a commit message",
|
|
7
|
+
"commit this", "amend commit", or any request to record changes in Git
|
|
8
|
+
history. Do NOT use for pull requests — use git-pr instead.
|
|
9
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Git Commit — Professional Workflow
|
|
13
|
+
|
|
14
|
+
## Golden Rule
|
|
15
|
+
|
|
16
|
+
> Every commit tells a story. The subject says WHAT, the body says WHY,
|
|
17
|
+
> and the diff shows HOW. Never repeat the diff in the message.
|
|
18
|
+
|
|
19
|
+
## Step 1 — Inspect the Working Tree
|
|
20
|
+
|
|
21
|
+
Before committing anything, understand the current state:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git status --short
|
|
25
|
+
git diff --stat
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Identify which files belong to which logical change. If there are
|
|
29
|
+
unrelated changes, they MUST go into separate commits (see Atomic
|
|
30
|
+
Commits below).
|
|
31
|
+
|
|
32
|
+
## Step 2 — Stage with Intent
|
|
33
|
+
|
|
34
|
+
Stage only the files that belong to ONE logical change:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git add <file1> <file2>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `git add -A` only when ALL changes belong to the same logical unit.
|
|
41
|
+
|
|
42
|
+
Review what is staged:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git diff --staged
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Read the diff carefully. You need it to write an accurate message.
|
|
49
|
+
|
|
50
|
+
## Step 3 — Determine the Commit Type
|
|
51
|
+
|
|
52
|
+
| Prefix | Meaning |
|
|
53
|
+
|------------|--------------------------------------------------|
|
|
54
|
+
| `feat` | New feature or user-facing capability |
|
|
55
|
+
| `fix` | Bug fix |
|
|
56
|
+
| `refactor` | Code restructuring, no behavior change |
|
|
57
|
+
| `docs` | Documentation only |
|
|
58
|
+
| `test` | Adding or updating tests |
|
|
59
|
+
| `perf` | Performance improvement |
|
|
60
|
+
| `style` | Formatting, whitespace, linting (no logic) |
|
|
61
|
+
| `chore` | Build, CI, dependencies, tooling |
|
|
62
|
+
| `security` | Security fix or hardening |
|
|
63
|
+
| `revert` | Reverting a previous commit |
|
|
64
|
+
|
|
65
|
+
## Step 4 — Write the Commit Message
|
|
66
|
+
|
|
67
|
+
### Format
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
<type>(<scope>): <subject>
|
|
71
|
+
|
|
72
|
+
<body>
|
|
73
|
+
|
|
74
|
+
<footer>
|
|
75
|
+
|
|
76
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Subject Line Rules
|
|
80
|
+
|
|
81
|
+
- Imperative mood: "add", "fix", "remove" (not "added", "fixes", "removed")
|
|
82
|
+
- Lowercase first letter after the colon
|
|
83
|
+
- No period at the end
|
|
84
|
+
- Maximum 72 characters
|
|
85
|
+
- Include scope when the change targets a specific module
|
|
86
|
+
|
|
87
|
+
Good examples:
|
|
88
|
+
```
|
|
89
|
+
feat(auth): add JWT refresh token rotation
|
|
90
|
+
fix(parser): handle empty input without panic
|
|
91
|
+
refactor(db): extract connection pooling into module
|
|
92
|
+
docs(readme): add installation instructions for ARM64
|
|
93
|
+
chore(deps): bump openai SDK to v4.50.0
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Bad examples:
|
|
97
|
+
```
|
|
98
|
+
Updated stuff # vague, no type, no scope
|
|
99
|
+
fix: Fixed the bug in auth module. # past tense, period, scope missing
|
|
100
|
+
feat(auth): Add JWT refresh token rotation for users to be able to
|
|
101
|
+
refresh their tokens automatically # too long, wraps
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Body Rules
|
|
105
|
+
|
|
106
|
+
- Leave ONE blank line between subject and body
|
|
107
|
+
- Explain WHY the change was needed, not WHAT changed
|
|
108
|
+
- Wrap at 72 characters
|
|
109
|
+
- Use bullet points for multiple reasons or details
|
|
110
|
+
- Reference design decisions or trade-offs if relevant
|
|
111
|
+
|
|
112
|
+
### Footer Rules
|
|
113
|
+
|
|
114
|
+
- Reference issues: `Closes #123`, `Refs #456`, `Fixes #789`
|
|
115
|
+
- Note breaking changes: `BREAKING CHANGE: <description>`
|
|
116
|
+
- Co-authors: `Co-authored-by: Name <email>`
|
|
117
|
+
|
|
118
|
+
### Watermark (MANDATORY)
|
|
119
|
+
|
|
120
|
+
The last line of every commit message MUST be:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This provides auditability. No exceptions.
|
|
127
|
+
|
|
128
|
+
## Step 5 — Execute the Commit
|
|
129
|
+
|
|
130
|
+
Use heredoc for clean multi-line messages:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
git commit -m "$(cat <<'EOF'
|
|
134
|
+
feat(skills): add git-commit skill for professional workflows
|
|
135
|
+
|
|
136
|
+
Introduce a dedicated skill that guides the agent through
|
|
137
|
+
Conventional Commits with proper subject, body, and footer
|
|
138
|
+
formatting. Ensures every commit carries the BluMa watermark
|
|
139
|
+
trailer for auditability.
|
|
140
|
+
|
|
141
|
+
- Atomic commit principles enforced
|
|
142
|
+
- Subject line validation (72 chars, imperative mood)
|
|
143
|
+
- Mandatory BluMa watermark trailer
|
|
144
|
+
|
|
145
|
+
Closes #55
|
|
146
|
+
|
|
147
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
148
|
+
EOF
|
|
149
|
+
)"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
For simple single-line commits (rare, only for truly trivial changes):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
git commit -m "chore(deps): bump typescript to v5.5.0
|
|
156
|
+
|
|
157
|
+
Generated-by: BluMa — Base Language Unit · Model Agent"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Step 6 — Verify
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
git log -1 --format=fuller
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Confirm the message is well-formed and the watermark is present.
|
|
167
|
+
|
|
168
|
+
## Atomic Commits
|
|
169
|
+
|
|
170
|
+
Each commit MUST represent exactly ONE logical change:
|
|
171
|
+
|
|
172
|
+
| Scenario | Commits |
|
|
173
|
+
|----------|---------|
|
|
174
|
+
| Added a feature + updated docs | 2 commits: `feat(...)` + `docs(...)` |
|
|
175
|
+
| Fixed a bug + added a test for it | 1 commit: `fix(...)` (test is part of the fix) |
|
|
176
|
+
| Renamed a variable across 10 files | 1 commit: `refactor(...)` |
|
|
177
|
+
| Fixed 2 unrelated bugs | 2 commits: `fix(...)` + `fix(...)` |
|
|
178
|
+
| New feature + refactored old code to support it | 2 commits: `refactor(...)` first, then `feat(...)` |
|
|
179
|
+
|
|
180
|
+
When in doubt: if you can describe the commit with "X and Y", it should
|
|
181
|
+
probably be two commits.
|
|
182
|
+
|
|
183
|
+
## Handling Special Cases
|
|
184
|
+
|
|
185
|
+
### Amending the Last Commit
|
|
186
|
+
|
|
187
|
+
Only amend if the commit has NOT been pushed:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
git add <forgotten-file>
|
|
191
|
+
git commit --amend --no-edit
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
To change the message:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
git commit --amend -m "$(cat <<'EOF'
|
|
198
|
+
<corrected message>
|
|
199
|
+
|
|
200
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
201
|
+
EOF
|
|
202
|
+
)"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Empty Commits (for CI triggers)
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git commit --allow-empty -m "$(cat <<'EOF'
|
|
209
|
+
chore(ci): trigger pipeline rebuild
|
|
210
|
+
|
|
211
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
212
|
+
EOF
|
|
213
|
+
)"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Reverting a Commit
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
git revert <hash> --no-edit
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Then amend to add context and watermark:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
git commit --amend -m "$(cat <<'EOF'
|
|
226
|
+
revert(auth): undo token expiry change
|
|
227
|
+
|
|
228
|
+
Reverts commit <hash>. The 30-minute expiry caused session drops
|
|
229
|
+
for users on slow connections. Reverting until a proper sliding
|
|
230
|
+
window solution is implemented.
|
|
231
|
+
|
|
232
|
+
Refs #130
|
|
233
|
+
|
|
234
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
235
|
+
EOF
|
|
236
|
+
)"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Quality Checklist
|
|
240
|
+
|
|
241
|
+
Before finalizing any commit, verify:
|
|
242
|
+
|
|
243
|
+
1. Type prefix is correct for the change
|
|
244
|
+
2. Scope accurately reflects the affected module
|
|
245
|
+
3. Subject is imperative, lowercase, under 72 chars
|
|
246
|
+
4. Body explains WHY (not WHAT)
|
|
247
|
+
5. Footer references relevant issues
|
|
248
|
+
6. Watermark `Generated-by: BluMa` is the last line
|
|
249
|
+
7. Only related changes are included (atomic)
|
|
250
|
+
8. No secrets, credentials, or .env files are staged
|
|
251
|
+
|
|
252
|
+
## Available References
|
|
253
|
+
|
|
254
|
+
- REFERENCE.md: Advanced patterns (signed commits, co-authors, commit hooks, monorepo conventions, interactive rebase guidance)
|
|
255
|
+
|
|
256
|
+
## Available Scripts
|
|
257
|
+
|
|
258
|
+
- validate_commit_msg.py: Validates a commit message string against Conventional Commits rules and BluMa watermark presence
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Git Commit — Advanced Patterns Reference
|
|
2
|
+
|
|
3
|
+
## Signed Commits (GPG / SSH)
|
|
4
|
+
|
|
5
|
+
When the repository or organization requires signed commits:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git commit -S -m "$(cat <<'EOF'
|
|
9
|
+
feat(auth): add PKCE support for OAuth2
|
|
10
|
+
|
|
11
|
+
<body>
|
|
12
|
+
|
|
13
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
14
|
+
EOF
|
|
15
|
+
)"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Verify signature:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git log --show-signature -1
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Note: BluMa should NOT configure GPG keys. If signing fails, inform the
|
|
25
|
+
user that they need to set up `user.signingkey` in their git config.
|
|
26
|
+
|
|
27
|
+
## Co-authored Commits
|
|
28
|
+
|
|
29
|
+
When the commit includes contributions from multiple people, add
|
|
30
|
+
co-author trailers BEFORE the BluMa watermark:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
feat(ui): redesign settings page layout
|
|
34
|
+
|
|
35
|
+
Implement the new card-based layout for the settings page as
|
|
36
|
+
discussed in the design review.
|
|
37
|
+
|
|
38
|
+
Co-authored-by: Maria Silva <maria@example.com>
|
|
39
|
+
Co-authored-by: João Santos <joao@example.com>
|
|
40
|
+
|
|
41
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The BluMa watermark ALWAYS goes last.
|
|
45
|
+
|
|
46
|
+
## Monorepo Commit Conventions
|
|
47
|
+
|
|
48
|
+
In monorepos, the scope should reflect the package path:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
feat(packages/auth): add session management
|
|
52
|
+
fix(apps/web): correct routing for nested layouts
|
|
53
|
+
chore(packages/shared-types): export AuthConfig interface
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For changes that span multiple packages, use the most specific common
|
|
57
|
+
ancestor as scope:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
refactor(packages): standardize error handling across all packages
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If there is no common ancestor, use no scope and list affected packages
|
|
64
|
+
in the body:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
chore: update TypeScript to v5.5 across all packages
|
|
68
|
+
|
|
69
|
+
Affected packages:
|
|
70
|
+
- packages/auth
|
|
71
|
+
- packages/api
|
|
72
|
+
- apps/web
|
|
73
|
+
- apps/mobile
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Commit Message Templates by Type
|
|
77
|
+
|
|
78
|
+
### feat — New Feature
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
feat(<scope>): <what the feature does>
|
|
82
|
+
|
|
83
|
+
<Why this feature is needed. What problem it solves for users.
|
|
84
|
+
Mention any design decisions or alternatives considered.>
|
|
85
|
+
|
|
86
|
+
- <Implementation detail 1>
|
|
87
|
+
- <Implementation detail 2>
|
|
88
|
+
|
|
89
|
+
Closes #<issue>
|
|
90
|
+
|
|
91
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### fix — Bug Fix
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
fix(<scope>): <what was broken and how it's fixed>
|
|
98
|
+
|
|
99
|
+
<Root cause analysis. What was happening, why, and how this
|
|
100
|
+
commit prevents it from recurring.>
|
|
101
|
+
|
|
102
|
+
Steps to reproduce (before fix):
|
|
103
|
+
1. <step>
|
|
104
|
+
2. <step>
|
|
105
|
+
3. <observe bug>
|
|
106
|
+
|
|
107
|
+
Fixes #<issue>
|
|
108
|
+
|
|
109
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### refactor — Code Restructuring
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
refactor(<scope>): <what was restructured>
|
|
116
|
+
|
|
117
|
+
<Why the refactoring was necessary. What becomes easier or
|
|
118
|
+
cleaner as a result. Confirm no behavior change.>
|
|
119
|
+
|
|
120
|
+
No functional changes. All existing tests pass unchanged.
|
|
121
|
+
|
|
122
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### perf — Performance Improvement
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
perf(<scope>): <what was optimized>
|
|
129
|
+
|
|
130
|
+
<Before/after metrics if available. What bottleneck was
|
|
131
|
+
identified and how it was resolved.>
|
|
132
|
+
|
|
133
|
+
Benchmark results:
|
|
134
|
+
- Before: <metric>
|
|
135
|
+
- After: <metric>
|
|
136
|
+
- Improvement: <percentage>
|
|
137
|
+
|
|
138
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### security — Security Fix
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
security(<scope>): <what vulnerability was addressed>
|
|
145
|
+
|
|
146
|
+
<Nature of the vulnerability (without exposing exploit details).
|
|
147
|
+
Severity level and impact assessment.>
|
|
148
|
+
|
|
149
|
+
Severity: Critical / High / Medium / Low
|
|
150
|
+
CVE: <if applicable>
|
|
151
|
+
|
|
152
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Interactive Rebase Guidance
|
|
156
|
+
|
|
157
|
+
BluMa should NEVER run `git rebase -i` automatically (it requires
|
|
158
|
+
interactive input). Instead, suggest it to the user:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
I recommend squashing the last 3 commits before pushing.
|
|
162
|
+
You can run:
|
|
163
|
+
|
|
164
|
+
git rebase -i HEAD~3
|
|
165
|
+
|
|
166
|
+
In the editor, change "pick" to "squash" (or "s") for the
|
|
167
|
+
commits you want to combine. Keep the first one as "pick".
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### When to Suggest Squashing
|
|
171
|
+
|
|
172
|
+
- Multiple "WIP" or "fix typo" commits
|
|
173
|
+
- Commits that undo then redo the same change
|
|
174
|
+
- A series of small fixes that logically belong together
|
|
175
|
+
|
|
176
|
+
### When NOT to Suggest Squashing
|
|
177
|
+
|
|
178
|
+
- Each commit represents a distinct, meaningful change
|
|
179
|
+
- The commit history tells a useful story for reviewers
|
|
180
|
+
- Different commits touch completely different areas
|
|
181
|
+
|
|
182
|
+
## Commit Hooks Awareness
|
|
183
|
+
|
|
184
|
+
BluMa should be aware that repositories may have commit hooks:
|
|
185
|
+
|
|
186
|
+
- **pre-commit**: Runs linters, formatters, tests before commit
|
|
187
|
+
- **commit-msg**: Validates commit message format
|
|
188
|
+
- **prepare-commit-msg**: Prepopulates commit message
|
|
189
|
+
|
|
190
|
+
If a commit fails due to a hook:
|
|
191
|
+
|
|
192
|
+
1. Read the hook's error output carefully
|
|
193
|
+
2. Fix the issue (formatting, linting, etc.)
|
|
194
|
+
3. Stage the fixes
|
|
195
|
+
4. Create a NEW commit (do NOT use --no-verify)
|
|
196
|
+
|
|
197
|
+
BluMa should NEVER use `--no-verify` to bypass hooks unless the user
|
|
198
|
+
explicitly requests it.
|
|
199
|
+
|
|
200
|
+
## Handling Large Changesets
|
|
201
|
+
|
|
202
|
+
If the staged changes are too large for a single atomic commit:
|
|
203
|
+
|
|
204
|
+
1. Use `git add -p` guidance (suggest to the user, don't run interactively)
|
|
205
|
+
2. Break the work into logical stages
|
|
206
|
+
3. Commit each stage separately
|
|
207
|
+
|
|
208
|
+
Suggested approach for the user:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
The staged changes touch 3 different concerns. I recommend
|
|
212
|
+
splitting this into separate commits:
|
|
213
|
+
|
|
214
|
+
1. First, stage only the refactoring:
|
|
215
|
+
git add src/utils/helpers.ts src/utils/format.ts
|
|
216
|
+
git commit -m "refactor(utils): extract formatting helpers"
|
|
217
|
+
|
|
218
|
+
2. Then stage the new feature:
|
|
219
|
+
git add src/features/export.ts src/features/export.test.ts
|
|
220
|
+
git commit -m "feat(export): add CSV export for reports"
|
|
221
|
+
|
|
222
|
+
3. Finally, the documentation:
|
|
223
|
+
git add docs/export.md README.md
|
|
224
|
+
git commit -m "docs(export): add CSV export usage guide"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Branch-Aware Commit Messages
|
|
228
|
+
|
|
229
|
+
When committing on feature branches, the scope can optionally mirror
|
|
230
|
+
the branch topic:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
Branch: feature/user-onboarding
|
|
234
|
+
Commit: feat(onboarding): add email verification step
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
For hotfix branches, always include urgency context:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
Branch: hotfix/auth-crash
|
|
241
|
+
Commit: fix(auth): prevent null dereference on expired tokens
|
|
242
|
+
|
|
243
|
+
This is a production hotfix. The null check was missing when
|
|
244
|
+
the token cache returns undefined for expired entries.
|
|
245
|
+
|
|
246
|
+
Fixes #789
|
|
247
|
+
|
|
248
|
+
Generated-by: BluMa — Base Language Unit · Model Agent
|
|
249
|
+
```
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validate a commit message against Conventional Commits format
|
|
4
|
+
and BluMa watermark requirements.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python validate_commit_msg.py "<commit message>"
|
|
8
|
+
python validate_commit_msg.py --last
|
|
9
|
+
python validate_commit_msg.py --range main..HEAD
|
|
10
|
+
|
|
11
|
+
Exit codes:
|
|
12
|
+
0 Message is valid
|
|
13
|
+
1 Message has issues
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
import re
|
|
19
|
+
|
|
20
|
+
TYPES = {"feat", "fix", "refactor", "docs", "test", "perf", "style", "chore", "security", "revert"}
|
|
21
|
+
|
|
22
|
+
SUBJECT_RE = re.compile(
|
|
23
|
+
r'^(' + '|'.join(TYPES) + r')'
|
|
24
|
+
r'(\([a-zA-Z0-9_/.-]+\))?'
|
|
25
|
+
r'!?:\s'
|
|
26
|
+
r'.{1,68}$'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
WATERMARK = "Generated-by: BluMa"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate_message(msg: str) -> list[str]:
|
|
33
|
+
issues = []
|
|
34
|
+
lines = msg.strip().split('\n')
|
|
35
|
+
|
|
36
|
+
if not lines:
|
|
37
|
+
return ["Empty commit message"]
|
|
38
|
+
|
|
39
|
+
subject = lines[0].strip()
|
|
40
|
+
|
|
41
|
+
if not SUBJECT_RE.match(subject):
|
|
42
|
+
parts = subject.split(':', 1)
|
|
43
|
+
if not parts or parts[0].split('(')[0] not in TYPES:
|
|
44
|
+
issues.append(f"Invalid type prefix. Expected one of: {', '.join(sorted(TYPES))}")
|
|
45
|
+
elif len(subject) > 72:
|
|
46
|
+
issues.append(f"Subject too long ({len(subject)} chars, max 72)")
|
|
47
|
+
else:
|
|
48
|
+
issues.append(f"Subject format invalid: \"{subject}\"")
|
|
49
|
+
|
|
50
|
+
if subject and subject[-1] == '.':
|
|
51
|
+
issues.append("Subject should not end with a period")
|
|
52
|
+
|
|
53
|
+
if subject and subject.split(': ', 1)[-1][:1].isupper():
|
|
54
|
+
issues.append("Subject description should start with lowercase")
|
|
55
|
+
|
|
56
|
+
if len(lines) > 1 and lines[1].strip() != '':
|
|
57
|
+
issues.append("Missing blank line between subject and body")
|
|
58
|
+
|
|
59
|
+
if WATERMARK not in msg:
|
|
60
|
+
issues.append("Missing BluMa watermark trailer")
|
|
61
|
+
else:
|
|
62
|
+
last_non_empty = ''
|
|
63
|
+
for line in reversed(lines):
|
|
64
|
+
if line.strip():
|
|
65
|
+
last_non_empty = line.strip()
|
|
66
|
+
break
|
|
67
|
+
if not last_non_empty.startswith("Generated-by:"):
|
|
68
|
+
issues.append("BluMa watermark should be the last non-empty line")
|
|
69
|
+
|
|
70
|
+
return issues
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_last_commit_msg() -> str:
|
|
74
|
+
result = subprocess.run(
|
|
75
|
+
["git", "log", "-1", "--format=%B"],
|
|
76
|
+
capture_output=True, text=True
|
|
77
|
+
)
|
|
78
|
+
if result.returncode != 0:
|
|
79
|
+
print(f"Error: {result.stderr.strip()}")
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
return result.stdout.strip()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_commit_msgs(commit_range: str) -> list[tuple[str, str]]:
|
|
85
|
+
result = subprocess.run(
|
|
86
|
+
["git", "log", commit_range, "--format=%h|||%B---END---"],
|
|
87
|
+
capture_output=True, text=True
|
|
88
|
+
)
|
|
89
|
+
if result.returncode != 0:
|
|
90
|
+
print(f"Error: {result.stderr.strip()}")
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
|
|
93
|
+
commits = []
|
|
94
|
+
for block in result.stdout.split("---END---"):
|
|
95
|
+
block = block.strip()
|
|
96
|
+
if not block:
|
|
97
|
+
continue
|
|
98
|
+
parts = block.split("|||", 1)
|
|
99
|
+
if len(parts) == 2:
|
|
100
|
+
commits.append((parts[0].strip(), parts[1].strip()))
|
|
101
|
+
return commits
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def print_result(label: str, msg: str, issues: list[str]):
|
|
105
|
+
subject = msg.split('\n')[0][:60]
|
|
106
|
+
if issues:
|
|
107
|
+
print(f" FAIL [{label}] {subject}")
|
|
108
|
+
for issue in issues:
|
|
109
|
+
print(f" - {issue}")
|
|
110
|
+
else:
|
|
111
|
+
print(f" OK [{label}] {subject}")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def main():
|
|
115
|
+
if len(sys.argv) < 2:
|
|
116
|
+
print("Usage:")
|
|
117
|
+
print(' python validate_commit_msg.py "<message>"')
|
|
118
|
+
print(" python validate_commit_msg.py --last")
|
|
119
|
+
print(" python validate_commit_msg.py --range main..HEAD")
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
|
|
122
|
+
has_errors = False
|
|
123
|
+
|
|
124
|
+
if sys.argv[1] == "--last":
|
|
125
|
+
msg = get_last_commit_msg()
|
|
126
|
+
issues = validate_message(msg)
|
|
127
|
+
print("Validating last commit:\n")
|
|
128
|
+
print_result("HEAD", msg, issues)
|
|
129
|
+
has_errors = bool(issues)
|
|
130
|
+
|
|
131
|
+
elif sys.argv[1] == "--range":
|
|
132
|
+
if len(sys.argv) < 3:
|
|
133
|
+
print("Error: --range requires a commit range (e.g. main..HEAD)")
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
commits = get_commit_msgs(sys.argv[2])
|
|
136
|
+
if not commits:
|
|
137
|
+
print(f"No commits in range {sys.argv[2]}")
|
|
138
|
+
sys.exit(0)
|
|
139
|
+
print(f"Validating {len(commits)} commit(s) in {sys.argv[2]}:\n")
|
|
140
|
+
for h, msg in commits:
|
|
141
|
+
issues = validate_message(msg)
|
|
142
|
+
print_result(h, msg, issues)
|
|
143
|
+
if issues:
|
|
144
|
+
has_errors = True
|
|
145
|
+
|
|
146
|
+
else:
|
|
147
|
+
msg = sys.argv[1]
|
|
148
|
+
issues = validate_message(msg)
|
|
149
|
+
print("Validating message:\n")
|
|
150
|
+
print_result("input", msg, issues)
|
|
151
|
+
has_errors = bool(issues)
|
|
152
|
+
|
|
153
|
+
print()
|
|
154
|
+
if has_errors:
|
|
155
|
+
print("Some commits need attention.")
|
|
156
|
+
sys.exit(1)
|
|
157
|
+
else:
|
|
158
|
+
print("All messages are valid.")
|
|
159
|
+
sys.exit(0)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
BluMa — Base Language Unit · Model Agent
|
|
2
|
+
Proprietary License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024-2026 BluMa Contributors
|
|
5
|
+
|
|
6
|
+
This skill is part of the BluMa CLI distribution.
|
|
7
|
+
It is provided as a bundled native skill and may not be
|
|
8
|
+
redistributed, modified, or used outside of the BluMa agent
|
|
9
|
+
framework without prior written permission.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
12
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
13
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
14
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
15
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
16
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
17
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
18
|
+
OTHER DEALINGS IN THE SOFTWARE.
|