pi-web-ui 0.63.2 → 0.63.3
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/dist/server/agent-service.js +220 -3
- package/dist/server/client-state.js +18 -0
- package/dist/server/dsh/dsh-agent-service.js +21 -0
- package/dist/server/index.js +11 -0
- package/dist/server/marker-service.js +270 -0
- package/dist/server/markers/builtins/notify.js +20 -0
- package/dist/server/markers/builtins/rename.js +102 -0
- package/dist/server/markers/builtins/services.js +119 -0
- package/dist/server/markers/builtins/todo.js +130 -0
- package/dist/server/markers/index.js +24 -0
- package/dist/server/markers/marker.js +53 -0
- package/dist/server/markers/registry.js +28 -0
- package/dist/server/markers/store.js +47 -0
- package/dist/server/settings-service.js +3 -0
- package/dist/server/slash-commands.js +34 -0
- package/dist/server/terminals.js +11 -0
- package/package.json +1 -1
- package/web/dist/assets/TerminalPanel-BFrV6B8W.js +2 -0
- package/web/dist/assets/index-BFoSybNe.js +324 -0
- package/web/dist/assets/index-D9G_7fPE.css +10 -0
- package/web/dist/icons/icon-1024.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/icons/maskable-1024.png +0 -0
- package/web/dist/icons/maskable-192.png +0 -0
- package/web/dist/icons/maskable-512.png +0 -0
- package/web/dist/index.html +20 -14
- package/web/dist/manifest.webmanifest +50 -0
- package/web/dist/sw.js +126 -0
- package/web/public/icons/icon-1024.png +0 -0
- package/web/public/icons/icon-192.png +0 -0
- package/web/public/icons/icon-512.png +0 -0
- package/web/public/icons/maskable-1024.png +0 -0
- package/web/public/icons/maskable-192.png +0 -0
- package/web/public/icons/maskable-512.png +0 -0
- package/web/public/manifest.webmanifest +50 -0
- package/web/public/sw.js +126 -0
- package/web/dist/assets/TerminalPanel-BK0SyRCf.js +0 -2
- package/web/dist/assets/index-BPbGqUpD.js +0 -323
- package/web/dist/assets/index-CrDJOsa5.css +0 -10
package/web/public/sw.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-web-ui — Progressive Web App service worker.
|
|
3
|
+
*
|
|
4
|
+
* Strategy overview
|
|
5
|
+
* -----------------
|
|
6
|
+
* pi-web-ui is a WebSocket-first app that needs a live backend, so we do NOT
|
|
7
|
+
* try to make it fully offline. Instead the SW focuses on what makes it a
|
|
8
|
+
* reliable *installable* PWA on mobile/desktop:
|
|
9
|
+
*
|
|
10
|
+
* - network-first for navigation requests (falls back to the cached app
|
|
11
|
+
* shell when the network flaps), and
|
|
12
|
+
* - cache-first for hashed static assets, which Vite fingerprints so a cache
|
|
13
|
+
* hit is always the right version until a new deploy publishes new hashes.
|
|
14
|
+
*
|
|
15
|
+
* Real-time / dynamic / credential-bearing routes (/ws, /api, /themes,
|
|
16
|
+
* /plugins) are always fetched from the network and never cached, so we never
|
|
17
|
+
* risk serving stale theme/plugin code or caching anything sensitive.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const STATIC_CACHE = "pi-web-ui-static-v1";
|
|
21
|
+
const SHELL_CACHE = "pi-web-ui-shell-v1";
|
|
22
|
+
|
|
23
|
+
// App root within this origin — "/" for root deployments, "/pi/" behind an
|
|
24
|
+
// nginx sub-path reverse proxy. All path checks below are relative to it, so
|
|
25
|
+
// the worker behaves identically under either deployment layout.
|
|
26
|
+
const SCOPE = new URL("./", self.registration.scope).pathname;
|
|
27
|
+
|
|
28
|
+
/** Map a request pathname to an app-relative path ("/pi/ws" → "/ws"), or null
|
|
29
|
+
* when the request lies outside the registration scope (shouldn't happen). */
|
|
30
|
+
function appPath(pathname) {
|
|
31
|
+
if (SCOPE === "/") return pathname;
|
|
32
|
+
if (pathname.startsWith(SCOPE)) return "/" + pathname.slice(SCOPE.length);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
self.addEventListener("install", (event) => {
|
|
37
|
+
// Take control as soon as this version activates so the current page is
|
|
38
|
+
// served by the new worker without requiring a second reload.
|
|
39
|
+
self.skipWaiting();
|
|
40
|
+
event.waitUntil(caches.open(SHELL_CACHE));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
self.addEventListener("activate", (event) => {
|
|
44
|
+
event.waitUntil(
|
|
45
|
+
caches
|
|
46
|
+
.keys()
|
|
47
|
+
.then((keys) =>
|
|
48
|
+
Promise.all(keys.filter((k) => k !== STATIC_CACHE && k !== SHELL_CACHE).map((k) => caches.delete(k))),
|
|
49
|
+
)
|
|
50
|
+
// Apply to already-open pages immediately.
|
|
51
|
+
.then(() => self.clients.claim()),
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Only cache simple, safe GET requests. Everything else goes straight through.
|
|
56
|
+
function isCachable(request) {
|
|
57
|
+
const method = request.method;
|
|
58
|
+
if (method !== "GET") return false;
|
|
59
|
+
|
|
60
|
+
const url = new URL(request.url);
|
|
61
|
+
if (url.origin !== self.location.origin) return false;
|
|
62
|
+
|
|
63
|
+
// Never cache real-time, dynamic or credential/data endpoints.
|
|
64
|
+
const path = appPath(url.pathname);
|
|
65
|
+
if (
|
|
66
|
+
path === null ||
|
|
67
|
+
path.startsWith("/ws") ||
|
|
68
|
+
path.startsWith("/api") ||
|
|
69
|
+
path.startsWith("/themes") ||
|
|
70
|
+
path.startsWith("/plugins")
|
|
71
|
+
) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
self.addEventListener("fetch", (event) => {
|
|
78
|
+
const { request } = event;
|
|
79
|
+
if (!isCachable(request)) {
|
|
80
|
+
// Let the browser/backend handle WebSockets, API calls and cross-origin
|
|
81
|
+
// requests normally.
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const requestUrl = new URL(request.url);
|
|
86
|
+
|
|
87
|
+
// Navigation → app shell. Network-first with cached fallback: users get the
|
|
88
|
+
// latest build when online but can still reopen the app while flaky.
|
|
89
|
+
if (request.mode === "navigate") {
|
|
90
|
+
event.respondWith(
|
|
91
|
+
fetch(request)
|
|
92
|
+
.then((response) => {
|
|
93
|
+
const copy = response.clone();
|
|
94
|
+
caches.open(SHELL_CACHE).then((cache) => cache.put(request, copy));
|
|
95
|
+
return response;
|
|
96
|
+
})
|
|
97
|
+
.catch(() => caches.match(request).then((cached) => cached || caches.match(SCOPE) || Response.error())),
|
|
98
|
+
);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Static assets (hashed by Vite) → cache-first.
|
|
103
|
+
const path = appPath(requestUrl.pathname);
|
|
104
|
+
const isStatic =
|
|
105
|
+
path !== null &&
|
|
106
|
+
(path.startsWith("/assets/") ||
|
|
107
|
+
path.startsWith("/icons/") ||
|
|
108
|
+
path === "/favicon.svg" ||
|
|
109
|
+
path === "/icon.ico" ||
|
|
110
|
+
path === "/manifest.webmanifest");
|
|
111
|
+
|
|
112
|
+
if (isStatic) {
|
|
113
|
+
event.respondWith(
|
|
114
|
+
caches.match(request).then((cached) => {
|
|
115
|
+
if (cached) return cached;
|
|
116
|
+
return fetch(request).then((response) => {
|
|
117
|
+
if (response && response.ok) {
|
|
118
|
+
const copy = response.clone();
|
|
119
|
+
caches.open(STATIC_CACHE).then((cache) => cache.put(request, copy));
|
|
120
|
+
}
|
|
121
|
+
return response;
|
|
122
|
+
});
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as c,j as s}from"./markdown-DRBrS2Nf.js";import{u as L,b as I,T as K,a as J,F as X,c as B,d as Q,e as U,f as V,g as W,h as Y,i as Z,r as ee}from"./index-BPbGqUpD.js";import{D as se,o as ne}from"./xterm-D1D2FVe3.js";import"./react-C9ovnpIm.js";function te({conversationId:n,terminalId:r,command:x,cwd:t,title:w,active:u,send:h,register:j}){const T=c.useRef(null),v=c.useRef(null),{locale:b}=L(),g=c.useRef(b);g.current=b;const o=x?JSON.stringify(x):"";return c.useEffect(()=>{const m=T.current;if(!m)return;const a=new se({theme:I(),fontFamily:'"SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace',fontSize:13,cursorBlink:!0,scrollback:8e3}),y=new ne;a.loadAddon(y),a.open(m),v.current={term:a,fit:y},u&&a.focus();const p=()=>{a.options.theme=I()};window.addEventListener(K,p),a.attachCustomKeyEventHandler(d=>{var R;if(d.type!=="keydown")return!0;const F=(R=d.key)==null?void 0:R.toLowerCase();if((d.ctrlKey||d.metaKey)&&F==="v")return!1;if(d.ctrlKey&&!d.shiftKey&&!d.altKey&&F==="c"&&a.hasSelection()){const C=a.textarea;return C&&(C.value=a.getSelection(),C.select()),!1}return!0});const k=j(n,r,{write:d=>a.write(d),dispose:()=>a.dispose()}),_=()=>{try{y.fit(),h({type:"terminal_resize",terminalId:r,conversationId:n,cols:a.cols,rows:a.rows})}catch{}},S=requestAnimationFrame(()=>{try{y.fit()}catch{}h(x?{type:"run_command",terminalId:r,conversationId:n,command:x,cols:a.cols,rows:a.rows}:{type:"terminal_create",terminalId:r,title:w,locale:g.current,conversationId:n,cwd:t,cols:a.cols,rows:a.rows})}),E=a.onData(d=>{h({type:"terminal_input",terminalId:r,conversationId:n,data:d})});let N=null;return typeof ResizeObserver<"u"&&(N=new ResizeObserver(()=>{m.offsetWidth>0&&m.offsetHeight>0&&_()}),N.observe(m)),()=>{cancelAnimationFrame(S),E.dispose(),window.removeEventListener(K,p),N==null||N.disconnect(),k(),a.dispose(),v.current=null}},[n,r,o,h,j]),c.useEffect(()=>{if(!u)return;const m=requestAnimationFrame(()=>{const a=v.current;if(a){try{a.fit.fit(),h({type:"terminal_resize",terminalId:r,conversationId:n,cols:a.term.cols,rows:a.term.rows})}catch{}a.term.focus()}});return()=>cancelAnimationFrame(m)},[u]),s.jsx("div",{ref:T,className:`term-xterm ${u?"":"hidden"}`})}const O={name:"",command:"",cwd:"${pwd}"};function re({chat:n,send:r,terminal:x}){const t=J(),[w,u]=c.useState(null),[h,j]=c.useState(!1),[T,v]=c.useState(!1),[b,g]=c.useState(null),[o,m]=c.useState(O),[a,y]=c.useState(null),p=c.useRef(null),[k,_]=c.useState(!0);c.useEffect(()=>{n.terminals.length===0?u(null):n.terminals.some(e=>e.id===w)||u(n.terminals[n.terminals.length-1].id)},[n.terminals,w]),c.useEffect(()=>{n.terminalActiveId&&(u(n.terminalActiveId),j(!1))},[n.terminalActiveId]),c.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]);const S=n.terminals.filter(e=>!e.agentBash),E=n.terminals.filter(e=>e.agentBash),N=e=>{var f;if(!n.ready)return;const l=ee(),i=n.activeConversationId||((f=n.state)==null?void 0:f.conversationId)||"";x.create({...e,id:l,conversationId:i,cols:e.cols??80,rows:e.rows??24,running:!0,exitCode:null}),u(l),j(!1)},d=()=>{var e;return N({title:t("terminalTitle",{n:S.length+1}),cwd:((e=n.state)==null?void 0:e.cwd)??""})},F=e=>{var f;const l=e.name||e.command,i=n.terminals.find(D=>D.title===l);if(i){x.restart(i.id),u(i.id),r({type:"run_command",terminalId:i.id,conversationId:i.conversationId,command:e,cols:80,rows:24});return}N({title:l,cwd:((f=n.state)==null?void 0:f.cwd)??"",command:e})},R=e=>{const l=n.terminals.find(i=>i.id===e);if(l&&r({type:"terminal_kill",terminalId:e,conversationId:l.conversationId}),x.close(e),w===e){const i=n.terminals.filter(f=>f.id!==e);u(i.length>0?i[i.length-1].id:null)}},C=e=>s.jsxs("div",{className:`term-tab ${e.id===w?"active":""}`,children:[s.jsxs("button",{type:"button",className:"term-tab-main",title:`${e.cwd}${e.command?`
|
|
2
|
-
> ${e.command.command}`:""}`,onClick:()=>{u(e.id),j(!1)},children:[s.jsx("span",{className:`term-tab-dot ${e.running?"run":"exit"}`}),s.jsxs("span",{className:"term-tab-title",children:[e.title,!e.running&&s.jsx("span",{className:"term-tab-exit",children:t("exited",{code:e.exitCode===null?"":` ${e.exitCode}`})})]})]}),s.jsx("button",{type:"button",className:"term-tab-close",title:t("closeTerminal"),onClick:()=>R(e.id),children:s.jsx(Z,{})})]},e.id),M=()=>{v(!0),g(null),m(O)},z=e=>{const l=n.commands[e];l&&(v(!1),g(e),m({name:l.name,command:l.command,cwd:l.cwd??""}))},A=()=>{v(!1),g(null)},$=()=>{const e=o.name.trim(),l=o.command.trim();if(!e||!l)return;const i=o.cwd.trim(),f={name:e,command:l,cwd:i||void 0},D=T?[...n.commands,f]:b!==null?n.commands.map((q,G)=>G===b?f:q):n.commands;r({type:"save_commands",commands:D}),A()},H=e=>{if(a===e){const l=n.commands.filter((i,f)=>f!==e);r({type:"save_commands",commands:l}),y(null),p.current&&clearTimeout(p.current)}else y(e),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>y(null),2500)},P=T||b!==null;return s.jsxs("div",{className:"terminal-view",children:[s.jsxs("aside",{className:`term-side term-commands ${h?"open":""}`,children:[s.jsxs("div",{className:"panel-header",children:[s.jsx("span",{className:"panel-title",children:t("commands")}),s.jsxs("div",{className:"panel-header-actions",children:[s.jsx("button",{type:"button",className:"panel-refresh",title:t("rerun"),onClick:()=>r({type:"list_commands"}),children:s.jsx(X,{})}),s.jsx("button",{type:"button",className:"panel-new",title:t("newCommand"),onClick:M,children:s.jsx(B,{})})]})]}),s.jsx("div",{className:"panel-body",children:P?s.jsxs("div",{className:"cmd-form",children:[s.jsx("label",{htmlFor:"cmd-name",children:t("name")}),s.jsx("input",{id:"cmd-name",className:"cmd-input",value:o.name,placeholder:t("exampleName"),autoFocus:!0,onChange:e=>m({...o,name:e.target.value})}),s.jsx("label",{htmlFor:"cmd-command",children:t("command")}),s.jsx("input",{id:"cmd-command",className:"cmd-input",value:o.command,placeholder:t("exampleCommand"),onChange:e=>m({...o,command:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&$()}}),s.jsxs("label",{htmlFor:"cmd-cwd",children:[t("directory")," ",s.jsx("span",{className:"cmd-hint",children:t("cwdHint")})]}),s.jsx("input",{id:"cmd-cwd",className:"cmd-input",value:o.cwd,placeholder:"${pwd}",onChange:e=>m({...o,cwd:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&$()}}),s.jsxs("div",{className:"cmd-form-actions",children:[s.jsx("button",{type:"button",className:"btn",onClick:A,children:t("cancel")}),s.jsx("button",{type:"button",className:"btn primary",disabled:!o.name.trim()||!o.command.trim(),onClick:$,children:t("save")})]})]}):s.jsxs(s.Fragment,{children:[n.commands.length===0&&s.jsx("div",{className:"panel-empty",children:t("noCommands")}),n.commands.map((e,l)=>s.jsxs("div",{className:"cmd-item",children:[s.jsx("button",{type:"button",className:"cmd-run",title:t("clickToRun"),onClick:()=>F(e),children:s.jsx(Q,{})}),s.jsxs("button",{type:"button",className:"cmd-main",title:t("clickToRun"),onClick:()=>F(e),children:[s.jsx("span",{className:"cmd-name",children:e.name}),s.jsx("span",{className:"cmd-command",children:e.command}),e.cwd&&s.jsx("span",{className:"cmd-cwd",children:e.cwd})]}),s.jsx("button",{type:"button",className:"cmd-act",title:t("edit"),onClick:()=>z(l),children:s.jsx(U,{})}),s.jsx("button",{type:"button",className:`cmd-act del ${a===l?"confirm":""}`,title:t("delete"),onClick:()=>H(l),children:a===l?t("confirmQ"):s.jsx(V,{})})]},l))]})}),s.jsxs("div",{className:"term-tabs-block",children:[s.jsxs("div",{className:"panel-header",children:[s.jsx("span",{className:"panel-title",children:t("terminal")}),s.jsx("button",{type:"button",className:"panel-new",title:t("newTerminal"),onClick:d,children:s.jsx(B,{})})]}),s.jsxs("div",{className:"panel-body",children:[n.terminals.length===0&&s.jsx("div",{className:"panel-empty",children:t("noTerminal")}),S.map(C),E.length>0&&s.jsxs("div",{className:"term-folder",children:[s.jsxs("button",{type:"button",className:`term-folder-header ${k?"open":""}`,title:t("aiBashGroup"),onClick:()=>_(e=>!e),children:[s.jsx("span",{className:"term-folder-caret",children:k?"▾":"▸"}),s.jsx("span",{className:"term-folder-title",children:t("aiBashGroup")}),s.jsx("span",{className:"term-folder-count",children:E.length})]}),k&&s.jsx("div",{className:"term-folder-body",children:E.map(C)})]})]})]})]}),s.jsxs("div",{className:"term-main",children:[h&&s.jsx("div",{className:"drawer-backdrop",onClick:()=>j(!1)}),s.jsx("button",{type:"button",className:"term-side-toggle",title:t("commands"),onClick:()=>j(e=>!e),children:s.jsx(W,{})}),n.terminals.length===0?s.jsxs("div",{className:"term-empty",children:[s.jsx(Y,{className:"term-empty-icon"}),s.jsx("div",{className:"term-empty-title",children:t("builtinTerminal")}),s.jsx("div",{className:"term-empty-sub",children:t("termEmptySub")})]}):n.terminals.map(e=>s.jsx(te,{conversationId:e.conversationId,terminalId:e.id,command:e.command,cwd:e.cwd,title:e.title,active:e.id===w,send:r,register:x.register},`${e.conversationId}:${e.id}`))]})]})}export{re as TerminalPanel};
|