@jmfederico/pi-web 1.202605.8 → 1.202605.9
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 +1 -1
- package/dist/client/assets/CodeViewer-BJm9p3hj.js +4 -0
- package/dist/client/assets/TerminalPanel-DMOCBUgN.js +47 -0
- package/dist/client/assets/index-CVt9MoKL.js +1049 -0
- package/dist/client/index.html +40 -2
- package/dist/server/app.js +2 -0
- package/dist/server/app.js.map +1 -1
- package/dist/server/piWebStatus.js +371 -0
- package/dist/server/piWebStatus.js.map +1 -0
- package/dist/server/sessiond.js +7 -1
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/editPreview.js +196 -0
- package/dist/server/sessions/editPreview.js.map +1 -0
- package/dist/server/sessions/piSessionService.js +154 -25
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionArchiveStore.js +168 -20
- package/dist/server/sessions/sessionArchiveStore.js.map +1 -1
- package/docs/plugins.md +3 -1
- package/package.json +2 -1
- package/pi-web-plugins/info/pi-web-plugin.js +2 -2
- package/pi-web-plugins/pi-web/package.json +9 -0
- package/pi-web-plugins/pi-web/pi-web-plugin.js +148 -0
- package/dist/client/assets/CodeViewer-Cp0QKepT.js +0 -4
- package/dist/client/assets/TerminalPanel-C7TcN1cv.js +0 -47
- package/dist/client/assets/index-b1ytby08.js +0 -871
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ Pi Web keeps its own state intentionally small:
|
|
|
101
101
|
|
|
102
102
|
Pi Web production installs can load trusted local UI plugins without rebuilding Pi Web. Plugins are browser-side ES modules that can add action-palette actions, workspace panels, and workspace-label metadata. They do not run in the session daemon and are not sandboxed.
|
|
103
103
|
|
|
104
|
-
The supported package shape is intentionally singular: `piWeb.plugins` entries with explicit `id` and `module`, plus a browser module that exports `{ apiVersion: 1, name, activate }`. The bundled `pi-web-plugins/info` plugin is the canonical real example.
|
|
104
|
+
The supported package shape is intentionally singular: `piWeb.plugins` entries with explicit `id` and `module`, plus a browser module that exports `{ apiVersion: 1, name, activate }`. The bundled `pi-web-plugins/info` plugin is the canonical minimal real example, and `pi-web-plugins/pi-web` demonstrates a dynamic status panel.
|
|
105
105
|
|
|
106
106
|
A useful prompt for AI agents:
|
|
107
107
|
|
|
@@ -0,0 +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-CVt9MoKL.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
|
+
:host { display: block; min-height: 0; height: 100%; }
|
|
3
|
+
.host { height: 100%; min-height: 0; overflow: auto; }
|
|
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};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import{i as w,c as m,d as x,b as c,a as y,n as b,e as T,r as d,t as k}from"./index-CVt9MoKL.js";import{D as h,o as u}from"./vendor-terminal-DjQ08hXu.js";import"./vendor-editor-core-B4Sq6exx.js";import"./vendor-editor-languages-DznYbTkJ.js";var S=Object.defineProperty,O=Object.getOwnPropertyDescriptor,a=(e,t,i,r)=>{for(var s=r>1?void 0:r?O(t,i):t,o=e.length-1,l;o>=0;o--)(l=e[o])&&(s=(r?l(t,i,s):l(s))||s);return r&&s&&S(t,i,s),s};const I={cursorBlink:!0,convertEol:!0,fontFamily:"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",fontSize:13},z={cols:100,rows:30};let n=class extends w{constructor(){super(...arguments),this.autoStart=!1,this.terminals=[],this.loading=!1,this.visible=!1,this.suppressTerminalInput=!1}connectedCallback(){super.connectedCallback(),this.themeObserver=new MutationObserver(()=>{this.applyTerminalTheme()}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["class","style","data-theme"]})}firstUpdated(){this.intersectionObserver=new IntersectionObserver(e=>{this.visible=e[0]?.isIntersecting===!0}),this.intersectionObserver.observe(this)}disconnectedCallback(){this.intersectionObserver?.disconnect(),this.intersectionObserver=void 0,this.themeObserver?.disconnect(),this.themeObserver=void 0,this.disposeTerminalView(),super.disconnectedCallback()}willUpdate(){const e=this.workspace?.path;e!==this.observedCwd&&(this.observedCwd=e,this.loadedCwd=void 0,this.terminals=[],this.selectedId=void 0,this.disposeTerminalView())}updated(){this.loadVisibleWorkspaceTerminals(),this.ensureTerminalView()}loadVisibleWorkspaceTerminals(){const e=this.workspace?.path;!this.visible||e===void 0||e===this.loadedCwd||(this.loadedCwd=e,this.loadTerminals())}async loadTerminals(){this.loading=!0,this.error=void 0;try{if(this.workspace===void 0)return;const e=await m.terminals(this.workspace.projectId,this.workspace.id);this.terminals=e,this.selectedId=e.find(t=>!t.exited)?.id??e[0]?.id,e.length===0&&this.autoStart&&await this.startTerminal()}catch(e){this.error=e instanceof Error?e.message:String(e)}finally{this.loading=!1}}async startTerminal(){if(this.workspace!==void 0){this.error=void 0;try{const e=this.measureTerminalSize()??z,t=await m.startTerminal(this.workspace.projectId,this.workspace.id,e);this.terminals=[...this.terminals,t],this.selectTerminal(t.id)}catch(e){this.error=e instanceof Error?e.message:String(e)}}}async closeTerminal(e,t){t.stopPropagation();try{if(this.workspace===void 0)return;await m.closeTerminal(this.workspace.projectId,this.workspace.id,e);const i=this.terminals.filter(r=>r.id!==e);this.terminals=i,this.selectedId===e&&(this.selectedId=i[0]?.id,this.disposeTerminalView())}catch(i){this.error=i instanceof Error?i.message:String(i)}}selectTerminal(e){this.selectedId!==e&&(this.selectedId=e,this.disposeTerminalView())}ensureTerminalView(){const e=this.workspace;if(!this.visible||this.terminal!==void 0||this.selectedId===void 0||this.terminalHost===void 0||e===void 0)return;const t=new h(f(this)),i=new u;t.loadAddon(i),t.open(this.terminalHost),this.terminal=t,this.fitAddon=i,this.resizeObserver=new ResizeObserver(()=>{this.fitAndNotify()}),this.resizeObserver.observe(this.terminalHost),t.onData(s=>{if(this.suppressTerminalInput)return;const o=C(s);o!==""&&this.send({type:"input",data:o})});const r=this.fitTerminal();this.connectSocket(e.projectId,e.id,this.selectedId,t,r),requestAnimationFrame(()=>{this.fitAndNotify()}),t.focus()}connectSocket(e,t,i,r,s){const o=x(e,t,i,s);o.binaryType="arraybuffer",this.socket=o,o.addEventListener("open",()=>{this.fitAndNotify()}),o.addEventListener("message",l=>{this.handleSocketMessage(l.data,i,r)}),o.addEventListener("close",()=>{this.socket===o&&(this.socket=void 0)})}async handleSocketMessage(e,t,i){try{const r=A(await $(e));r.type==="output"&&this.writeTerminalOutput(i,r.data,r.replay===!0),r.type==="exit"&&(i.writeln(`\r
|
|
2
|
+
[process exited${r.exitCode===void 0?"":` with code ${String(r.exitCode)}`}]`),this.terminals=this.terminals.map(s=>s.id===t?{...s,exited:!0,...r.exitCode===void 0?{}:{exitCode:r.exitCode}}:s)),r.type==="error"&&i.writeln(`\r
|
|
3
|
+
[terminal error: ${r.message}]`)}catch(r){i.writeln(`\r
|
|
4
|
+
[terminal error: ${r instanceof Error?r.message:String(r)}]`)}}writeTerminalOutput(e,t,i){if(!i){e.write(t);return}this.suppressTerminalInput=!0,e.write(t,()=>{this.suppressTerminalInput=!1})}fitAndNotify(){const e=this.fitTerminal();e!==void 0&&this.send({type:"resize",...e})}fitTerminal(){if(this.fitAddon===void 0||this.terminal===void 0)return;const e=this.fitAddon.proposeDimensions(),t=v(e);if(t!==void 0)return this.fitAddon.fit(),t}measureTerminalSize(){const e=this.fitTerminal();if(e!==void 0)return e;if(this.terminal!==void 0||this.terminalHost===void 0)return;const t=new h(f(this)),i=new u;t.loadAddon(i),t.open(this.terminalHost);const r=v(i.proposeDimensions());return t.dispose(),r}applyTerminalTheme(){this.terminal!==void 0&&(this.terminal.options.theme=g(this))}send(e){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify(e))}disposeTerminalView(){this.resizeObserver?.disconnect(),this.resizeObserver=void 0,this.socket?.close(),this.socket=void 0,this.terminal?.dispose(),this.terminal=void 0,this.fitAddon=void 0}render(){return c`
|
|
5
|
+
<section class="terminal-shell">
|
|
6
|
+
<div class="terminal-tabs">
|
|
7
|
+
${this.terminals.map(e=>c`
|
|
8
|
+
<button class=${this.selectedId===e.id?"selected":""} @click=${()=>{this.selectTerminal(e.id)}}>
|
|
9
|
+
<span>${e.name}${e.exited?" · exited":""}</span>
|
|
10
|
+
<small @click=${t=>{this.closeTerminal(e.id,t)}}>×</small>
|
|
11
|
+
</button>
|
|
12
|
+
`)}
|
|
13
|
+
<button class="new" ?disabled=${this.workspace===void 0} @click=${()=>{this.startTerminal()}}>+ Shell</button>
|
|
14
|
+
</div>
|
|
15
|
+
${this.error===void 0?null:c`<p class="error">${this.error}</p>`}
|
|
16
|
+
${this.loading?c`<p class="muted">Loading terminals…</p>`:null}
|
|
17
|
+
<div class="terminal-host"></div>
|
|
18
|
+
</section>
|
|
19
|
+
`}};n.styles=y`
|
|
20
|
+
:host { flex: 1 1 auto; min-height: 0; display: flex; }
|
|
21
|
+
.terminal-shell { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--pi-terminal-bg); }
|
|
22
|
+
.terminal-tabs { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; padding: 6px; border-bottom: 1px solid var(--pi-border-muted); background: var(--pi-bg); overflow: auto; }
|
|
23
|
+
button { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 180px; border: 1px solid var(--pi-border); border-radius: 7px; background: var(--pi-surface); color: var(--pi-text); padding: 5px 7px; cursor: pointer; }
|
|
24
|
+
button.selected { border-color: var(--pi-accent); background: var(--pi-selection-bg); }
|
|
25
|
+
button.new { flex: 0 0 auto; color: var(--pi-muted); }
|
|
26
|
+
button span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
27
|
+
button small { color: var(--pi-muted); font-size: 14px; line-height: 1; }
|
|
28
|
+
button small:hover { color: var(--pi-danger); }
|
|
29
|
+
button:disabled { opacity: .5; cursor: not-allowed; }
|
|
30
|
+
.terminal-host { flex: 1 1 auto; min-height: 0; padding: 6px; box-sizing: border-box; overflow: hidden; }
|
|
31
|
+
.terminal-host .xterm { height: 100%; cursor: text; position: relative; user-select: none; }
|
|
32
|
+
.terminal-host .xterm.focus, .terminal-host .xterm:focus { outline: none; }
|
|
33
|
+
.terminal-host .xterm-helpers { position: absolute; top: 0; z-index: 5; }
|
|
34
|
+
.terminal-host .xterm-helper-textarea { position: absolute !important; left: -9999em !important; top: 0 !important; width: 0 !important; height: 0 !important; min-width: 0 !important; min-height: 0 !important; padding: 0 !important; border: 0 !important; margin: 0 !important; opacity: 0 !important; z-index: -5 !important; white-space: nowrap !important; overflow: hidden !important; resize: none !important; outline: 0 !important; appearance: none !important; }
|
|
35
|
+
.terminal-host .xterm-viewport { position: absolute; inset: 0; overflow-y: scroll; cursor: default; background-color: var(--pi-terminal-bg); }
|
|
36
|
+
.terminal-host .xterm-screen { position: relative; }
|
|
37
|
+
.terminal-host .xterm-screen canvas { position: absolute; left: 0; top: 0; }
|
|
38
|
+
.terminal-host .xterm-char-measure-element { display: inline-block; visibility: hidden; position: absolute; top: 0; left: -9999em; line-height: normal; }
|
|
39
|
+
.terminal-host .xterm-accessibility:not(.debug), .terminal-host .xterm-message { position: absolute; inset: 0; z-index: 10; color: transparent; pointer-events: none; }
|
|
40
|
+
.terminal-host .xterm-accessibility-tree:not(.debug) *::selection { color: transparent; }
|
|
41
|
+
.terminal-host .xterm-accessibility-tree { font-family: monospace; user-select: text; white-space: pre; }
|
|
42
|
+
.terminal-host .xterm-accessibility-tree > div { transform-origin: left; width: fit-content; }
|
|
43
|
+
.terminal-host .live-region { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
|
|
44
|
+
.error { flex: 0 0 auto; margin: 0; padding: 8px; color: var(--pi-danger); border-bottom: 1px solid var(--pi-border); background: var(--pi-surface); }
|
|
45
|
+
.muted { margin: 10px; color: var(--pi-muted); }
|
|
46
|
+
.xterm { height: 100%; }
|
|
47
|
+
`;a([b({attribute:!1})],n.prototype,"workspace",2);a([b({type:Boolean})],n.prototype,"autoStart",2);a([T(".terminal-host")],n.prototype,"terminalHost",2);a([d()],n.prototype,"terminals",2);a([d()],n.prototype,"selectedId",2);a([d()],n.prototype,"loading",2);a([d()],n.prototype,"error",2);a([d()],n.prototype,"visible",2);n=a([k("terminal-panel")],n);function A(e){const t=JSON.parse(e);if(!N(t))return{type:"error",message:"Invalid terminal message"};const i=t;return i.type==="output"&&typeof i.data=="string"?{type:"output",data:i.data,...typeof i.replay=="boolean"?{replay:i.replay}:{}}:i.type==="exit"?{type:"exit",...typeof i.exitCode=="number"?{exitCode:i.exitCode}:{}}:i.type==="error"&&typeof i.message=="string"?{type:"error",message:i.message}:{type:"error",message:"Invalid terminal message"}}function C(e){return e.replaceAll("\x1B[I","").replaceAll("\x1B[O","")}async function $(e){return typeof e=="string"?e:e instanceof ArrayBuffer?new TextDecoder().decode(e):e instanceof Blob?await e.text():String(e)}function f(e){return{...I,theme:g(e)}}function g(e){return{background:p(e,"--pi-terminal-bg","#05070a"),foreground:p(e,"--pi-terminal-text","#e6edf3"),cursor:p(e,"--pi-accent","#58a6ff"),selectionBackground:p(e,"--pi-terminal-selection","#264f78")}}function p(e,t,i){const r=getComputedStyle(e).getPropertyValue(t).trim();return r===""?i:r}function v(e){if(!(e===void 0||!E(e.cols,e.rows)))return{cols:Math.floor(e.cols),rows:Math.floor(e.rows)}}function E(e,t){return Number.isFinite(e)&&Number.isFinite(t)&&e>0&&t>0}function N(e){return typeof e=="object"&&e!==null}export{n as TerminalPanel,C as filterTerminalInput};
|