@oddsquad/vite-plugin-lit 0.6.1 → 0.7.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 (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +28 -12
  3. package/bin.mjs +87 -5
  4. package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-F2EfZsFX.js → browser-agent-rpc-BXhoSh1z-BuCvPGjS.js} +2 -2
  5. package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-F2EfZsFX.js.map → browser-agent-rpc-BXhoSh1z-BuCvPGjS.js.map} +1 -1
  6. package/dist/client/assets/{index-B2HYO7lk.js → index-D632jo79.js} +22 -3
  7. package/dist/client/assets/index-D632jo79.js.map +1 -0
  8. package/dist/client/index.html +1 -1
  9. package/dist/standalone/lit-devtools.js +6820 -0
  10. package/lib/devframe/allowed-origins.d.ts +13 -0
  11. package/lib/devframe/allowed-origins.d.ts.map +1 -0
  12. package/lib/devframe/allowed-origins.js +63 -0
  13. package/lib/devframe/allowed-origins.js.map +1 -0
  14. package/lib/options.d.ts +26 -0
  15. package/lib/options.d.ts.map +1 -1
  16. package/lib/options.js +19 -0
  17. package/lib/options.js.map +1 -1
  18. package/lib/plugin.d.ts.map +1 -1
  19. package/lib/plugin.js +3 -0
  20. package/lib/plugin.js.map +1 -1
  21. package/lib/plugins/private-fields.d.ts +27 -0
  22. package/lib/plugins/private-fields.d.ts.map +1 -0
  23. package/lib/plugins/private-fields.js +259 -0
  24. package/lib/plugins/private-fields.js.map +1 -0
  25. package/lib/runtime/child-state.d.ts +100 -0
  26. package/lib/runtime/child-state.d.ts.map +1 -0
  27. package/lib/runtime/child-state.js +446 -0
  28. package/lib/runtime/child-state.js.map +1 -0
  29. package/lib/runtime/inspector/install.js +4 -1
  30. package/lib/runtime/inspector/install.js.map +1 -1
  31. package/lib/runtime/patch.d.ts +24 -0
  32. package/lib/runtime/patch.d.ts.map +1 -1
  33. package/lib/runtime/patch.js +22 -1
  34. package/lib/runtime/patch.js.map +1 -1
  35. package/lib/runtime/rpc-transport.d.ts +8 -0
  36. package/lib/runtime/rpc-transport.d.ts.map +1 -1
  37. package/lib/runtime/rpc-transport.js +1 -0
  38. package/lib/runtime/rpc-transport.js.map +1 -1
  39. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  40. package/lib/runtime/source-overlay/editors.js +9 -4
  41. package/lib/runtime/source-overlay/editors.js.map +1 -1
  42. package/lib/runtime/standalone.d.ts +27 -0
  43. package/lib/runtime/standalone.d.ts.map +1 -0
  44. package/lib/runtime/standalone.js +50 -0
  45. package/lib/runtime/standalone.js.map +1 -0
  46. package/lib/runtime/timeline/install.js +4 -2
  47. package/lib/runtime/timeline/install.js.map +1 -1
  48. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  49. package/lib/runtime/timeline/lifecycle.js +5 -1
  50. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  51. package/package.json +13 -9
  52. package/types/timeline.d.ts +4 -1
  53. package/types/timeline.d.ts.map +1 -1
  54. package/types/timeline.js.map +1 -1
  55. package/dist/client/assets/index-B2HYO7lk.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,45 @@
3
3
  Notable changes per release. Versions before 0.3.0 predate this file; see the
4
4
  git history for those.
5
5
 
