@pablopunk/webr 0.3.16 → 0.3.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.
@@ -8,7 +8,7 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Tooltip } from "@base-ui/react/tooltip";
9
9
  import { BotAvatar, botAvatarTypes } from "bot-avatars";
10
10
  import { Combobox } from "@base-ui/react/combobox";
11
- import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
11
+ import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from "@tanstack/react-query";
12
12
  import { Dialog } from "@base-ui/react/dialog";
13
13
  import { encode } from "uqr";
14
14
  import { ContextMenu } from "@base-ui/react/context-menu";
@@ -1817,24 +1817,40 @@ var hasOwnTextSelection = (target) => {
1817
1817
  return !!document.getSelection()?.toString();
1818
1818
  };
1819
1819
  function bindTerminalClipboard(host, terminal, canWriteFromTerminalOutput, onCopied) {
1820
+ const reportCopy = (copied) => onCopied(copied ? "copied" : "blocked");
1821
+ let textWaitingForClick;
1822
+ const copyWaitingTextOnUserGesture = () => {
1823
+ const text = textWaitingForClick;
1824
+ textWaitingForClick = void 0;
1825
+ if (text !== void 0) writeClipboardText(text).then(reportCopy);
1826
+ };
1827
+ const copyFromTerminalOutput = (text) => void writeClipboardText(text).then((copied) => {
1828
+ if (copied) return reportCopy(true);
1829
+ textWaitingForClick = text;
1830
+ onCopied("waiting-for-click");
1831
+ });
1820
1832
  const copySelectionOnRelease = () => {
1821
- if (terminal.hasSelection()) writeClipboardText(terminal.getSelection()).then(onCopied);
1833
+ if (terminal.hasSelection()) writeClipboardText(terminal.getSelection()).then(reportCopy);
1822
1834
  };
1823
1835
  const copySelectionOnShortcut = (event) => {
1824
1836
  if (event.defaultPrevented || !terminal.hasSelection() || hasOwnTextSelection(event.target)) return;
1825
1837
  event.clipboardData?.setData("text/plain", terminal.getSelection());
1826
1838
  event.preventDefault();
1827
- onCopied(true);
1839
+ reportCopy(true);
1828
1840
  };
1829
1841
  const osc52 = terminal.parser.registerOscHandler(OSC_CLIPBOARD, (data) => {
1830
1842
  const text = decodeOsc52ClipboardWrite(data);
1831
- if (text !== void 0 && canWriteFromTerminalOutput()) writeClipboardText(text).then(onCopied);
1843
+ if (text !== void 0 && canWriteFromTerminalOutput()) copyFromTerminalOutput(text);
1832
1844
  return true;
1833
1845
  });
1834
1846
  host.addEventListener("mouseup", copySelectionOnRelease);
1835
1847
  window.addEventListener("copy", copySelectionOnShortcut);
1848
+ window.addEventListener("pointerdown", copyWaitingTextOnUserGesture, true);
1849
+ window.addEventListener("keydown", copyWaitingTextOnUserGesture, true);
1836
1850
  return () => {
1837
1851
  osc52.dispose();
1852
+ window.removeEventListener("pointerdown", copyWaitingTextOnUserGesture, true);
1853
+ window.removeEventListener("keydown", copyWaitingTextOnUserGesture, true);
1838
1854
  host.removeEventListener("mouseup", copySelectionOnRelease);
1839
1855
  window.removeEventListener("copy", copySelectionOnShortcut);
1840
1856
  };
@@ -2082,6 +2098,98 @@ function RemoteAccess() {
2082
2098
  });
2083
2099
  }
2084
2100
  //#endregion
