spec-starter 1.0.0 → 1.0.1

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.
Files changed (3) hide show
  1. package/README.md +23 -8
  2. package/bin/index.js +83 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # spec-starter
2
2
 
3
- A Claude Code project template for structured feature development. Drop the `.claude/` folder into any project to get a repeatable workflow for taking features from raw idea to tested implementation.
3
+ A Claude Code project template for structured feature development. Run `npx spec-starter` in any project to get a repeatable workflow for taking features from raw idea to tested implementation.
4
4
 
5
5
  ## How it works
6
6
 
@@ -21,7 +21,7 @@ Each stage has a matching slash command. Commands are interactive: called withou
21
21
  | Command | No args | With arg |
22
22
  |---|---|---|
23
23
  | `/task` | List backlog tasks | Add idea to `.claude/tasks.md` |
24
- | `/feature:start` | List backlog tasks | Create feature folder + `2-brief.md` |
24
+ | `/feature:start` | List backlog tasks | Create feature folder + `1-feature.md` + `2-brief.md` |
25
25
  | `/feature:review` | List `[?]` features | Review current state and take next action |
26
26
  | `/feature:blueprint` | List `[x]` Brief features ready to blueprint | Generate `3-blueprint.md` |
27
27
  | `/feature:implement` | List `[x]` Blueprint features ready to implement | Implement + generate `4-e2e-checklist.md` |
@@ -41,10 +41,11 @@ Backlog idea (.claude/tasks.md)
41
41
  /feature:blueprint <slug> → .claude/_features/<slug>/3-blueprint.md [x] Blueprint
42
42
 
43
43
  /feature:implement <slug> → writes code (TDD), generates 4-e2e-checklist.md [x] Implement
44
+ ↓ [o] Review
45
+ · manually work through 4-e2e-checklist.md
44
46
 
45
- Manual review work through 4-e2e-checklist.md [x] Review
46
-
47
- /feature:finish <slug> → push branch, PR into dev, merge, mark Done [x] Done
47
+ /feature:finish <slug> push branch, PR into dev, merge, mark Done [x] Review
48
+ [x] Done
48
49
 
49
50
  /feature:test <slug> → walk e2e checklist interactively (post-merge QA)