6
+ ## 0.7.0 — 2026-09-29
7
+
8
+ Hot-patching covers two cases it used to get wrong: components with native
9
+ `#private` members, which threw, and child elements whose parent template you
10
+ edit, which lost their state. The standalone `lit-devtools dev` server also
11
+ gets pages to feed it: one script tag connects any page running Lit, whether
12
+ Vite serves it or not, directly or through a proxy. Two fixes ride along:
13
+ open-in-editor links lose a stray slash, and the timeline no longer misses the
14
+ first component's connect and disconnect.
15
+
16
+ ### Added
17
+
18
+ - **Components with `#private` fields keep hot-patching.** Editing an element
19
+ that uses native `#private` fields or methods now updates it in place and
20
+ keeps its private state, instead of throwing "Cannot read private member".
21
+ Set `hmr.privateFields: false` to keep real brand checks in dev.
22
+ - **Child components keep their state when you edit the parent.** Changing the
23
+ template a child element sits in no longer resets its `@state` and
24
+ `#private` fields; `hmr.childState: 'reuse'` keeps the original element
25
+ where it has no bindings, and `'reset'` restores the old behaviour. The
26
+ DevTools Settings tab can switch the mode live; the next edit uses it.
27
+ - **Pages outside Vite can feed the standalone panel.** `lit-devtools dev` now
28
+ prints a `<script src=".../lit-devtools.js">` tag; a page that loads it shows
29
+ its component tree, inspector and timeline in the panel, even when Vite
30
+ doesn't serve it or it's reached through a proxy or tunnel. Pages on
31
+ localhost connect on any port, and `--allow-origin` admits others, with `*`
32
+ for any subdomain (`--allow-origin 'https://*.webcontainer-api.io'` for
33
+ StackBlitz). HMR, source locations and open-in-editor still need Vite.
34
+
35
+ ### Fixed
36
+
37
+ - **Open-in-editor links use the documented URL form.** Links to VS Code,
38
+ Cursor, Zed and Windsurf no longer carry a double slash before absolute
39
+ paths like `/Users/...`.
40
+ - **The timeline records the first component's connect and disconnect.** On a
41
+ page with no Lit element when the DevTools runtime starts, the first
42
+ component defined afterwards now shows its `connectedCallback` and
43
+ `disconnectedCallback` events like the rest.
44
+
6
45
  ## 0.6.1 — 2026-09-29
7
46
 
8
47
  A fix release. Components whose `extends` clause holds braces load in dev
package/README.md CHANGED
@@ -121,21 +121,31 @@ The two differ in how the server is found, not in what it can do:
121
121
  plugin logs a warning saying so at startup, naming the reason.
122
122
 
123
123
  The CLI also has `lit-devtools dev`, a standalone devframe server. Started on
124
- its own it shows an empty panel, because it has no page of its own. A page
125
- served by a Vite dev server that loads this plugin's runtime can point itself
126
- at it and feed it the live component tree, inspector and timeline:
124
+ its own it shows an empty panel, because it has no page of its own. Add the
125
+ script tag it prints at startup to any page, including one that Vite does not
126
+ serve and one on another origin, and the page feeds it the live component tree,
127
+ inspector and timeline:
127
128
 
