opencami 1.8.2 → 1.8.5

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 (83) hide show
  1. package/README.md +139 -14
  2. package/bin/opencami.js +15 -6
  3. package/dist/client/assets/{CSPContext-DeJH85nm.js → CSPContext-6t3O1emU.js} +1 -1
  4. package/dist/client/assets/{DirectionContext-CxhRpXkm.js → DirectionContext-C6goXEY_.js} +1 -1
  5. package/dist/client/assets/_sessionKey-B5Viv43f.js +23 -0
  6. package/dist/client/assets/agents-BmE6QOwl.js +2 -0
  7. package/dist/client/assets/agents-screen-pHUzJxX5.js +1 -0
  8. package/dist/client/assets/bots-BeOkwrXr.js +2 -0
  9. package/dist/client/assets/{bots-screen-Be3cfGgq.js → bots-screen-B79bAYvf.js} +1 -1
  10. package/dist/client/assets/{button-D9Plv7hu.js → button-CK8tKQ-Z.js} +1 -1
  11. package/dist/client/assets/{composite-B2KCZKKL.js → composite-feK0c-xF.js} +1 -1
  12. package/dist/client/assets/{connect-DuJfnyNK.js → connect-02tmQV_v.js} +1 -1
  13. package/dist/client/assets/csharp-COcwbKMJ.js +1 -0
  14. package/dist/client/assets/{dashboard-00GpXm5V.js → dashboard-DQ0zDQKd.js} +1 -1
  15. package/dist/client/assets/event-BsD1rqGT.js +1 -0
  16. package/dist/client/assets/file-explorer-screen-Ds7LeJTd.js +1 -0
  17. package/dist/client/assets/files-e40B1zFy.js +2 -0
  18. package/dist/client/assets/go-CxLEBnE3.js +1 -0
  19. package/dist/client/assets/{index-Yo5UhdZV.js → index-lK3yGoTI.js} +1 -1
  20. package/dist/client/assets/{index-DtGzE-ea.js → index-rljDU_1M.js} +2 -2
  21. package/dist/client/assets/keyboard-shortcuts-dialog-Bb_GOr9L.js +1 -0
  22. package/dist/client/assets/main-Dq6jpr6-.js +210 -0
  23. package/dist/client/assets/{markdown-DtWnt4NA.js → markdown-C7_Aipwd.js} +37 -37
  24. package/dist/client/assets/memory-C7UG-1le.js +2 -0
  25. package/dist/client/assets/memory-screen-CUFBWsq5.js +1 -0
  26. package/dist/client/assets/menu-n6L--M9R.js +1 -0
  27. package/dist/client/assets/{opencami-logo-Bmge6-FB.js → opencami-logo-zuSBm5Br.js} +1 -1
  28. package/dist/client/assets/php-Dhbhpdrm.js +1 -0
  29. package/dist/client/assets/proxy-BU8Bw1Vt.js +9 -0
  30. package/dist/client/assets/{react-DODKNyyU.js → react-BLyCEWpN.js} +1 -1
  31. package/dist/client/assets/ruby-NiQIzKut.js +1 -0
  32. package/dist/client/assets/search-dialog-yB4w5ajo.js +1 -0
  33. package/dist/client/assets/session-export-dialog-qbZgd2Zo.js +1 -0
  34. package/dist/client/assets/settings-dialog-CHJbvpgk.js +1 -0
  35. package/dist/client/assets/skills-DoKPPhNY.js +2 -0
  36. package/dist/client/assets/{skills-panel-DSiH-DLs.js → skills-panel-BH27r3nC.js} +1 -1
  37. package/dist/client/assets/styles-CXV5jZiD.css +1 -0
  38. package/dist/client/assets/{swift-Dg5xB15N.js → swift-D82vCrfD.js} +1 -1
  39. package/dist/client/assets/switch-BD3a0LRm.js +1 -0
  40. package/dist/client/assets/tabs-DI1e-kzz.js +1 -0
  41. package/dist/client/assets/tooltip-BbH3QWvK.js +1 -0
  42. package/dist/client/assets/use-file-explorer-state-DBfLeAyz.js +12 -0
  43. package/dist/client/assets/{useBaseUiId-KQTzRPLp.js → useBaseUiId-MgM4ouhx.js} +1 -1
  44. package/dist/client/assets/{useCompositeItem-BPY2_hF_.js → useCompositeItem-OhltNFdZ.js} +1 -1
  45. package/dist/client/assets/{useControlled-B5pEEz2V.js → useControlled-BQxTgsOd.js} +1 -1
  46. package/dist/client/assets/{useMutation-BsQD6FKe.js → useMutation-12DyB3Ox.js} +1 -1
  47. package/dist/client/assets/useOnFirstRender-7qoaK5sI.js +1 -0
  48. package/dist/client/assets/{useQuery-CmAJuY2W.js → useQuery-Ctiljcrr.js} +1 -1
  49. package/dist/server/assets/{_sessionKey-Bq_fl7uv.js → _sessionKey-CH8wIyED.js} +3 -3
  50. package/dist/server/assets/{_tanstack-start-manifest_v-BMCAWon2.js → _tanstack-start-manifest_v-C5HBDfQB.js} +1 -1
  51. package/dist/server/assets/{index-C2hVqxBl.js → index-NcNCVGTL.js} +4 -3
  52. package/dist/server/assets/{router-bN_iTo0B.js → router-Brzpnz55.js} +449 -70
  53. package/dist/server/assets/{search-dialog-DReM5ZD2.js → search-dialog-BNhjVvKc.js} +5 -4
  54. package/dist/server/assets/{settings-dialog-BUOrQN3Z.js → settings-dialog-CWcmfDiV.js} +5 -4
  55. package/dist/server/server.js +195 -38
  56. package/package.json +4 -1
  57. package/dist/client/assets/_sessionKey-CQE0brGK.js +0 -23
  58. package/dist/client/assets/agents-CMTFd_sG.js +0 -2
  59. package/dist/client/assets/agents-screen-BNQGEqcW.js +0 -1
  60. package/dist/client/assets/bots-B6oGzCxP.js +0 -2
  61. package/dist/client/assets/csharp-K5feNrxe.js +0 -1
  62. package/dist/client/assets/event-DD8Cz4O9.js +0 -1
  63. package/dist/client/assets/file-explorer-screen-CxwemBES.js +0 -1
  64. package/dist/client/assets/files-DyBJVXBu.js +0 -2
  65. package/dist/client/assets/go-Dn2_MT6a.js +0 -1
  66. package/dist/client/assets/keyboard-shortcuts-dialog-BZwd-iyV.js +0 -1
  67. package/dist/client/assets/main-CgwdHc9W.js +0 -210
  68. package/dist/client/assets/memory-l756yiNq.js +0 -2
  69. package/dist/client/assets/memory-screen-BQtVRuzE.js +0 -1
  70. package/dist/client/assets/menu-BsS6CDf_.js +0 -1
  71. package/dist/client/assets/php-CDn_0X-4.js +0 -1
  72. package/dist/client/assets/popupStateMapping-D0ZbJR_o.js +0 -1
  73. package/dist/client/assets/proxy-CYZeDXoy.js +0 -9
  74. package/dist/client/assets/ruby-FDmvQDUv.js +0 -1
  75. package/dist/client/assets/search-dialog-DW91SK30.js +0 -1
  76. package/dist/client/assets/session-export-dialog-CliO9Ob-.js +0 -1
  77. package/dist/client/assets/settings-dialog-C1u52aju.js +0 -1
  78. package/dist/client/assets/skills-8T_avaVb.js +0 -2
  79. package/dist/client/assets/styles-DvaLh0o1.css +0 -1
  80. package/dist/client/assets/switch-DbgQPO6i.js +0 -1
  81. package/dist/client/assets/tabs-BsAvZnlD.js +0 -1
  82. package/dist/client/assets/tooltip-DLmutB5C.js +0 -1
  83. package/dist/client/assets/use-file-explorer-state-Cg_yDYJl.js +0 -12
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # OpenCami 🦎
2
2
 
