@polymorphism-tech/morph-spec 4.8.1 → 4.8.4

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 (44) hide show
  1. package/README.md +2 -2
  2. package/claude-plugin.json +1 -1
  3. package/docs/CHEATSHEET.md +1 -1
  4. package/docs/QUICKSTART.md +1 -1
  5. package/framework/hooks/dev/guard-version-numbers.js +1 -1
  6. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +1 -1
  7. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +1 -1
  8. package/framework/skills/level-1-workflows/phase-design/SKILL.md +1 -1
  9. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +1 -1
  10. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +1 -1
  11. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +1 -1
  12. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +1 -1
  13. package/package.json +4 -4
  14. package/.morph/analytics/threads-log.jsonl +0 -54
  15. package/.morph/state.json +0 -198
  16. package/docs/ARCHITECTURE.md +0 -328
  17. package/docs/COMMAND-FLOWS.md +0 -398
  18. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +0 -514
  19. package/docs/plans/2026-02-22-claude-settings.md +0 -517
  20. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +0 -730
  21. package/docs/plans/2026-02-22-morph-spec-next.md +0 -480
  22. package/docs/plans/2026-02-22-native-alignment-design.md +0 -201
  23. package/docs/plans/2026-02-22-native-alignment-impl.md +0 -927
  24. package/docs/plans/2026-02-22-native-enrichment-design.md +0 -246
  25. package/docs/plans/2026-02-22-native-enrichment.md +0 -737
  26. package/docs/plans/2026-02-23-ddd-architecture-refactor.md +0 -1155
  27. package/docs/plans/2026-02-23-ddd-nextsteps.md +0 -684
  28. package/docs/plans/2026-02-23-infra-architect-refactor.md +0 -439
  29. package/docs/plans/2026-02-23-nextjs-code-review-design.md +0 -157
  30. package/docs/plans/2026-02-23-nextjs-code-review-impl.md +0 -1256
  31. package/docs/plans/2026-02-23-nextjs-standards-design.md +0 -150
  32. package/docs/plans/2026-02-23-nextjs-standards-impl.md +0 -1848
  33. package/docs/plans/2026-02-24-cli-radical-simplification.md +0 -592
  34. package/docs/plans/2026-02-24-framework-failure-points.md +0 -125
  35. package/docs/plans/2026-02-24-morph-init-design.md +0 -337
  36. package/docs/plans/2026-02-24-morph-init-impl.md +0 -1269
  37. package/docs/plans/2026-02-24-tutorial-command-design.md +0 -71
  38. package/docs/plans/2026-02-24-tutorial-command.md +0 -298
  39. package/scripts/bump-version.js +0 -248
  40. package/scripts/generate-refs.js +0 -336
  41. package/scripts/generate-standards-registry.js +0 -44
  42. package/scripts/install-dev-hooks.js +0 -138
  43. package/scripts/scan-nextjs.mjs +0 -169
  44. package/scripts/validate-real.mjs +0 -255
