@maudecode/cove 2026.2.6-3 → 2026.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="./docs/banner.jpg" alt="Cove" width="640">
2
+ <img src="./docs/public/banner.jpg" alt="Cove" width="640">
3
3
  </p>
4
4
 
5
5
  <p align="center">
@@ -30,6 +30,7 @@
30
30
  - **File upload** — Drag & drop or paste images directly into chat
31
31
  - **Message search** — Find anything with text search and date filters
32
32
  - **Session management** — Create, rename, delete, and organize conversations
33
+ - **Command palette** — Press ⌘K to access any action instantly
33
34
 
34
35
  ### 🎛️ Operations Dashboard
35
36
  - **Cron Jobs** — Create and manage scheduled tasks with visual editors
@@ -40,6 +41,8 @@
40
41
  - **Devices** — Manage paired devices, approve pairing requests
41
42
  - **Logs** — Real-time log viewer with level filtering and search
42
43
  - **Debug** — RPC tester, event stream, connection diagnostics
44
+ - **Workspace** — Browse and edit agent configuration files with token counts
45
+ - **Usage** — Per-session analytics with timeline and cost breakdown
43
46
 
44
47
  ### 🎨 Customization
45
48
  - **12 themes** — Light, Dark, Nord, Dracula, Catppuccin, Tokyo Night, and more
@@ -56,22 +59,22 @@
56
59
 
57
60
  <details>
58
61
  <summary><strong>Chat Interface</strong></summary>
59
- <img src="./docs/chat.jpg" alt="Chat Interface" width="800">
62
+ <img src="./docs/public/chat.jpg" alt="Chat Interface" width="800">
60
63
  </details>
61
64
 
62
65
  <details>
63
66
  <summary><strong>Server Stats</strong></summary>
64
- <img src="./docs/server_stats.jpg" alt="Server Stats" width="800">
67
+ <img src="./docs/public/server_stats.jpg" alt="Server Stats" width="800">
65
68
  </details>
66
69
 
67
70
  <details>
68
71
  <summary><strong>Settings</strong></summary>
69
- <img src="./docs/cove_settings.jpg" alt="Cove Settings" width="800">
72
+ <img src="./docs/public/cove_settings.jpg" alt="Cove Settings" width="800">
70
73
  </details>
71
74
 
72
75
  <details>
73
76
  <summary><strong>Configuration Editor</strong></summary>
74
- <img src="./docs/config.jpg" alt="Configuration Editor" width="800">
77
+ <img src="./docs/public/config.jpg" alt="Configuration Editor" width="800">
75
78
  </details>
76
79
 
77
80
  ## 🚀 Quick Start
package/bin/cove.js CHANGED
@@ -19,6 +19,8 @@ const version = packageJson.version;
19
19
  const args = process.argv.slice(2);
20
20
  let port = 8080;
21
21
  let open = false;
22
+ let gatewayHost = process.env.GATEWAY_HOST || "127.0.0.1";
23
+ let gatewayPort = process.env.GATEWAY_PORT || "18789";
22
24
 
