opencami 1.8.13 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +4 -2
  2. package/dist/client/assets/{CSPContext-DATmz4sz.js → CSPContext-B3PAVjBL.js} +1 -1
  3. package/dist/client/assets/{DirectionContext-FHFKdJq_.js → DirectionContext-CR5CCisG.js} +1 -1
  4. package/dist/client/assets/_sessionKey-Bg_9uype.js +23 -0
  5. package/dist/client/assets/agents-BiTHBb6Z.js +2 -0
  6. package/dist/client/assets/{agents-screen-C58VLjES.js → agents-screen--ZMzN5cB.js} +1 -1
  7. package/dist/client/assets/bots-DxhRnQp5.js +2 -0
  8. package/dist/client/assets/{bots-screen-B8h4Y1VL.js → bots-screen-C_uJBNwI.js} +1 -1
  9. package/dist/client/assets/{button-BcUmP7JL.js → button-BciDmec0.js} +1 -1
  10. package/dist/client/assets/{composite--BBbKdxm.js → composite-DArWbFHm.js} +1 -1
  11. package/dist/client/assets/{connect-BmwKnEFP.js → connect-B48HecjN.js} +1 -1
  12. package/dist/client/assets/{dashboard-BWQl_-2-.js → dashboard-BVKx9FMy.js} +1 -1
  13. package/dist/client/assets/{event-BxzjTPjG.js → event-BCwqPPkP.js} +1 -1
  14. package/dist/client/assets/{file-explorer-screen-BAbbb_R4.js → file-explorer-screen-DPs-FWeA.js} +1 -1
  15. package/dist/client/assets/files-SEycwYCa.js +2 -0
  16. package/dist/client/assets/{follow-up-suggestions-Bq-xR5GV.js → follow-up-suggestions-BPjWBpiy.js} +1 -1
  17. package/dist/client/assets/{index-rOr2i8gW.js → index-0gdwm1_H.js} +1 -1
  18. package/dist/client/assets/{index-BTtT4Vbb.js → index-CGeJcqZ3.js} +1 -1
  19. package/dist/client/assets/{keyboard-shortcuts-dialog-BA8cBwWm.js → keyboard-shortcuts-dialog-CK_XTzLr.js} +1 -1
  20. package/dist/client/assets/{main-_1IghVZn.js → main-B2CrcRuC.js} +3 -3
  21. package/dist/client/assets/{markdown-CqIcraPO.js → markdown-CdkuX06F.js} +1 -1
  22. package/dist/client/assets/memory-C7lKdkmc.js +2 -0
  23. package/dist/client/assets/{memory-screen-GBzowsnE.js → memory-screen-C1RfLy-d.js} +1 -1
  24. package/dist/client/assets/{menu--FXN_JCl.js → menu-CIwnliij.js} +1 -1
  25. package/dist/client/assets/{opencami-logo-BFo87CeM.js → opencami-logo-SVuYD55V.js} +1 -1
  26. package/dist/client/assets/{proxy-CJ6-TEKD.js → proxy-BijR8W1L.js} +1 -1
  27. package/dist/client/assets/{react-BRYbnjMp.js → react-DWx7OvUo.js} +1 -1
  28. package/dist/client/assets/{search-dialog-CJS2GUnE.js → search-dialog-CB4KE8ec.js} +1 -1
  29. package/dist/client/assets/{search-sources-badge-D0YArqfp.js → search-sources-badge-B8Z-8sSf.js} +1 -1
  30. package/dist/client/assets/{session-export-dialog-Bc9YEPLs.js → session-export-dialog-tDiFuv3a.js} +1 -1
  31. package/dist/client/assets/{settings-dialog-SDzqDXsx.js → settings-dialog-aL-AH4Rt.js} +1 -1
  32. package/dist/client/assets/skills-D1T6uemU.js +2 -0
  33. package/dist/client/assets/{skills-panel-DIalYvpW.js → skills-panel-fjJQVMog.js} +1 -1
  34. package/dist/client/assets/styles-D0L88B64.css +1 -0
  35. package/dist/client/assets/{switch-BwmDNR0d.js → switch-Bn5uei2k.js} +1 -1
  36. package/dist/client/assets/{tabs-T1fJbUsm.js → tabs-DOBNAUVE.js} +1 -1
  37. package/dist/client/assets/{thinking-DUdE6Iej.js → thinking-dfGrFAMV.js} +1 -1
  38. package/dist/client/assets/{tooltip-DexBPu8g.js → tooltip-DOKkNFvu.js} +1 -1
  39. package/dist/client/assets/{use-file-explorer-state-eXs92yKN.js → use-file-explorer-state-BAa6Cxyr.js} +1 -1
  40. package/dist/client/assets/{useBaseUiId-DN9cOflS.js → useBaseUiId-DFpBD0sg.js} +1 -1
  41. package/dist/client/assets/{useCompositeItem-B_J-cnZX.js → useCompositeItem-B-Axq9-D.js} +1 -1
  42. package/dist/client/assets/{useControlled-DeDLOsPR.js → useControlled-CQHE0ITz.js} +1 -1
  43. package/dist/client/assets/{useMutation-TzgejsE_.js → useMutation-BFl-7GnD.js} +1 -1
  44. package/dist/client/assets/{useOnFirstRender-S4-xcV93.js → useOnFirstRender-DlXHIIGk.js} +1 -1
  45. package/dist/client/assets/{useQuery-BdjM5kzn.js → useQuery-D-sF8Tld.js} +1 -1
  46. package/dist/server/assets/{_sessionKey-DBzlGMo3.js → _sessionKey-D8TGrDRM.js} +429 -131
  47. package/dist/server/assets/{_tanstack-start-manifest_v-CX4xb59U.js → _tanstack-start-manifest_v-DalBo2bY.js} +1 -1
  48. package/dist/server/assets/{follow-up-suggestions-BmSFSY87.js → follow-up-suggestions-C65ptDij.js} +2 -2
  49. package/dist/server/assets/{index-C1dylvu-.js → index-gRco4Ina.js} +1 -1
  50. package/dist/server/assets/{router-CL6A11qi.js → router-DaKDqc9w.js} +72 -251
  51. package/dist/server/assets/{search-dialog-D8DvpPZw.js → search-dialog-DSSK93kq.js} +2 -2
  52. package/dist/server/assets/{settings-dialog-CeP-J_NJ.js → settings-dialog-DyWNblva.js} +2 -2
  53. package/dist/server/assets/{thinking-ClIWjSbx.js → thinking-CU0FRlzT.js} +2 -2
  54. package/dist/server/server.js +2 -2
  55. package/package.json +1 -1
  56. package/dist/client/assets/_sessionKey-D2ZMdqJ0.js +0 -23
  57. package/dist/client/assets/agents-9A0buuwT.js +0 -2
  58. package/dist/client/assets/bots-Lqt92ma0.js +0 -2
  59. package/dist/client/assets/files-DvIFms9G.js +0 -2
  60. package/dist/client/assets/memory-B3LyVZwO.js +0 -2
  61. package/dist/client/assets/skills-BVLjvrPU.js +0 -2
  62. package/dist/client/assets/styles-b2XYKZYx.css +0 -1
