spec-starter 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/.claude/_templates/e2e-checklist.md +31 -7
- package/.claude/_templates/feature.md +4 -0
- package/.claude/commands/feature/blueprint.md +24 -1
- package/.claude/commands/feature/test.md +16 -5
- package/.claude/skills/playwright-test.md +112 -0
- package/.claude/skills/project-init.md +5 -1
- package/README.md +23 -8
- package/bin/index.js +83 -37
- package/package.json +1 -1
|
@@ -1,26 +1,50 @@
|
|
|
1
1
|
# <feature_title> — E2E Checklist
|
|
2
2
|
|
|
3
|
-
Generated after implementation.
|
|
3
|
+
Generated after implementation. UI scenarios with a URL will run automatically via Playwright MCP if available; others require manual confirmation.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Happy Path
|
|
8
8
|
|
|
9
|
-
- [ ]
|
|
10
|
-
-
|
|
9
|
+
- [ ] **<Scenario 1 title>**
|
|
10
|
+
- **URL:** `/<path>`
|
|
11
|
+
- **Steps:**
|
|
12
|
+
1. <action using visible label or element description>
|
|
13
|
+
2. <action>
|
|
14
|
+
- **Expected:** <what should be visible or true when done>
|
|
15
|
+
|
|
16
|
+
- [ ] **<Scenario 2 title>**
|
|
17
|
+
- **URL:** `/<path>`
|
|
18
|
+
- **Steps:**
|
|
19
|
+
1. <action>
|
|
20
|
+
- **Expected:** <outcome>
|
|
11
21
|
|
|
12
22
|
## Edge Cases
|
|
13
23
|
|
|
14
|
-
- [ ]
|
|
15
|
-
-
|
|
24
|
+
- [ ] **<Edge case 1 title>**
|
|
25
|
+
- **URL:** `/<path>`
|
|
26
|
+
- **Steps:**
|
|
27
|
+
1. <how to trigger the edge case>
|
|
28
|
+
- **Expected:** <what the user should see>
|
|
29
|
+
|
|
30
|
+
- [ ] **<Non-browser check title>**
|
|
31
|
+
- <Describe what to run or check — no URL needed for non-browser scenarios>
|
|
16
32
|
|
|
17
33
|
## Error States
|
|
18
34
|
|
|
19
|
-
- [ ]
|
|
35
|
+
- [ ] **<Error scenario title>**
|
|
36
|
+
- **URL:** `/<path>`
|
|
37
|
+
- **Steps:**
|
|
38
|
+
1. <how to trigger the error>
|
|
39
|
+
- **Expected:** <error message or fallback the user should see>
|
|
20
40
|
|
|
21
41
|
## Integration Points
|
|
22
42
|
|
|
23
|
-
- [ ]
|
|
43
|
+
- [ ] **<Cross-feature or external dependency check>**
|
|
44
|
+
- **URL:** `/<path>`
|
|
45
|
+
- **Steps:**
|
|
46
|
+
1. <check to perform>
|
|
47
|
+
- **Expected:** <expected integration behavior>
|
|
24
48
|
|
|
25
49
|
---
|
|
26
50
|
|
|
@@ -106,10 +106,33 @@ In `1-feature.md`, change `- [o] Blueprint` to `- [x] Blueprint`.
|
|
|
106
106
|
|
|
107
107
|
**State update:** Do this immediately after blueprint.md is written.
|
|
108
108
|
|
|
109
|
+
### Step 6: Generate Mermaid diagram and update 1-feature.md
|
|
110
|
+
|
|
111
|
+
Based on the blueprint you just wrote, generate a Mermaid architecture diagram that shows the key components or layers and data flow between them. Use `graph TD` orientation (top-down) unless the feature is a linear pipeline, in which case `graph LR` (left-right) is clearer.
|
|
112
|
+
|
|
113
|
+
Guidelines:
|
|
114
|
+
- 5 to 12 nodes is ideal — keep it concise
|
|
115
|
+
- Label edges with the action or data being passed: `-->|user input|`, `-->|SQL query|`, etc.
|
|
116
|
+
- Use subgraphs only if there are clearly distinct tiers (e.g. Frontend / Backend)
|
|
117
|
+
- No commentary inside the `## Diagram` section — only the fenced code block
|
|
118
|
+
|
|
119
|
+
Open `1-feature.md` for this feature. Find the `## Diagram` section. If the section is not present (feature created before this template update), append the `## Diagram` section to the end of the file instead. Replace from `## Diagram` to the end of the file with:
|
|
120
|
+
|
|
121
|
+
````markdown
|
|
122
|
+
## Diagram
|
|
123
|
+
|
|
124
|
+
```mermaid
|
|
125
|
+
<your generated diagram here>
|
|
126
|
+
```
|
|
127
|
+
````
|
|
128
|
+
|
|
129
|
+
Use the Edit tool to make this replacement.
|
|
130
|
+
|
|
109
131
|
Output:
|
|
110
132
|
|
|
111
133
|
```
|
|
112
|
-
Blueprint written:
|
|
134
|
+
Blueprint written: .claude/_features/$ARGUMENTS/3-blueprint.md
|
|
135
|
+
Diagram updated: .claude/_features/$ARGUMENTS/1-feature.md (## Diagram)
|
|
113
136
|
|
|
114
137
|
Progress: [x] Brief [x] Blueprint [ ] Implement [ ] Review [ ] Done
|
|
115
138
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run through the e2e checklist for a completed feature
|
|
3
3
|
argument-hint: "<MM.DD-slug>"
|
|
4
|
-
allowed-tools: Read, Edit, Glob, Bash
|
|
4
|
+
allowed-tools: Read, Edit, Glob, Bash, mcp__playwright__*
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
Walk through the e2e checklist for a feature interactively. The feature must be marked `[x] Done` before testing is allowed.
|
|
@@ -89,6 +89,11 @@ Then stop.
|
|
|
89
89
|
|
|
90
90
|
**Read shared testing instructions:** Check if `.claude/testing.md` exists. If it does, read it and use it throughout — it contains app-specific context like how to start the app, base URLs, test accounts, browser/device preferences, and any other setup needed to run scenarios correctly.
|
|
91
91
|
|
|
92
|
+
**Playwright check:** Use the Skill tool to invoke the `playwright-test` skill. It will check whether Playwright MCP tools are available and report back.
|
|
93
|
+
|
|
94
|
+
- If available → use Playwright automatically for all UI scenarios (those with a **URL** field). Note this as `playwright_available = true`.
|
|
95
|
+
- If not available → fall back to manual for all UI scenarios. Note this as `playwright_available = false`.
|
|
96
|
+
|
|
92
97
|
### Step 2: Present the checklist and run scenarios
|
|
93
98
|
|
|
94
99
|
Output a summary of what you're about to test:
|
|
@@ -104,10 +109,16 @@ Then work through each section of the checklist in order:
|
|
|
104
109
|
|
|
105
110
|
For each unchecked scenario (`- [ ]`):
|
|
106
111
|
1. Present the scenario clearly — what to do and what to expect
|
|
107
|
-
2. For
|
|
108
|
-
3. For UI
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
2. For CLI/script scenarios: run with Bash and report the result
|
|
113
|
+
3. For UI scenarios (those with **URL**, **Steps**, and **Expected** fields):
|
|
114
|
+
- If `playwright_available = true`: run the scenario automatically using the `playwright-test` skill.
|
|
115
|
+
- PASS → mark the item `[x]`
|
|
116
|
+
- FAIL → mark the item `[!]`, note what failed, continue
|
|
117
|
+
- `[!] ERROR` → mark the item `[!]`, record the error evidence, continue
|
|
118
|
+
- If `playwright_available = false`: describe exactly what to check and ask the user: `Pass or fail?`
|
|
119
|
+
4. For manual scenarios (no URL field): describe exactly what to check and ask the user: `Pass or fail?`
|
|
120
|
+
5. If the user confirms pass: mark the item `- [x]` in `e2e-checklist.md` using the Edit tool
|
|
121
|
+
6. If the user says fail: mark the item `- [!]` in `e2e-checklist.md`, note what failed, and continue to the next scenario
|
|
111
122
|
|
|
112
123
|
Skip scenarios already marked `[x]` (previously passed) — report them as already passing.
|
|
113
124
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-test
|
|
3
|
+
description: Run UI scenarios automatically using Playwright MCP browser automation tools.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Playwright Test
|
|
7
|
+
|
|
8
|
+
Automate UI e2e scenario execution using Playwright MCP browser tools.
|
|
9
|
+
|
|
10
|
+
## Availability check
|
|
11
|
+
|
|
12
|
+
Before using this skill, confirm that Playwright MCP tools are present in your tool list (look for tools prefixed with `mcp__playwright__` or similar browser automation tools). If they are available, proceed with this skill. If they are not available, stop immediately and report to the caller: "Playwright MCP not available." Do not execute any scenarios. The caller is responsible for handling unavailability (typically by asking the user to confirm each scenario manually).
|
|
13
|
+
|
|
14
|
+
## Scenario structure
|
|
15
|
+
|
|
16
|
+
Each UI scenario in `4-e2e-checklist.md` follows this format:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
- [ ] **<Scenario title>**
|
|
20
|
+
- **URL:** `/<path>`
|
|
21
|
+
- **Steps:** numbered list of actions
|
|
22
|
+
- **Expected:** what should be visible/true when done
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Scenarios that have a URL, Steps, and Expected field are in scope for this skill. Scenarios without a URL (CLI checks, API checks, or manual-only verifications) are out of scope — the caller handles those via Bash or manual confirmation.
|
|
26
|
+
|
|
27
|
+
## Building full URLs
|
|
28
|
+
|
|
29
|
+
The `## Base URL` section in `.claude/testing.md` provides the origin. If a scenario URL is relative (starts with `/`), prepend the base URL.
|
|
30
|
+
|
|
31
|
+
Example: base URL `http://localhost:3000` + scenario URL `/dashboard` = `http://localhost:3000/dashboard`.
|
|
32
|
+
|
|
33
|
+
If `testing.md` has no base URL, ask the user to provide it before proceeding.
|
|
34
|
+
|
|
35
|
+
## Test accounts
|
|
36
|
+
|
|
37
|
+
If `.claude/testing.md` defines test credentials under `## Test accounts`, use them for any login flow before navigating to a protected route. Log in once at the start of the test run and reuse the session for subsequent scenarios where possible.
|
|
38
|
+
|
|
39
|
+
## Running a scenario
|
|
40
|
+
|
|
41
|
+
For each in-scope scenario:
|
|
42
|
+
|
|
43
|
+
### 1. Navigate
|
|
44
|
+
|
|
45
|
+
Navigate to the full URL using the Playwright navigation tool.
|
|
46
|
+
|
|
47
|
+
### 2. Execute steps
|
|
48
|
+
|
|
49
|
+
Work through the numbered steps in order:
|
|
50
|
+
|
|
51
|
+
- **Clicks:** locate the element by its visible label, text, or ARIA role — not by CSS selector. Then click it.
|
|
52
|
+
- **Form inputs:** use fill tools to enter values into fields, identified by their visible label or placeholder text.
|
|
53
|
+
- **Keyboard actions** (Enter, Tab, Escape, etc.): use key press tools.
|
|
54
|
+
|
|
55
|
+
After all steps are complete, take a screenshot to capture the final state.
|
|
56
|
+
|
|
57
|
+
### 3. Verify expected outcome
|
|
58
|
+
|
|
59
|
+
Use page content reading tools (accessibility tree or page text) to check whether the expected text or elements are present.
|
|
60
|
+
|
|
61
|
+
- If the expected outcome is present: **PASS**.
|
|
62
|
+
- If the expected outcome is absent or an error is visible: **FAIL**.
|
|
63
|
+
|
|
64
|
+
## Result reporting format
|
|
65
|
+
|
|
66
|
+
After each scenario, report the result in this format:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Scenario: <title>
|
|
70
|
+
Result: PASS
|
|
71
|
+
Evidence: <what was observed>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
or
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Scenario: <title>
|
|
78
|
+
Result: FAIL
|
|
79
|
+
Evidence: <what was observed>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Include specific observed text, element presence, or error messages as evidence. Do not report vague evidence like "page loaded correctly."
|
|
83
|
+
|
|
84
|
+
This skill reports results to the conversation only. It does not modify `4-e2e-checklist.md`. The caller is responsible for marking scenarios `[x]` (pass) or `[!]` (fail) based on this skill's reported outcomes.
|
|
85
|
+
|
|
86
|
+
## Error handling
|
|
87
|
+
|
|
88
|
+
If navigation fails or an element cannot be found, try once more using an alternate approach (e.g. a different locator strategy or a short wait before retrying).
|
|
89
|
+
|
|
90
|
+
If the scenario still cannot be completed after the second attempt, mark it with `[!]`, report the specific error and evidence, and continue to the next scenario. Never hang or retry infinitely.
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
Scenario: <title>
|
|
94
|
+
Result: [!] ERROR
|
|
95
|
+
Evidence: <specific error message or what was observed>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Output summary
|
|
99
|
+
|
|
100
|
+
After all scenarios are complete, output a summary table:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
## E2E Results
|
|
104
|
+
|
|
105
|
+
| Scenario | Result |
|
|
106
|
+
|----------|--------|
|
|
107
|
+
| <title> | PASS |
|
|
108
|
+
| <title> | FAIL |
|
|
109
|
+
| <title> | [!] ERROR |
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Then list any FAIL or ERROR scenarios with their full evidence for follow-up.
|
|
@@ -34,6 +34,7 @@ Ask one question about manual/e2e testing setup:
|
|
|
34
34
|
- Are there test accounts or credentials needed?
|
|
35
35
|
- Any browser or device requirements?
|
|
36
36
|
- Anything else needed to run through features manually?
|
|
37
|
+
- Is this a web app? If yes, what is the local dev base URL? (e.g. `http://localhost:3000`)
|
|
37
38
|
|
|
38
39
|
### 3. Update CLAUDE.md
|
|
39
40
|
|
|
@@ -57,7 +58,10 @@ Write `.claude/testing.md` with the manual testing setup gathered in Step 2. Thi
|
|
|
57
58
|
# Testing
|
|
58
59
|
|
|
59
60
|
## How to start the app
|
|
60
|
-
<dev server command
|
|
61
|
+
<dev server command>
|
|
62
|
+
|
|
63
|
+
## Base URL
|
|
64
|
+
<base URL for the running app, e.g. http://localhost:3000 — or "N/A" if not a web app>
|
|
61
65
|
|
|
62
66
|
## Test accounts
|
|
63
67
|
<credentials or "none required">
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# spec-starter
|
|
2
2
|
|
|
3
|
-
A Claude Code project template for structured feature development.
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
|
7
|
-
const
|
|
6
|
+
const PKG_DIR = path.join(__dirname, '..');
|
|
7
|
+
const TARGET_DIR = process.cwd();
|
|
8
|
+
const VERSION = require('../package.json').version;
|
|
8
9
|
|
|
9
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
['.claude/tasks.md', ''],
|
|
17
|
+
const SCAFFOLD_FILES = [
|
|
18
|
+
'.claude/settings.json',
|
|
23
19
|
];
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
51
|
-
fs.
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
94
|
+
// Prepend notice
|
|
95
|
+
fs.writeFileSync(CLAUDE_MD, notice + '\n\n' + existing);
|
|
63
96
|
}
|
|
64
97
|
}
|
|
65
98
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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();
|