claude-devkit-cli 1.0.0 → 1.1.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/package.json +2 -1
- package/src/commands/init.js +7 -2
- package/src/lib/installer.js +13 -3
- package/templates/.claude/CLAUDE.md +2 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-devkit-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CLI toolkit for spec-first development with Claude Code — hooks, commands, guards, and test runners",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-devkit": "./bin/devkit.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
31
|
"prepublishOnly": "rm -rf templates && cp -r ../kit templates",
|
|
32
|
+
"postpublish": "rm -rf templates",
|
|
32
33
|
"dev": "node bin/devkit.js"
|
|
33
34
|
},
|
|
34
35
|
"license": "MIT",
|
package/src/commands/init.js
CHANGED
|
@@ -90,10 +90,12 @@ export async function initCommand(path, opts) {
|
|
|
90
90
|
const manifest = createManifest(pkg.version, null, components);
|
|
91
91
|
let copied = 0;
|
|
92
92
|
let skipped = 0;
|
|
93
|
+
let identical = 0;
|
|
93
94
|
|
|
94
95
|
for (const file of files) {
|
|
95
96
|
const result = await installFile(file, targetDir, { force: opts.force });
|
|
96
97
|
if (result === 'copied') copied++;
|
|
98
|
+
else if (result === 'identical') identical++;
|
|
97
99
|
else skipped++;
|
|
98
100
|
|
|
99
101
|
// Record in manifest
|
|
@@ -162,11 +164,14 @@ export async function initCommand(path, opts) {
|
|
|
162
164
|
console.log(' .claude/CLAUDE.md — Project rules (review and customize)');
|
|
163
165
|
console.log(' .claude/settings.json — Hook configuration');
|
|
164
166
|
console.log(' .claude/hooks/ — 6 guards (file, path, glob, comment, sensitive, self-review)');
|
|
165
|
-
console.log(' .claude/commands/ — /plan, /test, /fix, /review, /commit
|
|
167
|
+
console.log(' .claude/commands/ — /plan, /challenge, /test, /fix, /review, /commit');
|
|
166
168
|
console.log(' scripts/build-test.sh — Universal test runner');
|
|
167
169
|
console.log(' docs/WORKFLOW.md — Workflow reference');
|
|
168
170
|
log.blank();
|
|
169
|
-
|
|
171
|
+
const parts = [`${copied} copied`];
|
|
172
|
+
if (identical > 0) parts.push(`${identical} identical`);
|
|
173
|
+
if (skipped > 0) parts.push(`${skipped} conflicted (use --force to overwrite)`);
|
|
174
|
+
console.log(` ${parts.join(', ')}`);
|
|
170
175
|
log.blank();
|
|
171
176
|
console.log('Next steps:');
|
|
172
177
|
console.log(' 1. Review .claude/CLAUDE.md — ensure project info is correct');
|
package/src/lib/installer.js
CHANGED
|
@@ -21,11 +21,11 @@ export const COMPONENTS = {
|
|
|
21
21
|
],
|
|
22
22
|
commands: [
|
|
23
23
|
'.claude/commands/plan.md',
|
|
24
|
+
'.claude/commands/challenge.md',
|
|
24
25
|
'.claude/commands/test.md',
|
|
25
26
|
'.claude/commands/fix.md',
|
|
26
27
|
'.claude/commands/review.md',
|
|
27
28
|
'.claude/commands/commit.md',
|
|
28
|
-
'.claude/commands/challenge.md',
|
|
29
29
|
],
|
|
30
30
|
config: [
|
|
31
31
|
'.claude/settings.json',
|
|
@@ -91,14 +91,24 @@ export function getAllFiles() {
|
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* Copy a single file from templates to target.
|
|
94
|
-
* @returns {string} 'copied' | 'skipped'
|
|
94
|
+
* @returns {string} 'copied' | 'skipped' | 'identical'
|
|
95
95
|
*/
|
|
96
96
|
export async function installFile(relativePath, targetDir, { force = false } = {}) {
|
|
97
97
|
const src = join(getTemplateDir(), relativePath);
|
|
98
98
|
const dst = join(targetDir, relativePath);
|
|
99
99
|
|
|
100
100
|
if (existsSync(dst) && !force) {
|
|
101
|
-
|
|
101
|
+
// Compare content to distinguish: identical, customized, or from another source
|
|
102
|
+
try {
|
|
103
|
+
const { hashFile } = await import('./hasher.js');
|
|
104
|
+
const srcHash = await hashFile(src);
|
|
105
|
+
const dstHash = await hashFile(dst);
|
|
106
|
+
if (srcHash === dstHash) {
|
|
107
|
+
log.same(`${relativePath} (identical)`);
|
|
108
|
+
return 'identical';
|
|
109
|
+
}
|
|
110
|
+
} catch { /* hash failed, treat as conflict */ }
|
|
111
|
+
log.warn(`${relativePath} (exists with different content — use --force to overwrite)`);
|
|
102
112
|
return 'skipped';
|
|
103
113
|
}
|
|
104
114
|
|
|
@@ -13,11 +13,10 @@ Every change follows this cycle: **SPEC → TEST PLAN → CODE + TESTS → BUILD
|
|
|
13
13
|
|
|
14
14
|
| Trigger | Commands | Details |
|
|
15
15
|
|---------|----------|---------|
|
|
16
|
-
| New feature | `/plan` → code in chunks → `/test` each chunk | Start with spec or description |
|
|
17
|
-
| Update feature | Update spec first → `/plan`
|
|
16
|
+
| New feature | `/plan` → `/challenge` (optional) → code in chunks → `/test` each chunk | Start with spec or description |
|
|
17
|
+
| Update feature | Update spec first → `/plan` → code → `/test` | Spec changes before code changes |
|
|
18
18
|
| Bug fix | `/fix "description"` | Test-first: write failing test → fix → green |
|
|
19
19
|
| Remove feature | Mark spec as removed → delete code + tests → build pass | Run full suite after removal |
|
|
20
|
-
| Stress-test plan | `/challenge` | Adversarial review before coding (optional) |
|
|
21
20
|
| Pre-merge check | `/review` | Diff-based quality gate |
|
|
22
21
|
| Commit changes | `/commit` | Secret scan + conventional commit |
|
|
23
22
|
|