create-marp-presentation 1.2.0 → 1.2.2

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.
@@ -0,0 +1,811 @@
1
+ # Optional Example Slides Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Add optional example slides demonstrating all Marp capabilities with interactive CLI prompt.
6
+
7
+ **Architecture:** Separate `template-optional/` folder contains example files that are conditionally copied when user accepts the prompt. CLI uses built-in `readline` for interactive input with non-interactive mode fallback.
8
+
9
+ **Tech Stack:** Node.js built-in modules (fs, path, readline), Jest for testing
10
+
11
+ ---
12
+
13
+ ## Task 1: Create template-optional directory structure
14
+
15
+ **Files:**
16
+ - Create: `template-optional/.gitkeep`
17
+ - Create: `template-optional/static/.gitkeep`
18
+
19
+ **Step 1: Create template-optional directory**
20
+
21
+ ```bash
22
+ mkdir -p template-optional/static
23
+ ```
24
+
25
+ **Step 2: Create .gitkeep files**
26
+
27
+ ```bash
28
+ touch template-optional/.gitkeep template-optional/static/.gitkeep
29
+ ```
30
+
31
+ **Step 3: Verify structure**
32
+
33
+ Run: `ls -la template-optional/ && ls -la template-optional/static/`
34
+ Expected: Both directories exist with .gitkeep files
35
+
36
+ **Step 4: Commit**
37
+
38
+ ```bash
39
+ git add template-optional/
40
+ git commit -m "feat: create template-optional directory structure"
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Task 2: Create demo image for examples
46
+
47
+ **Files:**
48
+ - Create: `template-optional/static/demo-image.png`
49
+
50
+ **Step 1: Generate minimal SVG**
51
+
52
+ Create a temporary SVG file with minimalist geometric design:
53
+
54
+ ```bash
55
+ cat > /tmp/demo-image.svg << 'EOF'
56
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="400" viewBox="0 0 800 400">
57
+ <rect width="800" height="400" fill="#f8f9fa"/>
58
+ <circle cx="200" cy="200" r="80" fill="#4a90d9" opacity="0.8"/>
59
+ <rect x="350" y="100" width="150" height="150" fill="#6c5ce7" opacity="0.7"/>
60
+ <polygon points="600,320 700,120 800,320" fill="#00b894" opacity="0.75"/>
61
+ <circle cx="500" cy="280" r="40" fill="#fd79a8" opacity="0.6"/>
62
+ <rect x="100" y="280" width="100" height="60" fill="#ffeaa7" opacity="0.8"/>
63
+ </svg>
64
+ EOF
65
+ ```
66
+
67
+ **Step 2: Convert SVG to PNG (requires ImageMagick or similar)**
68
+
69
+ If ImageMagick is available:
70
+ ```bash
71
+ convert /tmp/demo-image.svg template-optional/static/demo-image.png
72
+ ```
73
+
74
+ Alternative: Create a placeholder PNG using base64:
75
+
76
+ ```bash
77
+ # Create a minimal 100x50 PNG placeholder
78
+ echo "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF" | base64 -d > template-optional/static/demo-image.png 2>/dev/null || \
79
+ echo "Note: Demo image will be created manually or use online tool"
80
+ ```
81
+
82
+ If no image tool available, note in the file that a real image should be added:
83
+
84
+ ```bash
85
+ echo "Demo image placeholder - replace with actual 800x400 PNG" > template-optional/static/README.txt
86
+ ```
87
+
88
+ **Step 3: Verify image exists**
89
+
90
+ Run: `ls -la template-optional/static/`
91
+ Expected: demo-image.png exists (or README.txt as fallback)
92
+
93
+ **Step 4: Commit**
94
+
95
+ ```bash
96
+ git add template-optional/static/
97
+ git commit -m "feat: add demo image for example slides"
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Task 3: Create examples.md with all slide types
103
+
104
+ **Files:**
105
+ - Create: `template-optional/examples.md`
106
+
107
+ **Step 1: Write examples.md**
108
+
109
+ ```markdown
110
+ ---
111
+ marp: true
112
+ theme: default
113
+ paginate: true
114
+ math: katex
115
+ ---
116
+
117
+ # Marp Examples
118
+
119
+ Complete demonstration of Marp presentation capabilities
120
+
121
+ ---
122
+
123
+ ## Table of Contents
124
+
125
+ <!-- This auto-generates a table of contents -->
126
+ 1. [Basic Formatting](#basic-formatting)
127
+ 2. [Lists](#lists)
128
+ 3. [Quotes and Footnotes](#quotes-and-footnotes)
129
+ 4. [Code](#code)
130
+ 5. [Tables](#tables)
131
+ 6. [LaTeX Formulas](#latex-formulas)
132
+ 7. [Images](#images)
133
+ 8. [Multi-column Layouts](#multi-column-layouts)
134
+ 9. [Backgrounds and Styling](#backgrounds-and-styling)
135
+ 10. [Fragments (Animations)](#fragments-animations)
136
+
137
+ ---
138
+
139
+ ## Basic Formatting
140
+
141
+ ### Headings work like regular Markdown
142
+
143
+ This is **bold text** and this is *italic text*.
144
+
145
+ You can also use ~~strikethrough~~ and `inline code`.
146
+
147
+ ---
148
+
149
+ ## Lists
150
+
151
+ ### Unordered Lists
152
+
153
+ - First item
154
+ - Second item
155
+ - Nested item
156
+ - Another nested item
157
+ - Third item
158
+
159
+ ### Ordered Lists
160
+
161
+ 1. First step
162
+ 2. Second step
163
+ 3. Third step
164
+
165
+ ---
166
+
167
+ ## Quotes and Footnotes
168
+
169
+ > This is a blockquote.
170
+ > It can span multiple lines.
171
+ >
172
+ > — Author Name
173
+
174
+ Here's a sentence with a footnote[^1].
175
+
176
+ [^1]: This is the footnote content that appears at the bottom.
177
+
178
+ ---
179
+
180
+ ## Code
181
+
182
+ ### JavaScript
183
+
184
+ ```javascript
185
+ function greet(name) {
186
+ console.log(`Hello, ${name}!`);
187
+ }
188
+
189
+ greet('Marp');
190
+ ```
191
+
192
+ ### Python
193
+
194
+ ```python
195
+ def fibonacci(n):
196
+ if n <= 1:
197
+ return n
198
+ return fibonacci(n-1) + fibonacci(n-2)
199
+
200
+ print(fibonacci(10))
201
+ ```
202
+
203
+ ### Bash
204
+
205
+ ```bash
206
+ #!/bin/bash
207
+ echo "Building presentation..."
208
+ npx @marp-team/marp-cli presentation.md -o output.html
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Tables
214
+
215
+ ### Simple Table
216
+
217
+ | Feature | Status | Notes |
218
+ |---------|--------|-------|
219
+ | Markdown | ✅ | Full support |
220
+ | Code blocks | ✅ | Syntax highlighting |
221
+ | Images | ✅ | Local and remote |
222
+ | Math | ✅ | KaTeX support |
223
+
224
+ ### Aligned Columns
225
+
226
+ | Left | Center | Right |
227
+ |:-----|:------:|------:|
228
+ | Default | Centered | Numbers |
229
+ | Text | Text | 1,234 |
230
+ | More | Data | 5,678 |
231
+
232
+ ---
233
+
234
+ ## LaTeX Formulas
235
+
236
+ ### Inline and Block Math
237
+
238
+ Inline formula: $E = mc^2$
239
+
240
+ Block formula:
241
+
242
+ $$
243
+ \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
244
+ $$
245
+
246
+ ### More Examples
247
+
248
+ Quadratic formula:
249
+
250
+ $$
251
+ x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
252
+ $$
253
+
254
+ Matrix:
255
+
256
+ $$
257
+ \begin{pmatrix}
258
+ a & b \\
259
+ c & d
260
+ \end{pmatrix}
261
+ $$
262
+
263
+ ---
264
+
265
+ ## Images
266
+
267
+ ### Basic Image
268
+
269
+ ![Demo image](static/demo-image.png)
270
+
271
+ ### Sized Image
272
+
273
+ ![Width 300px](static/demo-image.png){ width=300px }
274
+
275
+ ---
276
+
277
+ ## Multi-column Layouts
278
+
279
+ ### Using HTML Tables
280
+
281
+ <table>
282
+ <tr>
283
+ <td>
284
+
285
+ **Left Column**
286
+
287
+ - Point one
288
+ - Point two
289
+ - Point three
290
+
291
+ </td>
292
+ <td>
293
+
294
+ **Right Column**
295
+
296
+ - Another point
297
+ - More content
298
+ - Final item
299
+
300
+ </td>
301
+ </tr>
302
+ </table>
303
+
304
+ ---
305
+
306
+ ## Backgrounds and Styling
307
+
308
+ <!-- _backgroundColor: #1a1a2e -->
309
+ <!-- _color: #eaeaea -->
310
+
311
+ ### Dark Slide
312
+
313
+ This slide has a custom dark background and light text color.
314
+
315
+ You can use HTML color codes or named colors.
316
+
317
+ ---
318
+
319
+ <!-- _backgroundImage: url('static/demo-image.png') -->
320
+ <!-- _backgroundOpacity: 0.3 -->
321
+
322
+ ### Image Background
323
+
324
+ This slide has an image background with reduced opacity.
325
+
326
+ ---
327
+
328
+ ## Fragments (Animations)
329
+
330
+ Use asterisk `*` for incremental reveal:
331
+
332
+ - *This appears first
333
+ - *This appears second
334
+ - *This appears third
335
+ - *This appears last
336
+
337
+ Press space to reveal each item!
338
+
339
+ ---
340
+
341
+ <!-- _paginate: false -->
342
+
343
+ # Thank You!
344
+
345
+ ## Questions?
346
+
347
+ - GitHub: https://github.com/marp-team/marp
348
+ - Docs: https://marp.app/
349
+
350
+ ```
351
+ Contact: your-email@example.com
352
+ ```
353
+ ```
354
+
355
+ Write this content to `template-optional/examples.md`.
356
+
357
+ **Step 2: Verify file created**
358
+
359
+ Run: `wc -l template-optional/examples.md`
360
+ Expected: ~200+ lines
361
+
362
+ **Step 3: Commit**
363
+
364
+ ```bash
365
+ git add template-optional/examples.md
366
+ git commit -m "feat: add examples.md with 13 slide types demonstrating Marp capabilities"
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Task 4: Add askCreateExamples function to CLI
372
+
373
+ **Files:**
374
+ - Modify: `index.js`
375
+
376
+ **Step 1: Add readline import at top of index.js**
377
+
378
+ After line 5 (`const { spawnSync } = require('child_process');`), add:
379
+
380
+ ```javascript
381
+ const readline = require('readline');
382
+ ```
383
+
384
+ **Step 2: Add askCreateExamples function**
385
+
386
+ After the `projectPath` variable (around line 23), add:
387
+
388
+ ```javascript
389
+ // Запрос на создание примеров слайдов
390
+ async function askCreateExamples() {
391
+ // Неинтерактивный режим — по умолчанию создаём примеры
392
+ if (!process.stdin.isTTY) {
393
+ return true;
394
+ }
395
+
396
+ return new Promise((resolve) => {
397
+ const rl = readline.createInterface({
398
+ input: process.stdin,
399
+ output: process.stdout
400
+ });
401
+
402
+ rl.question('Create example slides file? (Y/n) ', (answer) => {
403
+ rl.close();
404
+ const normalized = answer.toLowerCase().trim();
405
+ resolve(normalized !== 'n' && normalized !== 'no');
406
+ });
407
+ });
408
+ }
409
+ ```
410
+
411
+ **Step 3: Verify syntax**
412
+
413
+ Run: `node -c index.js`
414
+ Expected: No syntax errors
415
+
416
+ **Step 4: Commit**
417
+
418
+ ```bash
419
+ git add index.js
420
+ git commit -m "feat: add askCreateExamples function for interactive prompt"
421
+ ```
422
+
423
+ ---
424
+
425
+ ## Task 5: Add optional files copying logic to CLI
426
+
427
+ **Files:**
428
+ - Modify: `index.js`
429
+
430
+ **Step 1: Add copyOptionalFiles function**
431
+
432
+ After `copyDir` function (around line 63), add:
433
+
434
+ ```javascript
435
+ // Копирование опциональных файлов
436
+ const copyOptionalFiles = (destPath) => {
437
+ const optionalPath = path.join(__dirname, 'template-optional');
438
+
439
+ // Копируем examples.md
440
+ const examplesSrc = path.join(optionalPath, 'examples.md');
441
+ const examplesDest = path.join(destPath, 'examples.md');
442
+ if (fs.existsSync(examplesSrc)) {
443
+ fs.copyFileSync(examplesSrc, examplesDest);
444
+ }
445
+
446
+ // Копируем демо-изображение
447
+ const demoImageSrc = path.join(optionalPath, 'static', 'demo-image.png');
448
+ const demoImageDest = path.join(destPath, 'static', 'demo-image.png');
449
+ if (fs.existsSync(demoImageSrc)) {
450
+ fs.copyFileSync(demoImageSrc, demoImageDest);
451
+ }
452
+ };
453
+ ```
454
+
455
+ **Step 2: Verify syntax**
456
+
457
+ Run: `node -c index.js`
458
+ Expected: No syntax errors
459
+
460
+ **Step 3: Commit**
461
+
462
+ ```bash
463
+ git add index.js
464
+ git commit -m "feat: add copyOptionalFiles function"
465
+ ```
466
+
467
+ ---
468
+
469
+ ## Task 6: Integrate async flow into main CLI
470
+
471
+ **Files:**
472
+ - Modify: `index.js`
473
+
474
+ **Step 1: Wrap main logic in async IIFE**
475
+
476
+ Replace the main try block (lines 44-92) with async flow:
477
+
478
+ ```javascript
479
+ // Получаем путь к template
480
+ const templatePath = path.join(__dirname, 'template');
481
+
482
+ console.log(`Creating Marp presentation: ${projectName}`);
483
+ console.log();
484
+
485
+ // Основной async flow
486
+ (async () => {
487
+ try {
488
+ // Запрашиваем создание примеров
489
+ const createExamples = await askCreateExamples();
490
+
491
+ // Создаём папку проекта
492
+ fs.mkdirSync(projectPath, { recursive: true });
493
+
494
+ // Рекурсивно копируем template
495
+ copyDir(templatePath, projectPath);
496
+
497
+ console.log('✓ Project created');
498
+
499
+ // Копируем опциональные файлы
500
+ if (createExamples) {
501
+ copyOptionalFiles(projectPath);
502
+ console.log('✓ Example slides added');
503
+ console.log('✓ Demo image added to static/');
504
+ }
505
+ console.log();
506
+
507
+ // Запускаем npm install
508
+ console.log('Installing dependencies...');
509
+ const installResult = spawnSync('npm', ['install'], {
510
+ cwd: projectPath,
511
+ stdio: 'inherit',
512
+ });
513
+
514
+ if (installResult.status !== 0) {
515
+ console.error();
516
+ console.error('Failed to install dependencies.');
517
+ console.error('Please run "cd ' + projectName + ' && npm install" manually.');
518
+ process.exit(1);
519
+ }
520
+
521
+ console.log();
522
+ console.log('✓ Dependencies installed');
523
+ console.log();
524
+ console.log('Next steps:');
525
+ console.log(` cd ${projectName}`);
526
+ console.log(' npm run dev # Start live preview');
527
+ if (createExamples) {
528
+ console.log(' marp examples.md # Preview example slides');
529
+ }
530
+ console.log(' npm run build:all # Build all formats');
531
+ console.log();
532
+
533
+ } catch (err) {
534
+ console.error('Error creating project:', err.message);
535
+ process.exit(1);
536
+ }
537
+ })();
538
+ ```
539
+
540
+ **Step 2: Verify syntax**
541
+
542
+ Run: `node -c index.js`
543
+ Expected: No syntax errors
544
+
545
+ **Step 3: Commit**
546
+
547
+ ```bash
548
+ git add index.js
549
+ git commit -m "feat: integrate interactive prompt and optional files into CLI flow"
550
+ ```
551
+
552
+ ---
553
+
554
+ ## Task 7: Update package.json files field
555
+
556
+ **Files:**
557
+ - Modify: `package.json`
558
+
559
+ **Step 1: Update files array**
560
+
561
+ Change the `files` field from:
562
+
563
+ ```json
564
+ "files": [
565
+ "index.js",
566
+ "template/"
567
+ ],
568
+ ```
569
+
570
+ To:
571
+
572
+ ```json
573
+ "files": [
574
+ "index.js",
575
+ "template/",
576
+ "template-optional/"
577
+ ],
578
+ ```
579
+
580
+ **Step 2: Verify package.json is valid**
581
+
582
+ Run: `node -e "console.log(JSON.parse(require('fs').readFileSync('package.json')).files)"`
583
+ Expected: `['index.js', 'template/', 'template-optional/']`
584
+
585
+ **Step 3: Commit**
586
+
587
+ ```bash
588
+ git add package.json
589
+ git commit -m "feat: add template-optional to npm package files"
590
+ ```
591
+
592
+ ---
593
+
594
+ ## Task 8: Write tests for new CLI functionality
595
+
596
+ **Files:**
597
+ - Modify: `tests/cli.test.js`
598
+
599
+ **Step 1: Add test for examples.md creation**
600
+
601
+ Add this test to the existing test file:
602
+
603
+ ```javascript
604
+ describe('CLI with examples', () => {
605
+ const projectRoot = path.resolve(__dirname, '..');
606
+ const testProjects = [];
607
+
608
+ afterEach(() => {
609
+ for (const project of testProjects) {
610
+ if (fs.existsSync(project)) {
611
+ fs.rmSync(project, { recursive: true, force: true });
612
+ }
613
+ }
614
+ });
615
+
616
+ test('should create examples.md in non-interactive mode', () => {
617
+ const projectName = 'test-examples-auto';
618
+ const projectPath = path.join(projectRoot, projectName);
619
+ testProjects.push(projectPath);
620
+
621
+ // stdin is not a TTY in test environment, so examples should be created
622
+ const result = spawnSync('node', ['index.js', projectName], {
623
+ cwd: projectRoot,
624
+ });
625
+
626
+ expect(result.status).toBe(0);
627
+ expect(fs.existsSync(path.join(projectPath, 'examples.md'))).toBe(true);
628
+ expect(fs.existsSync(path.join(projectPath, 'static', 'demo-image.png'))).toBe(true);
629
+ });
630
+
631
+ test('should not create examples.md when user declines', () => {
632
+ const projectName = 'test-no-examples';
633
+ const projectPath = path.join(projectRoot, projectName);
634
+ testProjects.push(projectPath);
635
+
636
+ const result = spawnSync('node', ['index.js', projectName], {
637
+ cwd: projectRoot,
638
+ input: 'n\n',
639
+ });
640
+
641
+ expect(result.status).toBe(0);
642
+ expect(fs.existsSync(path.join(projectPath, 'examples.md'))).toBe(false);
643
+ });
644
+ });
645
+ ```
646
+
647
+ **Step 2: Run tests**
648
+
649
+ Run: `npm test`
650
+ Expected: All tests pass
651
+
652
+ **Step 3: Commit**
653
+
654
+ ```bash
655
+ git add tests/cli.test.js
656
+ git commit -m "test: add tests for optional examples feature"
657
+ ```
658
+
659
+ ---
660
+
661
+ ## Task 9: Manual integration testing
662
+
663
+ **Files:**
664
+ - None (manual testing)
665
+
666
+ **Step 1: Test interactive mode with examples**
667
+
668
+ ```bash
669
+ node index.js test-manual-with-examples
670
+ # When prompted: Press Enter or type 'y'
671
+ cd test-manual-with-examples
672
+ ls -la
673
+ # Verify: examples.md exists, static/demo-image.png exists
674
+ npm run dev
675
+ # Verify: presentation.md loads in browser
676
+ # Then: marp examples.md
677
+ # Verify: examples.md renders correctly
678
+ ```
679
+
680
+ **Step 2: Test interactive mode without examples**
681
+
682
+ ```bash
683
+ cd ..
684
+ node index.js test-manual-no-examples
685
+ # When prompted: type 'n'
686
+ cd test-manual-no-examples
687
+ ls -la
688
+ # Verify: examples.md does NOT exist, static/ exists but no demo-image.png
689
+ ```
690
+
691
+ **Step 3: Test non-interactive mode**
692
+
693
+ ```bash
694
+ cd ..
695
+ echo "" | node index.js test-piped-input
696
+ cd test-piped-input
697
+ ls -la
698
+ # Verify: examples.md exists (piped empty input = default yes)
699
+ ```
700
+
701
+ **Step 4: Clean up test projects**
702
+
703
+ ```bash
704
+ cd ..
705
+ rm -rf test-manual-with-examples test-manual-no-examples test-piped-input
706
+ ```
707
+
708
+ ---
709
+
710
+ ## Task 10: Update CLAUDE.md documentation
711
+
712
+ **Files:**
713
+ - Modify: `CLAUDE.md`
714
+
715
+ **Step 1: Add documentation for template-optional**
716
+
717
+ Add this section after "## Architecture":
718
+
719
+ ```markdown
720
+ ### Optional Template Files
721
+
722
+ The `template-optional/` folder contains files that are conditionally copied based on user preference:
723
+
724
+ - `examples.md` - Comprehensive demonstration of Marp capabilities (13 slides)
725
+ - `static/demo-image.png` - Demo image for image insertion examples
726
+
727
+ When users run `npx create-marp-presentation <name>`, they are prompted:
728
+ ```
729
+ Create example slides file? (Y/n)
730
+ ```
731
+
732
+ - Yes (default): Both `presentation.md` and `examples.md` are created
733
+ - No: Only `presentation.md` is created
734
+
735
+ In non-interactive mode (CI/CD), examples are created by default.
736
+ ```
737
+
738
+ **Step 2: Update Key Files table**
739
+
740
+ Add to the Key Files table:
741
+
742
+ ```markdown
743
+ | `template-optional/examples.md` | Comprehensive Marp capabilities demo (13 slide types) |
744
+ | `template-optional/static/demo-image.png` | Demo image for image insertion examples |
745
+ ```
746
+
747
+ **Step 3: Commit**
748
+
749
+ ```bash
750
+ git add CLAUDE.md
751
+ git commit -m "docs: update CLAUDE.md with template-optional documentation"
752
+ ```
753
+
754
+ ---
755
+
756
+ ## Task 11: Final verification and version bump
757
+
758
+ **Files:**
759
+ - Modify: `package.json`
760
+
761
+ **Step 1: Run all tests**
762
+
763
+ ```bash
764
+ npm test
765
+ ```
766
+ Expected: All tests pass
767
+
768
+ **Step 2: Test dry-run publish**
769
+
770
+ ```bash
771
+ npm publish --dry-run
772
+ ```
773
+ Expected: Package includes template-optional/ files
774
+
775
+ **Step 3: Bump version**
776
+
777
+ ```bash
778
+ # Update version in package.json from 1.0.1 to 1.1.0
779
+ npm version minor --no-git-tag-version
780
+ ```
781
+
782
+ **Step 4: Final commit**
783
+
784
+ ```bash
785
+ git add package.json
786
+ git commit -m "chore: bump version to 1.1.0 for optional examples feature"
787
+ ```
788
+
789
+ **Step 5: Push to remote**
790
+
791
+ ```bash
792
+ git push origin template-slides
793
+ ```
794
+
795
+ ---
796
+
797
+ ## Summary
798
+
799
+ | Task | Description | Files Changed |
800
+ |------|-------------|---------------|
801
+ | 1 | Create template-optional structure | `template-optional/.gitkeep`, `template-optional/static/.gitkeep` |
802
+ | 2 | Create demo image | `template-optional/static/demo-image.png` |
803
+ | 3 | Create examples.md | `template-optional/examples.md` |
804
+ | 4 | Add askCreateExamples function | `index.js` |
805
+ | 5 | Add copyOptionalFiles function | `index.js` |
806
+ | 6 | Integrate async flow | `index.js` |
807
+ | 7 | Update package.json files | `package.json` |
808
+ | 8 | Add tests | `tests/cli.test.js` |
809
+ | 9 | Manual testing | - |
810
+ | 10 | Update docs | `CLAUDE.md` |
811
+ | 11 | Final verification | `package.json` |