@@ -1,4 +1,4 @@
1
- const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "/root/opencami/src/routes/__root.tsx", "children": ["/", "/agents", "/bots", "/connect", "/dashboard", "/files", "/memory", "/new", "/skills", "/api/agents", "/api/cron", "/api/follow-ups", "/api/history", "/api/llm-features", "/api/models", "/api/paths", "/api/personas", "/api/ping", "/api/send", "/api/sessions", "/api/skills", "/api/stream", "/api/stt", "/api/tts", "/chat/$sessionKey", "/api/dashboard/crons", "/api/dashboard/gateway", "/api/dashboard/system", "/api/files/delete", "/api/files/download", "/api/files/info", "/api/files/list", "/api/files/mkdir", "/api/files/read", "/api/files/rename", "/api/files/save", "/api/files/upload"], "preloads": ["/assets/main-_1IghVZn.js"], "assets": [] }, "/": { "filePath": "/root/opencami/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-rOr2i8gW.js"] }, "/agents": { "filePath": "/root/opencami/src/routes/agents.tsx", "assets": [], "preloads": ["/assets/agents-9A0buuwT.js"] }, "/bots": { "filePath": "/root/opencami/src/routes/bots.tsx", "assets": [], "preloads": ["/assets/bots-Lqt92ma0.js"] }, "/connect": { "filePath": "/root/opencami/src/routes/connect.tsx", "assets": [], "preloads": ["/assets/connect-BmwKnEFP.js", "/assets/index-BTtT4Vbb.js", "/assets/button-BcUmP7JL.js", "/assets/react-BRYbnjMp.js"] }, "/dashboard": { "filePath": "/root/opencami/src/routes/dashboard.tsx", "assets": [], "preloads": ["/assets/dashboard-BWQl_-2-.js", "/assets/useQuery-BdjM5kzn.js"] }, "/files": { "filePath": "/root/opencami/src/routes/files.tsx", "assets": [], "preloads": ["/assets/files-DvIFms9G.js"] }, "/memory": { "filePath": "/root/opencami/src/routes/memory.tsx", "assets": [], "preloads": ["/assets/memory-B3LyVZwO.js"] }, "/new": { "filePath": "/root/opencami/src/routes/new.tsx", "assets": [], "preloads": ["/assets/new-DLlBm66g.js"] }, "/skills": { "filePath": "/root/opencami/src/routes/skills.tsx", "assets": [], "preloads": ["/assets/skills-BVLjvrPU.js"] }, "/api/agents": { "filePath": "/root/opencami/src/routes/api/agents.ts" }, "/api/cron": { "filePath": "/root/opencami/src/routes/api/cron.ts" }, "/api/follow-ups": { "filePath": "/root/opencami/src/routes/api/follow-ups.ts" }, "/api/history": { "filePath": "/root/opencami/src/routes/api/history.ts" }, "/api/llm-features": { "filePath": "/root/opencami/src/routes/api/llm-features.ts" }, "/api/models": { "filePath": "/root/opencami/src/routes/api/models.ts" }, "/api/paths": { "filePath": "/root/opencami/src/routes/api/paths.ts" }, "/api/personas": { "filePath": "/root/opencami/src/routes/api/personas.ts" }, "/api/ping": { "filePath": "/root/opencami/src/routes/api/ping.ts" }, "/api/send": { "filePath": "/root/opencami/src/routes/api/send.ts" }, "/api/sessions": { "filePath": "/root/opencami/src/routes/api/sessions.ts" }, "/api/skills": { "filePath": "/root/opencami/src/routes/api/skills.ts" }, "/api/stream": { "filePath": "/root/opencami/src/routes/api/stream.ts" }, "/api/stt": { "filePath": "/root/opencami/src/routes/api/stt.ts" }, "/api/tts": { "filePath": "/root/opencami/src/routes/api/tts.ts" }, "/chat/$sessionKey": { "filePath": "/root/opencami/src/routes/chat/$sessionKey.tsx", "assets": [], "preloads": ["/assets/_sessionKey-D2ZMdqJ0.js", "/assets/useQuery-BdjM5kzn.js", "/assets/tooltip-DexBPu8g.js", "/assets/button-BcUmP7JL.js", "/assets/useMutation-TzgejsE_.js", "/assets/use-file-explorer-state-eXs92yKN.js", "/assets/useBaseUiId-DN9cOflS.js", "/assets/useControlled-DeDLOsPR.js", "/assets/useOnFirstRender-S4-xcV93.js", "/assets/event-BxzjTPjG.js", "/assets/CSPContext-DATmz4sz.js", "/assets/DirectionContext-FHFKdJq_.js", "/assets/menu--FXN_JCl.js", "/assets/opencami-logo-BFo87CeM.js", "/assets/proxy-CJ6-TEKD.js", "/assets/markdown-CqIcraPO.js", "/assets/index-BTtT4Vbb.js", "/assets/react-BRYbnjMp.js"] }, "/api/dashboard/crons": { "filePath": "/root/opencami/src/routes/api/dashboard/crons.ts" }, "/api/dashboard/gateway": { "filePath": "/root/opencami/src/routes/api/dashboard/gateway.ts" }, "/api/dashboard/system": { "filePath": "/root/opencami/src/routes/api/dashboard/system.ts" }, "/api/files/delete": { "filePath": "/root/opencami/src/routes/api/files/delete.ts" }, "/api/files/download": { "filePath": "/root/opencami/src/routes/api/files/download.ts" }, "/api/files/info": { "filePath": "/root/opencami/src/routes/api/files/info.ts" }, "/api/files/list": { "filePath": "/root/opencami/src/routes/api/files/list.ts" }, "/api/files/mkdir": { "filePath": "/root/opencami/src/routes/api/files/mkdir.ts" }, "/api/files/read": { "filePath": "/root/opencami/src/routes/api/files/read.ts" }, "/api/files/rename": { "filePath": "/root/opencami/src/routes/api/files/rename.ts" }, "/api/files/save": { "filePath": "/root/opencami/src/routes/api/files/save.ts" }, "/api/files/upload": { "filePath": "/root/opencami/src/routes/api/files/upload.ts" } }, "clientEntry": "/assets/main-_1IghVZn.js" });
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "/root/opencami/src/routes/__root.tsx", "children": ["/", "/agents", "/bots", "/connect", "/dashboard", "/files", "/memory", "/new", "/skills", "/api/agents", "/api/cron", "/api/follow-ups", "/api/history", "/api/llm-features", "/api/models", "/api/paths", "/api/personas", "/api/ping", "/api/send", "/api/sessions", "/api/skills", "/api/stream", "/api/stt", "/api/tts", "/chat/$sessionKey", "/api/dashboard/crons", "/api/dashboard/gateway", "/api/dashboard/system", "/api/files/delete", "/api/files/download", "/api/files/info", "/api/files/list", "/api/files/mkdir", "/api/files/read", "/api/files/rename", "/api/files/save", "/api/files/upload"], "preloads": ["/assets/main-B2CrcRuC.js"], "assets": [] }, "/": { "filePath": "/root/opencami/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-0gdwm1_H.js"] }, "/agents": { "filePath": "/root/opencami/src/routes/agents.tsx", "assets": [], "preloads": ["/assets/agents-BiTHBb6Z.js"] }, "/bots": { "filePath": "/root/opencami/src/routes/bots.tsx", "assets": [], "preloads": ["/assets/bots-DxhRnQp5.js"] }, "/connect": { "filePath": "/root/opencami/src/routes/connect.tsx", "assets": [], "preloads": ["/assets/connect-B48HecjN.js", "/assets/index-CGeJcqZ3.js", "/assets/button-BciDmec0.js", "/assets/react-DWx7OvUo.js"] }, "/dashboard": { "filePath": "/root/opencami/src/routes/dashboard.tsx", "assets": [], "preloads": ["/assets/dashboard-BVKx9FMy.js", "/assets/useQuery-D-sF8Tld.js"] }, "/files": { "filePath": "/root/opencami/src/routes/files.tsx", "assets": [], "preloads": ["/assets/files-SEycwYCa.js"] }, "/memory": { "filePath": "/root/opencami/src/routes/memory.tsx", "assets": [], "preloads": ["/assets/memory-C7lKdkmc.js"] }, "/new": { "filePath": "/root/opencami/src/routes/new.tsx", "assets": [], "preloads": ["/assets/new-DLlBm66g.js"] }, "/skills": { "filePath": "/root/opencami/src/routes/skills.tsx", "assets": [], "preloads": ["/assets/skills-D1T6uemU.js"] }, "/api/agents": { "filePath": "/root/opencami/src/routes/api/agents.ts" }, "/api/cron": { "filePath": "/root/opencami/src/routes/api/cron.ts" }, "/api/follow-ups": { "filePath": "/root/opencami/src/routes/api/follow-ups.ts" }, "/api/history": { "filePath": "/root/opencami/src/routes/api/history.ts" }, "/api/llm-features": { "filePath": "/root/opencami/src/routes/api/llm-features.ts" }, "/api/models": { "filePath": "/root/opencami/src/routes/api/models.ts" }, "/api/paths": { "filePath": "/root/opencami/src/routes/api/paths.ts" }, "/api/personas": { "filePath": "/root/opencami/src/routes/api/personas.ts" }, "/api/ping": { "filePath": "/root/opencami/src/routes/api/ping.ts" }, "/api/send": { "filePath": "/root/opencami/src/routes/api/send.ts" }, "/api/sessions": { "filePath": "/root/opencami/src/routes/api/sessions.ts" }, "/api/skills": { "filePath": "/root/opencami/src/routes/api/skills.ts" }, "/api/stream": { "filePath": "/root/opencami/src/routes/api/stream.ts" }, "/api/stt": { "filePath": "/root/opencami/src/routes/api/stt.ts" }, "/api/tts": { "filePath": "/root/opencami/src/routes/api/tts.ts" }, "/chat/$sessionKey": { "filePath": "/root/opencami/src/routes/chat/$sessionKey.tsx", "assets": [], "preloads": ["/assets/_sessionKey-Bg_9uype.js", "/assets/useQuery-D-sF8Tld.js", "/assets/tooltip-DOKkNFvu.js", "/assets/button-BciDmec0.js", "/assets/useMutation-BFl-7GnD.js", "/assets/use-file-explorer-state-BAa6Cxyr.js", "/assets/useBaseUiId-DFpBD0sg.js", "/assets/useControlled-CQHE0ITz.js", "/assets/useOnFirstRender-DlXHIIGk.js", "/assets/event-BCwqPPkP.js", "/assets/CSPContext-B3PAVjBL.js", "/assets/DirectionContext-CR5CCisG.js", "/assets/menu-CIwnliij.js", "/assets/opencami-logo-SVuYD55V.js", "/assets/proxy-BijR8W1L.js", "/assets/markdown-CdkuX06F.js", "/assets/index-CGeJcqZ3.js", "/assets/react-DWx7OvUo.js"] }, "/api/dashboard/crons": { "filePath": "/root/opencami/src/routes/api/dashboard/crons.ts" }, "/api/dashboard/gateway": { "filePath": "/root/opencami/src/routes/api/dashboard/gateway.ts" }, "/api/dashboard/system": { "filePath": "/root/opencami/src/routes/api/dashboard/system.ts" }, "/api/files/delete": { "filePath": "/root/opencami/src/routes/api/files/delete.ts" }, "/api/files/download": { "filePath": "/root/opencami/src/routes/api/files/download.ts" }, "/api/files/info": { "filePath": "/root/opencami/src/routes/api/files/info.ts" }, "/api/files/list": { "filePath": "/root/opencami/src/routes/api/files/list.ts" }, "/api/files/mkdir": { "filePath": "/root/opencami/src/routes/api/files/mkdir.ts" }, "/api/files/read": { "filePath": "/root/opencami/src/routes/api/files/read.ts" }, "/api/files/rename": { "filePath": "/root/opencami/src/routes/api/files/rename.ts" }, "/api/files/save": { "filePath": "/root/opencami/src/routes/api/files/save.ts" }, "/api/files/upload": { "filePath": "/root/opencami/src/routes/api/files/upload.ts" } }, "clientEntry": "/assets/main-B2CrcRuC.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -2,7 +2,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect, memo } from "react";
3
3
  import { HugeiconsIcon } from "@hugeicons/react";
