@jmfederico/pi-web 1.202606.3 → 1.202606.4

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 (50) hide show
  1. package/README.md +11 -6
  2. package/dist/client/assets/{CodeViewer-iYSv2-dg.js → CodeViewer-CIG4PxA9.js} +1 -1
  3. package/dist/client/assets/{TerminalPanel-BpFW6j27.js → TerminalPanel-CKtvS-3H.js} +1 -1
  4. package/dist/client/assets/{index-D4dbiKXF.js → index-DDid7ddU.js} +367 -199
  5. package/dist/client/index.html +1 -1
  6. package/dist/config.js +51 -3
  7. package/dist/config.js.map +1 -1
  8. package/dist/pi-web-plugins/updates/pi-web-plugin.js +52 -56
  9. package/dist/pi-web-plugins/updates/updatesLogic.js +65 -0
  10. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +1 -5
  11. package/dist/server/app.js +1 -1
  12. package/dist/server/app.js.map +1 -1
  13. package/dist/server/configRoutes.js +7 -0
  14. package/dist/server/configRoutes.js.map +1 -1
  15. package/dist/server/index.js +2 -2
  16. package/dist/server/index.js.map +1 -1
  17. package/dist/server/piWebStatus.js +15 -6
  18. package/dist/server/piWebStatus.js.map +1 -1
  19. package/dist/server/sessiond.js +16 -2
  20. package/dist/server/sessiond.js.map +1 -1
  21. package/dist/server/sessions/attachmentService.js +61 -0
  22. package/dist/server/sessions/attachmentService.js.map +1 -0
  23. package/dist/server/sessions/piSessionService.js +105 -18
  24. package/dist/server/sessions/piSessionService.js.map +1 -1
  25. package/dist/server/sessions/sessionCommandService.js +5 -1
  26. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  27. package/dist/server/sessions/sessionRoutes.js +28 -4
  28. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  29. package/dist/server/sessions/spawnSessionTool.js +36 -0
  30. package/dist/server/sessions/spawnSessionTool.js.map +1 -0
  31. package/dist/server/sessions/spawnTargetResolver.js +36 -0
  32. package/dist/server/sessions/spawnTargetResolver.js.map +1 -0
  33. package/dist/shared/apiTypes.d.ts +41 -3
  34. package/dist/shared/apiTypes.js +2 -0
  35. package/dist/shared/apiTypes.js.map +1 -1
  36. package/dist/shared/capabilities.js +4 -2
  37. package/dist/shared/capabilities.js.map +1 -1
  38. package/dist/shared/federatedRoutes.js +1 -0
  39. package/dist/shared/federatedRoutes.js.map +1 -1
  40. package/dist/shared/piWebStatusParsing.js +0 -15
  41. package/dist/shared/piWebStatusParsing.js.map +1 -1
  42. package/dist/shared/promptAttachments.js +73 -0
  43. package/dist/shared/promptAttachments.js.map +1 -0
  44. package/dist/shared/thinkingLevels.d.ts +27 -0
  45. package/dist/shared/thinkingLevels.js +31 -0
  46. package/dist/shared/thinkingLevels.js.map +1 -0
  47. package/dist/shared/workspaceDeletion.js +1 -1
  48. package/dist/shared/workspaceDeletion.js.map +1 -1
  49. package/docs/plugins.md +3 -3
  50. package/package.json +25 -14
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PI WEB
1
+ # PI WEB — web UI for Pi Coding Agent
2
2
 
