@invisibleloop/pulse 0.14.1 → 0.15.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.
Files changed (46) hide show
  1. package/.claude/commands/build-page.md +5 -1
  2. package/.claude/commands/verify.md +23 -13
  3. package/docs/.claude/pulse-checklist.md +5 -3
  4. package/docs/public/.pulse-ui-version +1 -1
  5. package/docs/public/docs.css +236 -0
  6. package/docs/public/home-brut.css +998 -0
  7. package/docs/public/menu.js +237 -6
  8. package/docs/public/pulse-ui.css +44 -0
  9. package/docs/public/theme.css +8 -0
  10. package/docs/server.js +24 -0
  11. package/docs/src/lib/layout.js +51 -3
  12. package/docs/src/pages/getting-started.js +1 -1
  13. package/docs/src/pages/home.js +231 -312
  14. package/docs/src/pages/how-it-works.js +67 -12
  15. package/examples/.claude/commands/pulse-build.md +7 -0
  16. package/examples/.claude/commands/pulse-dev.md +7 -0
  17. package/examples/.claude/commands/pulse-start.md +9 -0
  18. package/examples/.claude/commands/pulse-stop.md +5 -0
  19. package/examples/.claude/commands/verify.md +84 -0
  20. package/examples/.claude/coverage-check.js +127 -0
  21. package/examples/.claude/pulse-checklist.md +177 -0
  22. package/examples/public/.pulse-ui-version +1 -0
  23. package/examples/public/pulse-ui.css +4031 -0
  24. package/examples/public/pulse-ui.js +257 -0
  25. package/package.json +1 -1
  26. package/public/.pulse-ui-version +1 -1
  27. package/public/pulse-ui.css +44 -0
  28. package/scripts/build.js +127 -21
  29. package/src/agent/checklist.md +5 -3
  30. package/src/agent/guide-components.md +2 -2
  31. package/src/agent/guide-examples.md +310 -32
  32. package/src/agent/guide-styles.md +15 -0
  33. package/src/agent/guide-templates.md +3 -0
  34. package/src/agent/identity.md +2 -1
  35. package/src/agent/skills/verify/SKILL.md +64 -28
  36. package/src/agent/workflow.md +53 -17
  37. package/src/cli/dev.js +49 -13
  38. package/src/cli/index.js +4 -10
  39. package/src/cli/logger.js +145 -0
  40. package/src/cli/scaffold.js +55 -1
  41. package/src/mcp/server.js +174 -26
  42. package/src/mcp/validate-worker.js +21 -6
  43. package/src/server/index.js +20 -16
  44. package/src/spec/schema.js +19 -3
  45. package/src/spec/schema.test.js +28 -0
  46. package/src/ui/button.js +1 -1
@@ -41,7 +41,7 @@ Use `pulse_validate` on the spec. Fix any errors before continuing.
41
41
 
42
42
  Check the project's server entry file (e.g. `src/server.js` or `pulse.config.js`) and add the new spec if needed.
43
43
 
44
- ### 6. Screenshot
44
+ ### 6. Screenshot and design approval
45
45
 
46
46
  Use `mcp__chrome-devtools__navigate_page` to load the page, then `mcp__chrome-devtools__take_screenshot`.
47
47
 
@@ -50,6 +50,10 @@ Check for:
50
50
  - Layout looks correct
51
51
  - No console errors via `mcp__chrome-devtools__list_console_messages`
52
52
 
53
+ Then use `ask_user` to ask: "Happy with the design and layout, or would you like any changes before I run tests and Lighthouse?" with choices: `["Yes, looks good — run tests and Lighthouse", "I'd like some changes first"]`
54
+
55
+ **Do not proceed to step 7 until the user explicitly confirms.** If they want changes, make them and return to step 6.
56
+
53
57
  ### 7. Run the checklist
54
58
 
55
59
  Go through `src/agent/checklist.md` and confirm every applicable point passes. Fix anything that fails.