2101
+ //#region src/client/update.ts
2102
+ var CHECK_MS = 9e5;
2103
+ var POLL_MS = 2e3;
2104
+ var GIVE_UP_MS = 18e4;
2105
+ var fetchStatus = async (signal) => {
2106
+ const response = await fetch("/api/update", { signal });
2107
+ if (!response.ok) throw new Error("Updates are not available.");
2108
+ return await response.json();
2109
+ };
2110
+ var postCheck = async () => {
2111
+ const response = await fetch("/api/update/check", { method: "POST" });
2112
+ if (!response.ok) throw new Error("Updates are not available.");
2113
+ return await response.json();
2114
+ };
2115
+ var confirmationMessage = ({ current, latest }) => `Update Webr from ${current} to ${latest}? Webr restarts and this page reloads. Running agents keep working.`;
2116
+ function useUpdate() {
2117
+ const [updatingFrom, setUpdatingFrom] = useState();
2118
+ const data = useQuery({
2119
+ queryKey: ["update"],
2120
+ queryFn: ({ signal }) => fetchStatus(signal),
2121
+ refetchInterval: updatingFrom ? POLL_MS : CHECK_MS,
2122
+ refetchOnWindowFocus: !updatingFrom
2123
+ }).data;
2124
+ const stopWaiting = useCallback((message) => {
2125
+ setUpdatingFrom(void 0);
2126
+ alertDialog(message);
2127
+ }, []);
2128
+ useEffect(() => {
2129
+ if (!updatingFrom || !data) return;
2130
+ if (data.current !== updatingFrom) window.location.reload();
2131
+ else if (data.state === "failed") stopWaiting(data.error ?? "The update failed.");
2132
+ }, [
2133
+ updatingFrom,
2134
+ data,
2135
+ stopWaiting
2136
+ ]);
2137
+ useEffect(() => {
2138
+ if (!updatingFrom) return;
2139
+ const timer = setTimeout(() => stopWaiting("Webr did not come back after the update. Reload this page, or restart Herdr."), GIVE_UP_MS);
2140
+ return () => clearTimeout(timer);
2141
+ }, [updatingFrom, stopWaiting]);
2142
+ const queryClient = useQueryClient();
2143
+ const [checking, setChecking] = useState(false);
2144
+ const checkNow = useCallback(async () => {
2145
+ setChecking(true);
2146
+ try {
2147
+ queryClient.setQueryData(["update"], await postCheck());
2148
+ } catch {
2149
+ await alertDialog("Webr could not check for updates.");
2150
+ } finally {
2151
+ setChecking(false);
2152
+ }
2153
+ }, [queryClient]);
2154
+ const requestUpdate = useCallback(async () => {
2155
+ if (!data || !await confirmDialog(confirmationMessage(data), { confirmLabel: "Update" })) return;
2156
+ if ((await fetch("/api/update", { method: "POST" }).catch(() => void 0))?.status === 202) setUpdatingFrom(data.current);
2157
+ else await alertDialog("Webr could not start the update.");
2158
+ }, [data]);
2159
+ return {
2160
+ status: data,
2161
+ updating: !!updatingFrom,
2162
+ checking,
2163
+ checkNow,
2164
+ requestUpdate
2165
+ };
2166
+ }
2167
+ //#endregion
2168
+ //#region src/components/UpdateSetting.tsx
2169
+ function UpdateSetting() {
2170
+ const { status, updating, checking, checkNow, requestUpdate } = useUpdate();
2171
+ const upToDate = status && !status.available;
2172
+ return /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", { children: "Updates" }), /* @__PURE__ */ jsxs("div", {
2173
+ className: "settings-row",
2174
+ children: [/* @__PURE__ */ jsxs("span", { children: [status ? `Webr ${status.current}` : "Webr", /* @__PURE__ */ jsx("small", {
2175
+ className: "device-meta",
2176
+ children: status?.available ? `Version ${status.latest} is available.` : upToDate ? "You are on the latest version." : "Checking for updates…"
2177
+ })] }), status?.available ? /* @__PURE__ */ jsx("button", {
2178
+ type: "button",
2179
+ className: "dialog-button is-primary",
2180
+ disabled: updating,
2181
+ onClick: () => void requestUpdate(),
2182
+ children: updating ? "Updating…" : `Update to ${status.latest}`
2183
+ }) : /* @__PURE__ */ jsx("button", {
2184
+ type: "button",
2185
+ className: "dialog-button",
2186
+ disabled: checking || !status,
2187
+ onClick: () => void checkNow(),
2188
+ children: checking ? "Checking…" : "Check for updates"
2189
+ })]
2190
+ })] });
2191
+ }
2192
+ //#endregion
2085
2193
  //#region src/components/SettingsView.tsx
2086
2194
  function SettingsView({ onOpenSidebar }) {
2087
2195
  const [behavior, setBehavior] = useState("worktree");
@@ -2128,6 +2236,7 @@ function SettingsView({ onOpenSidebar }) {
2128
2236
  children: "Threads"
2129
2237
  }),
2130
2238
  /* @__PURE__ */ jsx("h1", { children: "Settings" }),
2239
+ /* @__PURE__ */ jsx(UpdateSetting, {}),
2131
2240
  /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx("h2", { children: "Appearance" }), /* @__PURE__ */ jsxs("div", {
2132
2241
  className: "settings-row",
2133
2242
  children: [/* @__PURE__ */ jsx("span", { children: "Theme" }), /* @__PURE__ */ jsx(ThemeControl, { expanded: true })]
@@ -3036,54 +3145,6 @@ function Sidebar({ projects, threads, archived = [], machines, currentId, mode,
3036
3145
  })] });
3037
3146
  }
3038
3147
  //#endregion
