@runalabs/rill-cli 0.1.16 → 0.1.18

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 (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +196 -38
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -370,6 +370,8 @@ Progress runs through `uploading` → `queued` → `encoding` → `processing`
370
370
 
371
371
  Run `rill connect --email you@example.com` to authorize account access or keep your anonymous recordings. Open the displayed link, sign in, and enter the code yourself. Approval allows creation and reading of your existing and new recordings for 90 days, with automatic renewal of one-hour access tokens. Revoke the connection in Settings → Agent access to stop access and renewal. Deletion and changes to existing sharing settings are not included.
372
372
 
373
+ Browser approval does not finish the handshake: the CLI must collect and save credentials. With `--no-wait`, keep polling the returned `connect status <authorizationId>` command until `authenticated`. Starting with 0.1.17, the CLI checks the server even after its local approval deadline. Approval codes expire after ten minutes; successful approval starts a separate 30-minute collection window, with a 60-second lost-response retry window after first collection. If collection expires, run `connect --email` again with the same account to request fresh human approval while preserving the registration and recordings. Do not delete saved credentials to recover. Auth requests include the CLI version for consent-aware diagnostics.
374
+
373
375
  Use `rill record list` to list accessible recordings and `rill inspect <recording-id>` for private recording details. `rill inspect <share-url>` continues to work without account access. The existing `rill login` and `RILL_TOKEN` flows remain supported. Local credential storage requires macOS Keychain, Linux Secret Service, or Windows current-user DPAPI.
374
376
 
375
377
  ### Check the connected account
package/dist/cli.js CHANGED
@@ -127,6 +127,11 @@ function browserAttachment(cdpUrl, tabId) {
127
127
  };
128
128
  }
129
129
 
130
+ // src/version.ts
131
+ import { createRequire } from "module";
132
+ var packageJson = createRequire(import.meta.url)("../package.json");
133
+ var CLI_VERSION = packageJson.version;
134
+
130
135
  // src/agent-session.ts
131
136
  var JWT_GRANT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
132
137
  var CLAIM_GRANT = "urn:workos:agent-auth:grant-type:claim";
@@ -150,7 +155,7 @@ async function request(apiUrl, path, body, form = false) {
150
155
  method: "POST",
151
156
  redirect: "error",
152
157
  signal: AbortSignal.timeout(15e3),
153
- headers: { "Content-Type": form ? "application/x-www-form-urlencoded" : "application/json" },
158
+ headers: { "Content-Type": form ? "application/x-www-form-urlencoded" : "application/json", "X-Rill-CLI-Version": CLI_VERSION },
154
159
  body: form ? new URLSearchParams(Object.entries(body).map(([key2, value2]) => [key2, String(value2)])) : JSON.stringify(body)
155
160
  });
156
161
  const value = await response.json();