3
- **Version 1.7.0**
4
-
5
3
  A beautiful web client for [OpenClaw](https://github.com/openclaw/openclaw).
6
4
 
7
5
  [![npm](https://img.shields.io/npm/v/opencami)](https://www.npmjs.com/package/opencami)
@@ -9,37 +7,164 @@ A beautiful web client for [OpenClaw](https://github.com/openclaw/openclaw).
9
7
 
10
8
  ![OpenCami Chat Interface](docs/screenshots/opencami-chat.jpg)
11
9
 
12
- ## Quick Start
10
+ ## Install
11
+
12
+ ### Option 1 (recommended)
13
13
 
14
14
  ```bash
15
15
  curl -fsSL https://opencami.xyz/install.sh | bash
16
16
  ```
17
17
 
18
- Or via npm:
18
+ ### Option 2
19
19
 
20
20
  ```bash
21
21
  npm install -g opencami
22
- opencami
23
22
  ```
24
23
 
25
- Opens your browser to the chat interface.
24
+ ## Run
25
+
26
+ ### ✅ Recommended (OpenCami runs on the same machine as the OpenClaw Gateway)
27
+
28
+ ```bash
29
+ opencami --gateway ws://127.0.0.1:18789 --token <GATEWAY_TOKEN>
30
+ ```
31
+
32
+ Then open: `http://localhost:3000`
33
+
34
+ ### 🌐 Remote access over Tailscale (keep Gateway local)
35
+
36
+ This is the safest setup: **Gateway stays on loopback**, you access **OpenCami** via `https://<magicdns>:<port>`.
37
+
38
+ 1) In OpenClaw, allowlist the exact OpenCami URL (**no trailing slash**):
39
+
40
+ ```json5
41
+ {
42
+ "gateway": {
43
+ "controlUI": {
44
+ "allowedOrigins": ["https://<magicdns>:3001"]
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ 2) Restart the gateway:
51
+
52
+ ```bash
53
+ openclaw gateway restart
54
+ ```
55
+
56
+ 3) Start OpenCami with the same origin:
57
+
58
+ ```bash
59
+ opencami \
60
+ --gateway ws://127.0.0.1:18789 \
61
+ --token <GATEWAY_TOKEN> \
62
+ --origin https://<magicdns>:3001
63
+ ```
64
+
65
+ > ⚠️ Note: `--gateway` must be `ws://` or `wss://` (not `https://`).
66
+
67
+ ## CLI options
68
+
69
+ ```text
70
+ opencami [--port <n>] [--host <addr>] [--gateway <ws(s)://...>] [--token <token>] [--password <pw>] [--origin <url>] [--no-open]
71
+
72
+ --port <n> Port to listen on (default: 3000)
73
+ --host <addr> Host to bind to (default: 127.0.0.1)
74
+ --gateway <url> OpenClaw gateway WS URL (default: ws://127.0.0.1:18789)
75
+ --token <token> Gateway token (sets CLAWDBOT_GATEWAY_TOKEN)
76
+ --password <pw> Gateway password (sets CLAWDBOT_GATEWAY_PASSWORD)
77
+ --origin <url> Origin header for backend WS (sets OPENCAMI_ORIGIN)
78
+ --no-open Don't open browser on start
79
+ -h, --help Show help
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ You can also set env vars instead of flags:
85
+
86
+ ```bash
87
+ CLAWDBOT_GATEWAY_URL=ws://127.0.0.1:18789
88
+ CLAWDBOT_GATEWAY_TOKEN=...
89
+ OPENCAMI_ORIGIN=https://<magicdns>:3001 # only needed for remote HTTPS
90
+ ```
91
+
92
+ ## Troubleshooting (quick)
93
+
94
+ - **"origin not allowed"** → add the exact URL to `gateway.controlUI.allowedOrigins` *and* pass the same value as `--origin` / `OPENCAMI_ORIGIN` (exact match, no trailing `/`).
95
+ - **Pairing required** → approve the device in OpenClaw (`openclaw devices list/approve`).
96
+ - **Fallback (only if needed):** `OPENCAMI_DEVICE_AUTH_FALLBACK=1`
97
+
98
+ ---
99
+
100
+ ## Security notes
101
+
102
+ - Prefer `wss://` for remote connections.
103
+ - Prefer token auth (`CLAWDBOT_GATEWAY_TOKEN`) over password.
104
+ - Keep `allowedOrigins` minimal (exact origins only, no wildcards).
105
+ - Treat `OPENCAMI_DEVICE_AUTH_FALLBACK=true` as temporary compatibility mode.
106
+ - Do **not** expose OpenCami directly to the public internet without TLS + access controls.
107
+ - For Tailnet deployments, limit Tailnet device/user access.
108
+
109
+ ---
110
+
111
+ ## Troubleshooting
26
112
 
27
- ### Options
113
+ ### "origin not allowed"
28
114
 
29
- | Flag | Description | Default |
30
- |------|-------------|---------|
31
- | `--port` | Port to serve on | `3000` |
32
- | `--gateway` | OpenClaw gateway URL | `ws://127.0.0.1:18789` |
33
- | `--host` | Bind address | `localhost` |
34
- | `--no-open` | Don't open browser | — |
115
+ Cause: gateway rejected browser origin.
35
116
 
36
- ### Docker
117
+ Fix:
118
+ 1. Add origin to `gateway.controlUI.allowedOrigins` (exact match, no trailing `/`)
119
+ 2. Set identical `OPENCAMI_ORIGIN` (or `--origin`) in OpenCami
120
+ 3. Restart gateway (`openclaw gateway restart`)
121
+
122
+ ### Missing scope `operator.admin`
123
+
124
+ Cause: gateway auth succeeded but the device was paired with insufficient scopes.
125
+
126
+ Fix (v1.8.5+): delete the device identity and let OpenCami re-pair automatically:
127
+
128
+ ```bash
129
+ rm ~/.opencami/identity/device.json
130
+ # then restart OpenCami — it will re-pair with full scopes
131
+ ```
132
+
133
+ ### Pairing required / device pending approval
134
+
135
+ On first connect, OpenCami registers itself as a device on the gateway. Starting with v1.8.5, this happens automatically with full scopes (`operator.admin`, `operator.approvals`, `operator.pairing`) — no manual config required.
136
+
137
+ If you see a "device pending" error:
138
+ ```bash
139
+ openclaw devices list # find the pending device
140
+ openclaw devices approve <deviceId>
141
+ ```
142
+
143
+ After approval, OpenCami reconnects and stores a `deviceToken` for future sessions (no shared token needed).
144
+
145
+ ### Can’t connect to gateway at all
146
+
147
+ Checks:
148
+
149
+ ```bash
150
+ openclaw gateway status
151
+ echo "$CLAWDBOT_GATEWAY_URL"
152
+ echo "$CLAWDBOT_GATEWAY_TOKEN"
153
+ ```
154
+
155
+ Also verify URL scheme (`ws://` local, `wss://` remote).
156
+
157
+ ---
158
+
159
+ ## Docker
37
160
 
38
161
  ```bash
39
162
  docker build -t opencami .
40
163
  docker run -p 3000:3000 opencami
41
164
  ```
42
165
 
166
+ ---
167
+
43
168
  ## Features
44
169
 
45
170
  ### 💬 Chat & Communication
package/bin/opencami.js CHANGED
@@ -18,6 +18,9 @@ function getArg(name, def) {
18
18
  const port = parseInt(getArg('port', '3000'), 10);
19
19
  const host = getArg('host', '127.0.0.1');
20
20
  const gateway = getArg('gateway', 'ws://127.0.0.1:18789');
21
+ const token = getArg('token', '');
22
+ const password = getArg('password', '');
23
+ const origin = getArg('origin', '');
21
24
  const noOpen = args.includes('--no-open');
22
25
 
23
26
  if (args.includes('--help') || args.includes('-h')) {
@@ -27,17 +30,23 @@ if (args.includes('--help') || args.includes('-h')) {
27
30
  Usage: opencami [options]
28
31
 
29
32
  Options:
30
- --port <n> Port to listen on (default: 3000)
31
- --host <addr> Host to bind to (default: 127.0.0.1)
32
- --gateway <url> OpenClaw gateway URL (default: ws://127.0.0.1:18789)
33
- --no-open Don't open browser on start
34
- -h, --help Show this help
33
+ --port <n> Port to listen on (default: 3000)
34
+ --host <addr> Host to bind to (default: 127.0.0.1)
35
+ --gateway <url> OpenClaw gateway URL (default: ws://127.0.0.1:18789)
36
+ --token <token> Gateway token (sets CLAWDBOT_GATEWAY_TOKEN)
37
+ --password <pw> Gateway password (sets CLAWDBOT_GATEWAY_PASSWORD)
38
+ --origin <url> Origin to send in backend WS (sets OPENCAMI_ORIGIN)
39
+ --no-open Don't open browser on start
40
+ -h, --help Show this help
35
41
  `);
36
42
  process.exit(0);
37
43
  }
38
44
 
39
45
  // Set gateway env for the app
40
- process.env.OPENCLAW_GATEWAY = gateway;
46
+ process.env.CLAWDBOT_GATEWAY_URL = gateway;
47
+ if (token) process.env.CLAWDBOT_GATEWAY_TOKEN = token;
48
+ if (password) process.env.CLAWDBOT_GATEWAY_PASSWORD = password;
49
+ if (origin) process.env.OPENCAMI_ORIGIN = origin;
41
50
 
42
51
  const MIME_TYPES = {
43
52
  '.html': 'text/html',
@@ -1 +1 @@
1
- import{r as t}from"./main-CgwdHc9W.js";const e=t.createContext(void 0),o={disableStyleElements:!1};function s(){return t.useContext(e)??o}export{s as u};
1
+ import{r as t}from"./main-Dq6jpr6-.js";const e=t.createContext(void 0),o={disableStyleElements:!1};function s(){return t.useContext(e)??o}export{s as u};
@@ -1 +1 @@
1
- import{r as l}from"./main-CgwdHc9W.js";const E=["top","right","bottom","left"],p=Math.min,h=Math.max,L=Math.round,k=Math.floor,q=t=>({x:t,y:t}),x={left:"right",right:"left",bottom:"top",top:"bottom"},d={start:"end",end:"start"};function R(t,e,n){return h(t,p(e,n))}function T(t,e){return typeof t=="function"?t(e):t}function m(t){return t.split("-")[0]}function g(t){return t.split("-")[1]}function b(t){return t==="x"?"y":"x"}function A(t){return t==="y"?"height":"width"}const P=new Set(["top","bottom"]);function y(t){return P.has(m(t))?"y":"x"}function M(t){return b(y(t))}function v(t,e,n){n===void 0&&(n=!1);const s=g(t),i=M(t),o=A(i);let r=i==="x"?s===(n?"end":"start")?"right":"left":s==="start"?"bottom":"top";return e.reference[o]>e.floating[o]&&(r=a(r)),[r,a(r)]}function z(t){const e=a(t);return[c(t),e,c(e)]}function c(t){return t.replace(/start|end/g,e=>d[e])}const u=["left","right"],f=["right","left"],O=["top","bottom"],S=["bottom","top"];function C(t,e,n){switch(t){case"top":case"bottom":return n?e?f:u:e?u:f;case"left":case"right":return e?O:S;default:return[]}}function B(t,e,n,s){const i=g(t);let o=C(m(t),n==="start",s);return i&&(o=o.map(r=>r+"-"+i),e&&(o=o.concat(o.map(c)))),o}function a(t){return t.replace(/left|right|bottom|top/g,e=>x[e])}function w(t){return{top:0,right:0,bottom:0,left:0,...t}}function F(t){return typeof t!="number"?w(t):{top:t,right:t,bottom:t,left:t}}function G(t){const{x:e,y:n,width:s,height:i}=t;return{width:s,height:i,top:n,left:e,right:e+s,bottom:n+i,x:e,y:n}}const j=l.createContext(void 0);function H(){return l.useContext(j)?.direction??"ltr"}export{y as a,a as b,z as c,B as d,T as e,k as f,m as g,v as h,g as i,h as j,M as k,F as l,p as m,G as n,A as o,R as p,b as q,L as r,E as s,q as t,H as u};
1
+ import{r as l}from"./main-Dq6jpr6-.js";const E=["top","right","bottom","left"],p=Math.min,h=Math.max,L=Math.round,k=Math.floor,q=t=>({x:t,y:t}),x={left:"right",right:"left",bottom:"top",top:"bottom"},d={start:"end",end:"start"};function R(t,e,n){return h(t,p(e,n))}function T(t,e){return typeof t=="function"?t(e):t}function m(t){return t.split("-")[0]}function g(t){return t.split("-")[1]}function b(t){return t==="x"?"y":"x"}function A(t){return t==="y"?"height":"width"}const P=new Set(["top","bottom"]);function y(t){return P.has(m(t))?"y":"x"}function M(t){return b(y(t))}function v(t,e,n){n===void 0&&(n=!1);const s=g(t),i=M(t),o=A(i);let r=i==="x"?s===(n?"end":"start")?"right":"left":s==="start"?"bottom":"top";return e.reference[o]>e.floating[o]&&(r=a(r)),[r,a(r)]}function z(t){const e=a(t);return[c(t),e,c(e)]}function c(t){return t.replace(/start|end/g,e=>d[e])}const u=["left","right"],f=["right","left"],O=["top","bottom"],S=["bottom","top"];function C(t,e,n){switch(t){case"top":case"bottom":return n?e?f:u:e?u:f;case"left":case"right":return e?O:S;default:return[]}}function B(t,e,n,s){const i=g(t);let o=C(m(t),n==="start",s);return i&&(o=o.map(r=>r+"-"+i),e&&(o=o.concat(o.map(c)))),o}function a(t){return t.replace(/left|right|bottom|top/g,e=>x[e])}function w(t){return{top:0,right:0,bottom:0,left:0,...t}}function F(t){return typeof t!="number"?w(t):{top:t,right:t,bottom:t,left:t}}function G(t){const{x:e,y:n,width:s,height:i}=t;return{width:s,height:i,top:n,left:e,right:e+s,bottom:n+i,x:e,y:n}}const j=l.createContext(void 0);function H(){return l.useContext(j)?.direction??"ltr"}export{y as a,a as b,z as c,B as d,T as e,k as f,m as g,v as h,g as i,h as j,M as k,F as l,p as m,G as n,A as o,R as p,b as q,L as r,E as s,q as t,H as u};