128
- ```ts
129
- import {connectToDevServer} from '@oddsquad/vite-plugin-lit/connect.js';
130
-
131
- await connectToDevServer('http://localhost:5180/');
129
+ ```html
130
+ <script src="http://localhost:5180/lit-devtools.js"></script>
132
131
  ```
133
132
 
134
- The server asks for its one-time code unless you start it with `--no-auth`. What
135
- this does not do yet: put the runtime into a page that is not on a Vite dev
136
- server, and set up the cross-origin access and authentication a page on another
137
- origin needs. The dev server's `__connection.json` sends no CORS headers today,
138
- so from a different origin the connection is blocked by the browser.
133
+ Put it before the scripts that define your components. The server asks for its
134
+ one-time code unless you start it with `--no-auth`: type the code into the
135
+ prompt the page shows, open the page once with `#devframe_otp=<code>` on its
136
+ URL, or skip the gate on a loopback host with `--no-auth`. Pages on a loopback
137
+ origin (any port) may connect; for any other origin, pass it to the server with
138
+ `--allow-origin https://myapp.test:8443` (repeatable). A `*` in the host
139
+ matches any subdomain, e.g. `--allow-origin 'https://*.webcontainer-api.io'`
140
+ for StackBlitz, where every port gets its own origin.
141
+
142
+ Outside Vite the page has no build-time transforms, so HMR patching, source
143
+ locations and open-in-editor do not work there; the tree, inspector and timeline
144
+ do. A page that Vite serves can instead call `connectToDevServer()` from
145
+ `@oddsquad/vite-plugin-lit/connect.js`.
146
+
147
+ To try it from this repo, run `pnpm run standalone:demo`; see
148
+ [Playground](#playground).
139
149
 
140
150
  ## Playground
141
151
 
@@ -148,6 +158,12 @@ straight from the repo URL. Run it locally from the repo root:
148
158
  pnpm dev # builds the plugin, then serves http://localhost:5179
149
159
  ```
150
160
 
161
+ The same playground runs in standalone mode, built to static files and fed to
162
+ a `lit-devtools dev` panel on another port: `pnpm run standalone:demo` here, or
163
+ [on StackBlitz](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground?startScript=standalone)
164
+ with `?startScript=standalone`. StackBlitz installs the published plugin, so
165
+ that link works from the first release that ships standalone mode.
166
+
151
167
  ## Development
152
168
 
153
169
  Requires Node 26 and pnpm 12 (`corepack enable` picks up the pinned version).
package/bin.mjs CHANGED
@@ -30,7 +30,11 @@
30
30
  * @see plans/roadmap/03-cli-and-stdio-mcp.md
31
31
  */
32
32
 
33
+ import {readFile} from 'node:fs/promises';
34
+ import {createRequire} from 'node:module';
33
35
  import process from 'node:process';
36
+ import {pathToFileURL} from 'node:url';
37
+ import {resolveAllowedOrigins} from './lib/devframe/allowed-origins.js';
34
38
  import {createStandaloneLitDevframe} from './lib/devframe/rpc-source.js';
35
39
  import {PACKAGE_VERSION} from './lib/devframe/paths.js';
36
40
 
@@ -43,6 +47,12 @@ import {PACKAGE_VERSION} from './lib/devframe/paths.js';
43
47
  */
44
48
  const DEFAULT_DEV_PORT = 5180;
45
49
 
50
+ /** The script pages outside Vite load; built by `build:standalone`. */
51
+ const STANDALONE_SCRIPT = new URL(
52
+ './dist/standalone/lit-devtools.js',
53
+ import.meta.url
54
+ );
55
+
46
56
  /** True for a host only this machine can reach. */
47
57
  const isLoopbackHost = (host) =>
48
58
  host === 'localhost' ||
@@ -75,6 +85,13 @@ const main = async () => {
75
85
  .option('--port <port>', 'Port to listen on', {default: DEFAULT_DEV_PORT})
76
86
  .option('--host <host>', 'Host to bind to', {default: 'localhost'})
77
87
  .option('--open', 'Open the browser on start')
88
+ .option(
89
+ '--allow-origin <origin>',
90
+ 'Also let pages served from this origin connect, e.g. ' +
91
+ 'https://myapp.test:8443, or https://*.webcontainer-api.io for any ' +
92
+ 'host under a domain. Loopback origins on any port are always ' +
93
+ 'allowed. Repeatable.'
94
+ )
78
95
  .option(
79
96
  '--no-auth',
80
97
  'Skip the one-time-code gate, so a page can connect without a token'
@@ -95,16 +112,81 @@ const main = async () => {
95
112
  }
96
113
  const {createDevServer} = await import('devframe/adapters/dev');
97
114
  // A standalone server has no Vite, so it has no page of its own: the
98
- // panel stays empty until a page dials in with `connectToDevServer()`
99
- // (see `lib/runtime/rpc-transport.ts`), which carries the runtime's
100
- // usual channels over devframe RPC. Injecting the runtime into a page
101
- // that is not on a Vite dev server is not something this command does.
102
- await createDevServer(
115
+ // panel stays empty until a page dials in. It gets there by loading
116
+ // `/lit-devtools.js` (served below), which starts the runtime and calls
117
+ // `connectToDevServer()` (see `lib/runtime/rpc-transport.ts`). HMR
118
+ // patching and source metadata need Vite's transforms and are not part
119
+ // of it.
120
+ let allowedOrigins;
121
+ try {
122
+ allowedOrigins = resolveAllowedOrigins(
123
+ [flags.allowOrigin]
124
+ .flat()
125
+ .filter((origin) => origin != null)
126
+ .map(String)
127
+ );
128
+ } catch (error) {
129
+ console.error(`[lit-devtools] ${error.message}`);
130
+ process.exit(1);
131
+ }
132
+ let server;
133
+ const serveScript = async () => {
134
+ const headers = {
135
+ 'content-type': 'text/javascript; charset=utf-8',
136
+ 'cache-control': 'no-store',
137
+ };
138
+ let bundle;
139
+ try {
140
+ bundle = await readFile(STANDALONE_SCRIPT, 'utf8');
141
+ } catch {
142
+ return new Response(
143
+ '// lit-devtools: the standalone script is not built. ' +
144
+ 'Run `pnpm run build` in the package and restart.\n',
145
+ {status: 500, headers}
146
+ );
147
+ }
148
+ // The descriptor `__connection.json` would answer with, inlined so the
149
+ // page never fetches it: that request is cross-origin from a page
150
+ // that is not on this server, and gets no CORS headers. Picked, not
151
+ // spread, so nothing else devframe puts in it rides along to any page
152
+ // that can load a script tag.
153
+ const {backend, websocket, sse} = server.connectionMeta();
154
+ const config = {
155
+ url: server.origin + '/',
156
+ connectionMeta: {backend, websocket, sse},
157
+ };
158
+ return new Response(
159
+ `globalThis.__LIT_DEVTOOLS_CONNECT__ = ${JSON.stringify(config)};\n${bundle}`,
160
+ {headers}
161
+ );
162
+ };
163
+ // devframe mounts a static catch-all that answers 404 for paths it
164
+ // does not know, so a route added to its app in `onReady` would never be
165
+ // reached. The route has to go on the app *before* devframe's, which
166
+ // means handing it one -- built from the copy of h3 devframe itself
167
+ // resolves, so the two agree on the class.
168
+ const devframeRequire = createRequire(
169
+ import.meta.resolve('devframe/adapters/dev')
170
+ );
171
+ const {H3} = await import(
172
+ pathToFileURL(devframeRequire.resolve('h3')).href
173
+ );
174
+ const app = new H3();
175
+ app.use('/lit-devtools.js', serveScript);
176
+ server = await createDevServer(
103
177
  createStandaloneLitDevframe({version: PACKAGE_VERSION}),
104
178
  {
105
179
  host: flags.host,
106
180
  port: Number(flags.port),
107
181
  flags: {open: Boolean(flags.open), auth: flags.auth},
182
+ app,
183
+ ...(allowedOrigins !== undefined ? {allowedOrigins} : {}),
184
+ onReady({origin}) {
185
+ console.log(
186
+ `\n[lit-devtools] Add this to a page to connect it:\n\n` +
187
+ ` <script src="${origin}/lit-devtools.js"></script>\n`
188
+ );
189
+ },
108
190
  }
109
191
  );
110
192
  });
@@ -1,4 +1,4 @@
1
- import { n as onBrowserAgentToolsChanged, r as nanoid, t as listBrowserAgentTools } from "./index-B2HYO7lk.js";
1
+ import { n as onBrowserAgentToolsChanged, r as nanoid, t as listBrowserAgentTools } from "./index-D632jo79.js";
2
2
  //#region node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs
3
3
  var CLIENT_ID_STORAGE_KEY = "devframe:client-id";
4
4
  var memoryClientId;
@@ -66,4 +66,4 @@ function setupBrowserAgentRpcBridge(rpc) {
66
66
  //#endregion
67
67
  export { setupBrowserAgentRpcBridge };
68
68
 
69
- //# sourceMappingURL=browser-agent-rpc-BXhoSh1z-F2EfZsFX.js.map
69
+ //# sourceMappingURL=browser-agent-rpc-BXhoSh1z-BuCvPGjS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-agent-rpc-BXhoSh1z-F2EfZsFX.js","names":[],"sources":["../../../node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs"],"sourcesContent":["import { nanoid } from \"./utils/nanoid.mjs\";\nimport { n as onBrowserAgentToolsChanged, t as listBrowserAgentTools } from \"./browser-agent-Pu-FLk6I.mjs\";\n//#region src/client/client-id.ts\nconst CLIENT_ID_STORAGE_KEY = \"devframe:client-id\";\nlet memoryClientId;\n/**\n* This browser tab's stable client id: one nanoid per tab, persisted in\n* `sessionStorage` so it survives page reloads and RPC reconnects. The node\n* side uses it to tell connected tabs apart across reconnects (see #394).\n*\n* Tab duplication copies `sessionStorage`, so two tabs can briefly share an id\n* until per-tab disambiguation lands with the wider tab-metadata work.\n*/\nfunction resolveClientId(win = globalThis.window) {\n\ttry {\n\t\tconst storage = win?.sessionStorage;\n\t\tif (storage) {\n\t\t\tlet id = storage.getItem(CLIENT_ID_STORAGE_KEY);\n\t\t\tif (!id) {\n\t\t\t\tid = nanoid();\n\t\t\t\tstorage.setItem(CLIENT_ID_STORAGE_KEY, id);\n\t\t\t}\n\t\t\treturn id;\n\t\t}\n\t} catch {}\n\tmemoryClientId ??= nanoid();\n\treturn memoryClientId;\n}\n//#endregion\n//#region src/client/browser-agent-rpc.ts\n/** Mirror this document's browser-agent registry over its existing RPC connection. */\nfunction setupBrowserAgentRpcBridge(rpc) {\n\trpc.client.register({\n\t\tname: \"devframe:agent:invoke-client-tool\",\n\t\ttype: \"action\",\n\t\tjsonSerializable: true,\n\t\thandler: async (id, args) => {\n\t\t\tconst tool = listBrowserAgentTools().find((tool) => tool.id === id);\n\t\t\tif (!tool) throw new Error(`[devframe/agent] browser tool \"${id}\" not found`);\n\t\t\treturn await tool.invoke(args);\n\t\t}\n\t});\n\tlet queued = false;\n\tlet disposed = false;\n\tlet lastSyncedCount = 0;\n\tconst sync = () => {\n\t\tif (queued || disposed) return;\n\t\tqueued = true;\n\t\tqueueMicrotask(async () => {\n\t\t\tqueued = false;\n\t\t\tif (disposed) return;\n\t\t\tconst manifests = listBrowserAgentTools().map(({ invoke: _, ...manifest }) => manifest);\n\t\t\tif (manifests.length === 0 && lastSyncedCount === 0) return;\n\t\t\tlastSyncedCount = manifests.length;\n\t\t\tawait rpc.callOptional(\"devframe:agent:sync-client-tools\", resolveClientId(), manifests).catch(() => {});\n\t\t});\n\t};\n\tconst stopTools = onBrowserAgentToolsChanged(sync);\n\tconst stopConnection = rpc.events.on(\"connection:status\", (status) => {\n\t\tif (status === \"connected\") sync();\n\t});\n\tsync();\n\treturn () => {\n\t\tdisposed = true;\n\t\tstopTools();\n\t\tstopConnection();\n\t};\n}\n//#endregion\nexport { setupBrowserAgentRpcBridge };\n"],"x_google_ignoreList":[0],"mappings":";;AAGA,IAAM,wBAAwB;AAC9B,IAAI;;;;;;;;;AASJ,SAAS,gBAAgB,MAAM,WAAW,QAAQ;CACjD,IAAI;EACH,MAAM,UAAU,KAAK;EACrB,IAAI,SAAS;GACZ,IAAI,KAAK,QAAQ,QAAQ,qBAAqB;GAC9C,IAAI,CAAC,IAAI;IACR,KAAK,OAAO;IACZ,QAAQ,QAAQ,uBAAuB,EAAE;GAC1C;GACA,OAAO;EACR;CACD,QAAQ,CAAC;CACT,mBAAmB,OAAO;CAC1B,OAAO;AACR;;AAIA,SAAS,2BAA2B,KAAK;CACxC,IAAI,OAAO,SAAS;EACnB,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,SAAS,OAAO,IAAI,SAAS;GAC5B,MAAM,OAAO,sBAAsB,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,EAAE;GAClE,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,kCAAkC,GAAG,YAAY;GAC5E,OAAO,MAAM,KAAK,OAAO,IAAI;EAC9B;CACD,CAAC;CACD,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,kBAAkB;CACtB,MAAM,aAAa;EAClB,IAAI,UAAU,UAAU;EACxB,SAAS;EACT,eAAe,YAAY;GAC1B,SAAS;GACT,IAAI,UAAU;GACd,MAAM,YAAY,sBAAsB,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG,GAAG,eAAe,QAAQ;GACtF,IAAI,UAAU,WAAW,KAAK,oBAAoB,GAAG;GACrD,kBAAkB,UAAU;GAC5B,MAAM,IAAI,aAAa,oCAAoC,gBAAgB,GAAG,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;EACxG,CAAC;CACF;CACA,MAAM,YAAY,2BAA2B,IAAI;CACjD,MAAM,iBAAiB,IAAI,OAAO,GAAG,sBAAsB,WAAW;EACrE,IAAI,WAAW,aAAa,KAAK;CAClC,CAAC;CACD,KAAK;CACL,aAAa;EACZ,WAAW;EACX,UAAU;EACV,eAAe;CAChB;AACD"}
1
+ {"version":3,"file":"browser-agent-rpc-BXhoSh1z-BuCvPGjS.js","names":[],"sources":["../../../node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs"],"sourcesContent":["import { nanoid } from \"./utils/nanoid.mjs\";\nimport { n as onBrowserAgentToolsChanged, t as listBrowserAgentTools } from \"./browser-agent-Pu-FLk6I.mjs\";\n//#region src/client/client-id.ts\nconst CLIENT_ID_STORAGE_KEY = \"devframe:client-id\";\nlet memoryClientId;\n/**\n* This browser tab's stable client id: one nanoid per tab, persisted in\n* `sessionStorage` so it survives page reloads and RPC reconnects. The node\n* side uses it to tell connected tabs apart across reconnects (see #394).\n*\n* Tab duplication copies `sessionStorage`, so two tabs can briefly share an id\n* until per-tab disambiguation lands with the wider tab-metadata work.\n*/\nfunction resolveClientId(win = globalThis.window) {\n\ttry {\n\t\tconst storage = win?.sessionStorage;\n\t\tif (storage) {\n\t\t\tlet id = storage.getItem(CLIENT_ID_STORAGE_KEY);\n\t\t\tif (!id) {\n\t\t\t\tid = nanoid();\n\t\t\t\tstorage.setItem(CLIENT_ID_STORAGE_KEY, id);\n\t\t\t}\n\t\t\treturn id;\n\t\t}\n\t} catch {}\n\tmemoryClientId ??= nanoid();\n\treturn memoryClientId;\n}\n//#endregion\n//#region src/client/browser-agent-rpc.ts\n/** Mirror this document's browser-agent registry over its existing RPC connection. */\nfunction setupBrowserAgentRpcBridge(rpc) {\n\trpc.client.register({\n\t\tname: \"devframe:agent:invoke-client-tool\",\n\t\ttype: \"action\",\n\t\tjsonSerializable: true,\n\t\thandler: async (id, args) => {\n\t\t\tconst tool = listBrowserAgentTools().find((tool) => tool.id === id);\n\t\t\tif (!tool) throw new Error(`[devframe/agent] browser tool \"${id}\" not found`);\n\t\t\treturn await tool.invoke(args);\n\t\t}\n\t});\n\tlet queued = false;\n\tlet disposed = false;\n\tlet lastSyncedCount = 0;\n\tconst sync = () => {\n\t\tif (queued || disposed) return;\n\t\tqueued = true;\n\t\tqueueMicrotask(async () => {\n\t\t\tqueued = false;\n\t\t\tif (disposed) return;\n\t\t\tconst manifests = listBrowserAgentTools().map(({ invoke: _, ...manifest }) => manifest);\n\t\t\tif (manifests.length === 0 && lastSyncedCount === 0) return;\n\t\t\tlastSyncedCount = manifests.length;\n\t\t\tawait rpc.callOptional(\"devframe:agent:sync-client-tools\", resolveClientId(), manifests).catch(() => {});\n\t\t});\n\t};\n\tconst stopTools = onBrowserAgentToolsChanged(sync);\n\tconst stopConnection = rpc.events.on(\"connection:status\", (status) => {\n\t\tif (status === \"connected\") sync();\n\t});\n\tsync();\n\treturn () => {\n\t\tdisposed = true;\n\t\tstopTools();\n\t\tstopConnection();\n\t};\n}\n//#endregion\nexport { setupBrowserAgentRpcBridge };\n"],"x_google_ignoreList":[0],"mappings":";;AAGA,IAAM,wBAAwB;AAC9B,IAAI;;;;;;;;;AASJ,SAAS,gBAAgB,MAAM,WAAW,QAAQ;CACjD,IAAI;EACH,MAAM,UAAU,KAAK;EACrB,IAAI,SAAS;GACZ,IAAI,KAAK,QAAQ,QAAQ,qBAAqB;GAC9C,IAAI,CAAC,IAAI;IACR,KAAK,OAAO;IACZ,QAAQ,QAAQ,uBAAuB,EAAE;GAC1C;GACA,OAAO;EACR;CACD,QAAQ,CAAC;CACT,mBAAmB,OAAO;CAC1B,OAAO;AACR;;AAIA,SAAS,2BAA2B,KAAK;CACxC,IAAI,OAAO,SAAS;EACnB,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,SAAS,OAAO,IAAI,SAAS;GAC5B,MAAM,OAAO,sBAAsB,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,EAAE;GAClE,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,kCAAkC,GAAG,YAAY;GAC5E,OAAO,MAAM,KAAK,OAAO,IAAI;EAC9B;CACD,CAAC;CACD,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,kBAAkB;CACtB,MAAM,aAAa;EAClB,IAAI,UAAU,UAAU;EACxB,SAAS;EACT,eAAe,YAAY;GAC1B,SAAS;GACT,IAAI,UAAU;GACd,MAAM,YAAY,sBAAsB,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG,GAAG,eAAe,QAAQ;GACtF,IAAI,UAAU,WAAW,KAAK,oBAAoB,GAAG;GACrD,kBAAkB,UAAU;GAC5B,MAAM,IAAI,aAAa,oCAAoC,gBAAgB,GAAG,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;EACxG,CAAC;CACF;CACA,MAAM,YAAY,2BAA2B,IAAI;CACjD,MAAM,iBAAiB,IAAI,OAAO,GAAG,sBAAsB,WAAW;EACrE,IAAI,WAAW,aAAa,KAAK;CAClC,CAAC;CACD,KAAK;CACL,aAAa;EACZ,WAAW;EACX,UAAU;EACV,eAAe;CAChB;AACD"}
@@ -1457,7 +1457,7 @@ var listElements = (events) => {
1457
1457
  }));