3039
- //#region src/client/update.ts
3040
- var CHECK_MS = 18e5;
3041
- var POLL_MS = 2e3;
3042
- var GIVE_UP_MS = 18e4;
3043
- var fetchStatus = async (signal) => {
3044
- const response = await fetch("/api/update", { signal });
3045
- if (!response.ok) throw new Error("Updates are not available.");
3046
- return await response.json();
3047
- };
3048
- var confirmationMessage = ({ current, latest }) => `Update Webr from ${current} to ${latest}? Webr restarts and this page reloads. Running agents keep working.`;
3049
- function useUpdate() {
3050
- const [updatingFrom, setUpdatingFrom] = useState();
3051
- const data = useQuery({
3052
- queryKey: ["update"],
3053
- queryFn: ({ signal }) => fetchStatus(signal),
3054
- refetchInterval: updatingFrom ? POLL_MS : CHECK_MS,
3055
- refetchOnWindowFocus: !updatingFrom
3056
- }).data;
3057
- const stopWaiting = useCallback((message) => {
3058
- setUpdatingFrom(void 0);
3059
- alertDialog(message);
3060
- }, []);
3061
- useEffect(() => {
3062
- if (!updatingFrom || !data) return;
3063
- if (data.current !== updatingFrom) window.location.reload();
3064
- else if (data.state === "failed") stopWaiting(data.error ?? "The update failed.");
3065
- }, [
3066
- updatingFrom,
3067
- data,
3068
- stopWaiting
3069
- ]);
3070
- useEffect(() => {
3071
- if (!updatingFrom) return;
3072
- const timer = setTimeout(() => stopWaiting("Webr did not come back after the update. Reload this page, or restart Herdr."), GIVE_UP_MS);
3073
- return () => clearTimeout(timer);
3074
- }, [updatingFrom, stopWaiting]);
3075
- const requestUpdate = useCallback(async () => {
3076
- if (!data || !await confirmDialog(confirmationMessage(data), { confirmLabel: "Update" })) return;
3077
- if ((await fetch("/api/update", { method: "POST" }).catch(() => void 0))?.status === 202) setUpdatingFrom(data.current);
3078
- else await alertDialog("Webr could not start the update.");
3079
- }, [data]);
3080
- return {
3081
- status: data,
3082
- updating: !!updatingFrom,
3083
- requestUpdate
3084
- };
3085
- }
3086
- //#endregion
3087
3148
  //#region src/components/UpdateButton.tsx
3088
3149
  function UpdateButton() {
3089
3150
  const { status, updating, requestUpdate } = useUpdate();
@@ -4020,9 +4081,38 @@ function useImageAttachments({ machineId, active, writable, send, show }) {
4020
4081
  }
4021
4082
  //#endregion
4022
4083
  //#region src/client/terminal-links.ts
4023
- function openLinkOnModifierClick(event, uri) {
4024
- if (!event.metaKey && !event.ctrlKey) return;
4025
- window.open(uri, "_blank", "noopener,noreferrer");
4084
+ var URL_PATTERN = /https?:\/\/[^\s"'<>`]+/g;
4085
+ var TRAILING_PUNCTUATION = /[.,;:!?)\]}]+$/;
4086
+ var hasOpenModifier = (event) => event.metaKey || event.ctrlKey;
4087
+ function logicalLineAt(terminal, row) {
4088
+ const buffer = terminal.buffer.active;
4089
+ let first = row;
4090
+ while (first > 0 && buffer.getLine(first)?.isWrapped) first--;
4091
+ let text = "";
4092
+ let last = first;
4093
+ for (let index = first; buffer.getLine(index) && (index === first || buffer.getLine(index).isWrapped); index++) {
4094
+ text += buffer.getLine(index).translateToString(false, 0, terminal.cols);
4095
+ last = index;
4096
+ }
4097
+ return {
4098
+ text,
4099
+ offset: (row - first) * terminal.cols,
4100
+ last
4101
+ };
4102
+ }
4103
+ function urlAtCell(terminal, column, row) {
4104
+ const { text, offset } = logicalLineAt(terminal, row);
4105
+ const position = offset + column;
4106
+ for (const match of text.matchAll(URL_PATTERN)) {
4107
+ const url = match[0].replace(TRAILING_PUNCTUATION, "");
4108
+ if (position >= match.index && position < match.index + url.length) return url;
4109
+ }
4110
+ }
4111
+ function openLinkUnderModifierClick(terminal, event) {
4112
+ const rect = (terminal.element?.querySelector(".xterm-screen"))?.getBoundingClientRect();
4113
+ if (!hasOpenModifier(event) || !rect?.width || !rect.height) return;
4114
+ const url = urlAtCell(terminal, Math.floor((event.clientX - rect.left) / rect.width * terminal.cols), Math.floor((event.clientY - rect.top) / rect.height * terminal.rows) + terminal.buffer.active.viewportY);
4115
+ if (url) window.open(url, "_blank", "noopener,noreferrer");
4026
4116
  }
4027
4117
  //#endregion
4028
4118
  //#region src/components/useTerminalNotice.ts