@@ -8,51 +8,61 @@ Run the full verification loop on the current page or the page specified in $ARG
8
8
 
9
9
  If $ARGUMENTS is provided, use it as the file path or route. Otherwise, identify the most recently edited spec file from context.
10
10
 
11
- ### 2. Validate the spec
11
+ ### 2. Design approval (new builds only)
12
+
13
+ **Skip this step for edits, bug fixes, or "add X to existing Y" tasks.**
14
+
15
+ If this is a new page build (came through `pulse_intake` or `build-page`):
16
+
17
+ 1. Take a screenshot and describe what you see to the user.
18
+ 2. Use `ask_user` to ask: "Happy with the design and layout, or would you like any changes before I run Lighthouse?" — provide choices: `["Yes, looks good — proceed", "I'd like some changes first"]`
19
+ 3. **Do not proceed to step 3 until the user explicitly confirms.** If they want changes, stop here, make the changes, then restart from step 2. Lighthouse takes ~90 seconds — do not waste it on a design the user hasn't approved.
20
+
21
+ ### 3. Validate the spec
12
22
 
13
23
  Use `pulse_validate` with the spec file content. If validation fails, report every error clearly and stop — do not proceed to screenshot until the spec is valid.
14
24
 
15
- ### 3. Check the dev server
25
+ ### 4. Check the dev server
16
26
 
17
27
  Use `pulse_fetch_page` to confirm the server is responding for the route. If it errors, use `pulse_restart_server` and retry once.
18
28
 
19
- ### 4. Screenshot
29
+ ### 5. Screenshot
20
30
 
21
31
  Use `mcp__chrome-devtools__navigate_page` to load the page route, then `mcp__chrome-devtools__take_screenshot` to capture the result. Describe what you see — layout, content, any obvious rendering issues.
22
32
 
23
- ### 5. Lighthouse — desktop
33
+ ### 6. Lighthouse — desktop
24
34
 
25
35
  Run `mcp__chrome-devtools__lighthouse_audit` on the route with `{ "strategy": "desktop" }`.
26
36
 
27
- **Pass bar: Performance, Accessibility, Best Practices, and SEO must all be 100.** Report the actual scores. If any score is below 100, identify the failing audit(s), fix the issue, and restart from step 2.
37
+ **Pass bar: Performance, Accessibility, Best Practices, and SEO must all be 100.** Report the actual scores. If any score is below 100, identify the failing audit(s), fix the issue, and restart from step 3.
28
38
 
29
- ### 6. Lighthouse — mobile
39
+ ### 7. Lighthouse — mobile
30
40
 
31
41
  Run `mcp__chrome-devtools__lighthouse_audit` on the same route with `{ "strategy": "mobile" }`.
32
42
 
33
- **Same pass bar: all four categories must be 100.** Report the actual scores. If any score is below 100, fix and restart from step 2.
43
+ **Same pass bar: all four categories must be 100.** Report the actual scores. If any score is below 100, fix and restart from step 3.
34
44
 
35
- ### 7. Performance
45
+ ### 8. Performance
36
46
 
37
47
  Navigate to the page route, then run `mcp__chrome-devtools__performance_start_trace` with `reload: true` and `autoStop: true`. Report LCP and CLS. Flag any LCP insight that suggests a fixable problem (render-blocking resources, large image load delay, etc.).
38
48
 
39
- ### 8. Console errors
49
+ ### 9. Console errors
40
50
 
41
51
  Use `mcp__chrome-devtools__list_console_messages` — report any errors or unexpected warnings.
42
52
 
43
- ### 9. Code review
53
+ ### 10. Code review
44
54
 
45
55
  Call `pulse_review` with the spec file path. This runs a full code review AND atomically writes the `.pulse-verified` stamp server-side, eliminating any race condition with the stop hook.
46
56
 
47
57
  Work through every item the review returns. Fix anything that fails before proceeding.
48
58
 