3
3
  [![CI](https://github.com/jmfederico/pi-web/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jmfederico/pi-web/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/@jmfederico/pi-web)](https://www.npmjs.com/package/@jmfederico/pi-web)
@@ -10,9 +10,9 @@ Website: <https://pi-web.dev/>
10
10
 
11
11
  ![PI WEB](docs/assets/pi-web-banner.png)
12
12
 
13
- **Run AI coding agents on your own machine or server, keep them alive in real workspaces, and control everything from a browser.**
13
+ **Run Pi Coding Agent from a web UI, keep sessions alive in real workspaces, and supervise them from any device.**
14
14
 
15
- PI WEB is a web control plane for [Pi Coding Agent](https://github.com/earendil-works/pi/tree/main/packages/coding-agent). Add your repositories once, open project workspaces and git worktrees, start agent sessions inside them, and come back later without losing the work. Your browser becomes the cockpit; your server becomes the persistent development environment. Start on your laptop, check in from your phone, and continue from an iPad or another machine whenever that is the device you have at hand.
15
+ PI WEB is a web UI for [Pi Coding Agent](https://github.com/earendil-works/pi/tree/main/packages/coding-agent) that keeps agent sessions running on your own machine or server. Add your repositories once, open project workspaces and git worktrees, start sessions inside them, and come back later without losing the work. Your browser becomes the cockpit; your server becomes the persistent development environment. Start on your laptop, check in from your phone, and continue from an iPad or another machine whenever that is the device you have at hand.
16
16
 
17
17
  ![PI WEB demo](docs/assets/pi-web-demo.gif)
18
18
 
@@ -32,6 +32,10 @@ Agentic development works best when agents are not trapped inside a single local
32
32
 
33
33
  PI WEB connects those two worlds. The work stays in the server-side environment while you move between devices: laptop for deep focus, phone for a quick check-in, tablet for review, desktop when you are back at a desk. It is not trying to recreate the old desktop IDE in a browser; it is a control surface for persistent, parallel, human-in-the-loop agent work.
34
34
 
35
+ ### Is PI WEB a Pi web UI?
36
+
37
+ Yes. PI WEB is a Pi web UI for running and supervising Pi Coding Agent sessions from a browser. Unlike simple session viewers, PI WEB is built around persistent server-side workspaces, long-running session daemons, git worktrees, remote machines, and multi-device supervision.
38
+
35
39
  ## Core model
36
40
 
37
41
  PI WEB organizes work into four levels:
@@ -69,7 +73,7 @@ This maps naturally to real development work:
69
73
 
70
74
  ## Architecture
71
75
 
72
- PI WEB uses a split-process architecture so agent runtimes are not owned by the browser-facing dev server.
76
+ PI WEB uses a split-process architecture so agent runtimes are not owned by the browser-facing dev server. Under the hood, it acts as a browser-based control plane for sessions, workspaces, files, terminals, and trusted remote machines.
73
77
 
74
78
  ```text
75
79
  Browser UI
@@ -104,7 +108,7 @@ PI WEB keeps its own state intentionally small:
104
108
 
105
109
  ## Machine federation
106
110
 
107
- The Machines section lets one PI WEB instance act as a gateway to other PI WEB runtimes. Register a remote machine from **Actions → Add Machine** with the remote PI WEB base URL, for example a URL reachable over NetBird, Tailscale, WireGuard, an SSH tunnel, or a trusted reverse proxy. The browser continues talking to the local PI WEB origin; project, workspace, file, git, session, activity, and terminal HTTP/WebSocket traffic is proxied server-to-server. See the [Fleet guide](https://pi-web.dev/machines.html) for setup, trust model, and troubleshooting details.
111
+ The Machines section lets one PI WEB instance act as a gateway to other PI WEB runtimes. Register a remote machine from **Actions → Add Machine** with the remote PI WEB base URL, for example a URL reachable over NetBird, Tailscale, WireGuard, an SSH tunnel, or a trusted reverse proxy. The browser continues talking to the local PI WEB origin; project, workspace, file, git, session, activity, and terminal HTTP/WebSocket traffic is proxied server-to-server. See the [Fleet guide](https://pi-web.dev/machines) for setup, trust model, and troubleshooting details.
108
112
 
109
113
  Remote model-provider credentials and OAuth state stay on the target machine. API-key provider configuration can be proxied, but OAuth login should be completed by opening the remote PI WEB directly. Register remote machines only when you trust the endpoint and the network path: adding a machine gives this PI WEB server permission to contact that URL with the optional bearer token you configured.
110
114
 
@@ -118,7 +122,7 @@ A useful prompt for AI agents:
118
122
 
119
123
  ```text
120
124
  Build a PI WEB plugin for this project. Goal: <describe the UI behavior>.
121
- Before coding, read https://pi-web.dev/plugins.html and https://pi-web.dev/plugins.md.
125
+ Before coding, read https://pi-web.dev/plugins and https://pi-web.dev/plugins.md.
122
126
  Create it under ~/.pi-web/plugins/<plugin-id> using the documented PI WEB v1 plugin API.
123
127
  Validate with /pi-web-plugins/manifest.json and explain reload/debug steps.
124
128
  Do not modify PI WEB itself.
@@ -272,6 +276,7 @@ Environment variables:
272
276
  - `PI_WEB_SESSIOND_URL` — daemon URL used by the web process when connecting over TCP, for example `http://127.0.0.1:3001`. If you set `PI_WEB_SESSIOND_PORT`, set this for the web process too.
273
277
  - `PI_WEB_PROJECTS_FILE` — optional override for the projects storage JSON file. Defaults to `$PI_WEB_DATA_DIR/projects.json`.
274
278
  - `PI_WEB_MACHINES_FILE` — optional override for the remote machine registry JSON file. Defaults to `$PI_WEB_DATA_DIR/machines.json`.
279
+ - `PI_WEB_MAX_UPLOAD_BYTES` — maximum accepted HTTP request body size in bytes (covers pasted/attached images). Defaults to 64 MB. Also configurable as `maxUploadBytes` in `config.json`.
275
280
  - `PI_CODING_AGENT_SESSION_DIR` — Pi session storage directory. PI WEB follows the same session-location priority as Pi for web sessions: this environment variable, then `sessionDir` in Pi settings for the selected workspace, then Pi's default session directory.
276
281
  - `PI_CODING_AGENT_DIR` — Pi agent config directory. PI WEB uses this for Pi auth, settings, resources, and default session storage, matching Pi's own configuration layout.
277
282
 
@@ -1,4 +1,4 @@
1
- import{w as a,J as p,$ as h,A as m,X as g,U as f,_ as v,a0 as b}from"./vendor-editor-core-B4Sq6exx.js";import{g as y,r as w,p as C,h as x,c as j,m as _,j as k,a as u}from"./vendor-editor-languages-DznYbTkJ.js";import{d as E}from"./vendor-editor-legacy-B4QLsWF8.js";import{i as H,b as O,a as S,n as d,e as P,t as L}from"./index-D4dbiKXF.js";var D=Object.defineProperty,F=Object.getOwnPropertyDescriptor,i=(e,o,n,s)=>{for(var t=s>1?void 0:s?F(o,n):o,c=e.length-1,l;c>=0;c--)(l=e[c])&&(t=(s?l(o,n,t):l(t))||t);return s&&t&&D(o,n,t),t};let r=class extends H{constructor(){super(...arguments),this.content=""}firstUpdated(){this.recreateEditor()}updated(e){(e.has("content")||e.has("language"))&&this.recreateEditor()}disconnectedCallback(){this.view?.destroy(),this.view=void 0,super.disconnectedCallback()}render(){return O`<div class="host"></div>`}recreateEditor(){this.editorHost&&(this.view?.destroy(),this.view=new a({parent:this.editorHost,state:p.create({doc:this.content,extensions:[h(),m.of(g),f(v,{fallback:!0}),p.readOnly.of(!0),a.editable.of(!1),a.lineWrapping,M,...R(this.language)]})}))}};r.styles=S`
1
+ import{w as a,J as p,$ as h,A as m,X as g,U as f,_ as v,a0 as b}from"./vendor-editor-core-B4Sq6exx.js";import{g as y,r as w,p as C,h as x,c as j,m as _,j as k,a as u}from"./vendor-editor-languages-DznYbTkJ.js";import{d as E}from"./vendor-editor-legacy-B4QLsWF8.js";import{i as H,b as O,a as S,n as d,e as P,t as L}from"./index-DDid7ddU.js";var D=Object.defineProperty,F=Object.getOwnPropertyDescriptor,i=(e,o,n,s)=>{for(var t=s>1?void 0:s?F(o,n):o,c=e.length-1,l;c>=0;c--)(l=e[c])&&(t=(s?l(o,n,t):l(t))||t);return s&&t&&D(o,n,t),t};let r=class extends H{constructor(){super(...arguments),this.content=""}firstUpdated(){this.recreateEditor()}updated(e){(e.has("content")||e.has("language"))&&this.recreateEditor()}disconnectedCallback(){this.view?.destroy(),this.view=void 0,super.disconnectedCallback()}render(){return O`<div class="host"></div>`}recreateEditor(){this.editorHost&&(this.view?.destroy(),this.view=new a({parent:this.editorHost,state:p.create({doc:this.content,extensions:[h(),m.of(g),f(v,{fallback:!0}),p.readOnly.of(!0),a.editable.of(!1),a.lineWrapping,M,...R(this.language)]})}))}};r.styles=S`
2
2
  :host { display: block; min-height: 0; height: 100%; }
3
3
  .host { height: 100%; min-height: 0; overflow: auto; }
4
4
  `;i([d()],r.prototype,"content",2);i([d()],r.prototype,"language",2);i([P(".host")],r.prototype,"editorHost",2);r=i([L("code-viewer")],r);const M=a.theme({"&":{height:"100%",color:"var(--pi-text)",backgroundColor:"var(--pi-bg)",fontSize:"12px"},".cm-scroller":{fontFamily:"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",lineHeight:"1.45"},".cm-gutters":{backgroundColor:"var(--pi-bg)",color:"var(--pi-dim)",borderRight:"1px solid var(--pi-border-muted)"},".cm-activeLineGutter":{backgroundColor:"transparent"},".cm-activeLine":{backgroundColor:"transparent"},".cm-content":{caretColor:"transparent"},"&.cm-focused":{outline:"none"}});function R(e){if(e===void 0)return[];switch(e){case"typescript":return[u({typescript:!0})];case"javascript":return[u()];case"json":return[k()];case"markdown":return[_()];case"css":return[j()];case"html":return[x()];case"python":return[C()];case"rust":return[w()];case"go":return[y()];case"diff":return[b.define(E)];default:return[]}}export{r as CodeViewer};
@@ -1,4 +1,4 @@
1
- import{a as E,n as m,i as K,b as l,t as R,c as h,s as A,d as w,f as _,e as F,r as c}from"./index-D4dbiKXF.js";import{D as S,o as T}from"./vendor-terminal-DjQ08hXu.js";import"./vendor-editor-core-B4Sq6exx.js";import"./vendor-editor-languages-DznYbTkJ.js";const P="pi-web.terminal.softKeys",N="(pointer: coarse), (max-width: 760px)";function z(e,t){return e??t}function V(e){if(e==="true")return!0;if(e==="false")return!1}function $(){return typeof window<"u"&&"matchMedia"in window?window.matchMedia(N):void 0}function M(e){return e?.matches===!0}function B(e=$()){return z(O(),M(e))}function H(){return O()!==void 0}function O(e=D()){if(e!==void 0)try{return V(e.getItem(P))}catch{return}}function j(e,t=D()){if(t!==void 0)try{t.setItem(P,String(e))}catch{}}function D(){if(!(typeof window>"u"))try{return window.localStorage}catch{return}}const U=[{id:"escape",label:"Esc",ariaLabel:"Escape",title:"Send Escape"},{id:"tab",label:"Tab",ariaLabel:"Tab",title:"Send Tab"},{id:"ctrl-c",label:"Ctrl+C",ariaLabel:"Control C",title:"Interrupt the foreground process"},{id:"ctrl-d",label:"Ctrl+D",ariaLabel:"Control D",title:"Send EOF / close input"},{id:"ctrl-z",label:"Ctrl+Z",ariaLabel:"Control Z",title:"Suspend the foreground process"},{id:"ctrl-l",label:"Ctrl+L",ariaLabel:"Control L",title:"Clear / redraw the terminal"},{id:"ctrl-r",label:"Ctrl+R",ariaLabel:"Control R",title:"Reverse search history"},{id:"ctrl-u",label:"Ctrl+U",ariaLabel:"Control U",title:"Delete to the start of the line"},{id:"ctrl-w",label:"Ctrl+W",ariaLabel:"Control W",title:"Delete the previous word"},{id:"arrow-left",label:"←",ariaLabel:"Left arrow",title:"Move left"},{id:"arrow-up",label:"↑",ariaLabel:"Up arrow",title:"Move up / previous command"},{id:"arrow-down",label:"↓",ariaLabel:"Down arrow",title:"Move down / next command"},{id:"arrow-right",label:"→",ariaLabel:"Right arrow",title:"Move right"},{id:"home",label:"Home",ariaLabel:"Home",title:"Move to the start"},{id:"end",label:"End",ariaLabel:"End",title:"Move to the end"},{id:"page-up",label:"PgUp",ariaLabel:"Page up",title:"Page up"},{id:"page-down",label:"PgDn",ariaLabel:"Page down",title:"Page down"},{id:"delete",label:"Del",ariaLabel:"Delete",title:"Delete forward"},{id:"backspace",label:"⌫",ariaLabel:"Backspace",title:"Backspace"},{id:"meta-backward-word",label:"M-B",ariaLabel:"Meta B",title:"Move backward one word"},{id:"meta-forward-word",label:"M-F",ariaLabel:"Meta F",title:"Move forward one word"}],d="\x1B",q="";function Y(e,t){switch(e){case"escape":return d;case"tab":return" ";case"ctrl-c":return p("c");case"ctrl-d":return p("d");case"ctrl-z":return p("z");case"ctrl-l":return p("l");case"ctrl-r":return p("r");case"ctrl-u":return p("u");case"ctrl-w":return p("w");case"arrow-left":return b("D",t);case"arrow-up":return b("A",t);case"arrow-down":return b("B",t);case"arrow-right":return b("C",t);case"home":return x("H",t);case"end":return x("F",t);case"page-up":return`${d}[5~`;case"page-down":return`${d}[6~`;case"delete":return`${d}[3~`;case"backspace":return q;case"meta-backward-word":return`${d}b`;case"meta-forward-word":return`${d}f`}}function p(e){return String.fromCharCode(e.toUpperCase().charCodeAt(0)-64)}function b(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}function x(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}var W=Object.defineProperty,X=Object.getOwnPropertyDescriptor,y=(e,t,i,r)=>{for(var n=r>1?void 0:r?X(t,i):t,a=e.length-1,u;a>=0;a--)(u=e[a])&&(n=(r?u(t,i,n):u(n))||n);return r&&n&&W(t,i,n),n};const J=8,Z=500;let f=class extends K{constructor(){super(...arguments),this.refocusOnClick=!0,this.onInput=()=>{},this.lastPointerFinishedAt=0}sendSoftKey(e,t){this.onInput(Y(e.id,this.modes),t)}onSoftKeyPointerDown(e,t){e.pointerType==="mouse"&&e.button!==0||(e.preventDefault(),this.pointerStart={pointerId:e.pointerId,key:t,clientX:e.clientX,clientY:e.clientY})}onSoftKeyPointerMove(e){const t=this.pointerStart;t?.pointerId===e.pointerId&&I(t,e)&&this.finishSoftKeyPointer()}onSoftKeyPointerUp(e,t){const i=this.pointerStart;i?.pointerId===e.pointerId&&(e.preventDefault(),this.finishSoftKeyPointer(),!(i.key.id!==t.id||I(i,e))&&this.sendSoftKey(t,{refocus:e.pointerType==="mouse"}))}onSoftKeyPointerCancel(e){this.pointerStart?.pointerId===e.pointerId&&this.finishSoftKeyPointer()}finishSoftKeyPointer(){this.pointerStart=void 0,this.lastPointerFinishedAt=Date.now()}onSoftKeyClick(e,t){if(Date.now()-this.lastPointerFinishedAt<Z){e.preventDefault();return}this.sendSoftKey(t,{refocus:this.refocusOnClick})}render(){return l`
1
+ import{a as E,n as m,i as K,b as l,t as R,c as h,s as A,d as w,f as _,e as F,r as c}from"./index-DDid7ddU.js";import{D as S,o as T}from"./vendor-terminal-DjQ08hXu.js";import"./vendor-editor-core-B4Sq6exx.js";import"./vendor-editor-languages-DznYbTkJ.js";const P="pi-web.terminal.softKeys",N="(pointer: coarse), (max-width: 760px)";function z(e,t){return e??t}function V(e){if(e==="true")return!0;if(e==="false")return!1}function $(){return typeof window<"u"&&"matchMedia"in window?window.matchMedia(N):void 0}function M(e){return e?.matches===!0}function B(e=$()){return z(O(),M(e))}function H(){return O()!==void 0}function O(e=D()){if(e!==void 0)try{return V(e.getItem(P))}catch{return}}function j(e,t=D()){if(t!==void 0)try{t.setItem(P,String(e))}catch{}}function D(){if(!(typeof window>"u"))try{return window.localStorage}catch{return}}const U=[{id:"escape",label:"Esc",ariaLabel:"Escape",title:"Send Escape"},{id:"tab",label:"Tab",ariaLabel:"Tab",title:"Send Tab"},{id:"ctrl-c",label:"Ctrl+C",ariaLabel:"Control C",title:"Interrupt the foreground process"},{id:"ctrl-d",label:"Ctrl+D",ariaLabel:"Control D",title:"Send EOF / close input"},{id:"ctrl-z",label:"Ctrl+Z",ariaLabel:"Control Z",title:"Suspend the foreground process"},{id:"ctrl-l",label:"Ctrl+L",ariaLabel:"Control L",title:"Clear / redraw the terminal"},{id:"ctrl-r",label:"Ctrl+R",ariaLabel:"Control R",title:"Reverse search history"},{id:"ctrl-u",label:"Ctrl+U",ariaLabel:"Control U",title:"Delete to the start of the line"},{id:"ctrl-w",label:"Ctrl+W",ariaLabel:"Control W",title:"Delete the previous word"},{id:"arrow-left",label:"←",ariaLabel:"Left arrow",title:"Move left"},{id:"arrow-up",label:"↑",ariaLabel:"Up arrow",title:"Move up / previous command"},{id:"arrow-down",label:"↓",ariaLabel:"Down arrow",title:"Move down / next command"},{id:"arrow-right",label:"→",ariaLabel:"Right arrow",title:"Move right"},{id:"home",label:"Home",ariaLabel:"Home",title:"Move to the start"},{id:"end",label:"End",ariaLabel:"End",title:"Move to the end"},{id:"page-up",label:"PgUp",ariaLabel:"Page up",title:"Page up"},{id:"page-down",label:"PgDn",ariaLabel:"Page down",title:"Page down"},{id:"delete",label:"Del",ariaLabel:"Delete",title:"Delete forward"},{id:"backspace",label:"⌫",ariaLabel:"Backspace",title:"Backspace"},{id:"meta-backward-word",label:"M-B",ariaLabel:"Meta B",title:"Move backward one word"},{id:"meta-forward-word",label:"M-F",ariaLabel:"Meta F",title:"Move forward one word"}],d="\x1B",q="";function Y(e,t){switch(e){case"escape":return d;case"tab":return" ";case"ctrl-c":return p("c");case"ctrl-d":return p("d");case"ctrl-z":return p("z");case"ctrl-l":return p("l");case"ctrl-r":return p("r");case"ctrl-u":return p("u");case"ctrl-w":return p("w");case"arrow-left":return b("D",t);case"arrow-up":return b("A",t);case"arrow-down":return b("B",t);case"arrow-right":return b("C",t);case"home":return x("H",t);case"end":return x("F",t);case"page-up":return`${d}[5~`;case"page-down":return`${d}[6~`;case"delete":return`${d}[3~`;case"backspace":return q;case"meta-backward-word":return`${d}b`;case"meta-forward-word":return`${d}f`}}function p(e){return String.fromCharCode(e.toUpperCase().charCodeAt(0)-64)}function b(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}function x(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}var W=Object.defineProperty,X=Object.getOwnPropertyDescriptor,y=(e,t,i,r)=>{for(var n=r>1?void 0:r?X(t,i):t,a=e.length-1,u;a>=0;a--)(u=e[a])&&(n=(r?u(t,i,n):u(n))||n);return r&&n&&W(t,i,n),n};const J=8,Z=500;let f=class extends K{constructor(){super(...arguments),this.refocusOnClick=!0,this.onInput=()=>{},this.lastPointerFinishedAt=0}sendSoftKey(e,t){this.onInput(Y(e.id,this.modes),t)}onSoftKeyPointerDown(e,t){e.pointerType==="mouse"&&e.button!==0||(e.preventDefault(),this.pointerStart={pointerId:e.pointerId,key:t,clientX:e.clientX,clientY:e.clientY})}onSoftKeyPointerMove(e){const t=this.pointerStart;t?.pointerId===e.pointerId&&I(t,e)&&this.finishSoftKeyPointer()}onSoftKeyPointerUp(e,t){const i=this.pointerStart;i?.pointerId===e.pointerId&&(e.preventDefault(),this.finishSoftKeyPointer(),!(i.key.id!==t.id||I(i,e))&&this.sendSoftKey(t,{refocus:e.pointerType==="mouse"}))}onSoftKeyPointerCancel(e){this.pointerStart?.pointerId===e.pointerId&&this.finishSoftKeyPointer()}finishSoftKeyPointer(){this.pointerStart=void 0,this.lastPointerFinishedAt=Date.now()}onSoftKeyClick(e,t){if(Date.now()-this.lastPointerFinishedAt<Z){e.preventDefault();return}this.sendSoftKey(t,{refocus:this.refocusOnClick})}render(){return l`
2
2
  <div class="terminal-soft-keys" role="toolbar" aria-label="Terminal soft keys">
3
3
  ${U.map(e=>l`
4
4
  <button