@popmelt.com/core 0.20.3 → 0.21.1

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/README.md CHANGED
@@ -36,6 +36,169 @@ To add local object recognition to an existing Popmelt project, use:
36
36
  The integration installs See and adds it to the existing Core provider's
37
37
  `extensions` array without replacing Core.
38
38
 
39
+ ### Experimental standalone browser entry
40
+
41
+ The first framework-independent integration is available at `@popmelt.com/core/browser`.
42
+ It mounts Popmelt beside the host application, without JSX or a React provider in
43
+ your application code. React still renders Popmelt internally; the package's
44
+ existing React, React DOM, and Lucide React peer dependencies are still required.
45
+ This is an experimental DOM integration, not a claim of Vue/Svelte/Angular feature
46
+ parity. React-specific component hierarchy and library previews are not supplied
47
+ for other frameworks yet.
48
+
49
+ For a Vite host, keep the existing `@popmelt.com/core/vite` bridge plugin, then use
50
+ this in your browser entry:
51
+
52
+ ```js
53
+ if (import.meta.env.DEV) {
54
+ const { mountPopmelt } = await import('@popmelt.com/core/browser');
55
+ const popmelt = await mountPopmelt({ enabled: true });
56
+ import.meta.hot?.dispose(() => popmelt.unmount());
57
+ }
58
+ ```
59
+
60
+ Enablement is explicit: omitted/false `enabled` or a server-side call is a no-op
61
+ and does not load the renderer. `unmount()` removes the UI and releases its
62
+ subscriptions without deleting saved annotations or cancelling bridge jobs.
63
+ Call it before mounting again; simultaneous integrations on one page are rejected.
64
+ Use either this entry or `PopmeltProvider`, not both. Pass `bridgeUrl`, `projectId`,
65
+ or a host-router `navigate` callback when these are not supplied by your integration.
66
+ Explicit bridge/project options take effect before startup and restore prior
67
+ host bindings when unmounted; no manual browser-global assignment is needed.
68
+
69
+ For Vue, mount your app normally and mount Popmelt alongside it, not inside the
70
+ Vue component tree. Keep your Vue Vite plugin and add `popmelt()` to that same
71
+ plugin list. Connect the returned `unmount()` to your app's teardown (for example,
72
+ `app.onUnmount(() => popmelt.unmount())` in Vue 3.5+). With Vue Router, pass
73
+ `navigate: (url) => router.push(url)`; no router dependency is required by Core.
74
+
75
+ The plain HTML/JS fixture at `e2e/fixtures/browser` and Vue fixture at
76
+ `e2e/fixtures/vue` share a browser workflow: author and recover an annotation
77
+ draft through target replacement and page reload, submit it, receive streamed
78
+ and final replies, and continue the same thread after another target replacement.
79
+ Both verify durable thread history, stage a Steer edit, select Chat through the
80
+ toolbar, and recover the exact edited style and completed thread after reload.
81
+ Vanilla replacement creates a fresh DOM node without copying Popmelt attributes
82
+ or inline styles; Vue uses keyed rerenders. Both verify teardown/remount releases
83
+ Popmelt's UI and connection while preserving the host DOM and input state.
84
+
85
+ Vue additionally exercises real Vite SFC template/script hot updates and Vue
86
+ Router navigation/back. Hot updates must retain the same Popmelt renderer and
87
+ bridge connection, without a full-page reload. The tests edit temporary fixture
88
+ copies, not repository files.
89
+ Only the external provider process is controlled; HTTP, SSE, queue dispatch, and
90
+ durable thread storage use the real bridge. It does not run your installed agent.
91
+ Run both fixtures after building:
92
+
93
+ ```sh
94
+ pnpm run build
95
+ pnpm exec vitest run --config vitest.browser.config.ts e2e/browser-mount.browser.ts
96
+ ```
97
+
98
+ For a fresh tarball installation with the real Vite bridge plugin, run
99
+ `pnpm run vue:smoke`. This opt-in check needs npm registry access and Chrome
100
+ (`CHROME_PATH` can override its location). It installs into a temporary Vue app,
101
+ verifies bridge startup/shutdown and the toolbar, and checks that the
102
+ development-only import is absent from production output. It does not publish
103
+ or replace the separate package-size release gate.
104
+
105
+ The plain HTML/JS fixture still uses Vite and installed npm peers; this does not
106
+ validate a bundler-free script tag or arbitrary static-server integration.
107
+ The journeys use stable target IDs and Chrome, not a cross-browser or arbitrary
108
+ DOM-identity matrix. They validate the client-side DOM boundary, not Vue component
109
+ metadata. Router guards, nested routes, and hash-history mode are
110
+ not yet covered. Vue and its test tooling are development dependencies only;
111
+ they do not add a second Popmelt UI implementation or become runtime dependencies.
112
+
113
+ ### Experimental Nuxt integration
114
+
115
+ For Nuxt 4.5.2, install Popmelt and its internal renderer peers as development
116
+ dependencies, then add the module:
117
+
118
+ ```sh
119
+ npm install -D @popmelt.com/core react react-dom lucide-react
120
+ ```
121
+
122
+ ```ts
123
+ // nuxt.config.ts
124
+ export default defineNuxtConfig({
125
+ modules: ['@popmelt.com/core/nuxt'],
126
+ });
127
+ ```
128
+
129
+ No separate Vite plugin, React provider, or manual browser mount is needed.
130
+ The module starts the local bridge in development and mounts Popmelt after Nuxt
131
+ has mounted the client app. It uses Nuxt's router for navigation and releases
132
+ its bridge lease on graceful shutdown. When Nuxt's CLI exits immediately, the
133
+ existing lease-expiry cleanup stops an idle bridge within about a minute.
134
+ Production builds do not register the client
135
+ plugin or start the bridge. Optional `popmelt` settings are `port`, `projectRoot`,
136
+ and `bridge` (set `bridge: false` to disable automatic bridge startup).
137
+
138
+ Run `pnpm run nuxt:smoke` with a Nuxt-compatible Node version (22.19+, 24.11+,
139
+ or 26+) to check a fresh tarball installation. It requires npm registry access
140
+ and Chrome, like the Vue smoke check. The isolated fixture checks SSR/hydration,
141
+ thread recovery through navigation/back and template/script HMR, and production
142
+ exclusion. It also exercises annotation submission, streaming replies, same-thread
143
+ follow-ups, and staged style recovery through routing and reload. Provider responses
144
+ are controlled in that journey; it never launches your coding agent.
145
+ Nuxt 3, component metadata, and advanced router configurations are not yet tested.
146
+
147
+ ### Experimental Svelte and SvelteKit
148
+
149
+ Tested with Svelte 5.57.0, SvelteKit 2.70.3, and Vite 8.2.2. Install the same
150
+ development dependencies used by the standalone entry:
151
+
152
+ ```sh
153
+ npm install -D @popmelt.com/core react react-dom lucide-react
154
+ ```
155
+
156
+ Keep your existing Vite configuration and add `popmelt()` alongside `sveltekit()`
157
+ (or `svelte()` for a plain Svelte app):
158
+
159
+ ```js
160
+ import { sveltekit } from '@sveltejs/kit/vite';
161
+ import { popmelt } from '@popmelt.com/core/vite';
162
+
163
+ export default { plugins: [sveltekit(), popmelt()] };
164
+ ```
165
+
166
+ Mount once in your root `+layout.svelte`, without replacing its existing content:
167
+
168
+ ```svelte
169
+ <script>
170
+ import { onMount } from 'svelte';
171
+ import { goto } from '$app/navigation';
172
+ import { bridgeUrl, projectId } from 'virtual:popmelt/bridge';
173
+
174
+ onMount(() => {
175
+ if (!import.meta.env.DEV || !bridgeUrl || !projectId) return;
176
+ let disposed = false;
177
+ const pending = import('@popmelt.com/core/browser').then(({ mountPopmelt }) => {
178
+ if (!disposed) return mountPopmelt({ enabled: true, bridgeUrl, projectId, navigate: goto });
179
+ });
180
+ void pending.catch(console.error);
181
+ return () => {
182
+ disposed = true;
183
+ void pending.then((handle) => handle?.unmount()).catch(() => {});
184
+ };
185
+ });
186
+ </script>
187
+ ```
188
+
189
+ For plain Svelte, place this in `App.svelte` and omit the `goto` import and
190
+ `navigate` option, or supply your own router callback. TypeScript projects can
191
+ add `/// <reference types="@popmelt.com/core/vite/client" />` to their app's
192
+ ambient declarations for the virtual module types.
193
+
194
+ This setup is development-only, including during SSR. It does not provide
195
+ Svelte component metadata or framework-specific library previews. Advanced
196
+ Kit routing, form actions, and deployment adapters beyond Node are not yet tested.
197
+ Run `pnpm run svelte:smoke` with Node 24.11+, npm registry access, and Chrome
198
+ to check fresh Svelte and SvelteKit installs; it does not launch your coding agent.
199
+ The SvelteKit check also runs the shared annotation/reply/style-edit journey,
200
+ including same-thread continuation and recovery after navigation and reload.
201
+
39
202
  ## Use Popmelt
