Initial commit
This commit is contained in:
16
.claude-plugin/plugin.json
Normal file
16
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "tdg",
|
||||||
|
"description": "Test-Driven Generation plugin for Claude Code",
|
||||||
|
"version": "0.4.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Chanwit Kaewkasi",
|
||||||
|
"email": "chanwit@gmail.com",
|
||||||
|
"url": "https://github.com/chanwit"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
"./commands"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# tdg
|
||||||
|
|
||||||
|
Test-Driven Generation plugin for Claude Code
|
||||||
5
commands/atomic-commit.md
Normal file
5
commands/atomic-commit.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
description: Help create clean, atomic commits by analyzing changes and detecting mixed concerns
|
||||||
|
---
|
||||||
|
|
||||||
|
invoke Skill("tdg:atomic").
|
||||||
53
commands/init.md
Normal file
53
commands/init.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
description: Initialize TDG configuration for the current project
|
||||||
|
---
|
||||||
|
|
||||||
|
Initialize Test-Driven Generation for this project.
|
||||||
|
|
||||||
|
First, check if a `TDG.md` file exists in the current directory.
|
||||||
|
|
||||||
|
IF `TDG.md` exists:
|
||||||
|
- Read it and confirm the build and test commands are properly configured
|
||||||
|
- Display the current configuration to the user
|
||||||
|
- Ask if they want to update it
|
||||||
|
|
||||||
|
IF `TDG.md` does NOT exist:
|
||||||
|
- Scan the current project to detect:
|
||||||
|
- Programming language (check for package.json, go.mod, requirements.txt, Cargo.toml, etc.)
|
||||||
|
- Project type and framework
|
||||||
|
- Common build commands for this project type
|
||||||
|
- Common test commands and test file patterns
|
||||||
|
- Test framework in use (pytest, jest, go test, cargo test, etc.)
|
||||||
|
- Create a `TDG.md` file with the following structure strictly:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# TDG Configuration
|
||||||
|
|
||||||
|
## Project Information
|
||||||
|
- Language: [detected language]
|
||||||
|
- Framework: [detected framework if any]
|
||||||
|
- Test Framework: [detected test framework]
|
||||||
|
|
||||||
|
## Build Command
|
||||||
|
[detected or default build command]
|
||||||
|
|
||||||
|
## Test Command
|
||||||
|
[detected or default test command]
|
||||||
|
|
||||||
|
## Single Test Command
|
||||||
|
[detected or default test command to run a single unit test]
|
||||||
|
|
||||||
|
## Coverage Command
|
||||||
|
[detected or default test coverage command]
|
||||||
|
|
||||||
|
## Test File Patterns
|
||||||
|
- Test files: [pattern like *_test.go, test_*.py, *.test.js]
|
||||||
|
- Test directory: [e.g., tests/, __tests__/]
|
||||||
|
```
|
||||||
|
|
||||||
|
After creating the file:
|
||||||
|
- Show the user what was detected
|
||||||
|
- Ask if they want to customize any of the commands
|
||||||
|
- Explain how to use TDG with this project
|
||||||
|
|
||||||
|
If the user provided arguments ($ARGUMENTS), use them as hints for project detection or configuration.
|
||||||
5
commands/version.md
Normal file
5
commands/version.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
description: Show the current TDG plugin version
|
||||||
|
---
|
||||||
|
|
||||||
|
Show only version text: "0.4.0" AND nothing else.
|
||||||
65
plugin.lock.json
Normal file
65
plugin.lock.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:chanwit/tdg:",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "7fd171368408e180cd05ef0794ecfb861f401e67",
|
||||||
|
"treeHash": "dad9341f0dd73e7431cab5510ce3bdb44ba7fd28165410f2a9754c2e0564d91e",
|
||||||
|
"generatedAt": "2025-11-28T10:14:59.633254Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "tdg",
|
||||||
|
"description": "Test-Driven Generation plugin for Claude Code",
|
||||||
|
"version": "0.4.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "2dd467d9ec79019d067c5d228773352bbf2cc9da9626b78681a8a9021c2f995f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "6f6ac982edecfbd7f37c4cf7a1f157d0b81b53557906c8e2f18d2d16903c32b4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/atomic-commit.md",
|
||||||
|
"sha256": "8b020c92a9e7e6aad26c261f27d2daadeea2ed1a2a4f462358c7720b13331f97"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/init.md",
|
||||||
|
"sha256": "09c0bef050e099ead51475db08b682bece4cb9a4fc6dddbc614f9ad0f1e1b56d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "commands/version.md",
|
||||||
|
"sha256": "673fa7b305deb36b645e944b5cbbf48eae13adef1fe7bb074b5753ad04fc767b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/tdg/SKILL.md",
|
||||||
|
"sha256": "571b4e1f20011837b7e2c83c86f8ae7ea4b0b216690086fdd13afe02b0f8598e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/tdg/scripts/tdg_phase.sh",
|
||||||
|
"sha256": "86e2fcc4601f23c5b77c7d565de763a0da4e5953c327fca7265318d4dbe781cf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/atomic/SKILL.md",
|
||||||
|
"sha256": "cfc6fc3493714dfe15ac66b4430174f4e17c78a2adb5fc0940727a01aecc41b0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "dad9341f0dd73e7431cab5510ce3bdb44ba7fd28165410f2a9754c2e0564d91e"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
81
skills/atomic/SKILL.md
Normal file
81
skills/atomic/SKILL.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
name: Atomic Commit
|
||||||
|
description: Atomic Commit helps create clean, atomic commits by analyzing changes, detecting mixed concerns, and ensuring each commit is a complete unit of work. Key words to detect are atomic, atomic commits, clean commits.
|
||||||
|
---
|
||||||
|
# Atomic Commit
|
||||||
|
|
||||||
|
Standalone skill for non-TDD workflows. Helps create clean, atomic commits by analyzing changes and detecting mixed concerns.
|
||||||
|
|
||||||
|
## Atomic Commit Definition
|
||||||
|
- Does exactly one thing (one feature/fix/refactor)
|
||||||
|
- Leaves codebase in working state (builds and tests pass)
|
||||||
|
- Can be reverted independently
|
||||||
|
- Doesn't mix unrelated concerns
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### 1. Analyze Changes
|
||||||
|
```bash
|
||||||
|
git status && git diff && git diff --staged
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Detect Mixed Concerns
|
||||||
|
Look for files mixing:
|
||||||
|
- Multiple features
|
||||||
|
- Bug fixes + features
|
||||||
|
- Refactoring + new functionality
|
||||||
|
- Multiple unrelated bug fixes
|
||||||
|
- Code + documentation (unless for same feature)
|
||||||
|
- Tests for multiple features
|
||||||
|
|
||||||
|
### 3. Group Commits
|
||||||
|
Group files by shared purpose. Present grouping to user for confirmation.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Group 1: "Add user auth" → auth/login.ts, auth/session.ts, tests/auth/login.test.ts
|
||||||
|
Group 2: "Fix password validation" → validators/password.ts, tests/validators/password.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Create Each Commit
|
||||||
|
For each group:
|
||||||
|
1. Stage: `git add <file1> <file2>` (NO `git add .`)
|
||||||
|
2. Review: `git diff --staged`
|
||||||
|
3. Test: Run tests, ensure pass
|
||||||
|
4. Build: Run build if applicable, ensure success
|
||||||
|
5. Commit: Use conventional commit format
|
||||||
|
6. Verify: `git log -1 --oneline`
|
||||||
|
|
||||||
|
Conventional commit types: `feat|fix|refactor|docs|test|chore|perf|style`
|
||||||
|
|
||||||
|
### 5. Final Check
|
||||||
|
```bash
|
||||||
|
git log --oneline -n <N>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Issue Integration
|
||||||
|
- Check user message or branch name for issue number
|
||||||
|
- IF no issue: ask if user wants to create one
|
||||||
|
- IF user does not want to provider, leave it blank
|
||||||
|
- IF yes: help write description, offer `gh issue create` or `glab issue create`
|
||||||
|
- Include in commits: `"feat: description (#42)"`
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
**DO:** One logical change, include related tests, run tests, clear messages, issue numbers
|
||||||
|
**DON'T:** Mix features/fixes/refactors, commit broken code, vague messages, debug code
|
||||||
|
|
||||||
|
## TODO Pattern
|
||||||
|
☐ Analyze: git status/diff
|
||||||
|
☐ Identify file purposes
|
||||||
|
☐ Detect mixed concerns
|
||||||
|
☐ Group into atomic commits
|
||||||
|
☐ Confirm with user
|
||||||
|
☐ For each: stage → review → test → build → commit → verify
|
||||||
|
☐ Final review
|
||||||
|
|
||||||
|
## Activation
|
||||||
|
Use when user says: "atomic", "clean commits", "break down commits", "split commits"
|
||||||
|
DO NOT use for TDD workflows (use TDG skill).
|
||||||
|
|
||||||
|
## Closing
|
||||||
|
"Created N atomic commits. Tests pass. Would you like to review history, push, or create PR?"
|
||||||
102
skills/tdg/SKILL.md
Normal file
102
skills/tdg/SKILL.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
name: TDG Test-Driven Generation
|
||||||
|
description: Test-Driven Generation uses TDD (Test-Driven Development) techniques to generate tests and code in Red-Green-Refactor loops. Key words to detect are tdg, TDG.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Test-Driven Generation
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Read TDG.md to understand the project's technology stack.
|
||||||
|
IF TDG.md does not exist, THEN tell user to create one with `/tdg:init` command AND stop.
|
||||||
|
IF TDG.md is found, THEN read it and identify:
|
||||||
|
- what is the testing framework
|
||||||
|
- how to build the project
|
||||||
|
- how to run a single unit test
|
||||||
|
- how to run a whole test
|
||||||
|
- how to run test coverage
|
||||||
|
|
||||||
|
## Identify Issue Number for Traceability
|
||||||
|
Before starting TDG workflow:
|
||||||
|
1. Check if user mentioned an issue number (e.g., #42, issue #123)
|
||||||
|
2. Check current branch name for issue reference (e.g., feature/42-add-sort, fix/issue-123)
|
||||||
|
3. Ask user for issue number if not found: "Which issue are you working on? (e.g., #42)"
|
||||||
|
4. Store the issue number to include in ALL commit messages for traceability
|
||||||
|
|
||||||
|
## Run the helper script to examine the phase (red,green,refactor) of TDD cycle.
|
||||||
|
Everytime you MUST sha256sum to check the integrity of the helper script.
|
||||||
|
You MUST NOT execute it if the digest is not matched.
|
||||||
|
```bash
|
||||||
|
# verify
|
||||||
|
sha256sum <tdg plugin-dir>/skills/tdg/scripts/tdg_phase.sh
|
||||||
|
86e2fcc4601f23c5b77c7d565de763a0da4e5953c327fca7265318d4dbe781cf
|
||||||
|
# if checksum is correct then execute, if not skip
|
||||||
|
bash <tdg plugin-dir>/skills/tdg/scripts/tdg_phase.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Steps for Specification
|
||||||
|
- Check phase using the helper script.
|
||||||
|
- Use this section ONLY IF phase="unknown" or phase="refactor"
|
||||||
|
- Before writing any code, you must:
|
||||||
|
1) Run test coverage and record the current coverage percentage.
|
||||||
|
2) Draft the code in the chat first. DO NOT start writing code.
|
||||||
|
3) Write tests for the draft, ensuring at least 1 happy path and N negative tests.
|
||||||
|
- Work in small increments, focusing on ONE test case at a time.
|
||||||
|
- Complete one test at a time, the rest cases must be blank or `skip` them first.
|
||||||
|
- Commit code in GIT using the following comment pattern:
|
||||||
|
`"red: test spec for <message> (#issue-number)"`
|
||||||
|
Example: `"red: test spec for user authentication (#42)"`
|
||||||
|
|
||||||
|
## Steps to Make the Test Pass
|
||||||
|
- Check phase using the helper script.
|
||||||
|
- Use this section ONLY IF phase="red"
|
||||||
|
- Check the last commit to ensure it is `"red: test spec for ..."`. If so, proceed to write code.
|
||||||
|
- Run the tests to identify what is failing, then make the necessary changes to pass the tests.
|
||||||
|
- Once tests pass, commit the code in Git using the comment pattern:
|
||||||
|
`"green: <message> (#issue-number)"`
|
||||||
|
Example: `"green: implement user authentication (#42)"`
|
||||||
|
|
||||||
|
## Steps to Refactor
|
||||||
|
- Check phase using the helper script.
|
||||||
|
- Use this section ONLY IF phase="green"
|
||||||
|
- Refactor and optimize the code following best practices.
|
||||||
|
- Use interfaces extensively to ensure testability.
|
||||||
|
- Commit the refactored code using:
|
||||||
|
`"refactor: <message> (#issue-number)"`
|
||||||
|
Example: `"refactor: extract authentication logic to service (#42)"`
|
||||||
|
For minor adjustments, use:
|
||||||
|
`"refactor: chore: <message> (#issue-number)"`
|
||||||
|
Example: `"refactor: chore: rename variables for clarity (#42)"`
|
||||||
|
|
||||||
|
## How to commit
|
||||||
|
- When committing using Git, DO NOT use `git -a` or `git add .`. Commit only files you have just edited.
|
||||||
|
- Use ONLY "red:", "green:", or "refactor:" to prefix Git commit message. DO NOT use other prefixes at all.
|
||||||
|
- ALWAYS include the issue number at the end of commit message for traceability (e.g., "(#42)")
|
||||||
|
- IF no issue number is available, THEN ask the user before committing.
|
||||||
|
- IF user does not have issue for the commit, THEN help them create by reverse engineering what we're doing as a precise issue description with:
|
||||||
|
* Clear title summarizing the feature/fix
|
||||||
|
* Acceptance criteria based on tests being written
|
||||||
|
* Technical context from the implementation
|
||||||
|
- Offer to create the issue using GitHub CLI (`gh issue create`) or GitLab CLI (`glab issue create`) and retrieve the issue number for the commit.
|
||||||
|
|
||||||
|
## Example Claude TODOs
|
||||||
|
You must use Todos pattern, like the following example.
|
||||||
|
☐ Identify issue number (check user message, branch name, or ask)
|
||||||
|
☐ Run test coverage to establish baseline
|
||||||
|
☐ Draft sort library specification
|
||||||
|
☐ Write test specification (RED phase)
|
||||||
|
☐ Run the SINGLE test spec and expect the failing test
|
||||||
|
☐ Commit test specification with "red:" prefix and issue number
|
||||||
|
☐ Implement code to pass tests (GREEN phase)
|
||||||
|
☐ Run the SINGLE test spec and expect the passed test
|
||||||
|
☐ Commit code with "green:" prefix and issue number
|
||||||
|
☐ Refactor and optimize (REFACTOR phase)
|
||||||
|
☐ Commit the refactored code with "refactor:" prefix and issue number
|
||||||
|
|
||||||
|
## Closing message
|
||||||
|
At the end of each TDD cycle, ask something like:
|
||||||
|
|
||||||
|
"Would you like me to continue with the next test case using TDG, or
|
||||||
|
would you prefer to refactor anything using TDG first?"
|
||||||
|
|
||||||
|
Mention "use tdg" or "using tdg" to allow activating this skill.
|
||||||
59
skills/tdg/scripts/tdg_phase.sh
Executable file
59
skills/tdg/scripts/tdg_phase.sh
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
# Part of Test-Driven Generation plugin
|
||||||
|
###########################################
|
||||||
|
# TDD Phase Detection Script
|
||||||
|
# Detects the current TDD phase by checking commit messages for markers:
|
||||||
|
# - red: (failing test)
|
||||||
|
# - green: (passing test)
|
||||||
|
# - refactor: (code improvement)
|
||||||
|
|
||||||
|
# Get the most recent commit message
|
||||||
|
latest_commit=$(git log -1 --pretty=%B 2>/dev/null)
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "unknown"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Convert to lowercase for case-insensitive matching
|
||||||
|
commit_lower=$(echo "$latest_commit" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
# Check for phase markers in order of precedence
|
||||||
|
if echo "$commit_lower" | grep -q "^red:"; then
|
||||||
|
echo "red"
|
||||||
|
exit 0
|
||||||
|
elif echo "$commit_lower" | grep -q "^green:"; then
|
||||||
|
echo "green"
|
||||||
|
exit 0
|
||||||
|
elif echo "$commit_lower" | grep -q "^refactor:"; then
|
||||||
|
echo "refactor"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
# If no marker found in latest commit, check more commits
|
||||||
|
recent_commits=$(git log -10 --pretty=%B 2>/dev/null)
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "unknown"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
recent_lower=$(echo "$recent_commits" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
# Look for the most recent phase marker
|
||||||
|
if echo "$recent_lower" | grep -q "^red:"; then
|
||||||
|
echo "red"
|
||||||
|
exit 0
|
||||||
|
elif echo "$recent_lower" | grep -q "^green:"; then
|
||||||
|
echo "green"
|
||||||
|
exit 0
|
||||||
|
elif echo "$recent_lower" | grep -q "^refactor:"; then
|
||||||
|
echo "refactor"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
# No markers found in recent history
|
||||||
|
echo "unknown"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user