49
- ### 10. Close extra browser tabs
59
+ ### 11. Close extra browser tabs
50
60
 
51
61
  Use `mcp__chrome-devtools__list_pages` to get all open pages. Close every page **except the last one** — `close_page` refuses to close the final tab. `pageId` must be a number, not a string.
52
62
 
53
63
  If there is only one page open, skip this step — there is nothing to close.
54
64
 
55
- ### 11. Write verification stamp
65
+ ### 12. Write verification stamp
56
66
 
57
67
  `pulse_review` writes the stamp automatically. As a belt-and-suspenders backup, also run:
58
68
 
@@ -62,7 +72,7 @@ date +%s > .pulse-verified
62
72
 
63
73
  This ensures the stamp is present even if `pulse_review` was not called with a file path.
64
74
 
65
- ### 12. Report
75
+ ### 13. Report
66
76
 
67
77
  Summarise:
68
78
  - Validation: pass or fail (with errors if any)
@@ -36,13 +36,15 @@ Before finishing any spec, verify every point below. Fix anything that fails.
36
36
  - Navigation → `nav({ logo, links, actions })`
37
37
  - Footers → `footer({ logo, links, columns, legal, ... })`
38
38
 
39
- - **Creative override — raw HTML throughout is permitted** when the design intent genuinely calls for it: a highly custom visual identity, an asymmetric or typographically-driven layout, a brutalist/editorial/retro/neon/paper vibe where components would constrain the expression. This is a deliberate design decision, not a shortcut. When taking this path:
40
- - State it explicitly in the build brief: *"Building component-free — raw HTML throughout for creative control."*
39
+ - **Creative override — raw HTML throughout is permitted** when the design intent genuinely calls for it: a highly custom visual identity, an asymmetric or typographically-driven layout, a brutalist/editorial/retro/neon/paper vibe where components would constrain the expression, or a layout that requires features a component simply doesn't support (e.g. full-viewport height, custom gradient glows, clamp-scaled display type). This is a deliberate design decision, not a shortcut. When taking this path:
40
+ - **Declare it in a comment at the top of the spec** so the reviewer recognises it: `// component-free — creative override: <reason>`. This is the signal the review tool reads.
41
41
  - Functional atoms (`button`, `input`, `badge`, `modal`) should still come from components unless there is a specific design reason not to.
42
42
  - `/pulse-ui.css` is always required — it provides the token system your custom CSS will use.
43
43
  - The quality gate replaces the component checklist: **100/100/100/100 Lighthouse on both desktop and mobile is the pass bar.** A component-free page that passes every audit is correct. A component-heavy page that fails accessibility is not.
44
44
 
45
- - When reviewing a spec built under creative override, do not flag raw section HTML as a violation — check the Lighthouse results instead.
45
+ - **When reviewing**: before flagging a class name like `.hero` as a violation, first ask whether the `hero()` component could actually reproduce the layout. If the answer is no, it is a creative override — check Lighthouse instead of refactoring. Do not flatten a good custom layout into a generic component just to clear a pattern-match.
46
+
47
+ - **The review tool auto-detects creative override** from the spec comment. When detected, component pattern checks are shown as advisory (`⚡`) not as failures, and the Lighthouse gate is the stated pass bar.
46
48
 
47
49
  - **Never write App Store or Google Play download buttons by hand.** Always use `appBadge({ store: 'apple', href })` and `appBadge({ store: 'google', href })`. Raw `<a>` tags with badge images are incorrect — `appBadge` renders the correct accessible, styled badge for each store.
48
50
 
@@ -1 +1 @@
1
- 0.13.0
1
+ 0.14.2
@@ -1406,6 +1406,242 @@ a:hover {
1406
1406
  flex-shrink: 0;
1407
1407
  }
1408
1408
 
