@wbern/claude-instructions 1.9.0 → 1.10.0
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/LICENSE +21 -0
- package/README.md +20 -14
- package/bin/cli.js +215 -47
- package/downloads/with-beads/busycommit.md +16 -0
- package/downloads/with-beads/code-review.md +248 -0
- package/downloads/with-beads/commands-metadata.json +14 -0
- package/downloads/with-beads/commit.md +16 -0
- package/downloads/with-beads/gap.md +1 -0
- package/downloads/with-beads/plan.md +1 -2
- package/downloads/without-beads/busycommit.md +16 -0
- package/downloads/without-beads/code-review.md +246 -0
- package/downloads/without-beads/commands-metadata.json +14 -0
- package/downloads/without-beads/commit.md +16 -0
- package/downloads/without-beads/gap.md +1 -0
- package/package.json +4 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 wbern
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@ TDD workflow commands for Claude Code CLI.
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
npx @wbern/claude-instructions
|
|
24
|
+
|
|
25
|
+
// or
|
|
26
|
+
|
|
27
|
+
pnpm dlx @wbern/claude-instructions
|
|
24
28
|
```
|
|
25
29
|
|
|
26
30
|
The interactive installer lets you choose:
|
|
@@ -57,13 +61,14 @@ This ensures commands are regenerated whenever anyone runs `npm install`, `pnpm
|
|
|
57
61
|
|
|
58
62
|
| Option | Description |
|
|
59
63
|
|--------|-------------|
|
|
60
|
-
| `--variant=with-beads` |
|
|
61
|
-
| `--
|
|
62
|
-
| `--
|
|
63
|
-
| `--scope=user` | Install to `~/.claude/commands` (global) |
|
|
64
|
-
| `--prefix=my-` | Add prefix to command names (e.g., `my-commit.md`) |
|
|
65
|
-
| `--skip-template-injection` | Don't inject CLAUDE.md template content |
|
|
64
|
+
| `--variant=with-beads` | Command variant (with-beads, without-beads) |
|
|
65
|
+
| `--scope=project` | Installation scope (project, user) |
|
|
66
|
+
| `--prefix=my-` | Add prefix to command names |
|
|
66
67
|
| `--commands=commit,red,green` | Install only specific commands |
|
|
68
|
+
| `--skip-template-injection` | Skip injecting project CLAUDE.md customizations |
|
|
69
|
+
| `--update-existing` | Only update already-installed commands |
|
|
70
|
+
| `--overwrite` | Overwrite conflicting files without prompting |
|
|
71
|
+
| `--skip-on-conflict` | Skip conflicting files without prompting |
|
|
67
72
|
|
|
68
73
|
## Customizing Commands
|
|
69
74
|
|
|
@@ -190,14 +195,6 @@ flowchart TB
|
|
|
190
195
|
- `/issue` - Analyze GitHub issue and create TDD implementation plan
|
|
191
196
|
- `/plan` - Create implementation plan from feature/requirement with PRD-style discovery and TDD acceptance criteria
|
|
192
197
|
|
|
193
|
-
### Workflow
|
|
194
|
-
|
|
195
|
-
- `/commit` - Create a git commit following project standards
|
|
196
|
-
- `/busycommit` - Create multiple atomic git commits, one logical change at a time
|
|
197
|
-
- `/pr` - Creates a pull request using GitHub MCP
|
|
198
|
-
- `/summarize` - Summarize conversation progress and next steps
|
|
199
|
-
- `/gap` - Analyze conversation context for unaddressed items and gaps
|
|
200
|
-
|
|
201
198
|
### Test-Driven Development
|
|
202
199
|
|
|
203
200
|
- `/spike` - Execute TDD Spike Phase - exploratory coding to understand problem space before TDD
|
|
@@ -207,6 +204,15 @@ flowchart TB
|
|
|
207
204
|
- `/refactor` - Execute TDD Refactor Phase - improve code structure while keeping tests green
|
|
208
205
|
- `/cycle` - Execute complete TDD cycle - Red, Green, and Refactor phases in sequence
|
|
209
206
|
|
|
207
|
+
### Workflow
|
|
208
|
+
|
|
209
|
+
- `/commit` - Create a git commit following project standards
|
|
210
|
+
- `/busycommit` - Create multiple atomic git commits, one logical change at a time
|
|
211
|
+
- `/pr` - Creates a pull request using GitHub MCP
|
|
212
|
+
- `/summarize` - Summarize conversation progress and next steps
|
|
213
|
+
- `/gap` - Analyze conversation context for unaddressed items and gaps
|
|
214
|
+
- `/code-review` - Code review using dynamic category detection and domain-specific analysis
|
|
215
|
+
|
|
210
216
|
### Ship / Show / Ask
|
|
211
217
|
|
|
212
218
|
- `/ship` - Ship code directly to main - for small, obvious changes that don't need review
|
package/bin/cli.js
CHANGED
|
@@ -119,6 +119,7 @@ init_esm_shims();
|
|
|
119
119
|
import {
|
|
120
120
|
select,
|
|
121
121
|
text,
|
|
122
|
+
multiselect,
|
|
122
123
|
groupMultiselect,
|
|
123
124
|
isCancel,
|
|
124
125
|
intro,
|
|
@@ -496,7 +497,7 @@ var CATEGORY_ORDER = [
|
|
|
496
497
|
"Utilities",
|
|
497
498
|
"Ship / Show / Ask"
|
|
498
499
|
];
|
|
499
|
-
async function
|
|
500
|
+
async function loadCommandsMetadata(variant) {
|
|
500
501
|
const sourcePath = path2.join(
|
|
501
502
|
__dirname2,
|
|
502
503
|
"..",
|
|
@@ -505,7 +506,10 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
505
506
|
);
|
|
506
507
|
const metadataPath = path2.join(sourcePath, "commands-metadata.json");
|
|
507
508
|
const metadataContent = await fs.readFile(metadataPath, "utf-8");
|
|
508
|
-
|
|
509
|
+
return JSON.parse(metadataContent);
|
|
510
|
+
}
|
|
511
|
+
async function getCommandsGroupedByCategory(variant) {
|
|
512
|
+
const metadata = await loadCommandsMetadata(variant);
|
|
509
513
|
const grouped = {};
|
|
510
514
|
for (const [filename, data] of Object.entries(metadata)) {
|
|
511
515
|
const category = data.category;
|
|
@@ -519,6 +523,11 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
519
523
|
selectedByDefault: data.selectedByDefault !== false
|
|
520
524
|
});
|
|
521
525
|
}
|
|
526
|
+
for (const category of Object.keys(grouped)) {
|
|
527
|
+
if (!CATEGORY_ORDER.includes(category)) {
|
|
528
|
+
throw new Error(`Unknown category: ${category}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
522
531
|
for (const category of Object.keys(grouped)) {
|
|
523
532
|
grouped[category].sort((a, b) => {
|
|
524
533
|
const orderA = metadata[a.value].order;
|
|
@@ -527,12 +536,7 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
527
536
|
});
|
|
528
537
|
}
|
|
529
538
|
const sortedCategories = Object.keys(grouped).sort((a, b) => {
|
|
530
|
-
|
|
531
|
-
const indexB = CATEGORY_ORDER.indexOf(b);
|
|
532
|
-
if (indexA !== -1 && indexB !== -1) return indexA - indexB;
|
|
533
|
-
if (indexA !== -1) return -1;
|
|
534
|
-
if (indexB !== -1) return 1;
|
|
535
|
-
return a.localeCompare(b);
|
|
539
|
+
return CATEGORY_ORDER.indexOf(a) - CATEGORY_ORDER.indexOf(b);
|
|
536
540
|
});
|
|
537
541
|
const sortedGrouped = {};
|
|
538
542
|
for (const category of sortedCategories) {
|
|
@@ -540,6 +544,25 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
540
544
|
}
|
|
541
545
|
return sortedGrouped;
|
|
542
546
|
}
|
|
547
|
+
function extractLabelFromTool(tool) {
|
|
548
|
+
const match = tool.match(/^Bash\(([^:]+):/);
|
|
549
|
+
return match ? match[1] : tool;
|
|
550
|
+
}
|
|
551
|
+
async function getRequestedToolsOptions(variant) {
|
|
552
|
+
const metadata = await loadCommandsMetadata(variant);
|
|
553
|
+
const allTools = /* @__PURE__ */ new Set();
|
|
554
|
+
for (const data of Object.values(metadata)) {
|
|
555
|
+
if (data["_requested-tools"]) {
|
|
556
|
+
for (const tool of data["_requested-tools"]) {
|
|
557
|
+
allTools.add(tool);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return Array.from(allTools).map((tool) => ({
|
|
562
|
+
value: tool,
|
|
563
|
+
label: extractLabelFromTool(tool)
|
|
564
|
+
}));
|
|
565
|
+
}
|
|
543
566
|
function getDestinationPath(outputPath, scope) {
|
|
544
567
|
if (outputPath) {
|
|
545
568
|
return outputPath;
|
|
@@ -596,6 +619,20 @@ async function generateToDirectory(outputPath, variant, scope, options) {
|
|
|
596
619
|
} else {
|
|
597
620
|
await fs.copy(sourcePath, destinationPath, {});
|
|
598
621
|
}
|
|
622
|
+
if (options?.allowedTools && options.allowedTools.length > 0) {
|
|
623
|
+
for (const file of files) {
|
|
624
|
+
const filePath = path2.join(destinationPath, file);
|
|
625
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
626
|
+
const allowedToolsYaml = `allowed-tools: ${options.allowedTools.join(", ")}`;
|
|
627
|
+
const modifiedContent = content.replace(
|
|
628
|
+
/^---\n/,
|
|
629
|
+
`---
|
|
630
|
+
${allowedToolsYaml}
|
|
631
|
+
`
|
|
632
|
+
);
|
|
633
|
+
await fs.writeFile(filePath, modifiedContent);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
599
636
|
if (options?.commandPrefix) {
|
|
600
637
|
for (const file of files) {
|
|
601
638
|
const oldPath = path2.join(destinationPath, file);
|
|
@@ -770,11 +807,26 @@ async function main(args) {
|
|
|
770
807
|
let scope;
|
|
771
808
|
let commandPrefix;
|
|
772
809
|
let selectedCommands;
|
|
810
|
+
let selectedAllowedTools;
|
|
811
|
+
let cachedExistingFiles;
|
|
773
812
|
if (args?.variant && args?.scope && args?.prefix !== void 0) {
|
|
774
813
|
variant = args.variant;
|
|
775
814
|
scope = args.scope;
|
|
776
815
|
commandPrefix = args.prefix;
|
|
777
816
|
selectedCommands = args.commands;
|
|
817
|
+
if (args.updateExisting) {
|
|
818
|
+
cachedExistingFiles = await checkExistingFiles(
|
|
819
|
+
void 0,
|
|
820
|
+
variant,
|
|
821
|
+
scope,
|
|
822
|
+
{ commandPrefix: commandPrefix || "" }
|
|
823
|
+
);
|
|
824
|
+
selectedCommands = cachedExistingFiles.map((f) => f.filename);
|
|
825
|
+
if (selectedCommands.length === 0) {
|
|
826
|
+
log.warn("No existing commands found in target directory");
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
778
830
|
} else {
|
|
779
831
|
variant = await select({
|
|
780
832
|
message: "Select variant",
|
|
@@ -799,9 +851,34 @@ async function main(args) {
|
|
|
799
851
|
if (isCancel(commandPrefix)) {
|
|
800
852
|
return;
|
|
801
853
|
}
|
|
802
|
-
|
|
854
|
+
let groupedCommands = await getCommandsGroupedByCategory(
|
|
803
855
|
variant
|
|
804
856
|
);
|
|
857
|
+
if (args?.updateExisting) {
|
|
858
|
+
cachedExistingFiles = await checkExistingFiles(
|
|
859
|
+
void 0,
|
|
860
|
+
variant,
|
|
861
|
+
scope,
|
|
862
|
+
{ commandPrefix: commandPrefix || "" }
|
|
863
|
+
);
|
|
864
|
+
const existingFilenames = new Set(
|
|
865
|
+
cachedExistingFiles.map((f) => f.filename)
|
|
866
|
+
);
|
|
867
|
+
const filteredGrouped = {};
|
|
868
|
+
for (const [category, commands] of Object.entries(groupedCommands)) {
|
|
869
|
+
const filtered = commands.filter(
|
|
870
|
+
(cmd) => existingFilenames.has(cmd.value)
|
|
871
|
+
);
|
|
872
|
+
if (filtered.length > 0) {
|
|
873
|
+
filteredGrouped[category] = filtered;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
groupedCommands = filteredGrouped;
|
|
877
|
+
if (Object.keys(groupedCommands).length === 0) {
|
|
878
|
+
log.warn("No existing commands found in target directory");
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
805
882
|
const enabledCommandValues = Object.values(groupedCommands).flat().filter((cmd) => cmd.selectedByDefault).map((cmd) => cmd.value);
|
|
806
883
|
selectedCommands = await groupMultiselect({
|
|
807
884
|
message: "Select commands to install (Enter to accept all)",
|
|
@@ -811,32 +888,47 @@ async function main(args) {
|
|
|
811
888
|
if (isCancel(selectedCommands)) {
|
|
812
889
|
return;
|
|
813
890
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
891
|
+
const requestedToolsOptions = await getRequestedToolsOptions(
|
|
892
|
+
variant
|
|
893
|
+
);
|
|
894
|
+
if (requestedToolsOptions.length > 0) {
|
|
895
|
+
selectedAllowedTools = await multiselect({
|
|
896
|
+
message: "Select allowed tools for commands (optional)",
|
|
897
|
+
options: requestedToolsOptions
|
|
898
|
+
});
|
|
899
|
+
if (isCancel(selectedAllowedTools)) {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
822
902
|
}
|
|
823
|
-
|
|
903
|
+
}
|
|
904
|
+
const existingFiles = cachedExistingFiles ?? await checkExistingFiles(void 0, variant, scope, {
|
|
905
|
+
commandPrefix,
|
|
906
|
+
commands: selectedCommands
|
|
907
|
+
});
|
|
824
908
|
const skipFiles = [];
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
909
|
+
if (!args?.overwrite && !args?.skipOnConflict) {
|
|
910
|
+
for (const file of existingFiles) {
|
|
911
|
+
if (file.isIdentical) {
|
|
912
|
+
log.info(`${file.filename} is identical, skipping`);
|
|
913
|
+
skipFiles.push(file.filename);
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const stats = getDiffStats(file.existingContent, file.newContent);
|
|
917
|
+
const diff = formatCompactDiff(file.existingContent, file.newContent);
|
|
918
|
+
note(diff, `Diff: ${file.filename}`);
|
|
919
|
+
log.info(`+${stats.added} -${stats.removed}`);
|
|
920
|
+
const shouldOverwrite = await confirm({
|
|
921
|
+
message: `Overwrite ${file.filename}?`
|
|
922
|
+
});
|
|
923
|
+
if (!shouldOverwrite) {
|
|
924
|
+
skipFiles.push(file.filename);
|
|
925
|
+
}
|
|
830
926
|
}
|
|
831
|
-
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
message: `Overwrite ${file.filename}?`
|
|
837
|
-
});
|
|
838
|
-
if (!shouldOverwrite) {
|
|
839
|
-
skipFiles.push(file.filename);
|
|
927
|
+
} else if (args?.skipOnConflict) {
|
|
928
|
+
for (const file of existingFiles) {
|
|
929
|
+
if (!file.isIdentical) {
|
|
930
|
+
skipFiles.push(file.filename);
|
|
931
|
+
}
|
|
840
932
|
}
|
|
841
933
|
}
|
|
842
934
|
const result = await generateToDirectory(
|
|
@@ -847,7 +939,8 @@ async function main(args) {
|
|
|
847
939
|
commandPrefix,
|
|
848
940
|
skipTemplateInjection: args?.skipTemplateInjection,
|
|
849
941
|
commands: selectedCommands,
|
|
850
|
-
skipFiles
|
|
942
|
+
skipFiles,
|
|
943
|
+
allowedTools: selectedAllowedTools
|
|
851
944
|
}
|
|
852
945
|
);
|
|
853
946
|
const fullPath = scope === "project" ? `${process.cwd()}/.claude/commands` : `${os2.homedir()}/.claude/commands`;
|
|
@@ -860,36 +953,111 @@ Happy TDD'ing!`
|
|
|
860
953
|
);
|
|
861
954
|
}
|
|
862
955
|
|
|
863
|
-
// scripts/
|
|
864
|
-
|
|
865
|
-
var
|
|
866
|
-
|
|
867
|
-
|
|
956
|
+
// scripts/cli-options.ts
|
|
957
|
+
init_esm_shims();
|
|
958
|
+
var CLI_OPTIONS = [
|
|
959
|
+
{
|
|
960
|
+
flag: "--variant",
|
|
961
|
+
key: "variant",
|
|
962
|
+
type: "string",
|
|
963
|
+
description: "Command variant (with-beads, without-beads)",
|
|
964
|
+
example: "--variant=with-beads"
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
flag: "--scope",
|
|
968
|
+
key: "scope",
|
|
969
|
+
type: "string",
|
|
970
|
+
description: "Installation scope (project, user)",
|
|
971
|
+
example: "--scope=project"
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
flag: "--prefix",
|
|
975
|
+
key: "prefix",
|
|
976
|
+
type: "string",
|
|
977
|
+
description: "Add prefix to command names",
|
|
978
|
+
example: "--prefix=my-"
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
flag: "--commands",
|
|
982
|
+
key: "commands",
|
|
983
|
+
type: "array",
|
|
984
|
+
description: "Install only specific commands",
|
|
985
|
+
example: "--commands=commit,red,green"
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
flag: "--skip-template-injection",
|
|
989
|
+
key: "skipTemplateInjection",
|
|
990
|
+
type: "boolean",
|
|
991
|
+
description: "Skip injecting project CLAUDE.md customizations"
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
flag: "--update-existing",
|
|
995
|
+
key: "updateExisting",
|
|
996
|
+
type: "boolean",
|
|
997
|
+
description: "Only update already-installed commands"
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
flag: "--overwrite",
|
|
1001
|
+
key: "overwrite",
|
|
1002
|
+
type: "boolean",
|
|
1003
|
+
description: "Overwrite conflicting files without prompting"
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
flag: "--skip-on-conflict",
|
|
1007
|
+
key: "skipOnConflict",
|
|
1008
|
+
type: "boolean",
|
|
1009
|
+
description: "Skip conflicting files without prompting"
|
|
1010
|
+
}
|
|
868
1011
|
];
|
|
1012
|
+
function generateHelpText() {
|
|
1013
|
+
const lines = [
|
|
1014
|
+
"Usage: npx @wbern/claude-instructions [options]",
|
|
1015
|
+
"",
|
|
1016
|
+
"Options:"
|
|
1017
|
+
];
|
|
1018
|
+
for (const opt of CLI_OPTIONS) {
|
|
1019
|
+
const suffix = opt.type === "string" ? "=<value>" : opt.type === "array" ? "=<list>" : "";
|
|
1020
|
+
const padding = 28 - (opt.flag.length + suffix.length);
|
|
1021
|
+
lines.push(
|
|
1022
|
+
` ${opt.flag}${suffix}${" ".repeat(Math.max(1, padding))}${opt.description}`
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
lines.push(" --help, -h Show this help message");
|
|
1026
|
+
return lines.join("\n");
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// scripts/bin.ts
|
|
869
1030
|
function parseArgs(argv) {
|
|
870
1031
|
const args = {};
|
|
1032
|
+
const booleanOpts = CLI_OPTIONS.filter((o) => o.type === "boolean");
|
|
1033
|
+
const stringOpts = CLI_OPTIONS.filter((o) => o.type === "string");
|
|
1034
|
+
const arrayOpts = CLI_OPTIONS.filter((o) => o.type === "array");
|
|
871
1035
|
for (const arg of argv) {
|
|
872
|
-
for (const
|
|
873
|
-
if (arg === flag) {
|
|
874
|
-
args[key] = true;
|
|
1036
|
+
for (const opt of booleanOpts) {
|
|
1037
|
+
if (arg === opt.flag) {
|
|
1038
|
+
args[opt.key] = true;
|
|
875
1039
|
}
|
|
876
1040
|
}
|
|
877
|
-
for (const
|
|
878
|
-
const prefix =
|
|
1041
|
+
for (const opt of stringOpts) {
|
|
1042
|
+
const prefix = `${opt.flag}=`;
|
|
879
1043
|
if (arg.startsWith(prefix)) {
|
|
880
|
-
args[key] = arg.slice(prefix.length);
|
|
1044
|
+
args[opt.key] = arg.slice(prefix.length);
|
|
881
1045
|
}
|
|
882
1046
|
}
|
|
883
|
-
for (const
|
|
884
|
-
const prefix =
|
|
1047
|
+
for (const opt of arrayOpts) {
|
|
1048
|
+
const prefix = `${opt.flag}=`;
|
|
885
1049
|
if (arg.startsWith(prefix)) {
|
|
886
|
-
args[key] = arg.slice(prefix.length).split(",");
|
|
1050
|
+
args[opt.key] = arg.slice(prefix.length).split(",");
|
|
887
1051
|
}
|
|
888
1052
|
}
|
|
889
1053
|
}
|
|
890
1054
|
return args;
|
|
891
1055
|
}
|
|
892
1056
|
async function run(argv) {
|
|
1057
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
1058
|
+
console.log(generateHelpText());
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
893
1061
|
const args = parseArgs(argv);
|
|
894
1062
|
await main(args);
|
|
895
1063
|
}
|
|
@@ -17,6 +17,22 @@ Create multiple atomic git commits, committing the smallest possible logical uni
|
|
|
17
17
|
|
|
18
18
|
Include any of the following info if specified: $ARGUMENTS
|
|
19
19
|
|
|
20
|
+
## Commit Message Rules
|
|
21
|
+
|
|
22
|
+
Follows [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
23
|
+
|
|
24
|
+
1. **Format**: `type(#issue): description`
|
|
25
|
+
- Use `#123` for local repo issues
|
|
26
|
+
- Use `owner/repo#123` for cross-repo issues
|
|
27
|
+
- Common types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
|
|
28
|
+
|
|
29
|
+
2. **AI Credits**: **NEVER include AI credits in commit messages**
|
|
30
|
+
- No "Generated with Claude Code"
|
|
31
|
+
- No "Co-Authored-By: Claude" or "Co-Authored-By: Happy"
|
|
32
|
+
- Focus on the actual changes made, not conversation history
|
|
33
|
+
|
|
34
|
+
3. **Content**: Write clear, concise commit messages describing what changed and why
|
|
35
|
+
|
|
20
36
|
## Process
|
|
21
37
|
|
|
22
38
|
1. Run `git status` and `git diff` to review changes
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Code review using dynamic category detection and domain-specific analysis
|
|
3
|
+
argument-hint: (optional) [branch, PR#, or PR URL] - defaults to current branch
|
|
4
|
+
- Bash(git diff:*)
|
|
5
|
+
- Bash(git status:*)
|
|
6
|
+
- Bash(git log:*)
|
|
7
|
+
- Bash(git rev-parse:*)
|
|
8
|
+
- Bash(git merge-base:*)
|
|
9
|
+
- Bash(git branch:*)
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## General Guidelines
|
|
13
|
+
|
|
14
|
+
### Output Style
|
|
15
|
+
|
|
16
|
+
- **Never explicitly mention TDD** in code, comments, commits, PRs, or issues
|
|
17
|
+
- Write natural, descriptive code without meta-commentary about the development process
|
|
18
|
+
- The code should speak for itself - TDD is the process, not the product
|
|
19
|
+
|
|
20
|
+
Beads is available for task tracking. Use `mcp__beads__*` tools to manage issues (the user interacts via `bd` commands).
|
|
21
|
+
|
|
22
|
+
# Code Review
|
|
23
|
+
|
|
24
|
+
Perform a code review using dynamic category detection.
|
|
25
|
+
|
|
26
|
+
## Phase 0: Setup & Categorization
|
|
27
|
+
|
|
28
|
+
### Determine What to Review
|
|
29
|
+
|
|
30
|
+
Parse the argument to determine the review target:
|
|
31
|
+
|
|
32
|
+
| Input | Action |
|
|
33
|
+
|-------|--------|
|
|
34
|
+
| No argument | Detect divergence point, confirm scope with user |
|
|
35
|
+
| Branch name | Use specified branch as base |
|
|
36
|
+
| PR number (e.g., `123`) | Fetch PR diff from GitHub |
|
|
37
|
+
| PR URL (e.g., `https://github.com/owner/repo/pull/123`) | Extract PR number and fetch diff |
|
|
38
|
+
|
|
39
|
+
**For GitHub PRs:**
|
|
40
|
+
|
|
41
|
+
1. Try GitHub MCP first: `mcp__github__pull_request_read` with `method: "get_diff"`
|
|
42
|
+
2. Fall back to `gh` CLI: `gh pr diff <number>`
|
|
43
|
+
3. If neither works, report error and stop
|
|
44
|
+
|
|
45
|
+
**For local branches (no argument or branch name provided):**
|
|
46
|
+
|
|
47
|
+
1. **Get current branch**: `git rev-parse --abbrev-ref HEAD`
|
|
48
|
+
|
|
49
|
+
2. **Check for uncommitted changes**: `git status --porcelain`
|
|
50
|
+
- If output is non-empty, note that uncommitted changes exist
|
|
51
|
+
|
|
52
|
+
3. **Detect divergence point** (skip if branch name was provided as argument):
|
|
53
|
+
- Get all local branches except current: `git branch --format='%(refname:short)'`
|
|
54
|
+
- For each branch, find merge-base: `git merge-base HEAD <branch>`
|
|
55
|
+
- Count commits from merge-base to HEAD: `git rev-list --count <merge-base>..HEAD`
|
|
56
|
+
- The branch with the **fewest commits back** (closest merge-base) is the likely parent
|
|
57
|
+
- If no other branches exist, fall back to `main`, `master`, or `develop` if they exist as remote tracking branches
|
|
58
|
+
|
|
59
|
+
4. **Confirm scope with user** using `AskUserQuestion`:
|
|
60
|
+
|
|
61
|
+
**Question 1 - "Review scope"** (header: "Base branch"):
|
|
62
|
+
- Option A: `From <detected-branch>` — "Review N commits since diverging from <branch>"
|
|
63
|
+
- Option B: `Different branch` — "Specify another branch to compare against"
|
|
64
|
+
- Option C: `Uncommitted only` — "Review only staged/unstaged changes, skip committed work"
|
|
65
|
+
|
|
66
|
+
**Question 2 - "Include uncommitted?"** (header: "Uncommitted", only ask if uncommitted changes exist AND user didn't pick option C):
|
|
67
|
+
- Option A: `Yes` — "Include N staged/unstaged files in review"
|
|
68
|
+
- Option B: `No` — "Review only committed changes"
|
|
69
|
+
|
|
70
|
+
5. **Collect changed files** based on user selection:
|
|
71
|
+
- From branch: `git diff --name-only <base>...HEAD`
|
|
72
|
+
- Uncommitted unstaged: `git diff --name-only`
|
|
73
|
+
- Uncommitted staged: `git diff --name-only --cached`
|
|
74
|
+
- Combine and deduplicate the file list
|
|
75
|
+
|
|
76
|
+
6. **If no changes**: Report "Nothing to review" and stop
|
|
77
|
+
|
|
78
|
+
### Categorize Files
|
|
79
|
+
|
|
80
|
+
Check for CLAUDE.md - if it exists, note any project-specific review patterns.
|
|
81
|
+
|
|
82
|
+
Categorize each changed file into ONE primary category based on these patterns:
|
|
83
|
+
|
|
84
|
+
| Category | File Patterns |
|
|
85
|
+
|----------|---------------|
|
|
86
|
+
| Frontend/UI | `*.tsx`, `*.jsx`, `components/`, `pages/`, `views/`, `*.vue` |
|
|
87
|
+
| Frontend/Styling | `*.css`, `*.scss`, `*.less`, `styles/`, `*.tailwind*`, `*.styled.*` |
|
|
88
|
+
| Backend/API | `routes/`, `api/`, `controllers/`, `services/`, `*.controller.*`, `*.service.*`, `*.resolver.*` |
|
|
89
|
+
| Backend/Data | `migrations/`, `models/`, `prisma/`, `schema.*`, `*.model.*`, `*.entity.*` |
|
|
90
|
+
| Tooling/Config | `scripts/`, `*.config.*`, `package.json`, `tsconfig.*`, `vite.*`, `webpack.*`, `eslint.*` |
|
|
91
|
+
| CI/CD | `.github/`, `.gitlab-ci.*`, `Dockerfile`, `docker-compose.*`, `*.yml` in CI paths |
|
|
92
|
+
| Tests | `*.test.*`, `*.spec.*`, `__tests__/`, `__mocks__/`, `*.stories.*` |
|
|
93
|
+
| Docs | `*.md`, `docs/`, `README*`, `CHANGELOG*` |
|
|
94
|
+
|
|
95
|
+
Output the categorization:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
## Categorization
|
|
99
|
+
|
|
100
|
+
Base branch: <branch>
|
|
101
|
+
Total files changed: <n>
|
|
102
|
+
|
|
103
|
+
| Category | Files |
|
|
104
|
+
|----------|-------|
|
|
105
|
+
| <category> | <count> |
|
|
106
|
+
...
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Phase 1: Branch Brief
|
|
110
|
+
|
|
111
|
+
From the diff and recent commit messages (`git log <base>...HEAD --oneline`), infer:
|
|
112
|
+
|
|
113
|
+
- **Goal**: What this branch accomplishes (1-3 sentences)
|
|
114
|
+
- **Constraints**: Any implied requirements (security, performance, backwards compatibility)
|
|
115
|
+
- **Success checklist**: What must work after this change, what must not break
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
## Branch Brief
|
|
119
|
+
|
|
120
|
+
**Goal**: ...
|
|
121
|
+
**Constraints**: ...
|
|
122
|
+
**Checklist**:
|
|
123
|
+
- [ ] ...
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Phase 2: Category Reviews
|
|
127
|
+
|
|
128
|
+
For each detected category with changes, run a targeted review. Skip categories with no changes.
|
|
129
|
+
|
|
130
|
+
### Frontend/UI Review Criteria
|
|
131
|
+
|
|
132
|
+
- Accessibility: ARIA attributes, keyboard navigation, screen reader support
|
|
133
|
+
- Component patterns: Composition, prop drilling, context usage
|
|
134
|
+
- State management: Unnecessary re-renders, stale closures
|
|
135
|
+
- Performance: memo/useMemo/useCallback usage, lazy loading, bundle impact
|
|
136
|
+
|
|
137
|
+
### Frontend/Styling Review Criteria
|
|
138
|
+
|
|
139
|
+
- Responsive design: Breakpoints, mobile-first
|
|
140
|
+
- Design system: Token usage, consistent spacing/colors
|
|
141
|
+
- CSS specificity: Overly specific selectors, !important usage
|
|
142
|
+
- Theme support: Dark mode, CSS variables
|
|
143
|
+
|
|
144
|
+
### Backend/API Review Criteria
|
|
145
|
+
|
|
146
|
+
- Input validation: Sanitization, type checking, bounds
|
|
147
|
+
- Security: Authentication checks, authorization, injection risks
|
|
148
|
+
- Error handling: Proper status codes, meaningful messages, logging
|
|
149
|
+
- Performance: N+1 queries, missing indexes, pagination
|
|
150
|
+
|
|
151
|
+
### Backend/Data Review Criteria
|
|
152
|
+
|
|
153
|
+
- Migration safety: Reversibility, data preservation
|
|
154
|
+
- Data integrity: Constraints, foreign keys, nullability
|
|
155
|
+
- Index usage: Queries have appropriate indexes
|
|
156
|
+
- Backwards compatibility: Existing data still works
|
|
157
|
+
|
|
158
|
+
### Tooling/Config Review Criteria
|
|
159
|
+
|
|
160
|
+
- Breaking changes: Does this affect developer workflow?
|
|
161
|
+
- Dependency compatibility: Version conflicts, peer deps
|
|
162
|
+
- Build performance: Added build time, bundle size
|
|
163
|
+
|
|
164
|
+
### CI/CD Review Criteria
|
|
165
|
+
|
|
166
|
+
- Secrets exposure: Credentials in logs, env vars
|
|
167
|
+
- Pipeline efficiency: Caching, parallelization
|
|
168
|
+
- Failure handling: Notifications, rollback strategy
|
|
169
|
+
|
|
170
|
+
### Tests Review Criteria
|
|
171
|
+
|
|
172
|
+
- Coverage: Edge cases, error paths, boundaries
|
|
173
|
+
- Assertion quality: Specific assertions, not just "no error"
|
|
174
|
+
- Flaky patterns: Timing dependencies, order dependencies, shared state
|
|
175
|
+
|
|
176
|
+
### Docs Review Criteria
|
|
177
|
+
|
|
178
|
+
- Technical accuracy: Code examples work, APIs documented correctly
|
|
179
|
+
- Completeness: All new features documented
|
|
180
|
+
- Clarity: Easy to follow, good examples
|
|
181
|
+
|
|
182
|
+
**Output format per category:**
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
## <Category> Review (<n> files)
|
|
186
|
+
|
|
187
|
+
### file:line - [blocker|risky|nit] Title
|
|
188
|
+
Description of the issue and why it matters.
|
|
189
|
+
Suggested fix or question to investigate.
|
|
190
|
+
|
|
191
|
+
...
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Phase 3: Cross-Cutting Analysis
|
|
195
|
+
|
|
196
|
+
After reviewing all categories, check for cross-cutting issues:
|
|
197
|
+
|
|
198
|
+
- API changed but tests didn't update?
|
|
199
|
+
- New feature but no documentation?
|
|
200
|
+
- Migration added but no rollback tested?
|
|
201
|
+
- Config changed but README not updated?
|
|
202
|
+
- Security-sensitive code without corresponding test?
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
## Cross-Cutting Issues
|
|
206
|
+
|
|
207
|
+
- [ ] <issue description>
|
|
208
|
+
...
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Phase 4: Summary
|
|
212
|
+
|
|
213
|
+
### PR Description (draft)
|
|
214
|
+
|
|
215
|
+
Provide a ready-to-paste PR description:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
## What changed
|
|
219
|
+
- <by category, 1-2 bullets each>
|
|
220
|
+
|
|
221
|
+
## Why
|
|
222
|
+
- <motivation>
|
|
223
|
+
|
|
224
|
+
## Testing
|
|
225
|
+
- <how to verify>
|
|
226
|
+
|
|
227
|
+
## Notes
|
|
228
|
+
- <migration steps, breaking changes, etc.>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Review Checklist
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
## Before Merge
|
|
235
|
+
|
|
236
|
+
### Blockers (must fix)
|
|
237
|
+
- [ ] ...
|
|
238
|
+
|
|
239
|
+
### Risky (highlight to reviewers)
|
|
240
|
+
- [ ] ...
|
|
241
|
+
|
|
242
|
+
### Follow-ups (can defer)
|
|
243
|
+
- [ ] ...
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
Review target (branch name, PR number, or PR URL - leave empty for current branch): $ARGUMENTS
|
|
@@ -24,6 +24,20 @@
|
|
|
24
24
|
"category": "Workflow",
|
|
25
25
|
"order": 2
|
|
26
26
|
},
|
|
27
|
+
"code-review.md": {
|
|
28
|
+
"description": "Code review using dynamic category detection and domain-specific analysis",
|
|
29
|
+
"hint": "Review code",
|
|
30
|
+
"category": "Workflow",
|
|
31
|
+
"order": 35,
|
|
32
|
+
"_requested-tools": [
|
|
33
|
+
"Bash(git diff:*)",
|
|
34
|
+
"Bash(git status:*)",
|
|
35
|
+
"Bash(git log:*)",
|
|
36
|
+
"Bash(git rev-parse:*)",
|
|
37
|
+
"Bash(git merge-base:*)",
|
|
38
|
+
"Bash(git branch:*)"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
27
41
|
"commit.md": {
|
|
28
42
|
"description": "Create a git commit following project standards",
|
|
29
43
|
"hint": "Git commit",
|
|
@@ -17,6 +17,22 @@ Create a git commit following project standards
|
|
|
17
17
|
|
|
18
18
|
Include any of the following info if specified: $ARGUMENTS
|
|
19
19
|
|
|
20
|
+
## Commit Message Rules
|
|
21
|
+
|
|
22
|
+
Follows [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
23
|
+
|
|
24
|
+
1. **Format**: `type(#issue): description`
|
|
25
|
+
- Use `#123` for local repo issues
|
|
26
|
+
- Use `owner/repo#123` for cross-repo issues
|
|
27
|
+
- Common types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
|
|
28
|
+
|
|
29
|
+
2. **AI Credits**: **NEVER include AI credits in commit messages**
|
|
30
|
+
- No "Generated with Claude Code"
|
|
31
|
+
- No "Co-Authored-By: Claude" or "Co-Authored-By: Happy"
|
|
32
|
+
- Focus on the actual changes made, not conversation history
|
|
33
|
+
|
|
34
|
+
3. **Content**: Write clear, concise commit messages describing what changed and why
|
|
35
|
+
|
|
20
36
|
## Process
|
|
21
37
|
|
|
22
38
|
1. Run `git status` and `git diff` to review changes
|
|
@@ -19,6 +19,7 @@ Analyze the current conversation context and identify things that have not yet b
|
|
|
19
19
|
2. **Unused variables/results** - Values that were captured but never used
|
|
20
20
|
3. **Missing tests** - Functionality without test coverage
|
|
21
21
|
4. **Open issues** - Beads issues that are still open or in progress
|
|
22
|
+
|
|
22
23
|
5. **User requests** - Things the user asked for that weren't fully completed
|
|
23
24
|
6. **TODO comments** - Any TODOs mentioned in conversation
|
|
24
25
|
7. **Error handling gaps** - Missing error cases or edge cases
|
|
@@ -21,8 +21,7 @@ Beads is available for task tracking. Use `mcp__beads__*` tools to manage issues
|
|
|
21
21
|
|
|
22
22
|
$ARGUMENTS
|
|
23
23
|
|
|
24
|
-
(If no input provided, check conversation context or run `bd ready` to see existing work
|
|
25
|
-
)
|
|
24
|
+
(If no input provided, check conversation context or run `bd ready` to see existing work)
|
|
26
25
|
|
|
27
26
|
## Input Processing
|
|
28
27
|
|
|
@@ -15,6 +15,22 @@ Create multiple atomic git commits, committing the smallest possible logical uni
|
|
|
15
15
|
|
|
16
16
|
Include any of the following info if specified: $ARGUMENTS
|
|
17
17
|
|
|
18
|
+
## Commit Message Rules
|
|
19
|
+
|
|
20
|
+
Follows [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
21
|
+
|
|
22
|
+
1. **Format**: `type(#issue): description`
|
|
23
|
+
- Use `#123` for local repo issues
|
|
24
|
+
- Use `owner/repo#123` for cross-repo issues
|
|
25
|
+
- Common types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
|
|
26
|
+
|
|
27
|
+
2. **AI Credits**: **NEVER include AI credits in commit messages**
|
|
28
|
+
- No "Generated with Claude Code"
|
|
29
|
+
- No "Co-Authored-By: Claude" or "Co-Authored-By: Happy"
|
|
30
|
+
- Focus on the actual changes made, not conversation history
|
|
31
|
+
|
|
32
|
+
3. **Content**: Write clear, concise commit messages describing what changed and why
|
|
33
|
+
|
|
18
34
|
## Process
|
|
19
35
|
|
|
20
36
|
1. Run `git status` and `git diff` to review changes
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Code review using dynamic category detection and domain-specific analysis
|
|
3
|
+
argument-hint: (optional) [branch, PR#, or PR URL] - defaults to current branch
|
|
4
|
+
- Bash(git diff:*)
|
|
5
|
+
- Bash(git status:*)
|
|
6
|
+
- Bash(git log:*)
|
|
7
|
+
- Bash(git rev-parse:*)
|
|
8
|
+
- Bash(git merge-base:*)
|
|
9
|
+
- Bash(git branch:*)
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## General Guidelines
|
|
13
|
+
|
|
14
|
+
### Output Style
|
|
15
|
+
|
|
16
|
+
- **Never explicitly mention TDD** in code, comments, commits, PRs, or issues
|
|
17
|
+
- Write natural, descriptive code without meta-commentary about the development process
|
|
18
|
+
- The code should speak for itself - TDD is the process, not the product
|
|
19
|
+
|
|
20
|
+
# Code Review
|
|
21
|
+
|
|
22
|
+
Perform a code review using dynamic category detection.
|
|
23
|
+
|
|
24
|
+
## Phase 0: Setup & Categorization
|
|
25
|
+
|
|
26
|
+
### Determine What to Review
|
|
27
|
+
|
|
28
|
+
Parse the argument to determine the review target:
|
|
29
|
+
|
|
30
|
+
| Input | Action |
|
|
31
|
+
|-------|--------|
|
|
32
|
+
| No argument | Detect divergence point, confirm scope with user |
|
|
33
|
+
| Branch name | Use specified branch as base |
|
|
34
|
+
| PR number (e.g., `123`) | Fetch PR diff from GitHub |
|
|
35
|
+
| PR URL (e.g., `https://github.com/owner/repo/pull/123`) | Extract PR number and fetch diff |
|
|
36
|
+
|
|
37
|
+
**For GitHub PRs:**
|
|
38
|
+
|
|
39
|
+
1. Try GitHub MCP first: `mcp__github__pull_request_read` with `method: "get_diff"`
|
|
40
|
+
2. Fall back to `gh` CLI: `gh pr diff <number>`
|
|
41
|
+
3. If neither works, report error and stop
|
|
42
|
+
|
|
43
|
+
**For local branches (no argument or branch name provided):**
|
|
44
|
+
|
|
45
|
+
1. **Get current branch**: `git rev-parse --abbrev-ref HEAD`
|
|
46
|
+
|
|
47
|
+
2. **Check for uncommitted changes**: `git status --porcelain`
|
|
48
|
+
- If output is non-empty, note that uncommitted changes exist
|
|
49
|
+
|
|
50
|
+
3. **Detect divergence point** (skip if branch name was provided as argument):
|
|
51
|
+
- Get all local branches except current: `git branch --format='%(refname:short)'`
|
|
52
|
+
- For each branch, find merge-base: `git merge-base HEAD <branch>`
|
|
53
|
+
- Count commits from merge-base to HEAD: `git rev-list --count <merge-base>..HEAD`
|
|
54
|
+
- The branch with the **fewest commits back** (closest merge-base) is the likely parent
|
|
55
|
+
- If no other branches exist, fall back to `main`, `master`, or `develop` if they exist as remote tracking branches
|
|
56
|
+
|
|
57
|
+
4. **Confirm scope with user** using `AskUserQuestion`:
|
|
58
|
+
|
|
59
|
+
**Question 1 - "Review scope"** (header: "Base branch"):
|
|
60
|
+
- Option A: `From <detected-branch>` — "Review N commits since diverging from <branch>"
|
|
61
|
+
- Option B: `Different branch` — "Specify another branch to compare against"
|
|
62
|
+
- Option C: `Uncommitted only` — "Review only staged/unstaged changes, skip committed work"
|
|
63
|
+
|
|
64
|
+
**Question 2 - "Include uncommitted?"** (header: "Uncommitted", only ask if uncommitted changes exist AND user didn't pick option C):
|
|
65
|
+
- Option A: `Yes` — "Include N staged/unstaged files in review"
|
|
66
|
+
- Option B: `No` — "Review only committed changes"
|
|
67
|
+
|
|
68
|
+
5. **Collect changed files** based on user selection:
|
|
69
|
+
- From branch: `git diff --name-only <base>...HEAD`
|
|
70
|
+
- Uncommitted unstaged: `git diff --name-only`
|
|
71
|
+
- Uncommitted staged: `git diff --name-only --cached`
|
|
72
|
+
- Combine and deduplicate the file list
|
|
73
|
+
|
|
74
|
+
6. **If no changes**: Report "Nothing to review" and stop
|
|
75
|
+
|
|
76
|
+
### Categorize Files
|
|
77
|
+
|
|
78
|
+
Check for CLAUDE.md - if it exists, note any project-specific review patterns.
|
|
79
|
+
|
|
80
|
+
Categorize each changed file into ONE primary category based on these patterns:
|
|
81
|
+
|
|
82
|
+
| Category | File Patterns |
|
|
83
|
+
|----------|---------------|
|
|
84
|
+
| Frontend/UI | `*.tsx`, `*.jsx`, `components/`, `pages/`, `views/`, `*.vue` |
|
|
85
|
+
| Frontend/Styling | `*.css`, `*.scss`, `*.less`, `styles/`, `*.tailwind*`, `*.styled.*` |
|
|
86
|
+
| Backend/API | `routes/`, `api/`, `controllers/`, `services/`, `*.controller.*`, `*.service.*`, `*.resolver.*` |
|
|
87
|
+
| Backend/Data | `migrations/`, `models/`, `prisma/`, `schema.*`, `*.model.*`, `*.entity.*` |
|
|
88
|
+
| Tooling/Config | `scripts/`, `*.config.*`, `package.json`, `tsconfig.*`, `vite.*`, `webpack.*`, `eslint.*` |
|
|
89
|
+
| CI/CD | `.github/`, `.gitlab-ci.*`, `Dockerfile`, `docker-compose.*`, `*.yml` in CI paths |
|
|
90
|
+
| Tests | `*.test.*`, `*.spec.*`, `__tests__/`, `__mocks__/`, `*.stories.*` |
|
|
91
|
+
| Docs | `*.md`, `docs/`, `README*`, `CHANGELOG*` |
|
|
92
|
+
|
|
93
|
+
Output the categorization:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
## Categorization
|
|
97
|
+
|
|
98
|
+
Base branch: <branch>
|
|
99
|
+
Total files changed: <n>
|
|
100
|
+
|
|
101
|
+
| Category | Files |
|
|
102
|
+
|----------|-------|
|
|
103
|
+
| <category> | <count> |
|
|
104
|
+
...
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Phase 1: Branch Brief
|
|
108
|
+
|
|
109
|
+
From the diff and recent commit messages (`git log <base>...HEAD --oneline`), infer:
|
|
110
|
+
|
|
111
|
+
- **Goal**: What this branch accomplishes (1-3 sentences)
|
|
112
|
+
- **Constraints**: Any implied requirements (security, performance, backwards compatibility)
|
|
113
|
+
- **Success checklist**: What must work after this change, what must not break
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
## Branch Brief
|
|
117
|
+
|
|
118
|
+
**Goal**: ...
|
|
119
|
+
**Constraints**: ...
|
|
120
|
+
**Checklist**:
|
|
121
|
+
- [ ] ...
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Phase 2: Category Reviews
|
|
125
|
+
|
|
126
|
+
For each detected category with changes, run a targeted review. Skip categories with no changes.
|
|
127
|
+
|
|
128
|
+
### Frontend/UI Review Criteria
|
|
129
|
+
|
|
130
|
+
- Accessibility: ARIA attributes, keyboard navigation, screen reader support
|
|
131
|
+
- Component patterns: Composition, prop drilling, context usage
|
|
132
|
+
- State management: Unnecessary re-renders, stale closures
|
|
133
|
+
- Performance: memo/useMemo/useCallback usage, lazy loading, bundle impact
|
|
134
|
+
|
|
135
|
+
### Frontend/Styling Review Criteria
|
|
136
|
+
|
|
137
|
+
- Responsive design: Breakpoints, mobile-first
|
|
138
|
+
- Design system: Token usage, consistent spacing/colors
|
|
139
|
+
- CSS specificity: Overly specific selectors, !important usage
|
|
140
|
+
- Theme support: Dark mode, CSS variables
|
|
141
|
+
|
|
142
|
+
### Backend/API Review Criteria
|
|
143
|
+
|
|
144
|
+
- Input validation: Sanitization, type checking, bounds
|
|
145
|
+
- Security: Authentication checks, authorization, injection risks
|
|
146
|
+
- Error handling: Proper status codes, meaningful messages, logging
|
|
147
|
+
- Performance: N+1 queries, missing indexes, pagination
|
|
148
|
+
|
|
149
|
+
### Backend/Data Review Criteria
|
|
150
|
+
|
|
151
|
+
- Migration safety: Reversibility, data preservation
|
|
152
|
+
- Data integrity: Constraints, foreign keys, nullability
|
|
153
|
+
- Index usage: Queries have appropriate indexes
|
|
154
|
+
- Backwards compatibility: Existing data still works
|
|
155
|
+
|
|
156
|
+
### Tooling/Config Review Criteria
|
|
157
|
+
|
|
158
|
+
- Breaking changes: Does this affect developer workflow?
|
|
159
|
+
- Dependency compatibility: Version conflicts, peer deps
|
|
160
|
+
- Build performance: Added build time, bundle size
|
|
161
|
+
|
|
162
|
+
### CI/CD Review Criteria
|
|
163
|
+
|
|
164
|
+
- Secrets exposure: Credentials in logs, env vars
|
|
165
|
+
- Pipeline efficiency: Caching, parallelization
|
|
166
|
+
- Failure handling: Notifications, rollback strategy
|
|
167
|
+
|
|
168
|
+
### Tests Review Criteria
|
|
169
|
+
|
|
170
|
+
- Coverage: Edge cases, error paths, boundaries
|
|
171
|
+
- Assertion quality: Specific assertions, not just "no error"
|
|
172
|
+
- Flaky patterns: Timing dependencies, order dependencies, shared state
|
|
173
|
+
|
|
174
|
+
### Docs Review Criteria
|
|
175
|
+
|
|
176
|
+
- Technical accuracy: Code examples work, APIs documented correctly
|
|
177
|
+
- Completeness: All new features documented
|
|
178
|
+
- Clarity: Easy to follow, good examples
|
|
179
|
+
|
|
180
|
+
**Output format per category:**
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
## <Category> Review (<n> files)
|
|
184
|
+
|
|
185
|
+
### file:line - [blocker|risky|nit] Title
|
|
186
|
+
Description of the issue and why it matters.
|
|
187
|
+
Suggested fix or question to investigate.
|
|
188
|
+
|
|
189
|
+
...
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Phase 3: Cross-Cutting Analysis
|
|
193
|
+
|
|
194
|
+
After reviewing all categories, check for cross-cutting issues:
|
|
195
|
+
|
|
196
|
+
- API changed but tests didn't update?
|
|
197
|
+
- New feature but no documentation?
|
|
198
|
+
- Migration added but no rollback tested?
|
|
199
|
+
- Config changed but README not updated?
|
|
200
|
+
- Security-sensitive code without corresponding test?
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
## Cross-Cutting Issues
|
|
204
|
+
|
|
205
|
+
- [ ] <issue description>
|
|
206
|
+
...
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Phase 4: Summary
|
|
210
|
+
|
|
211
|
+
### PR Description (draft)
|
|
212
|
+
|
|
213
|
+
Provide a ready-to-paste PR description:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
## What changed
|
|
217
|
+
- <by category, 1-2 bullets each>
|
|
218
|
+
|
|
219
|
+
## Why
|
|
220
|
+
- <motivation>
|
|
221
|
+
|
|
222
|
+
## Testing
|
|
223
|
+
- <how to verify>
|
|
224
|
+
|
|
225
|
+
## Notes
|
|
226
|
+
- <migration steps, breaking changes, etc.>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Review Checklist
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
## Before Merge
|
|
233
|
+
|
|
234
|
+
### Blockers (must fix)
|
|
235
|
+
- [ ] ...
|
|
236
|
+
|
|
237
|
+
### Risky (highlight to reviewers)
|
|
238
|
+
- [ ] ...
|
|
239
|
+
|
|
240
|
+
### Follow-ups (can defer)
|
|
241
|
+
- [ ] ...
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
Review target (branch name, PR number, or PR URL - leave empty for current branch): $ARGUMENTS
|
|
@@ -24,6 +24,20 @@
|
|
|
24
24
|
"category": "Workflow",
|
|
25
25
|
"order": 2
|
|
26
26
|
},
|
|
27
|
+
"code-review.md": {
|
|
28
|
+
"description": "Code review using dynamic category detection and domain-specific analysis",
|
|
29
|
+
"hint": "Review code",
|
|
30
|
+
"category": "Workflow",
|
|
31
|
+
"order": 35,
|
|
32
|
+
"_requested-tools": [
|
|
33
|
+
"Bash(git diff:*)",
|
|
34
|
+
"Bash(git status:*)",
|
|
35
|
+
"Bash(git log:*)",
|
|
36
|
+
"Bash(git rev-parse:*)",
|
|
37
|
+
"Bash(git merge-base:*)",
|
|
38
|
+
"Bash(git branch:*)"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
27
41
|
"commit.md": {
|
|
28
42
|
"description": "Create a git commit following project standards",
|
|
29
43
|
"hint": "Git commit",
|
|
@@ -15,6 +15,22 @@ Create a git commit following project standards
|
|
|
15
15
|
|
|
16
16
|
Include any of the following info if specified: $ARGUMENTS
|
|
17
17
|
|
|
18
|
+
## Commit Message Rules
|
|
19
|
+
|
|
20
|
+
Follows [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
21
|
+
|
|
22
|
+
1. **Format**: `type(#issue): description`
|
|
23
|
+
- Use `#123` for local repo issues
|
|
24
|
+
- Use `owner/repo#123` for cross-repo issues
|
|
25
|
+
- Common types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
|
|
26
|
+
|
|
27
|
+
2. **AI Credits**: **NEVER include AI credits in commit messages**
|
|
28
|
+
- No "Generated with Claude Code"
|
|
29
|
+
- No "Co-Authored-By: Claude" or "Co-Authored-By: Happy"
|
|
30
|
+
- Focus on the actual changes made, not conversation history
|
|
31
|
+
|
|
32
|
+
3. **Content**: Write clear, concise commit messages describing what changed and why
|
|
33
|
+
|
|
18
34
|
## Process
|
|
19
35
|
|
|
20
36
|
1. Run `git status` and `git diff` to review changes
|
|
@@ -16,6 +16,7 @@ Analyze the current conversation context and identify things that have not yet b
|
|
|
16
16
|
1. **Incomplete implementations** - Code that was started but not finished
|
|
17
17
|
2. **Unused variables/results** - Values that were captured but never used
|
|
18
18
|
3. **Missing tests** - Functionality without test coverage
|
|
19
|
+
|
|
19
20
|
4. **User requests** - Things the user asked for that weren't fully completed
|
|
20
21
|
5. **TODO comments** - Any TODOs mentioned in conversation
|
|
21
22
|
6. **Error handling gaps** - Missing error cases or edge cases
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wbern/claude-instructions",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "TDD workflow commands for Claude Code CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./bin/cli.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"test:quick-manual": "pnpm build:cli && node bin/cli.js",
|
|
35
35
|
"generate": "tsx scripts/cli-generator.ts",
|
|
36
36
|
"test": "vitest run",
|
|
37
|
+
"test:coverage": "vitest run --coverage",
|
|
37
38
|
"test:watch": "vitest",
|
|
38
39
|
"typecheck": "tsc --noEmit",
|
|
39
40
|
"knip": "knip",
|
|
@@ -45,13 +46,13 @@
|
|
|
45
46
|
"@eslint/js": "^9.39.1",
|
|
46
47
|
"@types/fs-extra": "^11.0.4",
|
|
47
48
|
"@types/node": "^24.10.1",
|
|
49
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
48
50
|
"diff": "^8.0.2",
|
|
49
51
|
"eslint": "^9.39.1",
|
|
50
52
|
"husky": "^9.1.7",
|
|
51
53
|
"jscpd": "^4.0.5",
|
|
52
54
|
"knip": "^5.70.2",
|
|
53
55
|
"lint-staged": "^16.2.7",
|
|
54
|
-
"markdown-magic": "^4.0.4",
|
|
55
56
|
"markdownlint-cli": "^0.46.0",
|
|
56
57
|
"picocolors": "^1.1.1",
|
|
57
58
|
"prettier": "^3.7.2",
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"tsx": "^4.20.6",
|
|
60
61
|
"typescript": "^5.9.3",
|
|
61
62
|
"typescript-eslint": "^8.48.0",
|
|
62
|
-
"vitest": "^4.0.
|
|
63
|
+
"vitest": "^4.0.15"
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
66
|
"@clack/prompts": "^0.11.0",
|