50
51
  ```
@@ -91,9 +92,23 @@ You can also create or edit `.claude/testing.md` by hand at any time.
91
92
 
92
93
  ## Getting started
93
94
 
94
- 1. Copy this repo's `.claude/` folder into your project root
95
- 2. Run `/project-init` to generate `CLAUDE.md` with project context and `.claude/testing.md` with testing setup
96
- 3. Add ideas to `.claude/tasks.md` (one per line), then run `/feature:start <idea>` to turn one into a feature
95
+ In your project root:
96
+
97
+ ```bash
98
+ npx spec-starter
99
+ ```
100
+
101
+ Then open Claude Code — `project-init` runs automatically on first open, generating `CLAUDE.md` and `.claude/testing.md`.
102
+
103
+ Add ideas to `.claude/tasks.md` (one per line), then run `/feature:start <idea>` to turn one into a feature.
104
+
105
+ ## Updating
106
+
107
+ Run the same command again to sync the latest engine files. Your project data (`_features/`, `tasks.md`, `testing.md`, `CLAUDE.md`) is never touched. Claude will announce the update next time you open the project.
108
+
109
+ ```bash
110
+ npx spec-starter
111
+ ```
97
112
 
98
113
  ## Design principle
99
114
 
package/bin/index.js CHANGED
@@ -3,32 +3,26 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
- const src = path.join(__dirname, '..');
7
- const dest = process.cwd();
6
+ const PKG_DIR = path.join(__dirname, '..');
7
+ const TARGET_DIR = process.cwd();
8
+ const VERSION = require('../package.json').version;
8
9
 
9
- // Always overwrite — these are the engine files
10
- const engineDirs = [
10
+ const SCAFFOLD_DIRS = [
11
11
  '.claude/commands',
12
12
  '.claude/skills',
13
13
  '.claude/_templates',
14
14
  '.claude/hooks',
15
15
  ];
16
- const engineFiles = [
17
- '.claude/settings.json',
18
- ];
19
16
 
20
- // Create only if missing — project seeds
21
- const seedFiles = [
22
- ['.claude/tasks.md', ''],
17
+ const SCAFFOLD_FILES = [
18
+ '.claude/settings.json',
23
19
  ];
24
20
 
25
- // Never touch: .claude/_features/, CLAUDE.md, .claude/testing.md
26
-
27
- function copyDir(srcDir, destDir) {
28
- fs.mkdirSync(destDir, { recursive: true });
29
- for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
30
- const srcPath = path.join(srcDir, entry.name);
31
- const destPath = path.join(destDir, entry.name);
21
+ function copyDir(src, dest) {
22
+ fs.mkdirSync(dest, { recursive: true });
23
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
24
+ const srcPath = path.join(src, entry.name);
25
+ const destPath = path.join(dest, entry.name);
32
26
  if (entry.isDirectory()) {
33
27
  copyDir(srcPath, destPath);
34
28
  } else {
@@ -37,33 +31,85 @@ function copyDir(srcDir, destDir) {
37
31
  }
38
32
  }
39
33
 
40
- const isUpdate = fs.existsSync(path.join(dest, '.claude'));
41
- console.log(isUpdate ? 'Syncing spec-starter...\n' : 'Installing spec-starter...\n');
34
+ // Copy scaffold
35
+ for (const dir of SCAFFOLD_DIRS) {
36
+ const src = path.join(PKG_DIR, dir);
37
+ const dest = path.join(TARGET_DIR, dir);
38
+ if (fs.existsSync(src)) copyDir(src, dest);
39
+ }
42
40
 
43
- fs.mkdirSync(path.join(dest, '.claude'), { recursive: true });
41
+ for (const file of SCAFFOLD_FILES) {
42
+ const src = path.join(PKG_DIR, file);
43
+ const dest = path.join(TARGET_DIR, file);
44
+ if (fs.existsSync(src)) {
45
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
46
+ fs.copyFileSync(src, dest);
47
+ }
48
+ }
44
49
 
45
- for (const dir of engineDirs) {
46
- copyDir(path.join(src, dir), path.join(dest, dir));
47
- console.log(` ✓ ${dir}`);
50
+ // Version tracking
51
+ const VERSION_FILE = path.join(TARGET_DIR, '.claude', '.spec-starter-version');
52
+ const CLAUDE_MD = path.join(TARGET_DIR, 'CLAUDE.md');
53
+
54
+ function readInstalledVersion() {
55
+ try {
56
+ return JSON.parse(fs.readFileSync(VERSION_FILE, 'utf8')).version;
57
+ } catch {
58
+ return null;
59
+ }
48
60
  }
49
61
 
50
- for (const file of engineFiles) {
51
- fs.mkdirSync(path.dirname(path.join(dest, file)), { recursive: true });
52
- fs.copyFileSync(path.join(src, file), path.join(dest, file));
53
- console.log(` ✓ ${file}`);
62
+ function writeInstalledVersion() {
63
+ fs.writeFileSync(VERSION_FILE, JSON.stringify({ version: VERSION }, null, 2));
54
64
  }
55
65
 
56
- for (const [file, content] of seedFiles) {
57
- const destFile = path.join(dest, file);
58
- if (!fs.existsSync(destFile)) {
59
- fs.writeFileSync(destFile, content);
60
- console.log(` ✓ ${file} (created)`);
66
+ // Bootstrap CLAUDE.md for fresh installs
67
+ function writeBootstrapClaudeMd() {
68
+ const content = `<!-- spec-starter:bootstrap -->
69
+ Run the \`project-init\` skill now. Do not do anything else first.
70
+ <!-- /spec-starter:bootstrap -->
71
+ `;
72
+ fs.writeFileSync(CLAUDE_MD, content);
73
+ }
74
+
75
+ // Inject update notice into existing CLAUDE.md
76
+ const NOTICE_START = '<!-- spec-starter:notice -->';
77
+ const NOTICE_END = '<!-- /spec-starter:notice -->';
78
+
79
+ function injectUpdateNotice() {
80
+ const notice = `${NOTICE_START}
81
+ spec-starter was updated to v${VERSION}. Let the user know what changed, then remove this notice block from CLAUDE.md.
82
+ ${NOTICE_END}`;
83
+
84
+ const existing = fs.readFileSync(CLAUDE_MD, 'utf8');
85
+
86
+ if (existing.includes(NOTICE_START)) {
87
+ // Replace existing notice
88
+ const updated = existing.replace(
89
+ new RegExp(`${NOTICE_START}[\\s\\S]*?${NOTICE_END}`),
90
+ notice
91
+ );
92
+ fs.writeFileSync(CLAUDE_MD, updated);
61
93
  } else {
62
- console.log(` - ${file} (kept existing)`);
94
+ // Prepend notice
95
+ fs.writeFileSync(CLAUDE_MD, notice + '\n\n' + existing);
63
96
  }
64
97
  }
65
98
 
66
- console.log(isUpdate
67
- ? '\nDone. Engine files updated, project data untouched.'
68
- : '\nDone. Run /project-init in Claude Code to set up your project.'
69
- );
99
+ // Main
100
+ const installedVersion = readInstalledVersion();
101
+ const claudeMdExists = fs.existsSync(CLAUDE_MD);
102
+
103
+ if (!claudeMdExists) {
104
+ writeBootstrapClaudeMd();
105
+ console.log(`spec-starter v${VERSION} installed.`);
106
+ console.log('Open Claude Code — project-init will run automatically.');
107
+ } else if (installedVersion !== VERSION) {
108
+ injectUpdateNotice();
109
+ console.log(`spec-starter updated to v${VERSION}.`);
110
+ console.log('Claude will announce the update next time you open this project.');
111
+ } else {
112
+ console.log(`spec-starter v${VERSION} refreshed.`);
113
+ }
114
+
115
+ writeInstalledVersion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-starter",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Claude Code project template for structured feature development",
5
5
  "bin": {
6
6
  "spec-starter": "bin/index.js"