4
4
  import { Loading03Icon, ArrowRight01Icon } from "@hugeicons/core-free-icons";
5
- import { a as useLlmSettingsStore, b as getLlmHeaders } from "./_sessionKey-DBzlGMo3.js";
5
+ import { a as useLlmSettingsStore, b as getLlmHeaders } from "./_sessionKey-D8TGrDRM.js";
6
6
  import { c as cn } from "./button-kI8fEIZQ.js";
7
7
  import "@tanstack/react-router";
8
8
  import "@tanstack/react-query";
@@ -26,7 +26,7 @@ import "remark-gfm";
26
26
  import "./index-B_F4DTUu.js";
27
27
  import "zustand/middleware";
28
28
  import "react-dom";
29
- import "./router-CL6A11qi.js";
29
+ import "./router-DaKDqc9w.js";
30
30
  import "node:crypto";
31
31
  import "node:fs";
32
32
  import "node:os";
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useEffect } from "react";
3
- import { R as Route } from "./router-CL6A11qi.js";
3
+ import { R as Route } from "./router-DaKDqc9w.js";
4
4
  import "@tanstack/react-router";
5
5
  import "@tanstack/react-query";
6
6
  import "node:crypto";
@@ -12,7 +12,7 @@ import { execFile, execSync } from "node:child_process";
12
12
  import { promisify } from "node:util";
