@invisibleloop/pulse 0.2.9 → 0.2.11

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.
@@ -78,7 +78,12 @@ Validate the email format before submitting."`, 'bash'))}
78
78
  ├── .claude/
79
79
  │ ├── CLAUDE.md ← session instructions Claude reads on startup
80
80
  │ ├── settings.json ← hooks: syntax checks, colour guards, package blocklist
81
- │ └── pulse-checklist.md ← spec review checklist, kept in sync by Pulse
81
+ │ ├── pulse-checklist.md ← spec review checklist, kept in sync by Pulse
82
+ │ └── commands/ ← slash commands available inside Claude
83
+ │ ├── pulse-dev.md
84
+ │ ├── pulse-stop.md
85
+ │ ├── pulse-build.md
86
+ │ └── pulse-start.md
82
87
  ├── package.json
83
88
  └── pulse.config.js ← port and project settings`, 'bash'))}
84
89
  <p><code>src/pages/home.js</code> is a complete working spec — a counter with increment and decrement buttons. Open <a href="http://localhost:3000">localhost:3000</a> after running <code>/pulse-dev</code> to see it. Every new page you create goes into <code>src/pages/</code> and is discovered automatically.</p>
@@ -93,6 +98,18 @@ Validate the email format before submitting."`, 'bash'))}
93
98
  /pulse-report # Lighthouse audit + performance report`, 'bash'))}
94
99
  <p>You can also skip the commands entirely — just describe what you want and the agent handles the rest, including starting the dev server when needed.</p>
95
100
 
101
+ ${section('update', 'Keeping up to date')}
102
+ <p>When a new version of Pulse is released, update the package and then run <code>pulse update</code> from your project root:</p>
103
+ ${codeBlock(highlight(`npm update @invisibleloop/pulse
104
+ pulse update`, 'bash'))}
105
+ <p><code>pulse update</code> copies the latest UI assets and agent files into your project:</p>
106
+ <ul>
107
+ <li><code>public/pulse-ui.css</code> and <code>public/pulse-ui.js</code> — component library styles and behaviour</li>
108
+ <li><code>.claude/pulse-checklist.md</code> — spec review checklist</li>
109
+ <li><code>.claude/commands/</code> — slash commands</li>
110
+ </ul>
111
+ <p>Your own source files, <code>CLAUDE.md</code>, and <code>pulse.config.js</code> are never touched.</p>
112
+
96
113
  ${section('next-steps', 'Next steps')}
97
114
  <ul>
98
115
  <li><a href="/how-it-works">How It Works</a> — the MCP server, what the agent knows, and the full build cycle</li>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invisibleloop/pulse",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "type": "module",
5
5
  "description": "AI-first frontend framework. The spec is the source of truth.",
6
6
  "license": "MIT",
@@ -1 +1 @@
1
- 0.2.9
1
+ 0.2.11
@@ -0,0 +1,7 @@
1
+ Build this Pulse project for production.
2
+
3
+ ```bash
4
+ pulse build
5
+ ```
6
+
7
+ This bundles all pages into `public/dist/`. When complete, confirm the build succeeded and list the generated files.
@@ -0,0 +1,7 @@
1
+ Start (or restart) the Pulse dev server for this project.
2
+
3
+ ```bash
4
+ pulse stop; pulse dev
5
+ ```
6
+
7
+ The server port is read from `pulse.config.js` (defaults to 3000).
@@ -0,0 +1,9 @@
1
+ Start the Pulse production server for this project.
2
+
3
+ First ensure a build exists (`public/dist/`). Then run:
4
+
5
+ ```bash
6
+ pulse start
7
+ ```
8
+
9
+ The production server uses the port from `pulse.config.js` (defaults to 3000).
@@ -0,0 +1,5 @@
1
+ Stop the Pulse dev server for this project.
2
+
3
+ ```bash
4
+ pulse stop
5
+ ```
package/src/cli/dev.js CHANGED
@@ -71,6 +71,16 @@ const PUBLIC_DIR = path.join(ROOT, 'public')
71
71
  fs.copyFileSync(checklistSrc, checklistDst)