40
203
 
41
204
  1. Run your project locally and open it in a browser
@@ -83,11 +246,14 @@ Imprint opens the project's shared understanding. Use its filters to review grou
83
246
  - Press Escape to close the open thread
84
247
  - Press Backspace or Delete with a thread open, or with one of its historical annotations selected, to archive that thread
85
248
  - Right-click a draft comment or staged Steer change in its annotation rail to remove only that draft item
249
+ - Right-click a replied rail to dismiss it from the canvas without deleting its history or reverting applied edits. Press **Command/Control+Z** outside a text editor to restore it before reloading. Rails with fresh drafts or active runs are protected.
86
250
  - When a reply is queued, use its pencil or trash button to edit or delete that individual message before it starts. Save an edit with the checkmark or Command/Control+Enter; Escape cancels the edit
87
- - Codex permission requests appear in the thread as a compact action card. Expand it to inspect the exact command or file changes, then choose **Allow once** or **Deny**. Chat text is not a permission grant; Popmelt does not create remembered approvals. Your existing Codex permission rules still apply, so previously allowed commands may run without a new card. Unanswered requests expire after ten minutes, and disconnected runs cannot be approved
251
+ - Codex permission requests appear chronologically in the thread as a compact action card, while the canvas and toolbar show **Approval needed**. Expand the card to inspect the exact command or file changes, then choose **Allow once** or **Deny**. Answered requests become an inline tool icon and label, retained in the thread history. Chat text is not a permission grant; Popmelt does not create remembered approvals. Your existing Codex permission rules still apply, so previously allowed commands may run without a new card. After 10 seconds without a response, a run waiting solely on approval yields to other queued jobs. Approving it while parked moves it to the front of the waiting queue, without interrupting active work. The exact action resumes only after reacquiring a slot; unanswered requests expire on resumption (or at 10 seconds if the run cannot safely yield). Same-thread follow-ups cannot overtake a parked run, and disconnected runs cannot be approved.
88
252
 