@@ -4298,8 +4388,8 @@ function TerminalPane({ pane, machineId, threadId, active, canControl, onFocus }
4298
4388
  control.current?.input(text, true);
4299
4389
  }
4300
4390
  });
4301
- const showCopyResult = useRef((copied) => {});
4302
- showCopyResult.current = (copied) => copied ? show("Copied to clipboard", "info", 1200) : show("The browser blocked clipboard access.", "error", 4e3);
4391
+ const showCopyResult = useRef((outcome) => {});
4392
+ showCopyResult.current = (outcome) => outcome === "copied" ? show("Copied to clipboard", "info", 1200) : outcome === "waiting-for-click" ? show("Click or press a key to finish copying.", "info", 6e3) : show("The browser blocked clipboard access.", "error", 4e3);
4303
4393
  useEffect(() => {
4304
4394
  if (!host.current) return;
4305
4395
  let disposed = false;
@@ -4333,7 +4423,7 @@ function TerminalPane({ pane, machineId, threadId, active, canControl, onFocus }
4333
4423
  if (writableRef.current) host.current?.parentElement?.querySelector(".terminal-input-capture")?.focus();
4334
4424
  };
4335
4425
  terminal.textarea?.addEventListener("focus", redirectFocus);
4336
- const clipboard = bindTerminalClipboard(host.current, terminal, () => writableRef.current, (copied) => showCopyResult.current(copied));
4426
+ const clipboard = bindTerminalClipboard(host.current, terminal, () => writableRef.current, (outcome) => showCopyResult.current(outcome));
4337
4427
  const links = terminal.parser.registerOscHandler(8, () => true);
4338
4428
  if (!pane.terminalId) {
4339
4429
  clipboard();
@@ -4342,7 +4432,10 @@ function TerminalPane({ pane, machineId, threadId, active, canControl, onFocus }
4342
4432
  }
4343
4433
  const fit = new FitAddon();
4344
4434
  terminal.loadAddon(fit);
4345
- terminal.loadAddon(new WebLinksAddon(openLinkOnModifierClick));
4435
+ terminal.loadAddon(new WebLinksAddon(() => {}));
4436
+ const openLink = (event) => openLinkUnderModifierClick(terminal, event);
4437
+ const hostElement = host.current;
4438
+ hostElement.addEventListener("mouseup", openLink);
4346
4439
  const estimatedViewport = () => ({
4347
4440
  cols: Math.floor((host.current?.clientWidth ?? 640) / 8),
4348
4441
  rows: Math.floor((host.current?.clientHeight ?? 400) / 20)
@@ -4414,6 +4507,7 @@ function TerminalPane({ pane, machineId, threadId, active, canControl, onFocus }
4414
4507
  document.removeEventListener("visibilitychange", claimSize);
4415
4508
  terminal.textarea?.removeEventListener("focus", redirectFocus);
4416
4509
  clipboard();
4510
+ hostElement.removeEventListener("mouseup", openLink);
4417
4511
  links.dispose();
4418
4512
  resize.disconnect();
4419
4513
  colorObserver.disconnect();
@@ -1,6 +1,6 @@
1
1
  import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
2
2
  import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
3
- import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
3
+ import { n as $$Base, t as App } from "./App_XfPUtM-S.mjs";
4
4
  //#region src/pages/threads/[id].astro
5
5
  var _id__exports = /* @__PURE__ */ __exportAll({
6
6
  default: () => $$Id,
@@ -1,6 +1,6 @@
1
1
  import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
2
2
  import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
3
- import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
3
+ import { n as $$Base, t as App } from "./App_XfPUtM-S.mjs";
4
4
  //#region src/pages/sessions/[session]/tabs/[tab].astro
5
5
  var _tab__exports = /* @__PURE__ */ __exportAll({
6
6
  default: () => $$Tab,
@@ -1,6 +1,6 @@
1
1
  import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
2
2
  import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
3
- import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
3
+ import { n as $$Base, t as App } from "./App_XfPUtM-S.mjs";
4
4
  //#region src/pages/new.astro
5
5
  var new_exports = /* @__PURE__ */ __exportAll({
6
6
  default: () => $$New,
@@ -1,6 +1,6 @@
1
1
  import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
2
2
  import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
3
- import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
3
+ import { n as $$Base, t as App } from "./App_XfPUtM-S.mjs";
4
4
  //#region src/pages/settings.astro
5
5
  var settings_exports = /* @__PURE__ */ __exportAll({
6
6
  default: () => $$Settings,
@@ -2426,10 +2426,10 @@ var renderers = [Object.assign({
2426
2426
  //#endregion
2427
2427
  //#region \0virtual:astro:pages
2428
2428
  var _page0 = () => import("./chunks/node_C8FqXy_n.mjs").then((n) => n.t);
2429
- var _page1 = () => import("./chunks/new_D_b9CCPu.mjs");
2430
- var _page2 = () => import("./chunks/_tab__BXxhjK-Q.mjs");
2431
- var _page3 = () => import("./chunks/settings_DC2X19WH.mjs");
2432
- var _page4 = () => import("./chunks/_id__Dl1xEdu9.mjs");
2429
+ var _page1 = () => import("./chunks/new_-EySB3XL.mjs");
2430
+ var _page2 = () => import("./chunks/_tab__JQMRAwvi.mjs");
2431
+ var _page3 = () => import("./chunks/settings_Dmpl3S0r.mjs");
2432
+ var _page4 = () => import("./chunks/_id__dmqwXj3z.mjs");
2433
2433
  var _page5 = () => import("./chunks/index_Bvv1gpI0.mjs");
2434
2434
  var pageMap = /* @__PURE__ */ new Map([
2435
2435
  ["node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js", _page0],
@@ -2441,7 +2441,7 @@ var pageMap = /* @__PURE__ */ new Map([
2441
2441
  ]);
2442
2442
  //#endregion
2443
2443
  //#region \0virtual:astro:manifest
2444
- var _manifest = deserializeManifest({"rootDir":"file:///home/runner/work/webr/webr/","cacheDir":"file:///home/runner/work/webr/webr/node_modules/.astro/","outDir":"file:///home/runner/work/webr/webr/dist/","srcDir":"file:///home/runner/work/webr/webr/src/","publicDir":"file:///home/runner/work/webr/webr/public/","buildClientDir":"file:///home/runner/work/webr/webr/dist/client/","buildServerDir":"file:///home/runner/work/webr/webr/dist/server/","adapterName":"@astrojs/node","assetsDir":"_astro","routes":[{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"type":"page","component":"_server-islands.astro","params":["name"],"segments":[[{"content":"_server-islands","dynamic":false,"spread":false}],[{"content":"name","dynamic":true,"spread":false}]],"pattern":"^\\/_server-islands\\/([^/]+?)\\/?$","prerender":false,"isIndex":false,"fallbackRoutes":[],"route":"/_server-islands/[name]","origin":"internal","distURL":[],"_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/_image","component":"node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js","params":[],"pathname":"/_image","pattern":"^\\/_image\\/?$","segments":[[{"content":"_image","dynamic":false,"spread":false}]],"type":"endpoint","prerender":false,"fallbackRoutes":[],"distURL":[],"isIndex":false,"origin":"internal","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/new","isIndex":false,"type":"page","pattern":"^\\/new\\/?$","segments":[[{"content":"new","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/new.astro","pathname":"/new","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/sessions/[session]/tabs/[tab]","isIndex":false,"type":"page","pattern":"^\\/sessions\\/([^/]+?)\\/tabs\\/([^/]+?)\\/?$","segments":[[{"content":"sessions","dynamic":false,"spread":false}],[{"content":"session","dynamic":true,"spread":false}],[{"content":"tabs","dynamic":false,"spread":false}],[{"content":"tab","dynamic":true,"spread":false}]],"params":["session","tab"],"component":"src/pages/sessions/[session]/tabs/[tab].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/settings","isIndex":false,"type":"page","pattern":"^\\/settings\\/?$","segments":[[{"content":"settings","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/settings.astro","pathname":"/settings","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/threads/[id]","isIndex":false,"type":"page","pattern":"^\\/threads\\/([^/]+?)\\/?$","segments":[[{"content":"threads","dynamic":false,"spread":false}],[{"content":"id","dynamic":true,"spread":false}]],"params":["id"],"component":"src/pages/threads/[id].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/","isIndex":true,"type":"page","pattern":"^\\/$","segments":[],"params":[],"component":"src/pages/index.astro","pathname":"/","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}}],"serverLike":true,"middlewareMode":"classic","base":"/","trailingSlash":"ignore","compressHTML":"jsx","componentMetadata":[["/home/runner/work/webr/webr/src/pages/new.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/sessions/[session]/tabs/[tab].astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/settings.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/threads/[id].astro",{"propagation":"none","containsHead":true}]],"renderers":[],"clientDirectives":[["idle","(()=>{var l=(n,t)=>{let i=async()=>{await(await n())()},e=typeof t.value==\"object\"?t.value:void 0,s={timeout:e==null?void 0:e.timeout};\"requestIdleCallback\"in window?window.requestIdleCallback(i,s):setTimeout(i,s.timeout||200)};(self.Astro||(self.Astro={})).idle=l;window.dispatchEvent(new Event(\"astro:idle\"));})();"],["load","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).load=e;window.dispatchEvent(new Event(\"astro:load\"));})();"],["media","(()=>{var n=(a,t)=>{let i=async()=>{await(await a())()};if(t.value){let e=matchMedia(t.value);e.matches?i():e.addEventListener(\"change\",i,{once:!0})}};(self.Astro||(self.Astro={})).media=n;window.dispatchEvent(new Event(\"astro:media\"));})();"],["only","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event(\"astro:only\"));})();"],["visible","(()=>{var a=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value==\"object\"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let l of e)if(l.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=a;window.dispatchEvent(new Event(\"astro:visible\"));})();"]],"entryModules":{"\u0000noop-middleware":"virtual_astro_middleware.mjs","\u0000virtual:astro:server-island-manifest":"chunks/_virtual_astro_server-island-manifest_C1Q2srgE.mjs","\u0000virtual:astro:session-driver":"chunks/_virtual_astro_session-driver_Dp7RXjOf.mjs","\u0000virtual:astro:actions/noop-entrypoint":"chunks/noop-entrypoint_Z3zFhrGC.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/@astrojs+react@7.0.0_@types+node@22.20.4_@types+react-dom@19.3.0_@types+react@19.3.0__@_02aa85dceaccf3d763325676dd8540a8/node_modules/@astrojs/react/dist/vnode-children.js":"chunks/vnode-children_BSi0H4PL.mjs","@astrojs/node/server.js":"entry.mjs","\u0000virtual:astro:page:src/pages/threads/[id]@_@astro":"chunks/_id__Dl1xEdu9.mjs","\u0000virtual:astro:page:src/pages/sessions/[session]/tabs/[tab]@_@astro":"chunks/_tab__BXxhjK-Q.mjs","\u0000virtual:astro:page:src/pages/index@_@astro":"chunks/index_Bvv1gpI0.mjs","\u0000virtual:astro:page:src/pages/new@_@astro":"chunks/new_D_b9CCPu.mjs","\u0000virtual:astro:page:node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node@_@js":"chunks/node_C8FqXy_n.mjs","\u0000virtual:astro:page:src/pages/settings@_@astro":"chunks/settings_DC2X19WH.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/services/sharp.js":"chunks/sharp_8J8zk4Wd.mjs","/home/runner/work/webr/webr/src/components/App.tsx":"_astro/App.FpiLskEl.js","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/components/ClientRouter.astro?astro&type=script&index=0&lang.ts":"_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","@astrojs/react/client.js":"_astro/client.BDkzSRUN.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-fit@0.10.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-fit/lib/addon-fit.js":"_astro/addon-fit.jgKqzwky.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-web-links@0.11.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-web-links/lib/addon-web-links.js":"_astro/addon-web-links.C9lyQRxI.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-webgl@0.18.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-webgl/lib/addon-webgl.js":"_astro/addon-webgl.Bd5ox92E.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+xterm@5.5.0/node_modules/@xterm/xterm/lib/xterm.js":"_astro/xterm.B-l5AIf6.js","astro:scripts/before-hydration.js":""},"inlinedScripts":[],"assets":["/apple-touch-icon.png","/brand-mark.png","/favicon-16.png","/favicon-32.png","/favicon.ico","/icon-192.png","/icon-512.png","/icon-maskable-512.png","/manifest.webmanifest","/_astro/App.FpiLskEl.js","/_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","/_astro/addon-fit.jgKqzwky.js","/_astro/addon-web-links.C9lyQRxI.js","/_astro/addon-webgl.Bd5ox92E.js","/_astro/client.BDkzSRUN.js","/_astro/client.Bbg9OBwT.js","/_astro/client.CLSsMr2g.js","/_astro/xterm.B-l5AIf6.js","/_astro/App.L92siqEU.css","/_astro/jetbrains-mono.CFJaiWaY.woff2","/_astro/symbols-nerd.CEdkKAK8.woff2"],"buildFormat":"directory","checkOrigin":true,"actionBodySizeLimit":1048576,"serverIslandBodySizeLimit":1048576,"allowedDomains":[],"key":"z16FjxtdKR1/WYgfwbCkuUifz+joBnLKN4HyAmEN95Y=","sessionConfig":{"driver":"unstorage/drivers/fs-lite","options":{"base":"/home/runner/work/webr/webr/node_modules/.astro/sessions"}},"image":{},"devToolbar":{"enabled":false,"debugInfoOutput":""},"logLevel":"info","shouldInjectCspMetaTags":false});
2444
+ var _manifest = deserializeManifest({"rootDir":"file:///home/runner/work/webr/webr/","cacheDir":"file:///home/runner/work/webr/webr/node_modules/.astro/","outDir":"file:///home/runner/work/webr/webr/dist/","srcDir":"file:///home/runner/work/webr/webr/src/","publicDir":"file:///home/runner/work/webr/webr/public/","buildClientDir":"file:///home/runner/work/webr/webr/dist/client/","buildServerDir":"file:///home/runner/work/webr/webr/dist/server/","adapterName":"@astrojs/node","assetsDir":"_astro","routes":[{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"type":"page","component":"_server-islands.astro","params":["name"],"segments":[[{"content":"_server-islands","dynamic":false,"spread":false}],[{"content":"name","dynamic":true,"spread":false}]],"pattern":"^\\/_server-islands\\/([^/]+?)\\/?$","prerender":false,"isIndex":false,"fallbackRoutes":[],"route":"/_server-islands/[name]","origin":"internal","distURL":[],"_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/_image","component":"node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js","params":[],"pathname":"/_image","pattern":"^\\/_image\\/?$","segments":[[{"content":"_image","dynamic":false,"spread":false}]],"type":"endpoint","prerender":false,"fallbackRoutes":[],"distURL":[],"isIndex":false,"origin":"internal","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/new","isIndex":false,"type":"page","pattern":"^\\/new\\/?$","segments":[[{"content":"new","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/new.astro","pathname":"/new","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/sessions/[session]/tabs/[tab]","isIndex":false,"type":"page","pattern":"^\\/sessions\\/([^/]+?)\\/tabs\\/([^/]+?)\\/?$","segments":[[{"content":"sessions","dynamic":false,"spread":false}],[{"content":"session","dynamic":true,"spread":false}],[{"content":"tabs","dynamic":false,"spread":false}],[{"content":"tab","dynamic":true,"spread":false}]],"params":["session","tab"],"component":"src/pages/sessions/[session]/tabs/[tab].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/settings","isIndex":false,"type":"page","pattern":"^\\/settings\\/?$","segments":[[{"content":"settings","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/settings.astro","pathname":"/settings","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/threads/[id]","isIndex":false,"type":"page","pattern":"^\\/threads\\/([^/]+?)\\/?$","segments":[[{"content":"threads","dynamic":false,"spread":false}],[{"content":"id","dynamic":true,"spread":false}]],"params":["id"],"component":"src/pages/threads/[id].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/","isIndex":true,"type":"page","pattern":"^\\/$","segments":[],"params":[],"component":"src/pages/index.astro","pathname":"/","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}}],"serverLike":true,"middlewareMode":"classic","base":"/","trailingSlash":"ignore","compressHTML":"jsx","componentMetadata":[["/home/runner/work/webr/webr/src/pages/new.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/sessions/[session]/tabs/[tab].astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/settings.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/threads/[id].astro",{"propagation":"none","containsHead":true}]],"renderers":[],"clientDirectives":[["idle","(()=>{var l=(n,t)=>{let i=async()=>{await(await n())()},e=typeof t.value==\"object\"?t.value:void 0,s={timeout:e==null?void 0:e.timeout};\"requestIdleCallback\"in window?window.requestIdleCallback(i,s):setTimeout(i,s.timeout||200)};(self.Astro||(self.Astro={})).idle=l;window.dispatchEvent(new Event(\"astro:idle\"));})();"],["load","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).load=e;window.dispatchEvent(new Event(\"astro:load\"));})();"],["media","(()=>{var n=(a,t)=>{let i=async()=>{await(await a())()};if(t.value){let e=matchMedia(t.value);e.matches?i():e.addEventListener(\"change\",i,{once:!0})}};(self.Astro||(self.Astro={})).media=n;window.dispatchEvent(new Event(\"astro:media\"));})();"],["only","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event(\"astro:only\"));})();"],["visible","(()=>{var a=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value==\"object\"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let l of e)if(l.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=a;window.dispatchEvent(new Event(\"astro:visible\"));})();"]],"entryModules":{"\u0000noop-middleware":"virtual_astro_middleware.mjs","\u0000virtual:astro:server-island-manifest":"chunks/_virtual_astro_server-island-manifest_C1Q2srgE.mjs","\u0000virtual:astro:session-driver":"chunks/_virtual_astro_session-driver_Dp7RXjOf.mjs","\u0000virtual:astro:actions/noop-entrypoint":"chunks/noop-entrypoint_Z3zFhrGC.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/@astrojs+react@7.0.0_@types+node@22.20.4_@types+react-dom@19.3.0_@types+react@19.3.0__@_02aa85dceaccf3d763325676dd8540a8/node_modules/@astrojs/react/dist/vnode-children.js":"chunks/vnode-children_BSi0H4PL.mjs","@astrojs/node/server.js":"entry.mjs","\u0000virtual:astro:page:src/pages/threads/[id]@_@astro":"chunks/_id__dmqwXj3z.mjs","\u0000virtual:astro:page:src/pages/sessions/[session]/tabs/[tab]@_@astro":"chunks/_tab__JQMRAwvi.mjs","\u0000virtual:astro:page:src/pages/index@_@astro":"chunks/index_Bvv1gpI0.mjs","\u0000virtual:astro:page:src/pages/new@_@astro":"chunks/new_-EySB3XL.mjs","\u0000virtual:astro:page:node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node@_@js":"chunks/node_C8FqXy_n.mjs","\u0000virtual:astro:page:src/pages/settings@_@astro":"chunks/settings_Dmpl3S0r.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/services/sharp.js":"chunks/sharp_8J8zk4Wd.mjs","/home/runner/work/webr/webr/src/components/App.tsx":"_astro/App.BZmfW4_t.js","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/components/ClientRouter.astro?astro&type=script&index=0&lang.ts":"_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","@astrojs/react/client.js":"_astro/client.BDkzSRUN.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-fit@0.10.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-fit/lib/addon-fit.js":"_astro/addon-fit.jgKqzwky.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-web-links@0.11.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-web-links/lib/addon-web-links.js":"_astro/addon-web-links.C9lyQRxI.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-webgl@0.18.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-webgl/lib/addon-webgl.js":"_astro/addon-webgl.Bd5ox92E.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+xterm@5.5.0/node_modules/@xterm/xterm/lib/xterm.js":"_astro/xterm.B-l5AIf6.js","astro:scripts/before-hydration.js":""},"inlinedScripts":[],"assets":["/apple-touch-icon.png","/brand-mark.png","/favicon-16.png","/favicon-32.png","/favicon.ico","/icon-192.png","/icon-512.png","/icon-maskable-512.png","/manifest.webmanifest","/_astro/App.BZmfW4_t.js","/_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","/_astro/addon-fit.jgKqzwky.js","/_astro/addon-web-links.C9lyQRxI.js","/_astro/addon-webgl.Bd5ox92E.js","/_astro/client.BDkzSRUN.js","/_astro/client.Bbg9OBwT.js","/_astro/client.CLSsMr2g.js","/_astro/xterm.B-l5AIf6.js","/_astro/App.L92siqEU.css","/_astro/jetbrains-mono.CFJaiWaY.woff2","/_astro/symbols-nerd.CEdkKAK8.woff2"],"buildFormat":"directory","checkOrigin":true,"actionBodySizeLimit":1048576,"serverIslandBodySizeLimit":1048576,"allowedDomains":[],"key":"7N25S2SombltRl6Fvq20zN31p3AqIF8x63DL+IHD4Qs=","sessionConfig":{"driver":"unstorage/drivers/fs-lite","options":{"base":"/home/runner/work/webr/webr/node_modules/.astro/sessions"}},"image":{},"devToolbar":{"enabled":false,"debugInfoOutput":""},"logLevel":"info","shouldInjectCspMetaTags":false});
2445
2445
  var manifestRoutes = _manifest.routes;
2446
2446
  var manifest = Object.assign(_manifest, {
2447
2447
  renderers,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pablopunk/webr",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Control your Herdr agents from anywhere.",
5
5
  "keywords": [
6
6
  "herdr",
@@ -10,7 +10,7 @@ import { updateCheckDisabled } from './hint';
10
10
  import { detectPackageManager, installedPackagePath, isNpxRun } from './package-manager';
11
11
  import { isNewerVersion } from './versions';
12
12
 
13
- const REFRESH_MS = 6 * 60 * 60 * 1000;
13
+ const REFRESH_MS = 15 * 60 * 1000;
14
14
  const RESTART_GRACE_MS = 60 * 1000;
15
15
  const LOG_LINES_SHOWN = 4;
16
16
 
@@ -72,6 +72,11 @@ export class UpdateService implements Updates {
72
72
  if (latest) writeCachedLatest(latest, this.env);
73
73
  }
74
74
 
75
+ async check(): Promise<UpdateStatus> {
76
+ await this.refresh();
77
+ return this.status();
78
+ }
79
+
75
80
  status(): UpdateStatus {
76
81
  const { version: current } = packageInfo();
77
82
  const latest = readCachedLatest(this.env)?.latest ?? current;
@@ -56,6 +56,7 @@ export async function createHost(manager: RuntimeManager, origin: string, ssr?:
56
56
  if (transcriber) registerVoiceRoutes(app, transcriber);
57
57
  if (updates) {
58
58
  app.get('/api/update', async () => updates.status());
59
+ app.post('/api/update/check', async () => updates.check());
59
60
  app.post('/api/update', async (_request, reply) => { const status = updates.start(); return reply.code(status.state === 'updating' ? 202 : 409).send(status); });
60
61
  }
61
62
  app.get('/api/catalog/machines', async () => manager.bootstrap().machines);
@@ -2,4 +2,4 @@ export type UpdateState = 'idle' | 'updating' | 'failed';
2
2
 
3
3
  export type UpdateStatus = { current: string; latest: string; available: boolean; state: UpdateState; error?: string };
4
4
 
5
- export type Updates = { status: () => UpdateStatus; start: () => UpdateStatus };
5
+ export type Updates = { status: () => UpdateStatus; check: () => Promise<UpdateStatus>; start: () => UpdateStatus };