@@ -1,71 +0,0 @@
1
- # Design: `morph-spec tutorial` Command
2
-
3
- **Status:** COMPLETE (see implementation plan)
4
-
5
- **Date:** 2026-02-24
6
-
7
- ---
8
-
9
- ## Problem
10
-
11
- After `morph-spec init`, first-time users see a suggestion to run `morph-spec tutorial`, but the command doesn't exist. New users also lack a quick way to understand the spec-first workflow and its phase pipeline.
12
-
13
- ---
14
-
15
- ## Goal
16
-
17
- A self-contained CLI command that teaches the MORPH-SPEC mental model: the phase pipeline, what each phase produces, and how to trigger each phase. Pure stdout, no side effects.
18
-
19
- ---
20
-
21
- ## Approach: Workflow Walkthrough
22
-
23
- A static, colored terminal output that explains the full pipeline top-to-bottom. No arguments, no options, no network calls, no file I/O.
24
-
25
- Chosen over:
26
- - **Interactive mode** — risks accidentally modifying project state
27
- - **Quick reference** — duplicates `--help` with little added value
28
-
29
- ---
30
-
31
- ## Output Structure
32
-
33
- 1. **Header** — title + one-sentence philosophy
34
- 2. **Pipeline diagram** — ASCII showing phase sequence with optional phases bracketed
35
- 3. **Per-phase block** — for each of the 8 phases:
36
- - Phase name + number
37
- - What it does (1 sentence)
38
- - What it produces (output files)
39
- - How to trigger it (CLI command or `/slash-command` in Claude Code)
40
- 4. **Getting Started** — 3-step CTA ending with `morph-spec doctor` tip
41
-
42
- ---
43
-
44
- ## Implementation
45
-
46
- | Item | Detail |
47
- |------|--------|
48
- | File | `src/commands/project/tutorial.js` |
49
- | Export | `tutorialCommand` |
50
- | Registration (index) | `src/commands/project/index.js` |
51
- | Registration (bin) | `bin/morph-spec.js` |
52
- | Dependencies | `chalk` (already installed) |
53
- | Side effects | None — pure stdout |
54
- | Size | ~100 lines |
55
-
56
- Also: revert `init.js:518` back to `morph-spec tutorial` (the original intent).
57
-
58
- ---
59
-
60
- ## Phases Covered
61
-
62
- | Phase | Trigger |
63
- |-------|---------|
64
- | 0 · Proposal | `/morph-proposal <feature>` |
65
- | 1 · Setup | auto-triggered inside `/morph-proposal` |
66
- | 1.5 · UI/UX (optional) | `/phase-uiux <feature>` |
67
- | 2 · Design | `/phase-design <feature>` |
68
- | 3 · Clarify | `/phase-clarify <feature>` |
69
- | 4 · Tasks | auto-generated, or `/phase-tasks <feature>` |
70
- | 5 · Implement | `/morph-apply <feature>` |
71
- | 6 · Sync (optional) | `morph-spec sync <feature>` |
@@ -1,298 +0,0 @@
1
- # Tutorial Command Implementation Plan
2
-
3
- **Status:** COMPLETE
4
-
5
- > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
6
-
7
- **Goal:** Add a `morph-spec tutorial` command that prints the full MORPH-SPEC phase pipeline and getting-started steps to stdout.
8
-
9
- **Architecture:** Single new file `src/commands/project/tutorial.js` exporting `tutorialCommand`. Registered in `bin/morph-spec.js` and re-exported from `src/commands/project/index.js`. Pure stdout using `chalk` — no file I/O, no network, no side effects. Also reverts `init.js` to suggest `morph-spec tutorial` (instead of the broken replacement made in a prior session).
10
-
11
- **Tech Stack:** Node.js ESM, chalk (already installed), node:test + node:assert for tests.
12
-
13
- ---
14
-
15
- ### Task 1: Create `tutorial.js`
16
-
17
- **Files:**
18
- - Create: `src/commands/project/tutorial.js`
19
- - Test: `test/commands/tutorial.test.js`
20
-
21
- **Step 1: Write the failing test**
22
-
23
- Create `test/commands/tutorial.test.js`:
24
-
25
- ```js
26
- import { test, describe } from 'node:test';
27
- import assert from 'node:assert/strict';
28
- import { tutorialCommand } from '../../src/commands/project/tutorial.js';
29
-
30
- describe('tutorialCommand', () => {
31
- test('tutorialCommand is a function', () => {
32
- assert.equal(typeof tutorialCommand, 'function');
33
- });
34
-
35
- test('tutorialCommand runs without throwing', () => {
36
- assert.doesNotThrow(() => tutorialCommand());
37
- });
38
-
39
- test('tutorialCommand returns undefined (pure side-effect)', () => {
40
- const result = tutorialCommand();
41
- assert.equal(result, undefined);
42
- });
43
- });
44
- ```
45
-
46
- **Step 2: Run test to verify it fails**
47
-
48
- ```bash
49
- node --test test/commands/tutorial.test.js
50
- ```
51
- Expected: FAIL — "Cannot find module"
52
-
53
- **Step 3: Write the implementation**
54
-
55
- Create `src/commands/project/tutorial.js`:
56
-
57
- ```js
58
- /**
59
- * Tutorial Command
60
- *
61
- * Prints the MORPH-SPEC workflow pipeline and getting-started steps.
62
- * Pure stdout — no file I/O, no network, no side effects.
63
- *
64
- * Usage: morph-spec tutorial
65
- */
66
-
67
- import chalk from 'chalk';
68
-
69
- const PHASES = [
70
- {
71
- label: 'FASE 0 · PROPOSAL',
72
- what: 'Captures user story + acceptance criteria.',
73
- produces: '0-proposal/proposal.md',
74
- how: '/morph-proposal <feature> (in Claude Code)',
75
- },
76
- {
77
- label: 'FASE 1 · SETUP',
78
- what: 'Detects stack, activates agents, confirms environment.',
79
- produces: '.morph/state.json initialized',
80
- how: 'auto-triggered inside /morph-proposal',
81
- },
82
- {
83
- label: 'FASE 1.5 · UI/UX',
84
- what: 'Design system, mockups, component specs, user flows.',
85
- produces: '2-ui/{design-system,mockups,components,flows}.md',
86
- how: '/phase-uiux <feature> (in Claude Code)',
87
- optional: true,
88
- },
89
- {
90
- label: 'FASE 2 · DESIGN',
91
- what: 'Technical spec + C# contracts + architecture decisions.',
92
- produces: '1-design/{spec.md, contracts-level{N}.cs, decisions.md}',
93
- how: '/phase-design <feature> (in Claude Code)',
94
- },
95
- {
96
- label: 'FASE 3 · CLARIFY',
97
- what: 'Reviews spec for ambiguities, adds edge cases.',
98
- produces: '1-design/spec.md (updated with clarifications)',
99
- how: '/phase-clarify <feature> (in Claude Code)',
100
- },
101
- {
102
- label: 'FASE 4 · TASKS',
103
- what: 'Atomic task breakdown, DDD-aware.',
104
- produces: '3-tasks/tasks.md',
105
- how: 'auto-generated during /morph-proposal, or /phase-tasks <feature>',
106
- },
107
- {
108
- label: 'FASE 5 · IMPLEMENT',
109
- what: 'Code implementation with checkpoints every 3 tasks.',
110
- produces: '4-implement/recap.md + source code',
111
- how: '/morph-apply <feature> (in Claude Code)',
112
- },
113
- {
114
- label: 'FASE 6 · SYNC',
115
- what: 'Syncs decisions back to project standards.',
116
- produces: '.morph/framework/standards/ (updated)',
117
- how: 'morph-spec sync <feature>',
118
- optional: true,
119
- },
120
- ];
121
-
122
- const SEP = chalk.dim('─'.repeat(58));
123
-
124
- export function tutorialCommand() {
125
- console.log('');
126
- console.log(chalk.cyan.bold(' MORPH-SPEC Workflow Tutorial'));
127
- console.log(SEP);
128
- console.log('');
129
- console.log(
130
- chalk.white(
131
- ' MORPH-SPEC is spec-first: every feature goes through phases\n' +
132
- ' before any code is written. Each phase produces structured\n' +
133
- ' outputs that feed the next.'
134
- )
135
- );
136
- console.log('');
137
- console.log(SEP);
138
- console.log(chalk.cyan.bold(' PIPELINE'));
139
- console.log(SEP);
140
- console.log('');
141
- console.log(
142
- chalk.white(' proposal → setup → ') +
143
- chalk.dim('[uiux]') +
144
- chalk.white(' → design → clarify → tasks → implement → ') +
145
- chalk.dim('[sync]')
146
- );
147
- console.log(chalk.dim(' (phases in brackets are optional)'));
148
- console.log('');
149
-
150
- for (const phase of PHASES) {
151
- console.log(SEP);
152
- const label = phase.optional
153
- ? chalk.cyan.bold(` ${phase.label}`) + chalk.dim(' [optional]')
154
- : chalk.cyan.bold(` ${phase.label}`);
155
- console.log(label);
156
- console.log(chalk.white(` What: ${phase.what}`));
157
- console.log(chalk.dim(` Produces: ${phase.produces}`));
158
- console.log(chalk.green(` How: ${phase.how}`));
159
- console.log('');
160
- }
161
-
162
- console.log(SEP);
163
- console.log(chalk.cyan.bold(' GETTING STARTED'));
164
- console.log(SEP);
165
- console.log('');
166
- console.log(chalk.white(' 1. Open Claude Code in your project'));
167
- console.log(chalk.white(' 2. Run: ') + chalk.green('/morph-proposal <your-feature-name>'));
168
- console.log(chalk.white(' 3. Answer the questions — morph-spec handles the rest'));
169
- console.log('');
170
- console.log(chalk.dim(' Tip: run `morph-spec doctor` to verify your installation first.'));
171
- console.log('');
172
- }
173
- ```
174
-
175
- **Step 4: Run test to verify it passes**
176
-
177
- ```bash
178
- node --test test/commands/tutorial.test.js
179
- ```
180
- Expected: 3 passing
181
-
182
- **Step 5: Commit**
183
-
184
- ```bash
185
- git add src/commands/project/tutorial.js test/commands/tutorial.test.js
186
- git commit -m "feat(tutorial): add tutorial command with phase pipeline walkthrough"
187
- ```
188
-
189
- ---
190
-
191
- ### Task 2: Wire into project index and bin
192
-
193
- **Files:**
194
- - Modify: `src/commands/project/index.js`
195
- - Modify: `bin/morph-spec.js`
196
-
197
- **Step 1: Add export to `src/commands/project/index.js`**
198
-
199
- After the existing `export { updateCommand }` line, add:
200
-
201
- ```js
202
- export { tutorialCommand } from './tutorial.js';
203
- ```
204
-
205
- **Step 2: Add import to `bin/morph-spec.js`**
206
-
207
- After the `import { doctorCommand }` line (line ~13), add:
208
-
209
- ```js
210
- import { tutorialCommand } from '../src/commands/project/tutorial.js';
211
- ```
212
-
213
- **Step 3: Register the command in `bin/morph-spec.js`**
214
-
215
- After the `doctor` command block (~line 128), add:
216
-
217
- ```js
218
- program
219
- .command('tutorial')
220
- .description('Learn the MORPH-SPEC workflow — phase pipeline and getting started')
221
- .action(tutorialCommand);
222
- ```
223
-
224
- **Step 4: Smoke-test the CLI**
225
-
226
- ```bash
227
- node bin/morph-spec.js tutorial
228
- ```
229
- Expected: Full pipeline output printed to terminal without errors.
230
-
231
- ```bash
232
- node bin/morph-spec.js --help | grep tutorial
233
- ```
234
- Expected: `tutorial Learn the MORPH-SPEC workflow...`
235
-
236
- **Step 5: Commit**
237
-
238
- ```bash
239
- git add src/commands/project/index.js bin/morph-spec.js
240
- git commit -m "feat(tutorial): register tutorial command in CLI"
241
- ```
242
-
243
- ---
244
-
245
- ### Task 3: Restore the `init.js` suggestion message
246
-
247
- **Files:**
248
- - Modify: `src/commands/project/init.js:518`
249
-
250
- **Step 1: Revert the message**
251
-
252
- Find line 518 in `src/commands/project/init.js`. Replace:
253
-
254
- ```js
255
- logger.info('First time using morph-spec? Run `morph-spec doctor` to verify your setup, then `/morph-proposal <feature>` to start.');
256
- ```
257
-
258
- With:
259
-
260
- ```js
261
- logger.info('First time using morph-spec? Run `morph-spec tutorial` to get started.');
262
- ```
263
-
264
- **Step 2: Verify the change**
265
-
266
- ```bash
267
- grep -n "tutorial" src/commands/project/init.js
268
- ```
269
- Expected: line 518 shows `morph-spec tutorial`
270
-
271
- **Step 3: Commit**
272
-
273
- ```bash
274
- git add src/commands/project/init.js
275
- git commit -m "fix(init): restore morph-spec tutorial suggestion after command now exists"
276
- ```
277
-
278
- ---
279
-
280
- ### Task 4: Run full test suite
281
-
282
- **Step 1: Run all tests**
283
-
284
- ```bash
285
- node --test
286
- ```
287
- Expected: all existing tests pass + 3 new tutorial tests pass, 0 failures.
288
-
289
- **Step 2: If any failures, fix before continuing**
290
-
291
- Do not proceed until `node --test` shows 0 failures.
292
-
293
- **Step 3: Commit if any fixes were needed**
294
-
295
- ```bash
296
- git add -p
297
- git commit -m "fix(tutorial): address test suite issues"
298
- ```
@@ -1,248 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Version Bump Script for MORPH-SPEC Framework
5
- *
6
- * Updates the version number across all files that contain it.
7
- * Single source of truth: package.json
8
- *
9
- * Usage:
10
- * node scripts/bump-version.js patch # 4.8.0 → 4.8.1
11
- * node scripts/bump-version.js minor # 4.8.0 → 4.9.0
12
- * node scripts/bump-version.js major # 4.8.0 → 5.0.0
13
- * node scripts/bump-version.js 4.9.0 # explicit version
14
- * node scripts/bump-version.js --dry-run patch # preview changes
15
- *
16
- * npm script:
17
- * npm run version:bump -- patch
18
- * npm run version:bump -- --dry-run minor
19
- */
20
-
21
- import { readFileSync, writeFileSync, existsSync } from 'fs';
22
- import { join, dirname } from 'path';
23
- import { fileURLToPath } from 'url';
24
- import { glob } from 'glob';
25
-
26
- // ── Exported helpers (used by tests) ─────────────────────────────────
27
-
28
- /**
29
- * Compute a new version from a current version and bump type.
30
- * @param {string} current - Current semver (e.g. "4.8.0")
31
- * @param {string} type - "patch", "minor", "major", or explicit "X.Y.Z"
32
- * @returns {string} New version string
33
- */
34
- export function bumpVersion(current, type) {
35
- const [major, minor, patch] = current.split('.').map(Number);
36
- switch (type) {
37
- case 'major': return `${major + 1}.0.0`;
38
- case 'minor': return `${major}.${minor + 1}.0`;
39
- case 'patch': return `${major}.${minor}.${patch + 1}`;
40
- default: {
41
- if (/^\d+\.\d+\.\d+$/.test(type)) return type;
42
- throw new Error(`Invalid version or bump type: "${type}". Expected: patch, minor, major, or X.Y.Z`);
43
- }
44
- }
45
- }
46
-
47
- function escapeRegex(str) {
48
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
49
- }
50
-
51
- /**
52
- * Build the list of file updates for a version bump.
53
- * @param {string} rootDir - Project root directory
54
- * @param {string} currentVersion - Current version string
55
- * @param {string} newVersion - Target version string
56
- * @returns {Array<{file: string, replacements: Array<{pattern: RegExp, replacement: string}>}>}
57
- */
58
- export function buildFileUpdates(rootDir, currentVersion, newVersion) {
59
- const cv = escapeRegex(currentVersion);
60
-
61
- const updates = [
62
- {
63
- file: 'package.json',
64
- replacements: [
65
- { pattern: new RegExp(`"version":\\s*"${cv}"`), replacement: `"version": "${newVersion}"` },
66
- ],
67
- },
68
- {
69
- file: 'claude-plugin.json',
70
- replacements: [
71
- { pattern: new RegExp(`"version":\\s*"${cv}"`), replacement: `"version": "${newVersion}"` },
72
- ],
73
- },
74
- {
75
- file: 'README.md',
76
- replacements: [
77
- { pattern: new RegExp(`\\*\\*Version:\\*\\*\\s*${cv}`), replacement: `**Version:** ${newVersion}` },
78
- { pattern: new RegExp(`morph-spec v${cv}`), replacement: `morph-spec v${newVersion}` },
79
- ],
80
- },
81
- {
82
- file: 'docs/ARCHITECTURE.md',
83
- replacements: [
84
- { pattern: new RegExp(`morph-spec v${cv}`, 'g'), replacement: `morph-spec v${newVersion}` },
85
- ],
86
- },
87
- {
88
- file: 'docs/CHEATSHEET.md',
89
- replacements: [
90
- { pattern: new RegExp(`morph-spec v${cv}`), replacement: `morph-spec v${newVersion}` },
91
- ],
92
- },
93
- {
94
- file: 'docs/COMMAND-FLOWS.md',
95
- replacements: [
96
- { pattern: new RegExp(`Version:\\s*${cv}`), replacement: `Version: ${newVersion}` },
97
- { pattern: new RegExp(`morph-spec v${cv}`), replacement: `morph-spec v${newVersion}` },
98
- ],
99
- },
100
- {
101
- file: 'docs/QUICKSTART.md',
102
- replacements: [
103
- { pattern: new RegExp(`morph-spec v${cv}`), replacement: `morph-spec v${newVersion}` },
104
- ],
105
- },
106
- {
107
- file: 'framework/hooks/dev/guard-version-numbers.js',
108
- replacements: [
109
- { pattern: new RegExp(`MORPH-SPEC v${cv}`), replacement: `MORPH-SPEC v${newVersion}` },
110
- ],
111
- },
112
- ];
113
-
114
- // Skill files (cliVersion in YAML frontmatter)
115
- const skillFiles = glob.sync('framework/skills/level-1-workflows/*/SKILL.md', { cwd: rootDir });
116
- for (const sf of skillFiles) {
117
- updates.push({
118
- file: sf,
119
- replacements: [
120
- { pattern: new RegExp(`cliVersion:\\s*"${cv}"`), replacement: `cliVersion: "${newVersion}"` },
121
- ],
122
- });
123
- }
124
-
125
- return updates;
126
- }
127
-
128
- /**
129
- * Apply version updates to files on disk.
130
- * @param {string} rootDir - Project root directory
131
- * @param {Array} fileUpdates - From buildFileUpdates()
132
- * @param {{ dryRun?: boolean }} options
133
- * @returns {{ updatedCount: number, replacementCount: number, warnings: string[] }}
134
- */
135
- export function applyUpdates(rootDir, fileUpdates, { dryRun = false } = {}) {
136
- let updatedCount = 0;
137
- let replacementCount = 0;
138
- const warnings = [];
139
-
140
- for (const { file, replacements } of fileUpdates) {
141
- const fullPath = join(rootDir, file);
142
-
143
- if (!existsSync(fullPath)) {
144
- warnings.push(`SKIP ${file} (file not found)`);
145
- continue;
146
- }
147
-
148
- let content = readFileSync(fullPath, 'utf-8');
149
- let fileChanged = false;
150
-
151
- for (const { pattern, replacement } of replacements) {
152
- if (pattern.test(content)) {
153
- content = content.replace(pattern, replacement);
154
- fileChanged = true;
155
- replacementCount++;
156
- }
157
- }
158
-
159
- if (fileChanged) {
160
- if (!dryRun) {
161
- writeFileSync(fullPath, content, 'utf-8');
162
- }
163
- updatedCount++;
164
- } else {
165
- warnings.push(`${file} (no matches — pattern may have changed)`);
166
- }
167
- }
168
-
169
- return { updatedCount, replacementCount, warnings };
170
- }
171
-
172
- // ── CLI entry point ──────────────────────────────────────────────────
173
-
174
- const __dirname = dirname(fileURLToPath(import.meta.url));
175
- const isMainModule = process.argv[1]?.replace(/\\/g, '/').endsWith('scripts/bump-version.js');
176
-
177
- if (isMainModule) {
178
- const ROOT = join(__dirname, '..');
179
- const args = process.argv.slice(2);
180
- const dryRun = args.includes('--dry-run');
181
- const filtered = args.filter(a => a !== '--dry-run');
182
-
183
- if (filtered.length === 0) {
184
- console.error(
185
- 'Usage: node scripts/bump-version.js [--dry-run] <patch|minor|major|X.Y.Z>'
186
- );
187
- process.exit(1);
188
- }
189
-
190
- const input = filtered[0];
191
- const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
192
- const currentVersion = pkg.version;
193
-
194
- let newVersion;
195
- try {
196
- newVersion = bumpVersion(currentVersion, input);
197
- } catch (err) {
198
- console.error(err.message);
199
- process.exit(1);
200
- }
201
-
202
- if (newVersion === currentVersion) {
203
- console.log(`Version is already ${currentVersion}. Nothing to do.`);
204
- process.exit(0);
205
- }
206
-
207
- console.log(`\nBumping version: ${currentVersion} → ${newVersion}`);
208
- if (dryRun) console.log('(dry run — no files will be modified)\n');
209
- else console.log('');
210
-
211
- const fileUpdates = buildFileUpdates(ROOT, currentVersion, newVersion);
212
- const result = applyUpdates(ROOT, fileUpdates, { dryRun });
213
-
214
- for (const file of fileUpdates) {
215
- const fullPath = join(ROOT, file.file);
216
- if (existsSync(fullPath)) {
217
- const content = readFileSync(fullPath, 'utf-8');
218
- const hasMatch = file.replacements.some(r =>
219
- dryRun
220
- ? new RegExp(escapeRegex(currentVersion)).test(content)
221
- : new RegExp(escapeRegex(newVersion)).test(content)
222
- );
223
- if (hasMatch) console.log(` ✓ ${file.file}`);
224
- }
225
- }
226
-
227
- console.log('');
228
- if (result.warnings.length > 0) {
229
- console.log('Warnings:');
230
- for (const w of result.warnings) console.log(` ⚠ ${w}`);
231
- console.log('');
232
- }
233
-
234
- console.log(
235
- `${dryRun ? 'Would update' : 'Updated'} ${result.updatedCount} files (${result.replacementCount} replacements).`
236
- );
237
-
238
- if (dryRun) {
239
- console.log('\nRe-run without --dry-run to apply changes.');
240
- } else {
241
- console.log(`\nVersion is now ${newVersion}.`);
242
- console.log('Next steps:');
243
- console.log(' 1. Review changes: git diff');
244
- console.log(` 2. Commit: git commit -am "chore: bump version to ${newVersion}"`);
245
- console.log(` 3. Tag: git tag v${newVersion}`);
246
- console.log(' 4. Publish: npm publish');
247
- }
248
- }