89
253
  Interactive approvals require a Codex CLI that supports the app-server human-approval protocol (verified with 0.153.3). Popmelt checks the effective sandbox and reviewer before starting a coding turn; it does not fall back to unrestricted execution. Background memory review remains read-only and noninteractive. Network-specific and session-wide permission grants are not supported by this first version.
90
254
 
255
+ For an opt-in automatic-review trial, start the bridge or wrapped dev server with `POPMELT_CODEX_APPROVALS_REVIEWER=auto_review`. Eligible Codex approvals go to its native reviewer rather than a human; the sandbox and existing permission rules remain in place. This adds model usage and may still deny an action. The default remains human review (`user`); restarting without the variable restores it. Other providers are unchanged.
256
+
91
257
  Archiving hides a thread from the active canvas without deleting its stored conversation. Delete shortcuts are disabled while a text field is focused.
92
258
 
93
259
  ### Pointer gestures
@@ -121,6 +287,8 @@ Ambient capture stays out of toolbar-owned runs, so opening a thread from the in
121
287
 
122
288
  With your app running and the Popmelt canvas active, point at an element and ask Codex, “What am I pointing at?” You can also ask it to inspect a comment or explain what was discussed in an existing thread, without pointing at that item first.
123
289
 
290
+ The prompt hook also supplies a small, timestamped snapshot of bridge-managed runs in the conversation's primary and mounted stores: running, awaiting approval, and queued. This conversation is identified separately; other externally hosted conversations are not counted. Reads are bounded to 500 ms and unavailable bridges are reported as unavailable, not idle. This context is advisory—agents must check live status before restarting or interrupting a bridge.
291
+
124
292
  Popmelt supplies the canvas target and lets Codex read saved threads, unsent drafts, and staged changes as separate kinds of context. A small animated eye appears beside the target or its visible annotation rail during targeted tool access—even if the element itself is offscreen. It indicates access to that item, not the full time the agent spends thinking about it. Reading context does not submit your drafts or start another agent run.