1458
1458
  };
1459
1459
  //#endregion
1460
- //#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
1460
+ //#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorate.js
1461
1461
  function __decorate(decorators, target, key, desc) {
1462
1462
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1463
1463
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -7016,7 +7016,7 @@ async function getDevframeRpcClient(options = {}) {
7016
7016
  bootstrapAuthSettled = true;
7017
7017
  });
7018
7018
  if (connectionMeta.mcp) __vitePreload(async () => {
7019
- const { setupBrowserAgentRpcBridge } = await import("./browser-agent-rpc-BXhoSh1z-F2EfZsFX.js");
7019
+ const { setupBrowserAgentRpcBridge } = await import("./browser-agent-rpc-BXhoSh1z-BuCvPGjS.js");
7020
7020
  return { setupBrowserAgentRpcBridge };
7021
7021
  }, [], import.meta.url).then(({ setupBrowserAgentRpcBridge }) => {
7022
7022
  if (!closed) disposeBrowserAgentBridge = setupBrowserAgentRpcBridge(rpc);
@@ -11129,6 +11129,7 @@ var DevtoolsSettings = class DevtoolsSettings extends i$2 {
11129
11129
  return {
11130
11130
  hmrReconnect: s.hmr.reconnect,
11131
11131
  hmrOnIncompatible: s.hmr.onIncompatible,
11132
+ hmrChildState: s.hmr.childState,
11132
11133
  hmrIndicatorVisible: s.hmr.indicatorEnabled,
11133
11134
  hmrIndicatorCount: s.hmr.indicatorCount,
11134
11135
  sourceOverlayEditor: s.sourceOverlay.editor
@@ -11241,6 +11242,7 @@ var DevtoolsSettings = class DevtoolsSettings extends i$2 {
11241
11242
  </p>`;
11242
11243
  const reconnect = o.hmrReconnect ?? s.hmr.reconnect;
11243
11244
  const onIncompatible = o.hmrOnIncompatible ?? s.hmr.onIncompatible;
11245
+ const childState = o.hmrChildState ?? s.hmr.childState;
11244
11246
  const indicatorVisible = o.hmrIndicatorVisible ?? s.hmr.indicatorEnabled;
11245
11247
  const indicatorCount = o.hmrIndicatorCount ?? s.hmr.indicatorCount;
11246
11248
  return b`
@@ -11275,6 +11277,23 @@ var DevtoolsSettings = class DevtoolsSettings extends i$2 {
11275
11277
  ${this._ovrSource("hmrOnIncompatible", s.hmr.onIncompatible)}
11276
11278
  </td>
11277
11279
  </tr>
11280
+ <tr>
11281
+ <td class="key">child state</td>
11282
+ <td class="val">
11283
+ <select
11284
+ @change=${(e) => this._set("hmrChildState", e.target.value)}
11285
+ >
11286
+ ${[
11287
+ "transfer",
11288
+ "reuse",
11289
+ "reset"
11290
+ ].map((mode) => b`<option value=${mode} ?selected=${childState === mode}>
11291
+ ${mode}
11292
+ </option>`)}
11293
+ </select>
11294
+ ${this._ovrSource("hmrChildState", s.hmr.childState)}
11295
+ </td>
11296
+ </tr>
11278
11297
  <tr class=${s.hmr.indicatorEnabled ? "" : "row-disabled"}>
11279
11298
  <td class="key">indicator</td>
11280
11299
  <td class="val">
@@ -11726,4 +11745,4 @@ LitDevtoolsPanel = __decorate([t$2("lit-devtools-panel")], LitDevtoolsPanel);
11726
11745
  //#endregion
11727
11746
  export { onBrowserAgentToolsChanged as n, nanoid as r, listBrowserAgentTools as t };
11728
11747
 
11729
- //# sourceMappingURL=index-B2HYO7lk.js.map
11748
+ //# sourceMappingURL=index-D632jo79.js.map