13
13
  import { readFile, mkdir, writeFile, rename, stat, readdir, rm, realpath, lstat } from "node:fs/promises";
14
14
  import { posix } from "path";
15
- const appCss = "/assets/styles-b2XYKZYx.css";
15
+ const appCss = "/assets/styles-D0L88B64.css";
16
16
  const swRegisterScript = `
17
17
  (() => {
18
18
  // Skip PWA service worker inside Capacitor native shell — they conflict
@@ -372,11 +372,11 @@ const $$splitComponentImporter$2 = () => import("./agents-BuE0Yum3.js");
372
372
  const Route$t = createFileRoute("/agents")({
373
373
  component: lazyRouteComponent($$splitComponentImporter$2, "component")
374
374
  });
375
- const $$splitComponentImporter$1 = () => import("./index-C1dylvu-.js");
375
+ const $$splitComponentImporter$1 = () => import("./index-gRco4Ina.js");
376
376
  const Route$s = createFileRoute("/")({
377
377
  component: lazyRouteComponent($$splitComponentImporter$1, "component")
378
378
  });
379
- const $$splitComponentImporter = () => import("./_sessionKey-DBzlGMo3.js").then((n) => n.$);
379
+ const $$splitComponentImporter = () => import("./_sessionKey-D8TGrDRM.js").then((n) => n.$);
380
380
  const Route$r = createFileRoute("/chat/$sessionKey")({
381
381
  component: lazyRouteComponent($$splitComponentImporter, "component")
382
382
  });
@@ -529,7 +529,7 @@ function buildConnectParams(url, token, password, nonce) {
529
529
  const clientId = "openclaw-control-ui";
530
530
  const clientMode = "webchat";
531
531
  const role = "operator";
532
- const scopes = ["operator.admin", "operator.approvals", "operator.pairing"];
532
+ const scopes = ["operator.read", "operator.write", "operator.admin", "operator.approvals", "operator.pairing"];
533
533
  if (!nonce) {
534
534
  throw new Error(
535
535
  "OpenClaw did not send connect.challenge nonce in time. If you are connecting cross-origin, ensure your origin is allowed (gateway.controlUi.allowedOrigins)."
@@ -593,8 +593,7 @@ class PersistentGatewayConnection {
593
593
  connectPromise = null;
594
594
  pendingRpcs = /* @__PURE__ */ new Map();
595
595
  reconnectTimer = null;
596
- reconnectDelay = 1e3;
597
- maxReconnectDelay = 3e4;
596
+ reconnectAttempt = 0;
598
597
  destroyed = false;
599
598
  _devicePending = false;
600
599
  _deviceId = "";
@@ -658,6 +657,7 @@ class PersistentGatewayConnection {
658
657
  const timer = setTimeout(() => {
659
658
  if (done) return;
660
659
  done = true;
660
+ ws.off("message", onMessage);
661
661
  resolve2("");
662
662
  }, 3e3);
663
663
  const onMessage = (data) => {
@@ -737,7 +737,7 @@ class PersistentGatewayConnection {
737
737
  password: password || void 0
738
738
  },
739
739
  role: "operator",
740
- scopes: ["operator.admin", "operator.approvals", "operator.pairing"],
740
+ scopes: ["operator.read", "operator.write", "operator.admin", "operator.approvals", "operator.pairing"],
741
741
  userAgent: `opencami/${process.env.npm_package_version ?? "dev"} (node ${process.version})`,
742
742
  locale: process.env.LANG || "en"
743
743
  };
@@ -753,7 +753,7 @@ class PersistentGatewayConnection {
753
753
  this._devicePending = false;
754
754
  }
755
755
  this.connected = true;
756
- this.reconnectDelay = 1e3;
756
+ this.reconnectAttempt = 0;
757
757
  console.log("[gateway-ws] Persistent connection established");
758
758
  }
759
759
  _onMessage(data) {
@@ -777,7 +777,8 @@ class PersistentGatewayConnection {
777
777
  const event = {
778
778
  event: parsed.event,
779
779
  payload: parsed.payload ?? {},
780
- seq: parsed.seq
780
+ seq: parsed.seq,
781
+ stateVersion: typeof parsed.stateVersion === "number" ? parsed.stateVersion : void 0
781
782
  };
782
783
  const sessionKey = this._extractSessionKey(event);
783
784
  for (const listener of this.globalListeners) {
@@ -787,15 +788,20 @@ class PersistentGatewayConnection {
787
788
  }
788
789
  }
789
790
  if (sessionKey) {
790
- const listeners = this.sessionListeners.get(sessionKey);
791
- if (listeners && listeners.size > 0) {
792
- for (const listener of listeners) {
793
- try {
794
- listener(event);
795
- } catch {
791
+ let dispatched = false;
792
+ const eventSegments = sessionKey.split(":");
793
+ for (const [subKey, listeners] of this.sessionListeners) {
794
+ if (sessionKey === subKey || eventSegments.includes(subKey)) {
795
+ dispatched = true;
796
+ for (const listener of listeners) {
797
+ try {
798
+ listener(event);
799
+ } catch {
800
+ }
796
801
  }
797
802
  }
798
- } else {
803
+ }
804
+ if (!dispatched) {
799
805
  let buf = this.eventBuffer.get(sessionKey);
800
806
  if (!buf) {
801
807
  const timer = setTimeout(() => {
@@ -838,15 +844,18 @@ class PersistentGatewayConnection {
838
844
  }
839
845
  _scheduleReconnect() {
840
846
  if (this.reconnectTimer) return;
841
- const delay = this.reconnectDelay;
842
- this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
843
- console.log(`[gateway-ws] Reconnecting in ${delay}ms...`);
847
+ const base = 1e3;
848
+ const cap = 3e4;
849
+ const exponential = Math.min(cap, base * 2 ** this.reconnectAttempt);
850
+ const delay = Math.round(Math.random() * exponential);
851
+ this.reconnectAttempt++;
852
+ console.log(`[gateway-ws] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})...`);
844
853
  this.reconnectTimer = setTimeout(async () => {
845
854
  this.reconnectTimer = null;
846
855
  try {
847
856
  await this.ensureConnected();
848
857
  } catch (err) {
849
- console.error("[gateway-ws] Reconnect failed:", err instanceof Error ? err.message : err);
858
+ console.error(`[gateway-ws] Reconnect attempt ${this.reconnectAttempt} failed:`, err instanceof Error ? err.message : err);
850
859
  }
851
860
  }, delay);
852
861
  }
@@ -876,14 +885,22 @@ class PersistentGatewayConnection {
876
885
  this.sessionListeners.set(sessionKey, listeners);
877
886
  }
878
887
  listeners.add(listener);
879
- const buf = this.eventBuffer.get(sessionKey);
880
- if (buf) {
881
- this.eventBuffer.delete(sessionKey);
882
- clearTimeout(buf.timer);
883
- for (const event of buf.events) {
884
- try {
885
- listener(event);
886
- } catch {
888
+ const keysToFlush = [];
889
+ for (const bufKey of this.eventBuffer.keys()) {
890
+ if (bufKey === sessionKey || bufKey.split(":").includes(sessionKey)) {
891
+ keysToFlush.push(bufKey);
892
+ }
893
+ }
894
+ for (const bufKey of keysToFlush) {
895
+ const buf = this.eventBuffer.get(bufKey);
896
+ if (buf) {
897
+ this.eventBuffer.delete(bufKey);
898
+ clearTimeout(buf.timer);
899
+ for (const event of buf.events) {
900
+ try {
901
+ listener(event);
902
+ } catch {
903
+ }
887
904
  }
888
905
  }
889
906
  }
@@ -923,235 +940,30 @@ function getPersistentConnection() {
923
940
  }
924
941
  return _proc.__opencamiGatewayInstance;
925
942
  }
926
- const sharedGatewayClients = /* @__PURE__ */ new Map();
927
- function createGatewayClient() {
928
- const pendingRpcs = /* @__PURE__ */ new Map();
929
- const callbacks = /* @__PURE__ */ new Set();
930
- let ws = null;
931
- let closed = false;
932
- let connected = false;
933
- let connectPromise = null;
934
- function rejectAll(err) {
935
- for (const [, pending] of pendingRpcs) {
936
- clearTimeout(pending.timer);
937
- pending.reject(err);
938
- }
939
- pendingRpcs.clear();
940
- }
941
- function waitForRes(id, timeoutMs = 3e4) {
942
- return new Promise((resolve2, reject) => {
943
- const timer = setTimeout(() => {
944
- pendingRpcs.delete(id);
945
- reject(new Error(`RPC timeout waiting for ${id}`));
946
- }, timeoutMs);
947
- pendingRpcs.set(id, { resolve: resolve2, reject, timer });
948
- });
949
- }
950
- function emitError(error) {
951
- for (const callback of callbacks) {
952
- try {
953
- callback.onError?.(error);
954
- } catch {
955
- }
956
- }
957
- }
958
- function emitEvent(event) {
959
- for (const callback of callbacks) {
960
- try {
961
- callback.onEvent?.(event);
962
- } catch {
963
- }
964
- }
965
- }
966
- function handleMessage(data) {
967
- try {
968
- const str = typeof data === "string" ? data : data.toString();
969
- const parsed = JSON.parse(str);
970
- if (parsed.type === "res") {
971
- const pending = pendingRpcs.get(parsed.id);
972
- if (!pending) return;
973
- pendingRpcs.delete(parsed.id);
974
- clearTimeout(pending.timer);
975
- if (parsed.ok) pending.resolve(parsed.payload);
976
- else pending.reject(new GatewayResponseError(parsed.error?.message ?? "gateway error", parsed.error?.code));
977
- return;
978
- }
979
- if (parsed.type === "event") {
980
- emitEvent({
981
- event: parsed.event,
982
- payload: parsed.payload ?? {},
983
- seq: parsed.seq
984
- });
985
- }
986
- } catch {
987
- }
988
- }
989
- function handleClose() {
990
- const wasConnected = connected;
991
- connected = false;
992
- ws = null;
993
- rejectAll(new Error("Connection closed"));
994
- if (!closed && wasConnected) {
995
- emitError(new Error("Gateway client connection closed"));
996
- }
997
- }
998
- async function connect() {
999
- if (closed) throw new Error("Gateway client closed");
1000
- if (connected && ws?.readyState === WebSocket.OPEN) return;
1001
- if (connectPromise) return connectPromise;
1002
- connectPromise = (async () => {
1003
- const { url, token, password } = getGatewayConfig();
1004
- const origin = process.env.OPENCAMI_ORIGIN?.trim();
1005
- const nextWs = origin ? new WebSocket(url, { headers: { Origin: origin } }) : new WebSocket(url);
1006
- ws = nextWs;
1007
- await new Promise((resolve2, reject) => {
1008
- const onOpen = () => {
1009
- cleanup();
1010
- resolve2();
1011
- };
1012
- const onError = (err) => {
1013
- cleanup();
1014
- reject(new Error(`WS open error: ${err.message}`));
1015
- };
1016
- const cleanup = () => {
1017
- nextWs.off("open", onOpen);
1018
- nextWs.off("error", onError);
1019
- };
1020
- nextWs.on("open", onOpen);
1021
- nextWs.on("error", onError);
1022
- });
1023
- const nonce = await new Promise((resolve2) => {
1024
- let done = false;
1025
- const timer = setTimeout(() => {
1026
- if (done) return;
1027
- done = true;
1028
- resolve2("");
1029
- }, 3e3);
1030
- const onMessage = (data) => {
1031
- try {
1032
- const str = typeof data === "string" ? data : data.toString();
1033
- const parsed = JSON.parse(str);
1034
- if (parsed.type === "event" && parsed.event === "connect.challenge") {
1035
- const n = parsed.payload?.nonce;
1036
- if (typeof n === "string" && n.length > 0) {
1037
- clearTimeout(timer);
1038
- nextWs.off("message", onMessage);
1039
- if (done) return;
1040
- done = true;
1041
- resolve2(n);
1042
- }
1043
- }
1044
- } catch {
1045
- }
1046
- };
1047
- nextWs.on("message", onMessage);
1048
- });
1049
- nextWs.on("message", handleMessage);
1050
- nextWs.on("close", handleClose);
1051
- nextWs.on("error", (err) => {
1052
- emitError(new Error(`Gateway client error: ${err.message}`));
1053
- });
1054
- const connectId = randomUUID();
1055
- const connectParams = buildConnectParams(url, token, password, nonce);
1056
- nextWs.send(JSON.stringify({
1057
- type: "req",
1058
- id: connectId,
1059
- method: "connect",
1060
- params: connectParams
1061
- }));
1062
- const hello = await waitForRes(connectId, 1e4);
1063
- if (hello?.auth?.deviceToken) {
1064
- const identity = loadOrCreateDeviceIdentity();
1065
- storeDeviceToken(identity.deviceId, url, hello.auth.deviceToken);
1066
- }
1067
- connected = true;
1068
- })();
1069
- try {
1070
- await connectPromise;
1071
- } finally {
1072
- connectPromise = null;
1073
- }
1074
- }
1075
- async function sendReq(method, params) {
1076
- await connect();
1077
- if (!ws || ws.readyState !== WebSocket.OPEN) {
1078
- throw new Error("Gateway client not connected");
1079
- }
1080
- const id = randomUUID();
1081
- ws.send(JSON.stringify({ type: "req", id, method, params }));
1082
- return await waitForRes(id);
1083
- }
1084
- function close() {
1085
- if (closed) return;
1086
- closed = true;
1087
- connected = false;
1088
- rejectAll(new Error("Gateway client closed"));
1089
- const currentWs = ws;
1090
- ws = null;
1091
- if (currentWs) {
1092
- currentWs.off("message", handleMessage);
1093
- currentWs.off("close", handleClose);
1094
- currentWs.close();
1095
- }
1096
- callbacks.clear();
1097
- }
1098
- function isClosed() {
1099
- return closed;
1100
- }
1101
- function addCallbacks(callbacksToAdd) {
1102
- if (!callbacksToAdd?.onEvent && !callbacksToAdd?.onError) {
1103
- return () => {
1104
- };
1105
- }
1106
- callbacks.add(callbacksToAdd);
1107
- return () => {
1108
- callbacks.delete(callbacksToAdd);
1109
- };
1110
- }
1111
- return { connect, sendReq, close, isClosed, addCallbacks };
1112
- }
1113
- function releaseGatewayClient(key) {
1114
- const entry = sharedGatewayClients.get(key);
1115
- if (!entry) return;
1116
- entry.refs -= 1;
1117
- if (entry.refs > 0) return;
1118
- entry.client.close();
1119
- sharedGatewayClients.delete(key);
1120
- }
1121
943
  async function acquireGatewayClient(key, callbacks) {
1122
- const existing = sharedGatewayClients.get(key);
1123
- if (existing && !existing.client.isClosed()) {
1124
- existing.refs += 1;
1125
- const removeCallbacks2 = existing.client.addCallbacks(callbacks);
1126
- return {
1127
- client: existing.client,
1128
- release: () => {
1129
- removeCallbacks2();
1130
- releaseGatewayClient(key);
1131
- }
1132
- };
944
+ const conn = getPersistentConnection();
945
+ await conn.ensureConnected();
946
+ let unsubscribe = null;
947
+ if (callbacks?.onEvent) {
948
+ unsubscribe = conn.subscribe(key, callbacks.onEvent);
1133
949
  }
1134
- const client = createGatewayClient();
1135
- const removeCallbacks = client.addCallbacks(callbacks);
1136
- await client.connect();
1137
- sharedGatewayClients.set(key, { refs: 1, client });
1138
950
  return {
1139
- client,
951
+ client: {
952
+ connect: () => conn.ensureConnected(),
953
+ sendReq: (method, params) => conn.rpc(method, params),
954
+ close: () => {
955
+ },
956
+ isClosed: () => !conn.isConnected,
957
+ addCallbacks: () => () => {
958
+ }
959
+ },
1140
960
  release: () => {
1141
- removeCallbacks();
1142
- releaseGatewayClient(key);
961
+ unsubscribe?.();
1143
962
  }
1144
963
  };
1145
964
  }
1146
- async function gatewayRpcShared(method, params, key) {
1147
- if (!key) {
1148
- return gatewayRpc(method, params);
1149
- }
1150
- const existing = sharedGatewayClients.get(key);
1151
- if (!existing || existing.client.isClosed()) {
1152
- return gatewayRpc(method, params);
1153
- }
1154
- return existing.client.sendReq(method, params);
965
+ async function gatewayRpcShared(method, params, _key) {
966
+ return gatewayRpc(method, params);
1155
967
  }
1156
968
  async function gatewayRpc(method, params) {
1157
969
  const conn = getPersistentConnection();
@@ -1528,6 +1340,8 @@ const Route$o = createFileRoute("/api/stream")({
1528
1340
  let closed = false;
1529
1341
  let heartbeat = null;
1530
1342
  let releaseClient = null;
1343
+ let lastSeq = -1;
1344
+ let lastEventFingerprint = "";
1531
1345
  function writeChunk(chunk) {
1532
1346
  if (closed) return;
1533
1347
  try {
@@ -1564,9 +1378,16 @@ const Route$o = createFileRoute("/api/stream")({
1564
1378
  try {
1565
1379
  const handle = await acquireGatewayClient(key, {
1566
1380
  onEvent(event) {
1381
+ if (typeof event.seq === "number") {
1382
+ if (event.seq <= lastSeq) return;
1383
+ lastSeq = event.seq;
1384
+ }
1385
+ const fp = event.event + ":" + JSON.stringify(event.payload);
1386
+ if (fp === lastEventFingerprint) return;
1387
+ lastEventFingerprint = fp;
1567
1388
  const p = event.payload;
1568
1389
  const eventSessionKey = typeof p?.sessionKey === "string" ? p.sessionKey : "";
1569
- if (eventSessionKey && !eventSessionKey.includes(key)) {
1390
+ if (eventSessionKey && eventSessionKey !== key && !eventSessionKey.split(":").includes(key)) {
1570
1391
  return;
1571
1392
  }
1572
1393
  send({
@@ -5,7 +5,7 @@ import { HugeiconsIcon } from "@hugeicons/react";
5
5
  import { Search01Icon, Cancel01Icon, Loading03Icon } from "@hugeicons/core-free-icons";
6
6
  import { D as DialogRoot, a as DialogContent } from "./use-file-explorer-state-E6cUvMva.js";
7
7
  import { useQueryClient } from "@tanstack/react-query";
8
- import { c as chatQueryKeys } from "./_sessionKey-DBzlGMo3.js";
8
+ import { c as chatQueryKeys } from "./_sessionKey-D8TGrDRM.js";
9
9
  import { c as cn } from "./button-kI8fEIZQ.js";
10
10
  import "@base-ui/react/dialog";
11
11
  import "zustand";
@@ -26,7 +26,7 @@ import "remark-gfm";
26
26
  import "./index-B_F4DTUu.js";
27
27
  import "zustand/middleware";
28
28
  import "react-dom";
29
- import "./router-CL6A11qi.js";
29
+ import "./router-DaKDqc9w.js";
30
30
  import "node:crypto";
31
31
  import "node:fs";
32
32
  import "node:os";
@@ -8,7 +8,7 @@ import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescr
8
8
  import { S as Switch } from "./switch-BZzwkgAQ.js";
9
9
  import { T as Tabs, a as TabsList, b as TabsTab } from "./tabs-CWbp3mT4.js";
10
10
  import { u as useChatSettings } from "./index-B_F4DTUu.js";
11
- import { u as useLlmSettings, g as getLlmProviderDefaults } from "./_sessionKey-DBzlGMo3.js";
11
+ import { u as useLlmSettings, g as getLlmProviderDefaults } from "./_sessionKey-D8TGrDRM.js";
12
12
  import "@base-ui/react/merge-props";
13
13
  import "@base-ui/react/use-render";
14
14
  import "class-variance-authority";
@@ -35,7 +35,7 @@ import "react-markdown";
35
35
  import "remark-breaks";
36
36
  import "remark-gfm";
37
37
  import "react-dom";
38
- import "./router-CL6A11qi.js";
38
+ import "./router-DaKDqc9w.js";
39
39
  import "node:crypto";
40
40
  import "node:fs";
41
41
  import "node:os";
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
- import { C as Collapsible, d as CollapsibleTrigger, e as CollapsiblePanel } from "./_sessionKey-DBzlGMo3.js";
3
+ import { C as Collapsible, d as CollapsibleTrigger, e as CollapsiblePanel } from "./_sessionKey-D8TGrDRM.js";
4
4
  import { HugeiconsIcon } from "@hugeicons/react";
5
5
  import { ArrowDown01Icon } from "@hugeicons/core-free-icons";
6
6
  import { B as Button } from "./button-kI8fEIZQ.js";
@@ -26,7 +26,7 @@ import "remark-gfm";
26
26
  import "./index-B_F4DTUu.js";
27
27
  import "zustand/middleware";
28
28
  import "react-dom";
29
- import "./router-CL6A11qi.js";
29
+ import "./router-DaKDqc9w.js";
30
30
  import "node:crypto";
31
31
  import "node:fs";
32
32
  import "node:os";
@@ -184,7 +184,7 @@ function getResponse() {
184
184
  return event.res;
185
185
  }
186
186
  async function getStartManifest(matchedRoutes) {
187
- const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-CX4xb59U.js");
187
+ const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-DalBo2bY.js");
188
188
  const startManifest = tsrStartManifest();
189
189
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
190
190
  rootRoute.assets = rootRoute.assets || [];
@@ -753,7 +753,7 @@ let entriesPromise;
753
753
  let baseManifestPromise;
754
754
  let cachedFinalManifestPromise;
755
755
  async function loadEntries() {
756
- const routerEntry = await import("./assets/router-CL6A11qi.js").then((n) => n.r);
756
+ const routerEntry = await import("./assets/router-DaKDqc9w.js").then((n) => n.r);
757
757
  const startEntry = await import("./assets/start-HYkvq4Ni.js");
758
758
  return { startEntry, routerEntry };
759
759
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencami",
3
- "version": "1.8.13",
3
+ "version": "1.9.1",
4
4
  "type": "module",
5
5
  "description": "OpenCami - A beautiful web client for OpenClaw",
6
6
  "bin": {