23
25
  for (let i = 0; i < args.length; i++) {
24
26
  if (args[i] === "--port" || args[i] === "-p") {
@@ -41,6 +43,10 @@ Options:
41
43
  -v, --version Show version number
42
44
  -h, --help Show this help message
43
45
 
46
+ Environment Variables:
47
+ GATEWAY_HOST Gateway hostname for canvas proxy (default: 127.0.0.1)
48
+ GATEWAY_PORT Gateway port for canvas proxy (default: 18789)
49
+
44
50
  Examples:
45
51
  npx @maudecode/cove
46
52
  npx @maudecode/cove --port 3000
@@ -77,6 +83,40 @@ function isPathSafe(requestedPath, baseDir) {
77
83
  return fullPath === baseDir || fullPath.startsWith(baseDir + "/");
78
84
  }
79
85
 
86
+ /**
87
+ * Proxy /_canvas/* requests to gateway's canvas host
88
+ */
89
+ async function handleCanvasProxy(req, res, urlPath) {
90
+ if (!urlPath.startsWith("/_canvas")) return false;
91
+
92
+ const targetPath = urlPath.replace("/_canvas", "") || "/";
93
+ const targetUrl = `http://${gatewayHost}:${gatewayPort}/__openclaw__/canvas${targetPath}`;
94
+
95
+ try {
96
+ const response = await fetch(targetUrl, {
97
+ headers: {
98
+ Host: `${gatewayHost}:${gatewayPort}`,
99
+ Accept: "*/*",
100
+ },
101
+ });
102
+
103
+ const contentType = response.headers.get("Content-Type") || "application/octet-stream";
104
+ const buffer = Buffer.from(await response.arrayBuffer());
105
+
106
+ res.writeHead(response.status, {
107
+ "Content-Type": contentType,
108
+ "Cache-Control": "no-store",
109
+ "Access-Control-Allow-Origin": "*",
110
+ });
111
+ res.end(buffer);
112
+ } catch (err) {
113
+ console.error("Canvas proxy error:", err.message);
114
+ res.writeHead(502);
115
+ res.end(`Canvas proxy error: ${err.message}`);
116
+ }
117
+ return true;
118
+ }
119
+
80
120
  // Serve static files
81
121
  const server = createServer(async (req, res) => {
82
122
  try {
@@ -90,6 +130,11 @@ const server = createServer(async (req, res) => {
90
130
  return;
91
131
  }
92
132
 
133
+ // Canvas proxy
134
+ if (await handleCanvasProxy(req, res, urlPath)) {
135
+ return;
136
+ }
137
+
93
138
  // Decode URL and resolve path
94
139
  const decodedPath = decodeURIComponent(urlPath);
95
140
  let filePath = resolve(distDir, "." + decodedPath);
@@ -140,6 +185,7 @@ server.listen(port, () => {
140
185
  🏖️ Cove v${version} is running!
141
186
 
142
187
  Local: ${url}
188
+ Proxy: /_canvas/* → http://${gatewayHost}:${gatewayPort}/__openclaw__/canvas/*
143
189
 
144
190
  Connect to your OpenClaw gateway to get started.
145
191
  Press Ctrl+C to stop.
@@ -0,0 +1,12 @@
1
+ import{c as $,A as W,q as A,y as j,i as c,p as E,a as T,H as q,D as B,d as r,b as L,e as Y,M as R,f as G,g as X,h as J,j as ie,k as ce,l as Q,m as V,n as Z,o as ee,r as m,s as ue,t as de,u as ve,v as he,w as t,x as D,I as _,E as te,X as ne,C as ae,z as me,B as oe,F as fe,G as pe,J as we,L as se}from"./index-B3H4uilc.js";const xe=$("grip-horizontal",[["circle",{cx:"12",cy:"9",r:"1",key:"124mty"}],["circle",{cx:"19",cy:"9",r:"1",key:"1ruzo2"}],["circle",{cx:"5",cy:"9",r:"1",key:"1a8b28"}],["circle",{cx:"12",cy:"15",r:"1",key:"1e56xg"}],["circle",{cx:"19",cy:"15",r:"1",key:"1a92ep"}],["circle",{cx:"5",cy:"15",r:"1",key:"5r1jwy"}]]);const ge=$("maximize-2",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"m21 3-7 7",key:"1l2asr"}],["path",{d:"m3 21 7-7",key:"tjx5ai"}],["path",{d:"M9 21H3v-6",key:"wtvkvv"}]]);const ye=$("minimize-2",[["path",{d:"m14 10 7-7",key:"oa77jy"}],["path",{d:"M20 10h-6V4",key:"mjg0md"}],["path",{d:"m3 21 7-7",key:"tjx5ai"}],["path",{d:"M4 14h6v6",key:"rmj7iw"}]]);const be=$("picture-in-picture-2",[["path",{d:"M21 9V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10c0 1.1.9 2 2 2h4",key:"daa4of"}],["rect",{width:"10",height:"7",x:"12",y:"13",rx:"2",key:"1nb8gs"}]]);function Me(){const I=W(!1),a=W(!1),d=W({x:0,y:0,panelX:0,panelY:0}),l=W({x:0,y:0,width:0,height:0,panelX:0,panelY:0}),P=W(""),O=A(s=>{if(s.target.closest("button"))return;s.preventDefault(),I.current=!0,X.value=!0;const u=J(s);d.current={x:u.x,y:u.y,panelX:E.value,panelY:T.value},document.body.style.cursor="grabbing",document.body.style.userSelect="none"},[]),U=A((s,u)=>{s.preventDefault(),"stopPropagation"in s&&s.stopPropagation(),a.current=!0,X.value=!0,P.current=u;const v=J(s);l.current={x:v.x,y:v.y,width:L.value,height:Y.value,panelX:E.value,panelY:T.value};const z={n:"n-resize",s:"s-resize",e:"e-resize",w:"w-resize",ne:"ne-resize",nw:"nw-resize",se:"se-resize",sw:"sw-resize"};document.body.style.cursor=z[u]||"nwse-resize",document.body.style.userSelect="none"},[]),N=A(s=>{s.preventDefault(),a.current=!0,X.value=!0,l.current={x:s.clientX,y:s.clientY,width:L.value,height:Y.value,panelX:E.value,panelY:T.value},document.body.style.userSelect="none";const u=window.innerWidth*ie,v=window.innerHeight*ce,z=S=>{if(r.value==="left"){const n=S.clientX-l.current.x;L.value=Math.min(u,Math.max(R,l.current.width+n))}else if(r.value==="right"){const n=l.current.x-S.clientX;L.value=Math.min(u,Math.max(R,l.current.width+n))}else if(r.value==="top"){const n=S.clientY-l.current.y;Y.value=Math.min(v,Math.max(G,l.current.height+n))}},H=()=>{a.current=!1,X.value=!1,document.body.style.userSelect="",document.removeEventListener("mousemove",z),document.removeEventListener("mouseup",H)};document.addEventListener("mousemove",z),document.addEventListener("mouseup",H)},[]);return j(()=>{const s=(n,f)=>{if(I.current){const y=window.innerWidth,e=window.innerHeight;if(c.value){const o=n-d.current.x,b=f-d.current.y,p=d.current.panelX+o,M=d.current.panelY+b,h=200;E.value=Math.max(0,Math.min(p,y-h)),T.value=Math.max(0,Math.min(M,e-q));return}if(n<B)r.value="left";else if(n>y-B)r.value="right";else if(f<B)r.value="top";else{if(r.value!=="floating")E.value=Math.max(0,Math.min(n-L.value/2,y-L.value)),T.value=Math.max(0,Math.min(f-q/2,e-Y.value)),d.current={x:n,y:f,panelX:E.value,panelY:T.value};else{const o=n-d.current.x,b=f-d.current.y,p=d.current.panelX+o,M=d.current.panelY+b;E.value=Math.max(0,Math.min(p,y-L.value)),T.value=Math.max(0,Math.min(M,e-Y.value))}r.value="floating"}}if(a.current&&r.value==="floating"){const y=P.current,{x:e,y:o,width:b,height:p}=l.current,M=window.innerWidth,h=window.innerHeight;let i=b,k=p,C=l.current.panelX,w=l.current.panelY;if(y.includes("e")&&(i=Math.max(R,b+(n-e))),y.includes("w")){const x=e-n,g=b+x;g>=R&&(i=g,C=l.current.panelX-x)}if(y.includes("s")&&(k=Math.max(G,p+(f-o))),y.includes("n")){const x=o-f,g=p+x;g>=G&&(k=g,w=l.current.panelY-x)}C+i>M&&(i=M-C),w+k>h&&(k=h-w),C<0&&(i+=C,C=0),w<0&&(k+=w,w=0),L.value=Math.max(R,i),Y.value=Math.max(G,k),E.value=Math.max(0,C),T.value=Math.max(0,w)}},u=()=>{(I.current||a.current)&&(I.current=!1,a.current=!1,X.value=!1,document.body.style.cursor="",document.body.style.userSelect="")},v=n=>s(n.clientX,n.clientY),z=n=>{if(n.touches.length===1){const f=n.touches[0];s(f.clientX,f.clientY)}},H=()=>u(),S=()=>u();return document.addEventListener("mousemove",v),document.addEventListener("mouseup",H),document.addEventListener("touchmove",z,{passive:!1}),document.addEventListener("touchend",S),()=>{document.removeEventListener("mousemove",v),document.removeEventListener("mouseup",H),document.removeEventListener("touchmove",z),document.removeEventListener("touchend",S)}},[]),{handleDragStart:O,handleResizeStart:U,handleDockedResizeStart:N}}function ze(){if(V.value&&!m.value){if(pe.value)return;m.value=!0,c.value=!1}else!V.value&&m.value&&(m.value=!1)}const re=we(typeof window<"u"&&window.innerWidth<se);typeof window<"u"&&window.addEventListener("resize",()=>{re.value=window.innerWidth<se});const Se=100;function De(){const{handleDragStart:I,handleResizeStart:a,handleDockedResizeStart:d}=Me(),[l,P]=Q(0),[O,U]=Q(!1),N=W(0),s=W(null),u=W(null);j(()=>V.subscribe(ze),[]),j(()=>Z.subscribe(e=>{if(!e)return;const{js:o,resolve:b,reject:p}=e;Z.value=null;const M=s.current;if(!M?.contentWindow){p("No iframe available for eval");return}try{const h=M.contentWindow.eval(o);b(h)}catch(h){p(String(h))}}),[]),j(()=>ee.subscribe(e=>{if(!e)return;const{maxWidth:o,quality:b,outputFormat:p,resolve:M,reject:h}=e;ee.value=null;try{const i=u.current;if(i&&i.complete){const w=document.createElement("canvas");let x=i.naturalWidth||i.width||100,g=i.naturalHeight||i.height||100;if(x>o||g>o){const K=o/Math.max(x,g);x=Math.round(x*K),g=Math.round(g*K)}w.width=x,w.height=g;const F=w.getContext("2d");if(F){F.drawImage(i,0,0,x,g);const K=p==="png"?"image/png":"image/jpeg",le=w.toDataURL(K,b);M(le);return}}const k=s.current;if(!k?.contentWindow){h("No canvas content available for snapshot (no img or iframe ref)");return}if(!k.contentDocument){h("Cannot access iframe document (cross-origin?)");return}h("HTML snapshot not yet implemented - use images for now")}catch(i){h(`Snapshot failed: ${i}`)}}),[]),j(()=>{const e=o=>{o.key==="Escape"&&m.value&&(m.value=!1),(o.metaKey||o.ctrlKey)&&o.shiftKey&&o.key==="c"&&(o.preventDefault(),m.value=!m.value)};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[]);const v=ue.value,z=de.value,H=ve.value,S=he.value;if(!m.value)return null;const n=e=>{N.current=e.touches[0].clientY,U(!0)},f=e=>{if(!O)return;const o=e.touches[0].clientY-N.current;P(Math.max(0,o))},y=()=>{U(!1),l>Se&&(m.value=!1),P(0)};return re.value?t("div",{class:`fixed inset-x-0 bottom-0 z-50 bg-[var(--color-bg-surface)] rounded-t-2xl border-t border-[var(--color-border)] shadow-soft-xl flex flex-col ${O?"":"transition-transform duration-200"}`,style:{height:"70vh",maxHeight:"70vh",transform:`translateY(${l}px)`},children:[t("div",{class:"flex flex-col items-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none",onTouchStart:n,onTouchMove:f,onTouchEnd:y,children:t("div",{class:"w-10 h-1 bg-[var(--color-border)] rounded-full"})}),t("div",{class:"flex items-center justify-between px-4 py-2 border-b border-[var(--color-border)]",children:[t("span",{class:"text-sm font-medium text-[var(--color-text-primary)]",children:D("canvas.title")}),t("div",{class:"flex items-center gap-1",children:[v&&t(_,{icon:t(te,{}),label:D("canvas.openUrlInNewTab"),size:"sm",onClick:()=>window.open(v,"_blank")}),t(_,{icon:t(ne,{}),label:D("canvas.close"),size:"sm",onClick:()=>m.value=!1})]})]}),t("div",{class:"flex-1 overflow-hidden",children:t(ae,{url:v,blobUrl:z,contentType:H,content:S,iframeRef:s,imgRef:u})})]}):t("div",{class:`
2
+ fixed z-50
3
+ bg-[var(--color-bg-surface)]
4
+ shadow-soft-xl
5
+ flex flex-col
6
+ overflow-hidden
7
+ animate-[fade-in-scale_150ms_ease-out]
8
+ ${c.value?"rounded-full border-0":"rounded-xl border border-[var(--color-border)]"}
9
+ `,style:{...me.value,position:"fixed"},children:[t("div",{class:`
10
+ flex items-center gap-2 px-3 cursor-grab active:cursor-grabbing select-none shrink-0
11
+ ${c.value?"py-2":"py-2 border-b border-[var(--color-border)]"}
12
+ `,style:{height:`${q}px`},onMouseDown:I,onTouchStart:I,children:[t(xe,{class:"w-4 h-4 text-[var(--color-text-muted)] shrink-0"}),t("span",{class:"text-sm font-medium text-[var(--color-text-primary)] truncate flex-1",children:D("canvas.title")}),t("div",{class:"flex items-center gap-1",children:[v&&!c.value&&t(_,{icon:t(te,{}),label:D("canvas.openUrlInNewTab"),size:"sm",onClick:()=>window.open(v,"_blank")}),!c.value&&t(_,{icon:t(be,{}),label:D("canvas.openCanvasTab"),size:"sm",onClick:()=>{window.open("/canvas","_blank"),m.value=!1}}),t(_,{icon:c.value?t(ge,{}):t(ye,{}),label:c.value?D("canvas.maximize"):D("canvas.minimize"),size:"sm",onClick:()=>{c.value?r.value=oe.value:(oe.value=r.value,r.value!=="floating"&&(E.value=window.innerWidth-220,T.value=window.innerHeight-60),r.value="floating"),c.value=!c.value}}),t(_,{icon:t(ne,{}),label:D("canvas.close"),size:"sm",onClick:()=>m.value=!1})]})]}),!c.value&&t("div",{class:"flex-1 overflow-hidden relative",children:[t(ae,{url:v,blobUrl:z,contentType:H,content:S,iframeRef:s,imgRef:u}),X.value&&t("div",{class:"absolute inset-0 z-10"})]}),r.value==="floating"&&!c.value&&t(fe,{children:[t("div",{class:"absolute bottom-0 right-0 w-4 h-4 cursor-se-resize z-10 touch-none",onMouseDown:e=>a(e,"se"),onTouchStart:e=>a(e,"se")}),t("div",{class:"absolute bottom-0 left-0 w-4 h-4 cursor-sw-resize z-10 touch-none",onMouseDown:e=>a(e,"sw"),onTouchStart:e=>a(e,"sw")}),t("div",{class:"absolute top-11 right-0 w-4 h-4 cursor-ne-resize z-10 touch-none",onMouseDown:e=>a(e,"ne"),onTouchStart:e=>a(e,"ne")}),t("div",{class:"absolute top-11 left-0 w-4 h-4 cursor-nw-resize z-10 touch-none",onMouseDown:e=>a(e,"nw"),onTouchStart:e=>a(e,"nw")}),t("div",{class:"absolute right-0 w-2 cursor-e-resize touch-none",style:{top:"60px",height:"calc(100% - 76px)"},onMouseDown:e=>a(e,"e"),onTouchStart:e=>a(e,"e")}),t("div",{class:"absolute left-0 w-2 cursor-w-resize touch-none",style:{top:"60px",height:"calc(100% - 76px)"},onMouseDown:e=>a(e,"w"),onTouchStart:e=>a(e,"w")}),t("div",{class:"absolute bottom-0 h-2 cursor-s-resize touch-none",style:{left:"16px",width:"calc(100% - 32px)"},onMouseDown:e=>a(e,"s"),onTouchStart:e=>a(e,"s")})]}),r.value==="left"&&!c.value&&t("div",{class:"absolute right-0 top-0 w-2 h-full cursor-e-resize",onMouseDown:d}),r.value==="right"&&!c.value&&t("div",{class:"absolute left-0 top-0 w-2 h-full cursor-w-resize",onMouseDown:d}),r.value==="top"&&!c.value&&t("div",{class:"absolute left-0 bottom-0 w-full h-2 cursor-s-resize",onMouseDown:d})]})}export{De as CanvasPanel};