@invisibleloop/pulse 0.20.1 → 0.20.3
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/commands/pulse-start.md +11 -0
- package/.claude/commands/pulse-stop.md +5 -0
- package/.claude/commands/verify.md +17 -11
- package/docs/.claude/coverage-check.js +153 -84
- package/examples/.claude/coverage-check.js +153 -84
- package/package.json +1 -1
- package/public/.pulse-ui-version +1 -1
- package/scripts/build.js +1 -1
- package/scripts/css-purge.js +65 -3
- package/scripts/css-purge.test.js +16 -0
- package/scripts/strip-server.test.js +11 -1
- package/src/agent/commands/pulse-start.md +6 -4
- package/src/agent/commands/pulse-stop.md +1 -1
- package/src/agent/commands/verify.md +17 -11
- package/src/agent/coverage-check.js +154 -90
- package/src/agent/guide-components.md +2 -2
- package/src/agent/identity.md +2 -2
- package/src/agent/workflow.md +21 -4
- package/src/cli/cli.test.js +72 -0
- package/src/cli/dev.js +23 -3
- package/src/cli/index.js +5 -2
- package/src/cli/scaffold.js +2 -2
- package/src/mcp/mcp.test.js +44 -0
- package/src/mcp/server.js +523 -33
- package/src/mcp/validate-worker.js +3 -0
- package/src/runtime/index.js +9 -0
- package/src/server/index.js +21 -30
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
import { validateSpec } from '../spec/schema.js'
|
|
13
13
|
|
|
14
|
+
import { existsSync } from 'fs'
|
|
15
|
+
|
|
14
16
|
const tmpFile = process.argv[2]
|
|
15
17
|
if (!tmpFile) { process.stdout.write('Invalid: no file path provided'); process.exit(0) }
|
|
18
|
+
if (!existsSync(tmpFile)) { process.stdout.write(`Invalid: file not found — ${tmpFile}`); process.exit(0) }
|
|
16
19
|
|
|
17
20
|
let mod
|
|
18
21
|
try {
|
package/src/runtime/index.js
CHANGED
|
@@ -296,8 +296,15 @@ function bindEvents(el, dispatch, signal) {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
// Dialog open — data-dialog-open="dialogId"
|
|
299
|
+
// If the element also carries data-event, fire the mutation first so the view
|
|
300
|
+
// re-renders with updated state before the dialog opens.
|
|
299
301
|
const dialogOpenTarget = e.target?.closest?.('[data-dialog-open]')
|
|
300
302
|
if (dialogOpenTarget) {
|
|
303
|
+
const eventAttr = dialogOpenTarget.dataset.event
|
|
304
|
+
if (eventAttr) {
|
|
305
|
+
const [type, name] = parseEventAttr(eventAttr)
|
|
306
|
+
if (type === 'click') { e.preventDefault(); dispatch(name, e) }
|
|
307
|
+
}
|
|
301
308
|
const dialog = document.getElementById(dialogOpenTarget.dataset.dialogOpen)
|
|
302
309
|
if (dialog?.showModal) { e.preventDefault(); dialog.showModal() }
|
|
303
310
|
return
|
|
@@ -472,6 +479,8 @@ function morphAttrs(cur, nxt) {
|
|
|
472
479
|
}
|
|
473
480
|
}
|
|
474
481
|
for (const { name } of Array.from(cur.attributes)) {
|
|
482
|
+
// `open` on <dialog> is managed by the native showModal/close API — never remove it
|
|
483
|
+
if (cur.tagName === 'DIALOG' && name === 'open') continue
|
|
475
484
|
if (!nxt.hasAttribute(name)) cur.removeAttribute(name)
|
|
476
485
|
}
|
|
477
486
|
}
|
package/src/server/index.js
CHANGED
|
@@ -611,9 +611,25 @@ export async function createServer(entries, options = {}) {
|
|
|
611
611
|
const brandCache = new TtlCache(500)
|
|
612
612
|
brandCache.startEviction(30_000) // brand TTL is 60s, scan every 30s
|
|
613
613
|
|
|
614
|
-
// Load manifest — maps source hydrate paths to production bundle paths
|
|
615
|
-
|
|
616
|
-
|
|
614
|
+
// Load manifest — maps source hydrate paths to production bundle paths.
|
|
615
|
+
// When staticDir is set and no manifest is explicitly provided, the manifest is
|
|
616
|
+
// re-read from disk on every request so that `pulse build` takes effect immediately
|
|
617
|
+
// without a server restart. The file is small (~1 kB) and the read is synchronous,
|
|
618
|
+
// so the overhead is negligible.
|
|
619
|
+
// When manifest is an explicit object (including {} from the dev server to disable
|
|
620
|
+
// manifest-based hydration), it is used as-is without disk reads. This ensures that
|
|
621
|
+
// passing manifest: {} always means "no manifest" — even when staticDir is set.
|
|
622
|
+
const _manifestStatic = (manifest !== null && typeof manifest === 'object') ? manifest : null
|
|
623
|
+
const _manifestPath = _manifestStatic ? null
|
|
624
|
+
: typeof manifest === 'string' ? manifest
|
|
625
|
+
: (manifest === null && staticDir) ? path.join(staticDir, 'dist', 'manifest.json') : null
|
|
626
|
+
const getHydrateMap = _manifestStatic
|
|
627
|
+
? () => _manifestStatic
|
|
628
|
+
: () => {
|
|
629
|
+
if (!_manifestPath) return {}
|
|
630
|
+
try { return JSON.parse(fs.readFileSync(_manifestPath, 'utf8')) } catch { return {} }
|
|
631
|
+
}
|
|
632
|
+
|
|
617
633
|
|
|
618
634
|
// Auto-detect favicon in staticDir
|
|
619
635
|
const faviconPath = staticDir
|
|
@@ -905,6 +921,8 @@ export async function createServer(entries, options = {}) {
|
|
|
905
921
|
ctx.store = await resolveStoreState(storeDef, ctx)
|
|
906
922
|
}
|
|
907
923
|
|
|
924
|
+
const hydrateMap = getHydrateMap()
|
|
925
|
+
const runtimeBundle = hydrateMap['_runtime'] || ''
|
|
908
926
|
const spec = resolveSpec(match.spec, hydrateMap)
|
|
909
927
|
|
|
910
928
|
// Per-spec timeout overrides the global default
|
|
@@ -1691,33 +1709,6 @@ function mergeCtxHeaders(ctx, headers) {
|
|
|
1691
1709
|
// Manifest & spec resolution
|
|
1692
1710
|
// ---------------------------------------------------------------------------
|
|
1693
1711
|
|
|
1694
|
-
/**
|
|
1695
|
-
* Load a hydrate manifest.
|
|
1696
|
-
* Accepts a manifest object, a path to a JSON file, or auto-detects from
|
|
1697
|
-
* staticDir/dist/manifest.json when staticDir is set.
|
|
1698
|
-
*
|
|
1699
|
-
* @param {Object|string|null} manifest
|
|
1700
|
-
* @param {string|null} staticDir
|
|
1701
|
-
* @returns {Object} map of source paths → bundle paths
|
|
1702
|
-
*/
|
|
1703
|
-
function loadManifest(manifest, staticDir) {
|
|
1704
|
-
if (!manifest && !staticDir) return {}
|
|
1705
|
-
|
|
1706
|
-
if (manifest && typeof manifest === 'object') return manifest
|
|
1707
|
-
|
|
1708
|
-
const manifestPath = typeof manifest === 'string'
|
|
1709
|
-
? manifest
|
|
1710
|
-
: staticDir ? path.join(staticDir, 'dist', 'manifest.json') : null
|
|
1711
|
-
|
|
1712
|
-
if (!manifestPath) return {}
|
|
1713
|
-
|
|
1714
|
-
try {
|
|
1715
|
-
return JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
1716
|
-
} catch {
|
|
1717
|
-
return {}
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
1712
|
/**
|
|
1722
1713
|
* Return a copy of the spec with the hydrate path and any meta.styles paths
|
|
1723
1714
|
* resolved to their production bundle paths (if manifest entries exist).
|