125
293
 
126
294
  When several copies of the app are open, recent canvas interaction helps select the intended page. If the target is still ambiguous, Codex can ask which page you mean instead of guessing. Focus is a timestamped snapshot, so keep the intended target selected or point again when needed.
@@ -248,9 +416,14 @@ export default defineConfig({
248
416
  });
249
417
  ```
250
418
 
251
- ### Astro
419
+ ### Experimental Astro integration
252
420
 
253
- Add the Astro integration:
421
+ For Astro 7.3.1, install Popmelt and its internal renderer peers as development
422
+ dependencies, then add the Astro integration:
423
+
424
+ ```sh
425
+ npm install -D @popmelt.com/core react react-dom lucide-react
426
+ ```
254
427
 
255
428
  ```js
256
429
  // astro.config.mjs
@@ -262,6 +435,20 @@ export default defineConfig({
262
435
  });
263
436
  ```
264
437
 
438
+ The integration starts the bridge and mounts Popmelt automatically in development;
439
+ no React island or provider is needed. It supports DOM annotations and style edits,
440
+ with thread recovery through reloads and Astro ClientRouter navigation. Production
441
+ builds and previews do not mount Popmelt or start its bridge.
442
+
443
+ If your project already mounts a Popmelt provider, use `popmelt({ client: false })`
444
+ to keep that provider in charge of the UI. The existing `port`, `projectRoot`,
445
+ `basePath`, and `bridge` options remain available.
446
+
447
+ Run `pnpm run astro:smoke` with Node 24.11+, npm registry access, and Chrome for
448
+ the fresh-install browser journey. Provider responses are controlled; it does not
449
+ launch your coding agent. Astro component metadata, framework-specific island
450
+ previews, and deployment adapters are not yet covered.
451
+
265
452
  ### Other development servers
266
453
 
267
454
  The wrapper can start Popmelt alongside another development command:
@@ -439,7 +626,7 @@ Popmelt is designed for local development. As with any AI-assisted coding, your
439
626
  | `I` | Enter Imprint mode |
440
627
  | Command/Control+Enter | Send all pending work |
441
628
  | Command/Control+C | Capture a screenshot for pending work when no text is selected |
442
- | Command/Control+Z | Undo a pending change |
629
+ | Command/Control+Z | Undo a pending change or thread dismissal |
443
630
  | Command/Control+Shift+Z | Redo a pending change |
444
631
  | Backspace/Delete | Archive the open or selected historical thread |
445
632
  | Command/Control+Backspace/Delete | Clear all annotations and pending changes |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "popmelt-core",
3
- "version": "0.20.3",
3
+ "version": "0.21.1",
4
4
  "description": "Point out what you mean, talk through changes, and keep your AI on the same page.",
5
5
  "author": {
6
6
  "name": "Popmelt",