1409
+ /* ─── Sidebar search ─────────────────────────────────────────────────────────── */
1410
+ .sidebar-search-wrap {
1411
+ display: flex;
1412
+ align-items: center;
1413
+ gap: 0.4rem;
1414
+ padding: 0.6rem 0.75rem;
1415
+ border-bottom: 1px solid var(--border-subtle);
1416
+ flex-shrink: 0;
1417
+ position: relative;
1418
+ }
1419
+
1420
+ .sidebar-search-icon {
1421
+ color: var(--muted-2);
1422
+ flex-shrink: 0;
1423
+ pointer-events: none;
1424
+ }
1425
+
1426
+ .sidebar-search {
1427
+ flex: 1;
1428
+ min-width: 0;
1429
+ background: transparent;
1430
+ border: none;
1431
+ outline: none;
1432
+ font-family: var(--font);
1433
+ font-size: 0.82rem;
1434
+ color: var(--text);
1435
+ padding: 0;
1436
+ line-height: 1.4;
1437
+ }
1438
+
1439
+ .sidebar-search::placeholder {
1440
+ color: var(--muted-2);
1441
+ }
1442
+
1443
+ .sidebar-search::-webkit-search-cancel-button {
1444
+ -webkit-appearance: none;
1445
+ }
1446
+
1447
+ .sidebar-search-full {
1448
+ display: flex;
1449
+ align-items: center;
1450
+ justify-content: center;
1451
+ width: 22px;
1452
+ height: 22px;
1453
+ flex-shrink: 0;
1454
+ background: var(--surface-2);
1455
+ border: 1px solid var(--border);
1456
+ border-radius: 4px;
1457
+ color: var(--muted-2);
1458
+ cursor: pointer;
1459
+ transition: color 0.1s, background 0.1s;
1460
+ }
1461
+
1462
+ .sidebar-search-full:hover {
1463
+ color: var(--text);
1464
+ background: var(--border);
1465
+ }
1466
+
1467
+ .sidebar-no-results {
1468
+ padding: 0.75rem 1.25rem;
1469
+ font-size: 0.8rem;
1470
+ color: var(--muted-2);
1471
+ }
1472
+
1473
+ /* ─── Search overlay ─────────────────────────────────────────────────────────── */
1474
+ .search-overlay {
1475
+ position: fixed;
1476
+ inset: 0;
1477
+ z-index: 500;
1478
+ display: flex;
1479
+ align-items: flex-start;
1480
+ justify-content: center;
1481
+ padding-top: 10vh;
1482
+ }
1483
+
1484
+ .search-overlay[hidden] {
1485
+ display: none;
1486
+ }
1487
+
1488
+ .search-overlay-backdrop {
1489
+ position: absolute;
1490
+ inset: 0;
1491
+ background: rgba(0, 0, 0, 0.6);
1492
+ backdrop-filter: blur(3px);
1493
+ }
1494
+
1495
+ .search-overlay-panel {
1496
+ position: relative;
1497
+ width: min(640px, calc(100vw - 2rem));
1498
+ background: var(--surface);
1499
+ border: 1px solid var(--border);
1500
+ border-radius: 12px;
1501
+ box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
1502
+ display: flex;
1503
+ flex-direction: column;
1504
+ overflow: hidden;
1505
+ max-height: 70vh;
1506
+ }
1507
+
1508
+ .search-overlay-header {
1509
+ display: flex;
1510
+ align-items: center;
1511
+ gap: 0.75rem;
1512
+ padding: 0.875rem 1rem;
1513
+ border-bottom: 1px solid var(--border-subtle);
1514
+ flex-shrink: 0;
1515
+ }
1516
+
1517
+ .search-overlay-input-wrap {
1518
+ display: flex;
1519
+ align-items: center;
1520
+ gap: 0.6rem;
1521
+ flex: 1;
1522
+ color: var(--muted-2);
1523
+ }
1524
+
1525
+ .search-overlay-input {
1526
+ flex: 1;
1527
+ background: transparent;
1528
+ border: none;
1529
+ outline: none;
1530
+ font-family: var(--font);
1531
+ font-size: 1rem;
1532
+ color: var(--text);
1533
+ padding: 0;
1534
+ line-height: 1.4;
1535
+ }
1536
+
1537
+ .search-overlay-input::placeholder {
1538
+ color: var(--muted-2);
1539
+ }
1540
+
1541
+ .search-overlay-input::-webkit-search-cancel-button {
1542
+ -webkit-appearance: none;
1543
+ }
1544
+
1545
+ .search-overlay-close {
1546
+ font-family: var(--mono);
1547
+ font-size: 0.7rem;
1548
+ color: var(--muted-2);
1549
+ background: var(--surface-2);
1550
+ border: 1px solid var(--border);
1551
+ border-radius: 4px;
1552
+ padding: 0.2rem 0.5rem;
1553
+ cursor: pointer;
1554
+ flex-shrink: 0;
1555
+ }
1556
+
1557
+ .search-overlay-results {
1558
+ overflow-y: auto;
1559
+ flex: 1;
1560
+ padding: 0.5rem;
1561
+ }
1562
+
1563
+ .search-result {
1564
+ display: block;
1565
+ padding: 0.65rem 0.75rem;
1566
+ border-radius: 6px;
1567
+ text-decoration: none;
1568
+ color: var(--text);
1569
+ transition: background 0.1s;
1570
+ }
1571
+
1572
+ .search-result:hover,
1573
+ .search-result--selected {
1574
+ background: var(--surface-2);
1575
+ }
1576
+
1577
+ .search-result-meta {
1578
+ margin-bottom: 0.15rem;
1579
+ }
1580
+
1581
+ .search-result-section {
1582
+ font-size: 0.68rem;
1583
+ font-weight: 600;
1584
+ text-transform: uppercase;
1585
+ letter-spacing: 0.08em;
1586
+ color: var(--accent);
1587
+ }
1588
+
1589
+ .search-result-title {
1590
+ font-size: 0.9rem;
1591
+ font-weight: 500;
1592
+ color: var(--text);
1593
+ line-height: 1.4;
1594
+ }
1595
+
1596
+ .search-result-title mark,
1597
+ .search-result-snip mark {
1598
+ background: rgba(201, 184, 0, 0.3);
1599
+ color: inherit;
1600
+ border-radius: 2px;
1601
+ }
1602
+
1603
+ .search-result-snip {
1604
+ font-size: 0.78rem;
1605
+ color: var(--muted-2);
1606
+ margin-top: 0.25rem;
1607
+ line-height: 1.5;
1608
+ display: -webkit-box;
1609
+ -webkit-line-clamp: 2;
1610
+ -webkit-box-orient: vertical;
1611
+ overflow: hidden;
1612
+ }
1613
+
1614
+ .search-overlay-empty {
1615
+ padding: 2rem 1rem;
1616
+ text-align: center;
1617
+ color: var(--muted-2);
1618
+ font-size: 0.9rem;
1619
+ }
1620
+
1621
+ .search-overlay-footer {
1622
+ display: flex;
1623
+ gap: 1.25rem;
1624
+ padding: 0.6rem 1rem;
1625
+ border-top: 1px solid var(--border-subtle);
1626
+ flex-shrink: 0;
1627
+ font-size: 0.72rem;
1628
+ color: var(--muted-2);
1629
+ }
1630
+
1631
+ .search-overlay-footer kbd {
1632
+ display: inline-flex;
1633
+ align-items: center;
1634
+ justify-content: center;
1635
+ font-family: var(--mono);
1636
+ font-size: 0.68rem;
1637
+ background: var(--surface-2);
1638
+ border: 1px solid var(--border);
1639
+ border-radius: 3px;
1640
+ padding: 0.1rem 0.35rem;
1641
+ color: var(--muted-2);
1642
+ margin-right: 0.2rem;
1643
+ }
1644
+
1409
1645
  .logo-link {
1410
1646
  display: flex;
1411
1647
  align-items: center;