@@ -246,6 +251,12 @@ async function connectAgent(apiUrl, email3, options = {}) {
246
251
  async function beginConnection(apiUrl, email3) {
247
252
  if (process.env.RILL_TOKEN) throw new Error("Unset RILL_TOKEN before connecting a local identity.");
248
253
  let saved = parseAuthorization(await loadStoredCredential(apiUrl));
254
+ if (saved?.connection?.status === "pending" && saved.connection.expiresAt <= Date.now()) {
255
+ if (saved.connection.email !== email3) throw new Error("Use the original account to finish or recover this connection.");
256
+ const result = await pollSavedConnection(apiUrl, saved.connection.id);
257
+ if (result.status !== "expired") return result;
258
+ saved = parseAuthorization(await loadStoredCredential(apiUrl));
259
+ }
249
260
  if (saved?.connection?.status === "pending" && saved.connection.expiresAt > Date.now()) {
250
261
  if (saved.connection.email !== email3) throw new Error("A connection for another email is pending. Let it expire before starting a different connection.");
251
262
  process.stderr.write(`Open ${saved.connection.verificationUri}
@@ -259,6 +270,22 @@ Sign in as ${email3} and enter ${saved.connection.userCode}. Approve only the re
259
270
  const result = await request(apiUrl, "/agent/identity/claim", { claim_token: saved.claimToken, email: email3 });
260
271
  claim = result.claim_attempt;
261
272
  } catch (error51) {
273
+ if (error51 instanceof AgentAuthError && error51.code === "claim_already_approved") {
274
+ saved.connection ??= {
275
+ id: randomBytes(16).toString("hex"),
276
+ email: email3,
277
+ verificationUri: "",
278
+ userCode: "",
279
+ expiresAt: Date.now(),
280
+ interval: 5,
281
+ nextPollAt: 0,
282
+ status: "pending"
283
+ };
284
+ saved.connection.status = "pending";
285
+ saved.connection.nextPollAt = 0;
286
+ await save(apiUrl, saved);
287
+ return pollSavedConnection(apiUrl, saved.connection.id);
288
+ }
262
289
  if (!(error51 instanceof AgentAuthError) || error51.code !== "claim_expired") throw error51;
263
290
  }
264
291
  }
@@ -309,11 +336,6 @@ async function pollSavedConnection(apiUrl, authorizationId) {
309
336
  if (!saved?.connection || saved.connection.id !== authorizationId) throw new AgentAuthError("authorization_not_found", "No matching saved connection for this API URL. Use the latest connect response.");
310
337
  const connection = saved.connection;
311
338
  if (connection.status !== "pending") return connectionView(apiUrl, saved);
312
- if (Date.now() >= connection.expiresAt) {
313
- connection.status = "expired";
314
- await save(apiUrl, saved);
315
- return connectionView(apiUrl, saved);
316
- }
317
339
  if (Date.now() < connection.nextPollAt) return connectionView(apiUrl, saved);
318
340
  connection.nextPollAt = Date.now() + connection.interval * 1e3;
319
341
  await save(apiUrl, saved);
@@ -322,7 +344,7 @@ async function pollSavedConnection(apiUrl, authorizationId) {
322
344
  saved = withTokens({ version: 1, anonymous: false, connection: { ...connection, status: "authenticated", userCode: "" } }, tokens);
323
345
  } catch (error51) {
324
346
  if (!(error51 instanceof AgentAuthError)) throw error51;
325
- if (error51.code === "expired_token" || error51.code === "claim_expired") connection.status = "expired";
347
+ if (error51.code === "expired_token" || error51.code === "claim_expired" || error51.code === "claim_delivery_expired" || error51.code === "claimed_or_in_flight" && Date.now() >= connection.expiresAt) connection.status = "expired";
326
348
  else if (error51.code === "access_denied" || error51.code === "claim_revoked") connection.status = "denied";
327
349
  else if (error51.code === "slow_down") {
328
350
  connection.interval += 5;
@@ -15777,7 +15799,8 @@ var interactionReportFields = {
15777
15799
  sideEffects: external_exports.array(sideEffectSchema).max(30).optional(),
15778
15800
  cleanup: external_exports.literal("not_attempted").optional()
15779
15801
  };
15780
- var cloudSubmission = external_exports.object({ ...interactionFields, id: external_exports.string().uuid(), url: cloudRunTarget, prompt: external_exports.string().trim().min(1).max(2e3), expectation: external_exports.string().trim().min(1).max(1e3).optional(), account: external_exports.string().regex(/^[a-z0-9-]{1,60}$/).optional() }).strict();
15802
+ var cloudRunPrompt = external_exports.string().min(1).max(2e3).refine((value) => Boolean(value.trim()), "Describe what you want Rill to do.");
15803
+ var cloudSubmission = external_exports.object({ ...interactionFields, id: external_exports.string().uuid(), url: cloudRunTarget, prompt: cloudRunPrompt, expectation: external_exports.string().trim().min(1).max(1e3).optional(), account: external_exports.string().regex(/^[a-z0-9-]{1,60}$/).optional() }).strict();
15781
15804
  var siteAccountSchema = external_exports.object({
15782
15805
  name: external_exports.string().regex(/^[a-z0-9-]{1,60}$/),
15783
15806
  origin: publicTarget.refine((v) => new URL(v).protocol === "https:" && new URL(v).origin === v, "Use an exact HTTPS origin."),
@@ -15831,15 +15854,70 @@ var agentOutcomeSchema = external_exports.object({
15831
15854
  evidence: external_exports.string().max(1e3)
15832
15855
  }).strict();
15833
15856
 
15857
+ // ../recorder/src/collaborator-pointer.ts
15858
+ var collaboratorPointerSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="17.3" height="17.3" viewBox="-0.75 -0.75 17.3 17.3">
15859
+ <!-- Hotspot is (0, 0) in user units: 0.75px right and 0.75px down from the SVG's top-left corner. -->
15860
+ <defs>
15861
+ <linearGradient id="rill-pointer-fill" x1="0" y1="0" x2=".6" y2="1">
15862
+ <stop offset="0" style="stop-color: var(--rill-cursor-accent-light, #8f91f5)"/>
15863
+ <stop offset=".55" style="stop-color: var(--rill-cursor-accent, #6366f1)"/>
15864
+ </linearGradient>
15865
+ </defs>
15866
+ <path d="M0 0L4.1 14.9Q4.5 16.5 5.5 15.2L8.8 8.8L15.2 5.5Q16.5 4.5 14.9 4.1Z" fill="url(#rill-pointer-fill)" stroke="#fff" stroke-width="1.5" stroke-linejoin="round"/>
15867
+ </svg>`;
15868
+ var collaboratorPointerMarkup = `<span class="rill-cursor-shape">${collaboratorPointerSvg}</span><span class="rill-cursor-label">Rill</span>`;
15869
+ var collaboratorPointerStyles = `
15870
+ .rill-cursor-visual { position:absolute; left:0; top:0; width:0; height:0; --rill-cursor-accent-light:color-mix(in srgb,var(--rill-cursor-accent) 72%,#fff); }
15871
+ .rill-cursor-shape { position:absolute; left:-.75px; top:-.75px; width:17.3px; height:17.3px; }
15872
+ .rill-cursor-shape svg { display:block; width:17.3px; height:17.3px; transform-origin:.75px .75px; transition:transform 110ms ease-out; filter:drop-shadow(0 .5px 1px rgba(12,12,18,.25)) drop-shadow(0 1.5px 3px rgba(12,12,18,.14)); }
15873
+ .rill-cursor-visual.is-pressed .rill-cursor-shape svg { transform:scale(.86); transition-duration:50ms; }
15874
+ .rill-cursor-label { position:absolute; left:10px; top:15px; height:15px; padding:0 6px; display:flex; align-items:center; border-radius:8px; font:600 9px/1 system-ui,sans-serif; letter-spacing:.02em; color:#fff; white-space:nowrap; opacity:.92; background:linear-gradient(180deg,color-mix(in srgb,var(--rill-cursor-accent) 78%,#fff),var(--rill-cursor-accent)); box-shadow:0 0 0 1.25px #fff,0 1px 3px rgba(12,12,18,.18),0 0 1px 1.25px rgba(12,12,18,.1); }
15875
+ .rill-cursor-visual.label-left .rill-cursor-label { left:auto; right:4px; }
15876
+ .rill-cursor-visual.label-above .rill-cursor-label { top:auto; bottom:6px; }
15877
+ @media (prefers-reduced-motion:reduce) { .rill-cursor-shape svg { transition:none; } }
15878
+ `;
15879
+
15880
+ // ../recorder/src/scroll-capsule.ts
15881
+ var scrollCapsuleSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="20.5" height="42.5" viewBox="0 0 20.5 42.5">
15882
+ <!-- Capsule body is 18 x 40 at (1.25, 1.25); the white edge sits 1.25px outside it. Shown pointing down. -->
15883
+ <defs>
15884
+ <linearGradient id="rill-capsule-fill" x1="0" y1="0" x2="0" y2="1">
15885
+ <stop offset="0" style="stop-color: var(--rill-cursor-accent-light, #8588f4)"/>
15886
+ <stop offset="1" style="stop-color: var(--rill-cursor-accent, #6366f1)"/>
15887
+ </linearGradient>
15888
+ </defs>
15889
+ <rect x="1.25" y="1.25" width="18" height="40" rx="9" fill="url(#rill-capsule-fill)" stroke="#fff" stroke-width="2.5" paint-order="stroke"/>
15890
+ <!-- For scrolling up, rotate this group 180deg around the capsule center (10.25, 21.25). -->
15891
+ <g id="chevrons" fill="none" stroke="#fff" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
15892
+ <path d="M5.85 11.05Q8.85 13.85 10.25 15.25Q11.65 13.85 14.65 11.05" opacity=".32"/>
15893
+ <path d="M5.85 19.05Q8.85 21.85 10.25 23.25Q11.65 21.85 14.65 19.05" opacity=".6"/>
15894
+ <path d="M5.85 27.05Q8.85 29.85 10.25 31.25Q11.65 29.85 14.65 27.05" opacity=".95"/>
15895
+ </g>
15896
+ </svg>`;
15897
+ var scrollCapsuleStyles = `
15898
+ .scroll-indicator { position:absolute; right:12.75px; bottom:10.75px; width:20.5px; height:42.5px; opacity:0; transform:translateY(4px) scale(.92); transform-origin:center; transition:opacity 180ms ease-out,transform 180ms ease-out; filter:drop-shadow(0 1px 1.5px rgba(12,12,18,.18)) drop-shadow(0 4px 5px rgba(12,12,18,.12)); --rill-cursor-accent-light:color-mix(in srgb,var(--rill-cursor-accent) 78%,#fff); }
15899
+ .scroll-indicator.is-visible { opacity:1; transform:none; transition:opacity 160ms ease-out,transform 260ms cubic-bezier(.2,.9,.3,1.25); }
15900
+ .scroll-indicator svg { position:absolute; left:50%; top:50%; width:20.5px; height:42.5px; translate:-50% -50%; transform-origin:center; }
15901
+ .scroll-indicator[data-direction="right"],.scroll-indicator[data-direction="left"] { width:42.5px; height:20.5px; }
15902
+ .scroll-indicator[data-direction="right"] svg { rotate:-90deg; }
15903
+ .scroll-indicator[data-direction="left"] svg { rotate:90deg; }
15904
+ .scroll-indicator[data-direction="unknown"] #chevrons { visibility:hidden; }
15905
+ @media (prefers-reduced-motion:reduce) { .scroll-indicator,.scroll-indicator.is-visible { transform:none; transition:none; } }
15906
+ `;
15907
+
15834
15908
  // ../recorder/src/cursor-overlay.ts
15835
15909
  function installCursorOverlay(options) {
15836
15910
  const scope = window;
15837
15911
  if (scope[options.key]) return;
15838
15912
  let host;
15913
+ let scrollTimer;
15914
+ let scrollExitTimer;
15839
15915
  const controller = new AbortController();
15840
15916
  const animations = /* @__PURE__ */ new Set();
15841
15917
  const cleanup = () => {
15842
15918
  controller.abort();
15919
+ window.clearTimeout(scrollTimer);
15920
+ window.clearTimeout(scrollExitTimer);
15843
15921
  for (const animation of animations) animation.cancel();
15844
15922
  host?.remove();
15845
15923
  delete scope[options.key];
@@ -15855,48 +15933,135 @@ function installCursorOverlay(options) {
15855
15933
  const style = document.createElement("style");
15856
15934
  style.textContent = `
15857
15935
  :host, * { pointer-events: none !important; }
15858
- .pointer { position:absolute; left:0; top:0; display:none; width:24px; height:28px; }
15859
- .halo { position:absolute; left:-12px; top:-12px; width:26px; height:26px; border-radius:50%; background:${options.color}; opacity:.22; }
15860
- svg { position:absolute; left:-2px; top:-2px; width:24px; height:28px; filter:drop-shadow(0 1px 2px #0008); }
15861
- .pulse { position:absolute; width:32px; height:32px; box-sizing:border-box; border:2px solid ${options.color}; border-radius:50%; }
15936
+ ${options.pointerStyles}
15937
+ .pointer { display:none; --rill-cursor-accent:${options.color}; }
15938
+ ${options.scrollStyles}
15939
+ .scroll-indicator { --rill-cursor-accent:${options.color}; }
15940
+ .click-dot, .click-ring { position:absolute; border-radius:50%; transform:translate(-50%,-50%); }
15941
+ .click-dot { width:5px; height:5px; background:${options.color}; box-shadow:0 0 0 1px #fff,0 0 2px rgba(0,0,0,.3); }
15942
+ .click-ring { box-sizing:border-box; border:1px solid ${options.color}; box-shadow:0 0 0 .5px #fffc,inset 0 0 0 .5px #fffc,0 0 2px rgba(0,0,0,.25); }
15862
15943
  `;
15863
15944
  const pointer = document.createElement("div");
15864
- pointer.className = "pointer";
15865
- pointer.innerHTML = '<div class="halo"></div><svg viewBox="0 0 24 28" xmlns="http://www.w3.org/2000/svg"><path d="M3 2 L3 22 L8 17 L12 25 L16 23 L12 15 L20 15 Z" fill="white" stroke="#171717" stroke-width="1.5" stroke-linejoin="round"/></svg>';
15866
- root.append(style, pointer);
15945
+ pointer.className = "pointer rill-cursor-visual";
15946
+ pointer.innerHTML = options.pointerMarkup;
15947
+ const scrollIndicator = document.createElement("div");
15948
+ scrollIndicator.className = "scroll-indicator";
15949
+ scrollIndicator.innerHTML = options.scrollMarkup;
15950
+ const chevrons = scrollIndicator.querySelector("#chevrons");
15951
+ root.append(style, pointer, scrollIndicator);
15867
15952
  document.documentElement.appendChild(host);
15868
15953
  const listenerOptions = { capture: true, passive: true, signal: controller.signal };
15954
+ const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
15955
+ let scrollDirection;
15956
+ let drift;
15957
+ const stopDrift = () => {
15958
+ if (!drift) return;
15959
+ animations.delete(drift);
15960
+ drift.cancel();
15961
+ drift = void 0;
15962
+ };
15963
+ const showScroll = (direction) => {
15964
+ window.clearTimeout(scrollTimer);
15965
+ window.clearTimeout(scrollExitTimer);
15966
+ scrollIndicator.dataset.direction = direction;
15967
+ chevrons.setAttribute("transform", direction === "up" ? "rotate(180 10.25 21.25)" : "");
15968
+ scrollIndicator.classList.add("is-visible");
15969
+ if (reducedMotion.matches || direction === "unknown") stopDrift();
15970
+ else if (direction !== scrollDirection || !drift) {
15971
+ stopDrift();
15972
+ const distance = direction === "up" || direction === "left" ? -3 : 3;
15973
+ const translate = direction === "left" || direction === "right" ? `${distance}px 0` : `0 ${distance}px`;
15974
+ drift = scrollIndicator.animate([
15975
+ { translate: "0 0", easing: "cubic-bezier(.4,0,.6,1)" },
15976
+ { translate, offset: 0.65, easing: "cubic-bezier(.4,0,.2,1)" },
15977
+ { translate: "0 0" }
15978
+ ], { duration: 820, iterations: Infinity });
15979
+ animations.add(drift);
15980
+ void drift.finished.catch(() => void 0);
15981
+ }
15982
+ scrollDirection = direction;
15983
+ scrollTimer = window.setTimeout(() => {
15984
+ scrollIndicator.classList.remove("is-visible");
15985
+ if (reducedMotion.matches) stopDrift();
15986
+ else scrollExitTimer = window.setTimeout(stopDrift, 180);
15987
+ }, 550);
15988
+ };
15989
+ reducedMotion.addEventListener("change", () => {
15990
+ if (reducedMotion.matches) stopDrift();
15991
+ }, { signal: controller.signal });
15992
+ const positions = /* @__PURE__ */ new WeakMap();
15993
+ positions.set(document, { x: window.scrollX, y: window.scrollY });
15994
+ document.addEventListener("scroll", (event) => {
15995
+ if (!event.isTrusted || document.hidden) return;
15996
+ const target = event.target;
15997
+ if (target !== document && !(target instanceof Element)) return;
15998
+ const position = target === document ? { x: window.scrollX, y: window.scrollY } : { x: target.scrollLeft, y: target.scrollTop };
15999
+ const previous = positions.get(target);
16000
+ positions.set(target, position);
16001
+ const dx = previous ? position.x - previous.x : 0;
16002
+ const dy = previous ? position.y - previous.y : 0;
16003
+ if (previous && !dx && !dy) return;
16004
+ const direction = !previous ? "unknown" : Math.abs(dy) >= Math.abs(dx) ? dy > 0 ? "down" : "up" : dx > 0 ? "right" : "left";
16005
+ showScroll(direction);
16006
+ }, listenerOptions);
15869
16007
  const hide = () => {
15870
16008
  pointer.style.display = "none";
16009
+ pointer.classList.remove("is-pressed");
15871
16010
  };
15872
16011
  const move = (event) => {
15873
- if (event.pointerType === "touch") return;
16012
+ if (event.pointerType === "touch") return false;
15874
16013
  if (event.target instanceof HTMLIFrameElement || event.target instanceof HTMLFrameElement) {
15875
16014
  hide();
15876
- return;
16015
+ return false;
15877
16016
  }
15878
16017
  pointer.style.display = "block";
15879
16018
  pointer.style.transform = `translate(${event.clientX}px, ${event.clientY}px)`;
16019
+ pointer.classList.toggle("label-left", event.clientX > window.innerWidth - 90);
16020
+ pointer.classList.toggle("label-above", event.clientY > window.innerHeight - 34);
16021
+ pointer.classList.toggle("is-pressed", event.buttons !== 0);
16022
+ return true;
16023
+ };
16024
+ const release = (event) => {
16025
+ if (event.pointerType !== "touch") pointer.classList.toggle("is-pressed", event.type !== "pointercancel" && event.buttons !== 0);
15880
16026
  };
15881
16027
  document.addEventListener("pointermove", move, listenerOptions);
15882
16028
  document.addEventListener("pointerover", move, listenerOptions);
15883
- document.addEventListener("pointerdown", (event) => {
15884
- if (event.pointerType === "touch") return;
15885
- move(event);
15886
- const pulse = document.createElement("div");
15887
- pulse.className = "pulse";
15888
- pulse.style.left = `${event.clientX - 16}px`;
15889
- pulse.style.top = `${event.clientY - 16}px`;
15890
- root.insertBefore(pulse, pointer);
15891
- const animation = pulse.animate([
15892
- { transform: "scale(.4)", opacity: 0.9 },
15893
- { transform: "scale(1.8)", opacity: 0 }
15894
- ], { duration: 400, easing: "ease-out" });
16029
+ document.addEventListener("pointerup", release, listenerOptions);
16030
+ document.addEventListener("pointercancel", release, listenerOptions);
16031
+ const animateFeedback = (element, frames, duration3, easing) => {
16032
+ root.insertBefore(element, pointer);
16033
+ const animation = element.animate(frames, { duration: duration3, easing });
15895
16034
  animations.add(animation);
15896
16035
  void animation.finished.catch(() => void 0).finally(() => {
15897
16036
  animations.delete(animation);
15898
- pulse.remove();
16037
+ element.remove();
15899
16038
  });
16039
+ };
16040
+ document.addEventListener("pointerdown", (event) => {
16041
+ if (!move(event)) return;
16042
+ const dot = document.createElement("div");
16043
+ dot.className = "click-dot";
16044
+ dot.style.left = `${event.clientX}px`;
16045
+ dot.style.top = `${event.clientY}px`;
16046
+ animateFeedback(dot, reducedMotion.matches ? [{ opacity: 1 }, { opacity: 0 }] : [
16047
+ { transform: "translate(-50%,-50%) scale(1)", opacity: 1, offset: 0 },
16048
+ { transform: "translate(-50%,-50%) scale(1)", opacity: 1, offset: 0.5 },
16049
+ { transform: "translate(-50%,-50%) scale(.3)", opacity: 0, offset: 1 }
16050
+ ], reducedMotion.matches ? 120 : 300, "ease-in");
16051
+ const ring = document.createElement("div");
16052
+ ring.className = "click-ring";
16053
+ ring.style.left = `${event.clientX}px`;
16054
+ ring.style.top = `${event.clientY}px`;
16055
+ if (event.button === 2) ring.style.borderStyle = "dashed";
16056
+ if (reducedMotion.matches) {
16057
+ ring.style.width = "26px";
16058
+ ring.style.height = "26px";
16059
+ }
16060
+ animateFeedback(ring, reducedMotion.matches ? [{ opacity: 1 }, { opacity: 0 }] : [
16061
+ { width: "4px", height: "4px", opacity: 1, offset: 0 },
16062
+ { opacity: 1, offset: 0.4 },
16063
+ { width: "26px", height: "26px", opacity: 0, offset: 1 }
16064
+ ], reducedMotion.matches ? 120 : 320, "cubic-bezier(.2,.7,.2,1)");
15900
16065
  }, listenerOptions);
15901
16066
  document.addEventListener("pointerout", (event) => {
15902
16067
  if (!event.relatedTarget) hide();
@@ -15914,7 +16079,7 @@ async function attachCursorOverlay(page, cdp, input) {
15914
16079
  if (!appearance.enabled) return async () => {
15915
16080
  };
15916
16081
  const key2 = `__rillCursor_${crypto.randomUUID().replaceAll("-", "")}`;
15917
- const source = `(${installCursorOverlay.toString()})(${JSON.stringify({ ...appearance, key: key2 })})`;
16082
+ const source = `(${installCursorOverlay.toString()})(${JSON.stringify({ ...appearance, key: key2, pointerMarkup: collaboratorPointerMarkup, pointerStyles: collaboratorPointerStyles, scrollMarkup: scrollCapsuleSvg, scrollStyles: scrollCapsuleStyles })})`;
15918
16083
  await cdp.send("Page.enable");
15919
16084
  const { identifier } = await cdp.send("Page.addScriptToEvaluateOnNewDocument", { source });
15920
16085
  let stopped = false;
@@ -16771,13 +16936,6 @@ async function withRunFeedback(session, start) {
16771
16936
 
16772
16937
  // src/doctor.ts
16773
16938
  import { spawn as spawn7 } from "child_process";
16774
-
16775
- // src/version.ts
16776
- import { createRequire } from "module";
16777
- var packageJson = createRequire(import.meta.url)("../package.json");
16778
- var CLI_VERSION = packageJson.version;
16779
-
16780
- // src/doctor.ts
16781
16939
  var defaultDependencies = {
16782
16940
  platform: process.platform,
16783
16941
  encoding: "remote",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runalabs/rill-cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Record, inspect, and share agent-controlled browser runs with Rill.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {