@reticlehq/vite-plugin 3.1.0 → 3.3.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.
package/dist/index.cjs CHANGED
@@ -80,8 +80,6 @@ function ensurePairingToken(dir) {
80
80
  // src/index.ts
81
81
  var import_node_os2 = require("node:os");
82
82
  var import_node_path8 = require("node:path");
83
- var import_core6 = require("@babel/core");
84
- var import_babel_plugin = __toESM(require("@reticlehq/babel-plugin"), 1);
85
83
 
86
84
  // ../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
87
85
  var external_exports = {};
@@ -4124,6 +4122,119 @@ var coerce = {
4124
4122
  };
4125
4123
  var NEVER = INVALID;
4126
4124
 
4125
+ // ../../../core/dist/wire/constants/event-types.js
4126
+ var EventType = {
4127
+ DOM_ADDED: "dom.added",
4128
+ DOM_REMOVED: "dom.removed",
4129
+ DOM_ATTR: "dom.attr",
4130
+ DOM_TEXT: "dom.text",
4131
+ NET_REQUEST: "net.request",
4132
+ NET_PENDING: "net.pending",
4133
+ /** An SSE (EventSource) or WebSocket frame — a message on a long-lived streaming connection. */
4134
+ NET_STREAM: "net.stream",
4135
+ /** A web-perf metric a screenshot can't verify: LCP, cumulative layout shift, or a long task. */
4136
+ PERF: "perf",
4137
+ ROUTE_CHANGE: "route.change",
4138
+ CONSOLE_LOG: "console.log",
4139
+ CONSOLE_WARN: "console.warn",
4140
+ CONSOLE_ERROR: "console.error",
4141
+ CONSOLE_INFO: "console.info",
4142
+ CONSOLE_DEBUG: "console.debug",
4143
+ ERROR_UNCAUGHT: "error.uncaught",
4144
+ VISIBLE_SHOWN: "visible.shown",
4145
+ ANIM_START: "anim.start",
4146
+ ANIM_END: "anim.end",
4147
+ SCROLL_POSITION: "scroll.position",
4148
+ REVEAL_SHOWN: "reveal.shown",
4149
+ SIGNAL: "signal",
4150
+ STATE_CHANGE: "state.change",
4151
+ /** a write to localStorage/sessionStorage/cookies — `data: { area, key, old?, new? }` (values redacted). */
4152
+ STORAGE_CHANGE: "storage.change",
4153
+ /** page-level visibility/focus health (distinct from element-level VISIBLE_*). */
4154
+ PAGE_HEALTH: "page.health",
4155
+ /**
4156
+ * synthetic: the page called window.open, so the consequence of what was just clicked may live in
4157
+ * another browsing context this one cannot observe (an OAuth popup is the archetype).
4158
+ * `data: { href }` — the URL the page asked to open, when it named one.
4159
+ */
4160
+ CONTEXT_OPENED: "context.opened",
4161
+ /**
4162
+ * The app opened a native `alert`/`confirm`/`prompt` while Reticle was driving it.
4163
+ *
4164
+ * Recorded because Reticle ANSWERS these rather than letting them block — a native dialog halts
4165
+ * the main thread, and the SDK's own message pump is on that thread, so one `confirm` behind a
4166
+ * driven click made the tab permanently unresponsive with no recovery from inside the session.
4167
+ * Answering silently would trade a wedge for an invisible one, so the question the app asked, and
4168
+ * the answer given, ride out as an event.
4169
+ */
4170
+ DIALOG_OPENED: "dialog.opened",
4171
+ /** aggregated React commits over a throttle window (dev builds) — `data: { commits }`. Commit storms /
4172
+ * wasted re-renders show up here without a per-render flood. */
4173
+ RENDER_COMMIT: "render.commit",
4174
+ /** element focus moved — `data: { to, from, toBody }`. Focus dropping to body after an act is a regression. */
4175
+ FOCUS_CHANGE: "focus.change",
4176
+ /**
4177
+ * a form field's value moved — `data: { field, kind, value?, redacted?, length }`.
4178
+ *
4179
+ * The DOM observer never saw this: `value` is in its attribute allowlist, but React and every
4180
+ * controlled input set the PROPERTY, so `MutationObserver` does not fire. `value` is omitted and
4181
+ * `redacted` set for a password, a sensitive name, or a payment autocomplete hint; `length` is
4182
+ * always present, because "it was wiped" is assertable without carrying anybody's data.
4183
+ */
4184
+ FIELD_CHANGE: "field.change",
4185
+ /** browser → bridge: a human recording compiled in-page. */
4186
+ FLOW_RECORDED: "flow.recorded",
4187
+ /** synthetic: browser transport queue overflowed; events were dropped. `data: { dropped: number }`. */
4188
+ TRANSPORT_OVERFLOW: "transport.overflow",
4189
+ /**
4190
+ * synthetic: a per-channel cap truncated a batch (e.g. a DOM mutation flood). `data: { channel, dropped }`.
4191
+ * Marks downstream rollups/envelopes as built on incomplete data — a ledger that lies at scale is worse
4192
+ * than no ledger, so truncation is never silent.
4193
+ */
4194
+ TRUNCATED: "truncated",
4195
+ /**
4196
+ * synthetic: the SDK detected a region it CANNOT observe (a cross-origin iframe, a closed shadow root).
4197
+ * `data: { kind: BlindSpotKind, count }`. Surfaced on results as `coverage: partial` so a green never
4198
+ * implies it saw everything.
4199
+ */
4200
+ BLIND_SPOT: "blind-spot",
4201
+ /** synthetic: the SDK ITSELF failed (an observer threw). `data: { site, message, errorType }`.
4202
+ * Rides the existing bridge — no outbound request. See browser/observers/sdk-failure.ts. */
4203
+ SDK_FAILED: "sdk.failed",
4204
+ /**
4205
+ * synthetic (driven only): CDP/Playwright-authoritative network detail for a response the in-page
4206
+ * fetch/XHR wrapper also saw — full response headers + authoritative status/mimeType the page-side
4207
+ * wrapper can't reach. `data: { url, method?, status, headers, resourceType? }`. Merged onto the
4208
+ * matching in-page NET_REQUEST so the driven view never loses fidelity to an outside-in tool.
4209
+ */
4210
+ NET_DETAIL: "net.detail",
4211
+ /**
4212
+ * Live-control: browser → bridge. A human acted on the presenter panel.
4213
+ * `data: { kind: HumanControlKind; text?: string }`. Rides the existing EventMessage.
4214
+ */
4215
+ HUMAN_CONTROL: "human.control",
4216
+ /**
4217
+ * Human review: browser → bridge. A human pinned a mistake to an element on the running page
4218
+ * (the "annotate the bug where you see it" loop). `data` narrows to HumanMarkDataSchema — a note
4219
+ * plus a re-resolvable element anchor (and its source file:line when the framework stamped one) so
4220
+ * the agent that drains the mark knows exactly which element and which source to fix.
4221
+ */
4222
+ HUMAN_MARK: "human.mark",
4223
+ /**
4224
+ * The app produced a FILE — a Blob handed to `URL.createObjectURL`, usually saved by clicking an
4225
+ * anchor with `download`. `data: { filename?, mimeType, bytes, lines?, preview? }`. The one artifact
4226
+ * class no outside-the-browser tool can inspect: it never crosses the network, so there is no
4227
+ * request to intercept. See `observers/download.ts` for the defect that motivated it.
4228
+ */
4229
+ DOWNLOAD: "download",
4230
+ /**
4231
+ * Browser -> bridge: a person used the HUD — pressed a control, or the HUD changed how it sits.
4232
+ * `data` narrows to HudUseDataSchema: names only. Telemetry, not evidence: the session takes it
4233
+ * off the wire before the buffer, so no verdict, settle or agent read ever sees it.
4234
+ */
4235
+ HUD_USED: "hud.used"
4236
+ };
4237
+
4127
4238
  // ../../../core/dist/wire/constants/constants.js
4128
4239
  var RETICLE_DEFAULT_PORT = 4400;
4129
4240
  var RETICLE_WS_PATH = "/reticle";
@@ -4213,7 +4324,42 @@ var ReticleEnv = {
4213
4324
  /** Base URL for the harness's model API, for a proxy or a gateway. */
4214
4325
  HARNESS_BASE_URL: "RETICLE_HARNESS_BASE_URL",
4215
4326
  /** Hard ceiling on harness model turns in one drive. Bounds cost, not value. */
4216
- HARNESS_MAX_STEPS: "RETICLE_HARNESS_MAX_STEPS"
4327
+ HARNESS_MAX_STEPS: "RETICLE_HARNESS_MAX_STEPS",
4328
+ /**
4329
+ * Which model backs the harness driver: `anthropic` (the default) or `jev`.
4330
+ *
4331
+ * Two drivers exist because the driver's job turns out not to need a text generator. It picks the
4332
+ * next action and says what it expects; the verdict is decided afterwards by the engine, with no
4333
+ * model anywhere near it. A System One model answers typed questions against a state, which is
4334
+ * exactly that job and none of the rest, so it can drive without being able to generate a
4335
+ * sentence. Unset keeps the existing behaviour for everybody who has not asked for this.
4336
+ */
4337
+ HARNESS_DRIVER: "RETICLE_HARNESS_DRIVER",
4338
+ /**
4339
+ * A direct Jev key, for this repo's own benchmarks and for anyone holding a TypeSafe account.
4340
+ *
4341
+ * Users are not expected to have one. The ordinary path is the key they already minted on the
4342
+ * platform (`RETICLE_API_KEY`), which reaches Jev through the proxy at `RETICLE_CLOUD_URL` —
4343
+ * this variable is the escape hatch that skips it, and it takes precedence when both are set so
4344
+ * that a developer debugging the upstream is never silently talking to the proxy instead.
4345
+ */
4346
+ HARNESS_JEV_KEY: "JEV_API_KEY",
4347
+ /** Base URL for the Jev API, for a proxy or a gateway. Defaults to TypeSafe's own endpoint. */
4348
+ HARNESS_JEV_URL: "RETICLE_HARNESS_JEV_URL",
4349
+ /** A direct OpenAI key. As with Jev, the ordinary path is the platform key and its proxy. */
4350
+ HARNESS_OPENAI_KEY: "OPENAI_API_KEY",
4351
+ /** Model the OpenAI driver uses. Defaults to a small one — see `DEFAULT_OPENAI_MODEL`. */
4352
+ HARNESS_OPENAI_MODEL: "RETICLE_HARNESS_OPENAI_MODEL",
4353
+ /**
4354
+ * The API key minted on the platform, and the host it belongs to.
4355
+ *
4356
+ * Read through `apiKeyFrom()`, never directly — see the note on that function for why there are
4357
+ * two names for one key and why neither may be dropped.
4358
+ */
4359
+ API_KEY: "RETICLE_API_KEY",
4360
+ /** The name this key had until 2026-09. Still honoured; see `apiKeyFrom()`. */
4361
+ CLOUD_KEY: "RETICLE_CLOUD_KEY",
4362
+ CLOUD_URL: "RETICLE_CLOUD_URL"
4217
4363
  };
4218
4364
  var TRANSPORT_LIMITS = {
4219
4365
  MAX_MESSAGE_BYTES: 1024 * 1024,
@@ -4290,18 +4436,53 @@ var ReticleDir = {
4290
4436
  IMPACT_FILE: "impact.json",
4291
4437
  /** what changes were SUPPOSED to make true —.reticle/intent.json (git-checked, reviewed) */
4292
4438
  INTENT_FILE: "intent.json",
4439
+ /**
4440
+ * The sharded form of the same ledger —.reticle/intent/ (git-checked, for the same reason).
4441
+ *
4442
+ * Named here rather than inline at the store that writes it, because the partition guard over
4443
+ * this object is what decides whether a name Reticle creates is committed or ignored. A directory
4444
+ * spelled as a free string somewhere else is one the guard cannot see, so nobody ever makes that
4445
+ * decision: `intent/` was written into users' repositories for that reason alone, neither
4446
+ * classified nor ignored.
4447
+ */
4448
+ INTENT_SUBDIR: "intent",
4449
+ /**
4450
+ * what a drive types into a field, keyed by the field's label —.reticle/fill-values.json.
4451
+ *
4452
+ * Git-checked on purpose. A generated value is paid for once and then belongs to the project: the
4453
+ * next drive reuses it for free, a replay sends exactly what the recording sent, and a human who
4454
+ * dislikes one can edit the file rather than argue with a model.
4455
+ */
4456
+ FILL_VALUES_FILE: "fill-values.json",
4293
4457
  /** opt-in pixel baselines —.reticle/visual/<name>.png + <name>.diff.png. */
4294
4458
  VISUAL_SUBDIR: "visual",
4295
4459
  /** verification-run artifacts —.reticle/runs/<runId>.json (the OEM/CI-consumable verdict). */
4296
4460
  RUNS_SUBDIR: "runs",
4297
4461
  /** fail-to-pass bug capsules —.reticle/capsules/<id>.json (a minimal failing flow + its evidence). */
4298
4462
  CAPSULES_SUBDIR: "capsules",
4463
+ /**
4464
+ * Where a feedback report refused delivery is copied — .reticle/feedback/.
4465
+ *
4466
+ * Named here rather than at the writer because the partition over this object is what decides
4467
+ * whether a name Reticle creates is committed, ignored, or swept. It was spelled as a free string
4468
+ * in three separate files, so the guard could not see it and nobody was ever asked.
4469
+ */
4470
+ FEEDBACK_SUBDIR: "feedback",
4299
4471
  /** durable causal journal —.reticle/sessions/<id>/{events,actions}.jsonl (the substrate). */
4300
4472
  SESSIONS_SUBDIR: "sessions",
4301
4473
  /** append-only event ledger inside a session dir (one ReticleEvent per line). */
4302
4474
  JOURNAL_EVENTS_FILE: "events.jsonl",
4303
4475
  /** append-only action ledger inside a session dir (one JournalAction per line). */
4304
4476
  JOURNAL_ACTIONS_FILE: "actions.jsonl",
4477
+ /**
4478
+ * the event ledger's closure report — .reticle/sessions/<id>/events.closed.json.
4479
+ *
4480
+ * Written once, when the byte ceiling refuses a batch, and never removed. Its PRESENCE is what
4481
+ * makes the ceiling durable: a session id survives a reload, so the next connection reopens the
4482
+ * same ledger with an empty memory, and a bound that lives only in one object's field is a bound
4483
+ * per connection. Its CONTENTS are the loss report a time-windowed query cannot filter away.
4484
+ */
4485
+ JOURNAL_EVENTS_CLOSED_FILE: "events.closed.json",
4305
4486
  /** learned expected-envelopes per route, accumulated across runs (the deviation-report baseline). */
4306
4487
  ENVELOPES_FILE: "envelopes.json",
4307
4488
  /** learned ambient (action-less churn) region map — excluded from settle/summaries/envelopes. */
@@ -4352,102 +4533,6 @@ var RING_BUFFER_DEFAULTS = {
4352
4533
  MAX_AGE_MS: 6e4,
4353
4534
  MAX_BYTES: TRANSPORT_LIMITS.MAX_BUFFER_BYTES
4354
4535
  };
4355
- var EventType = {
4356
- DOM_ADDED: "dom.added",
4357
- DOM_REMOVED: "dom.removed",
4358
- DOM_ATTR: "dom.attr",
4359
- DOM_TEXT: "dom.text",
4360
- NET_REQUEST: "net.request",
4361
- NET_PENDING: "net.pending",
4362
- /** An SSE (EventSource) or WebSocket frame — a message on a long-lived streaming connection. */
4363
- NET_STREAM: "net.stream",
4364
- /** A web-perf metric a screenshot can't verify: LCP, cumulative layout shift, or a long task. */
4365
- PERF: "perf",
4366
- ROUTE_CHANGE: "route.change",
4367
- CONSOLE_LOG: "console.log",
4368
- CONSOLE_WARN: "console.warn",
4369
- CONSOLE_ERROR: "console.error",
4370
- CONSOLE_INFO: "console.info",
4371
- CONSOLE_DEBUG: "console.debug",
4372
- ERROR_UNCAUGHT: "error.uncaught",
4373
- VISIBLE_SHOWN: "visible.shown",
4374
- ANIM_START: "anim.start",
4375
- ANIM_END: "anim.end",
4376
- SCROLL_POSITION: "scroll.position",
4377
- REVEAL_SHOWN: "reveal.shown",
4378
- SIGNAL: "signal",
4379
- STATE_CHANGE: "state.change",
4380
- /** a write to localStorage/sessionStorage/cookies — `data: { area, key, old?, new? }` (values redacted). */
4381
- STORAGE_CHANGE: "storage.change",
4382
- /** page-level visibility/focus health (distinct from element-level VISIBLE_*). */
4383
- PAGE_HEALTH: "page.health",
4384
- /**
4385
- * synthetic: the page called window.open, so the consequence of what was just clicked may live in
4386
- * another browsing context this one cannot observe (an OAuth popup is the archetype).
4387
- * `data: { href }` — the URL the page asked to open, when it named one.
4388
- */
4389
- CONTEXT_OPENED: "context.opened",
4390
- /**
4391
- * The app opened a native `alert`/`confirm`/`prompt` while Reticle was driving it.
4392
- *
4393
- * Recorded because Reticle ANSWERS these rather than letting them block — a native dialog halts
4394
- * the main thread, and the SDK's own message pump is on that thread, so one `confirm` behind a
4395
- * driven click made the tab permanently unresponsive with no recovery from inside the session.
4396
- * Answering silently would trade a wedge for an invisible one, so the question the app asked, and
4397
- * the answer given, ride out as an event.
4398
- */
4399
- DIALOG_OPENED: "dialog.opened",
4400
- /** aggregated React commits over a throttle window (dev builds) — `data: { commits }`. Commit storms /
4401
- * wasted re-renders show up here without a per-render flood. */
4402
- RENDER_COMMIT: "render.commit",
4403
- /** element focus moved — `data: { to, from, toBody }`. Focus dropping to body after an act is a regression. */
4404
- FOCUS_CHANGE: "focus.change",
4405
- /** browser → bridge: a human recording compiled in-page. */
4406
- FLOW_RECORDED: "flow.recorded",
4407
- /** synthetic: browser transport queue overflowed; events were dropped. `data: { dropped: number }`. */
4408
- TRANSPORT_OVERFLOW: "transport.overflow",
4409
- /**
4410
- * synthetic: a per-channel cap truncated a batch (e.g. a DOM mutation flood). `data: { channel, dropped }`.
4411
- * Marks downstream rollups/envelopes as built on incomplete data — a ledger that lies at scale is worse
4412
- * than no ledger, so truncation is never silent.
4413
- */
4414
- TRUNCATED: "truncated",
4415
- /**
4416
- * synthetic: the SDK detected a region it CANNOT observe (a cross-origin iframe, a closed shadow root).
4417
- * `data: { kind: BlindSpotKind, count }`. Surfaced on results as `coverage: partial` so a green never
4418
- * implies it saw everything.
4419
- */
4420
- BLIND_SPOT: "blind-spot",
4421
- /** synthetic: the SDK ITSELF failed (an observer threw). `data: { site, message, errorType }`.
4422
- * Rides the existing bridge — no outbound request. See browser/observers/sdk-failure.ts. */
4423
- SDK_FAILED: "sdk.failed",
4424
- /**
4425
- * synthetic (driven only): CDP/Playwright-authoritative network detail for a response the in-page
4426
- * fetch/XHR wrapper also saw — full response headers + authoritative status/mimeType the page-side
4427
- * wrapper can't reach. `data: { url, method?, status, headers, resourceType? }`. Merged onto the
4428
- * matching in-page NET_REQUEST so the driven view never loses fidelity to an outside-in tool.
4429
- */
4430
- NET_DETAIL: "net.detail",
4431
- /**
4432
- * Live-control: browser → bridge. A human acted on the presenter panel.
4433
- * `data: { kind: HumanControlKind; text?: string }`. Rides the existing EventMessage.
4434
- */
4435
- HUMAN_CONTROL: "human.control",
4436
- /**
4437
- * Human review: browser → bridge. A human pinned a mistake to an element on the running page
4438
- * (the "annotate the bug where you see it" loop). `data` narrows to HumanMarkDataSchema — a note
4439
- * plus a re-resolvable element anchor (and its source file:line when the framework stamped one) so
4440
- * the agent that drains the mark knows exactly which element and which source to fix.
4441
- */
4442
- HUMAN_MARK: "human.mark",
4443
- /**
4444
- * The app produced a FILE — a Blob handed to `URL.createObjectURL`, usually saved by clicking an
4445
- * anchor with `download`. `data: { filename?, mimeType, bytes, lines?, preview? }`. The one artifact
4446
- * class no outside-the-browser tool can inspect: it never crosses the network, so there is no
4447
- * request to intercept. See `observers/download.ts` for the defect that motivated it.
4448
- */
4449
- DOWNLOAD: "download"
4450
- };
4451
4536
  var RETICLE_RENDER_PREHOOK = "__reticleRenderPreHook";
4452
4537
  var CONSOLE_LEVEL_PREFIX = "console.";
4453
4538
  var CONSOLE_LEVELS = [
@@ -4461,6 +4546,7 @@ var CONSOLE_LEVELS = [
4461
4546
  var DATA_RETICLE_SOURCE_ATTR = "data-reticle-source";
4462
4547
  var RETICLE_ROOT_GLOBAL = "__RETICLE_ROOT__";
4463
4548
  var RETICLE_SDK_VERSION_GLOBAL = "__RETICLE_SDK_VERSION__";
4549
+ var RETICLE_IGNORE_MARKER = "@reticle-ignore";
4464
4550
 
4465
4551
  // ../../../core/dist/identity/project-id.js
4466
4552
  var PROJECT_ID_HASH_LENGTH = 8;
@@ -4749,6 +4835,51 @@ function stampSvelte(code, id, load = defaultLoadCompiler) {
4749
4835
  return out;
4750
4836
  }
4751
4837
 
4838
+ // src/stamping.ts
4839
+ var import_core6 = require("@babel/core");
4840
+ var import_babel_plugin = __toESM(require("@reticlehq/babel-plugin"), 1);
4841
+ var import_ignore = require("@reticlehq/babel-plugin/ignore");
4842
+ var JSX_FILE = /\.[jt]sx$/;
4843
+ var VIRTUAL_PREFIX = "\0";
4844
+ var NODE_MODULES = "node_modules";
4845
+ function stampableId(id) {
4846
+ if (id.startsWith(VIRTUAL_PREFIX)) return null;
4847
+ if (id.includes(NODE_MODULES)) return null;
4848
+ return id.split("?")[0] ?? id;
4849
+ }
4850
+ var TEST_FILE = /(?:\.(?:test|spec)\.[^./]+$)|(?:^|\/)__tests__\//;
4851
+ function shouldStamp(id) {
4852
+ const clean = stampableId(id);
4853
+ if (null === clean) return false;
4854
+ if (TEST_FILE.test(clean)) return false;
4855
+ return JSX_FILE.test(clean);
4856
+ }
4857
+ function shouldStampSvelte(id) {
4858
+ const clean = stampableId(id);
4859
+ return clean !== null && SVELTE_FILE.test(clean);
4860
+ }
4861
+ function stamp(code, id) {
4862
+ const out = (0, import_core6.transformSync)(code, {
4863
+ filename: id,
4864
+ plugins: [import_babel_plugin.default],
4865
+ parserOpts: { plugins: ["jsx", "typescript"] },
4866
+ sourceMaps: true,
4867
+ configFile: false,
4868
+ babelrc: false
4869
+ });
4870
+ if (out?.code === void 0 || null === out.code) return null;
4871
+ return {
4872
+ code: out.code,
4873
+ map: out.map === void 0 || null === out.map ? null : JSON.stringify(out.map)
4874
+ };
4875
+ }
4876
+ function optsOutOfStamping(code, id) {
4877
+ return (shouldStamp(id) || shouldStampSvelte(id)) && (0, import_ignore.isSourceStampingIgnored)(code);
4878
+ }
4879
+ function ignoredFileNotice(id) {
4880
+ return `[reticle] ${id} opts out of source stamping (${RETICLE_IGNORE_MARKER} on its first line) \u2014 elements in it will have no file:line.`;
4881
+ }
4882
+
4752
4883
  // src/installed.ts
4753
4884
  var import_node_fs5 = require("node:fs");
4754
4885
  var import_node_path7 = require("node:path");
@@ -4847,6 +4978,227 @@ function optimizerOptions(key, inherited, add) {
4847
4978
  };
4848
4979
  }
4849
4980
 
4981
+ // src/disabled-browser-stub.ts
4982
+ var RETICLE_DISABLED_STUB = "\0reticle-disabled-stub";
4983
+ var isReticleDisabledWebBuild = (desktop, command) => !desktop && "build" === command;
4984
+ var RETICLE_DISABLED_STUB_CODE = `
4985
+ export class Reticle {
4986
+ connect() {}
4987
+ signal() {}
4988
+ state() {}
4989
+ renderCommit() {}
4990
+ describe() {}
4991
+ endSession() {}
4992
+ observeHotUpdates() {}
4993
+ disconnect() {}
4994
+
4995
+ get connected() {
4996
+ return false;
4997
+ }
4998
+ }
4999
+
5000
+ export const reticle = new Reticle();
5001
+
5002
+ export const SESSION_AUTO = 'auto';
5003
+
5004
+ export function setIgnoreSelectors() {}
5005
+
5006
+ export function registerAdapter() {}
5007
+ export function identifyComponent() {
5008
+ return null;
5009
+ }
5010
+ export function readComponentState() {
5011
+ return undefined;
5012
+ }
5013
+ export function elementHasHoverHandlers() {
5014
+ return false;
5015
+ }
5016
+ export function adapterNames() {
5017
+ return [];
5018
+ }
5019
+
5020
+ export function registerStore() {}
5021
+ export function unregisterStore() {}
5022
+ export function storeNames() {
5023
+ return [];
5024
+ }
5025
+ export function readStores() {
5026
+ return {};
5027
+ }
5028
+ export function readStoresWithTruncation() {
5029
+ return { stores: {} };
5030
+ }
5031
+ export function sourceOwner() {
5032
+ return undefined;
5033
+ }
5034
+ export function markAdapterSource() {}
5035
+
5036
+ export function tanstackQueryStore() {
5037
+ return undefined;
5038
+ }
5039
+ export function jotaiStore() {
5040
+ return undefined;
5041
+ }
5042
+ export function xstateStore() {
5043
+ return undefined;
5044
+ }
5045
+ export function valtioStore() {
5046
+ return undefined;
5047
+ }
5048
+ export function mobxStore() {
5049
+ return undefined;
5050
+ }
5051
+ export function recoilStore() {
5052
+ return undefined;
5053
+ }
5054
+ export function svelteStore() {
5055
+ return undefined;
5056
+ }
5057
+ export function piniaStore() {
5058
+ return undefined;
5059
+ }
5060
+ export function pushStore() {
5061
+ return undefined;
5062
+ }
5063
+
5064
+ export function registerCapabilities() {}
5065
+ export function getCapabilities() {
5066
+ return {};
5067
+ }
5068
+ export function hasCapabilities() {
5069
+ return false;
5070
+ }
5071
+ export function setCapabilitiesListener() {}
5072
+
5073
+ export function createReticleEmitter() {
5074
+ return {
5075
+ signal() {},
5076
+ state() {},
5077
+ };
5078
+ }
5079
+
5080
+ export function commitAndSignal() {}
5081
+ export function registerReticleDomain() {}
5082
+
5083
+ export function buildSnapshot() {
5084
+ return {};
5085
+ }
5086
+
5087
+ export function inspectChart() {
5088
+ return {};
5089
+ }
5090
+ export function canvasChartData() {
5091
+ return {};
5092
+ }
5093
+
5094
+ export function matchQuery() {
5095
+ return false;
5096
+ }
5097
+ export function runQuery() {
5098
+ return undefined;
5099
+ }
5100
+
5101
+ export function executeAction() {
5102
+ return undefined;
5103
+ }
5104
+ export function executeSequence() {
5105
+ return undefined;
5106
+ }
5107
+
5108
+ export function describe() {
5109
+ return undefined;
5110
+ }
5111
+ export function getRole() {
5112
+ return undefined;
5113
+ }
5114
+ export function getAccessibleName() {
5115
+ return undefined;
5116
+ }
5117
+ export function getStates() {
5118
+ return {};
5119
+ }
5120
+ export function isVisible() {
5121
+ return false;
5122
+ }
5123
+
5124
+ export class RefRegistry {
5125
+ get size() {
5126
+ return 0;
5127
+ }
5128
+
5129
+ markEdited() {}
5130
+
5131
+ mintedBeforeLastEdit() {
5132
+ return false;
5133
+ }
5134
+
5135
+ refFor() {
5136
+ return undefined;
5137
+ }
5138
+
5139
+ resolve() {
5140
+ return null;
5141
+ }
5142
+ }
5143
+
5144
+ export const refs = new RefRegistry();
5145
+
5146
+ export class Annotator {
5147
+ constructor() {}
5148
+
5149
+ get active() {
5150
+ return false;
5151
+ }
5152
+
5153
+ get markCount() {
5154
+ return 0;
5155
+ }
5156
+
5157
+ mount() {}
5158
+ unmount() {}
5159
+ }
5160
+
5161
+ export function installAnnotator() {}
5162
+
5163
+ export function resolveMarkAnchor() {
5164
+ return undefined;
5165
+ }
5166
+ `;
5167
+
5168
+ // src/connect-args.ts
5169
+ function connectArgs(options) {
5170
+ const args = {};
5171
+ const port = options.port ?? RETICLE_DEFAULT_PORT;
5172
+ if (port !== RETICLE_DEFAULT_PORT) args["url"] = bridgeWsUrl(port);
5173
+ if (options.session !== void 0) args["session"] = options.session;
5174
+ if (options.projectId !== void 0) args["projectId"] = options.projectId;
5175
+ if (options.token !== void 0) args["token"] = options.token;
5176
+ if (options.root !== void 0 && options.root.length > 0) args["root"] = options.root;
5177
+ if (options.sdkVersion !== void 0 && options.sdkVersion.length > 0) {
5178
+ args["sdkVersion"] = options.sdkVersion;
5179
+ }
5180
+ if (true === options.desktop) args["allowInProduction"] = true;
5181
+ if (true === options.captureNetworkBodies || "1" === process.env["VITE_RETICLE_CAPTURE_BODIES"]) {
5182
+ args["captureNetworkBodies"] = true;
5183
+ }
5184
+ if (false === options.sourceMapping) args["sourceMapping"] = false;
5185
+ if (false === options.captureErrorBodies || "1" === process.env["VITE_RETICLE_NO_ERROR_BODIES"]) {
5186
+ args["captureErrorBodies"] = false;
5187
+ }
5188
+ const envBodyChars = Number(process.env["VITE_RETICLE_BODY_MAX_CHARS"]);
5189
+ const bodyChars = options.networkBodyMaxChars ?? (Number.isFinite(envBodyChars) && envBodyChars > 0 ? envBodyChars : void 0);
5190
+ if (bodyChars !== void 0) {
5191
+ args["networkBodyMaxChars"] = bodyChars;
5192
+ }
5193
+ if (true === options.exposePresenter || "1" === process.env["VITE_RETICLE_EXPOSE_PRESENTER"]) {
5194
+ args["exposePresenter"] = true;
5195
+ }
5196
+ if (true === options.allowNonLocalhost || "1" === process.env["VITE_RETICLE_ALLOW_NON_LOCALHOST"]) {
5197
+ args["allowNonLocalhost"] = true;
5198
+ }
5199
+ return Object.keys(args).length > 0 ? JSON.stringify(args) : "";
5200
+ }
5201
+
4850
5202
  // src/plugin-name.ts
4851
5203
  var RETICLE_VITE_PLUGIN_NAME = "reticle";
4852
5204
 
@@ -4905,9 +5257,6 @@ function isVitestBrowserServer(config) {
4905
5257
  var RETICLE_PACKAGE2 = "@reticlehq/react";
4906
5258
  var RETICLE_SENSOR = "@reticlehq/browser";
4907
5259
  var RETICLE_TOKEN_GLOBAL = "__RETICLE_TOKEN__";
4908
- var JSX_FILE = /\.[jt]sx$/;
4909
- var VIRTUAL_PREFIX = "\0";
4910
- var NODE_MODULES = "node_modules";
4911
5260
  var RETICLE_CONNECT_MODULE = "/@reticle-connect";
4912
5261
  function connectModuleUrl(base) {
4913
5262
  if (void 0 === base || !base.startsWith("/")) return RETICLE_CONNECT_MODULE;
@@ -4942,34 +5291,6 @@ function isHtmlEntry(id, specifier, root) {
4942
5291
  }
4943
5292
  return candidate.endsWith(target.startsWith("/") ? target : `/${target}`);
4944
5293
  }
4945
- function stampableId(id) {
4946
- if (id.startsWith(VIRTUAL_PREFIX)) return null;
4947
- if (id.includes(NODE_MODULES)) return null;
4948
- return id.split("?")[0] ?? id;
4949
- }
4950
- function shouldStamp(id) {
4951
- const clean = stampableId(id);
4952
- return clean !== null && JSX_FILE.test(clean);
4953
- }
4954
- function shouldStampSvelte(id) {
4955
- const clean = stampableId(id);
4956
- return clean !== null && SVELTE_FILE.test(clean);
4957
- }
4958
- function stamp(code, id) {
4959
- const out = (0, import_core6.transformSync)(code, {
4960
- filename: id,
4961
- plugins: [import_babel_plugin.default],
4962
- parserOpts: { plugins: ["jsx", "typescript"] },
4963
- sourceMaps: true,
4964
- configFile: false,
4965
- babelrc: false
4966
- });
4967
- if (out?.code === void 0 || null === out.code) return null;
4968
- return {
4969
- code: out.code,
4970
- map: out.map === void 0 || null === out.map ? null : JSON.stringify(out.map)
4971
- };
4972
- }
4973
5294
  function readPairingToken() {
4974
5295
  const override = process.env[ReticleEnv.PAIRING_TOKEN_DIR];
4975
5296
  const dir = override !== void 0 && override.length > 0 ? override : (0, import_node_path8.join)((0, import_node_os2.homedir)(), ReticleDir.ROOT);
@@ -4984,33 +5305,6 @@ function warnIfTokenMissing(token) {
4984
5305
  }
4985
5306
  return token;
4986
5307
  }
4987
- function connectArgs(options) {
4988
- const args = {};
4989
- const port = options.port ?? RETICLE_DEFAULT_PORT;
4990
- if (port !== RETICLE_DEFAULT_PORT) args["url"] = bridgeWsUrl(port);
4991
- if (options.session !== void 0) args["session"] = options.session;
4992
- if (options.projectId !== void 0) args["projectId"] = options.projectId;
4993
- if (options.token !== void 0) args["token"] = options.token;
4994
- if (options.root !== void 0 && options.root.length > 0) args["root"] = options.root;
4995
- if (options.sdkVersion !== void 0 && options.sdkVersion.length > 0) {
4996
- args["sdkVersion"] = options.sdkVersion;
4997
- }
4998
- if (true === options.desktop) args["allowInProduction"] = true;
4999
- if (true === options.captureNetworkBodies || "1" === process.env["VITE_RETICLE_CAPTURE_BODIES"]) {
5000
- args["captureNetworkBodies"] = true;
5001
- }
5002
- if (false === options.sourceMapping) args["sourceMapping"] = false;
5003
- if (false === options.captureErrorBodies || "1" === process.env["VITE_RETICLE_NO_ERROR_BODIES"]) {
5004
- args["captureErrorBodies"] = false;
5005
- }
5006
- if (true === options.exposePresenter || "1" === process.env["VITE_RETICLE_EXPOSE_PRESENTER"]) {
5007
- args["exposePresenter"] = true;
5008
- }
5009
- if (true === options.allowNonLocalhost || "1" === process.env["VITE_RETICLE_ALLOW_NON_LOCALHOST"]) {
5010
- args["allowNonLocalhost"] = true;
5011
- }
5012
- return Object.keys(args).length > 0 ? JSON.stringify(args) : "";
5013
- }
5014
5308
  var RETICLE_DEV_MODULE_CANDIDATES = [
5015
5309
  "src/reticle-dev.ts",
5016
5310
  "src/reticle-dev.js",
@@ -5073,6 +5367,7 @@ function reticle(options = {}) {
5073
5367
  let vitestBrowser = false;
5074
5368
  const warn = options.onWarn ?? ((message) => globalThis.console.warn(message));
5075
5369
  let injected = false;
5370
+ const announcedIgnored = /* @__PURE__ */ new Set();
5076
5371
  let htmlTransformed = false;
5077
5372
  const resolveLazy = () => {
5078
5373
  const port = resolved.port ?? discoverDaemonPort(resolved.projectId);
@@ -5095,10 +5390,6 @@ function reticle(options = {}) {
5095
5390
  });
5096
5391
  return {
5097
5392
  name: RETICLE_VITE_PLUGIN_NAME,
5098
- // Web: serve-only, so a production bundle can never carry the SDK — gating is the tool's job.
5099
- // Desktop: a packaged renderer IS a production build with no dev server, so the plugin must also
5100
- // run for `vite build` or the shipped app has no connect() at all.
5101
- ...true === options.desktop ? {} : { apply: "serve" },
5102
5393
  enforce: "pre",
5103
5394
  /**
5104
5395
  * Declare the SDK itself and the optimizer cache fingerprint.
@@ -5182,6 +5473,7 @@ function reticle(options = {}) {
5182
5473
  };
5183
5474
  },
5184
5475
  transform(code, id) {
5476
+ if (isReticleDisabledWebBuild(desktop, command)) return null;
5185
5477
  if (desktop && inject && isHtmlEntry(id, htmlEntrySpecifier, root)) {
5186
5478
  injected = true;
5187
5479
  const withConnect = `${connectModuleSource(resolveLazy())}
@@ -5190,6 +5482,13 @@ ${code}`;
5190
5482
  return stamped ?? { code: withConnect, map: null };
5191
5483
  }
5192
5484
  if (!sourceMapping) return null;
5485
+ if (optsOutOfStamping(code, id)) {
5486
+ if (!announcedIgnored.has(id)) {
5487
+ announcedIgnored.add(id);
5488
+ warn(ignoredFileNotice(id));
5489
+ }
5490
+ return null;
5491
+ }
5193
5492
  if (shouldStampSvelte(id)) {
5194
5493
  const stamped = stampSvelte(code, id);
5195
5494
  return null === stamped ? null : { code: stamped, map: null };
@@ -5198,12 +5497,18 @@ ${code}`;
5198
5497
  return stamp(code, id);
5199
5498
  },
5200
5499
  resolveId(id, importer) {
5500
+ if (isReticleDisabledWebBuild(desktop, command) && id === RETICLE_SENSOR) {
5501
+ return RETICLE_DISABLED_STUB;
5502
+ }
5201
5503
  if (desktop && inject && importer !== void 0 && importer.includes(".html")) {
5202
5504
  htmlEntrySpecifier = id;
5203
5505
  }
5204
5506
  return inject && id === RETICLE_CONNECT_MODULE ? RETICLE_CONNECT_MODULE : null;
5205
5507
  },
5206
5508
  load(id) {
5509
+ if (isReticleDisabledWebBuild(desktop, command) && id === RETICLE_DISABLED_STUB) {
5510
+ return RETICLE_DISABLED_STUB_CODE;
5511
+ }
5207
5512
  if (!inject || id !== RETICLE_CONNECT_MODULE) return null;
5208
5513
  const source = currentConnectSource();
5209
5514
  lastServedConnectSource = source;
@@ -5288,6 +5593,7 @@ ${code}`;
5288
5593
  checkHtmlHookForTest: watch.checkHtmlHookRan,
5289
5594
  injectionWatchForTest: watch,
5290
5595
  transformIndexHtml() {
5596
+ if (isReticleDisabledWebBuild(desktop, command)) return [];
5291
5597
  htmlTransformed = true;
5292
5598
  if (desktop && inject && "serve" === command) watch.armDesktopCheck();
5293
5599
  if (!inject || desktop) return [];