72
72
  }
73
73
 
74
+ // Sync slash commands into .claude/commands/ so /pulse-dev etc. always exist
75
+ const commandsSrc = new URL('../agent/commands', import.meta.url).pathname
76
+ const commandsDst = path.join(ROOT, '.claude', 'commands')
77
+ if (fs.existsSync(commandsSrc)) {
78
+ fs.mkdirSync(commandsDst, { recursive: true })
79
+ for (const file of fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'))) {
80
+ fs.copyFileSync(path.join(commandsSrc, file), path.join(commandsDst, file))
81
+ }
82
+ }
83
+
74
84
  console.log(` ✓ pulse-ui assets synced (v${pkgVersion})\n`)
75
85
  })()
76
86
 
package/src/cli/index.js CHANGED
@@ -289,7 +289,7 @@ async function runUpdate(root) {
289
289
  const dst = path.join(publicDir, asset)
290
290
  if (!fs.existsSync(src)) { missing.push(asset); continue }
291
291
  fs.copyFileSync(src, dst)
292
- updated.push(asset)
292
+ updated.push(`public/${asset}`)
293
293
  }
294
294
 
295
295
  // Sync agent checklist into .claude/
@@ -301,12 +301,23 @@ async function runUpdate(root) {
301
301
  updated.push('.claude/pulse-checklist.md')
302
302
  }
303
303
 
304
+ // Sync slash commands into .claude/commands/
305
+ const commandsSrc = new URL('../agent/commands', import.meta.url).pathname
306
+ const commandsDst = path.join(root, '.claude', 'commands')
307
+ if (fs.existsSync(commandsSrc)) {
308
+ fs.mkdirSync(commandsDst, { recursive: true })
309
+ for (const file of fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'))) {
310
+ fs.copyFileSync(path.join(commandsSrc, file), path.join(commandsDst, file))
311
+ updated.push(`.claude/commands/${file}`)
312
+ }
313
+ }
314
+
304
315
  // Read the new version for the success message
305
316
  const versionFile = path.join(publicDir, '.pulse-ui-version')
306
317
  const version = fs.existsSync(versionFile) ? fs.readFileSync(versionFile, 'utf8').trim() : '?'
307
318
 
308
- console.log(`\n⚡ Pulse UI updated to ${version}\n`)
309
- for (const f of updated) console.log(` ✓ public/${f}`)
319
+ console.log(`\n⚡ Pulse updated to ${version}\n`)
320
+ for (const f of updated) console.log(` ✓ ${f}`)
310
321
  for (const f of missing) console.log(` ✗ ${f} not found in package`)
311
322
  console.log()
312
323
  }
@@ -85,6 +85,14 @@ ${port !== 3000 ? ` port: ${port},\n` : ''}}
85
85
  // CLAUDE.md — in .claude/ so it's alongside Claude Code's own config, not cluttering the project root
86
86
  write(targetDir, '.claude/CLAUDE.md', claudeMd(name))
87
87
 
88
+ // Slash commands — copied from src/agent/commands/ so scaffold and dev sync stay in lock-step
89
+ const commandsSrc = new URL('../agent/commands', import.meta.url).pathname
90
+ if (fs.existsSync(commandsSrc)) {
91
+ for (const file of fs.readdirSync(commandsSrc).filter(f => f.endsWith('.md'))) {
92
+ write(targetDir, `.claude/commands/${file}`, fs.readFileSync(path.join(commandsSrc, file), 'utf8'))
93
+ }
94
+ }
95
+
88
96
  // settings.json — hooks that enforce correct agent behaviour
89
97
  write(targetDir, '.claude/settings.json', JSON.stringify({
90
98
  hooks: {
@@ -408,3 +416,4 @@ function write(dir, relPath, content) {
408
416
  fs.mkdirSync(path.dirname(filePath), { recursive: true })
409
417
  fs.writeFileSync(filePath, content, 'utf8')
410
418
  }
419
+