@rainmanhhh/pi-web 0.8.7

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 (161) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +147 -0
  3. package/README.zh-CN.md +145 -0
  4. package/dist/server.mjs +403 -0
  5. package/dist/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  6. package/dist/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  7. package/dist/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  8. package/dist/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  9. package/dist/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  10. package/dist/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  11. package/dist/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  12. package/dist/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  13. package/dist/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  14. package/dist/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  15. package/dist/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  16. package/dist/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  17. package/dist/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  18. package/dist/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  19. package/dist/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  20. package/dist/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  21. package/dist/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  22. package/dist/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  23. package/dist/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  24. package/dist/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  25. package/dist/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  26. package/dist/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  27. package/dist/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  28. package/dist/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  29. package/dist/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  30. package/dist/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  31. package/dist/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  32. package/dist/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  33. package/dist/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  34. package/dist/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  35. package/dist/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  36. package/dist/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  37. package/dist/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  38. package/dist/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  39. package/dist/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  40. package/dist/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  41. package/dist/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  42. package/dist/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  43. package/dist/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  44. package/dist/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  45. package/dist/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  46. package/dist/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  47. package/dist/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  48. package/dist/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  49. package/dist/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  50. package/dist/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  51. package/dist/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  52. package/dist/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  53. package/dist/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  54. package/dist/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  55. package/dist/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  56. package/dist/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  57. package/dist/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  58. package/dist/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  59. package/dist/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  60. package/dist/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  61. package/dist/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  62. package/dist/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  63. package/dist/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  64. package/dist/static/assets/_baseFor-D6HAxaEF.js +1 -0
  65. package/dist/static/assets/arc-Cev3HYkO.js +1 -0
  66. package/dist/static/assets/architecture-YZFGNWBL-DSVeA3Mc.js +1 -0
  67. package/dist/static/assets/architectureDiagram-Q4EWVU46-BUaFXLue.js +36 -0
  68. package/dist/static/assets/array-BifhSqXX.js +1 -0
  69. package/dist/static/assets/blockDiagram-DXYQGD6D-BD7crHZn.js +132 -0
  70. package/dist/static/assets/c4Diagram-AHTNJAMY-BTvR1Qix.js +10 -0
  71. package/dist/static/assets/channel-DSbgxqFl.js +1 -0
  72. package/dist/static/assets/chunk-4BX2VUAB-C9I87hfN.js +1 -0
  73. package/dist/static/assets/chunk-4TB4RGXK-CYXNKQNe.js +206 -0
  74. package/dist/static/assets/chunk-55IACEB6-DAYR8bYh.js +1 -0
  75. package/dist/static/assets/chunk-5FUZZQ4R-BghvyuR7.js +62 -0
  76. package/dist/static/assets/chunk-5PVQY5BW-CZT35iHI.js +2 -0
  77. package/dist/static/assets/chunk-BSJP7CBP-BclwT518.js +1 -0
  78. package/dist/static/assets/chunk-EDXVE4YY-C4TkNvln.js +1 -0
  79. package/dist/static/assets/chunk-ENJZ2VHE-BNRddB0h.js +10 -0
  80. package/dist/static/assets/chunk-FMBD7UC4-4iiTC4rp.js +15 -0
  81. package/dist/static/assets/chunk-ICPOFSXX-BIhiNjvk.js +122 -0
  82. package/dist/static/assets/chunk-K5T4RW27-FpH_VPgE.js +94 -0
  83. package/dist/static/assets/chunk-OYMX7WX6-Dg0dFe8H.js +231 -0
  84. package/dist/static/assets/chunk-QZHKN3VN-DnoLcr4T.js +1 -0
  85. package/dist/static/assets/chunk-U2HBQHQK-CJqSKuXA.js +70 -0
  86. package/dist/static/assets/chunk-X2U36JSP-DVXuKdYc.js +1 -0
  87. package/dist/static/assets/chunk-YZCP3GAM-D4t97aMk.js +1 -0
  88. package/dist/static/assets/chunk-ZZ45TVLE-D3ALxVxH.js +1 -0
  89. package/dist/static/assets/classDiagram-6PBFFD2Q-3fKgRhOi.js +1 -0
  90. package/dist/static/assets/classDiagram-v2-HSJHXN6E-3fKgRhOi.js +1 -0
  91. package/dist/static/assets/clone-Dgktwry5.js +1 -0
  92. package/dist/static/assets/cose-bilkent-S5V4N54A-CVHW-V1c.js +1 -0
  93. package/dist/static/assets/cytoscape.esm-KkXhEuBu.js +321 -0
  94. package/dist/static/assets/dagre-DANBRJgS.js +1 -0
  95. package/dist/static/assets/dagre-KV5264BT-RX495Ogs.js +4 -0
  96. package/dist/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  97. package/dist/static/assets/diagram-5BDNPKRD-B3TQrwLp.js +10 -0
  98. package/dist/static/assets/diagram-G4DWMVQ6-DMTfV1fq.js +24 -0
  99. package/dist/static/assets/diagram-MMDJMWI5-BA8Bf6LU.js +43 -0
  100. package/dist/static/assets/diagram-TYMM5635-DZgWIMF2.js +24 -0
  101. package/dist/static/assets/dist-C_yfW-4f.js +1 -0
  102. package/dist/static/assets/erDiagram-SMLLAGMA-BPjiJgpM.js +85 -0
  103. package/dist/static/assets/flatten-DYA82rhy.js +1 -0
  104. package/dist/static/assets/flowDiagram-DWJPFMVM-C8itnDyk.js +162 -0
  105. package/dist/static/assets/ganttDiagram-T4ZO3ILL-QijQZ_7A.js +292 -0
  106. package/dist/static/assets/gitGraph-7Q5UKJZL-DUTBJasc.js +1 -0
  107. package/dist/static/assets/gitGraphDiagram-UUTBAWPF-B4SbXUo2.js +106 -0
  108. package/dist/static/assets/graphlib-CAZZWEle.js +1 -0
  109. package/dist/static/assets/highlighted-body-OFNGDK62-B6SZt-Xj.js +1 -0
  110. package/dist/static/assets/index-BSAN2ZmA.css +1 -0
  111. package/dist/static/assets/index-CtaBtFPm.js +492 -0
  112. package/dist/static/assets/info-OMHHGYJF-y8VVrvpT.js +1 -0
  113. package/dist/static/assets/infoDiagram-42DDH7IO-SEL8m7Hn.js +2 -0
  114. package/dist/static/assets/init-C-OQMol4.js +1 -0
  115. package/dist/static/assets/ishikawaDiagram-UXIWVN3A-BiGygTnl.js +70 -0
  116. package/dist/static/assets/journeyDiagram-VCZTEJTY-x16DmnC7.js +139 -0
  117. package/dist/static/assets/kanban-definition-6JOO6SKY-B_Vmy_se.js +89 -0
  118. package/dist/static/assets/katex-9tSoZCUs.js +257 -0
  119. package/dist/static/assets/line-BXZmYadU.js +1 -0
  120. package/dist/static/assets/linear-BDsPwGxk.js +1 -0
  121. package/dist/static/assets/mermaid-GHXKKRXX-CZfowopI.js +1 -0
  122. package/dist/static/assets/mermaid-parser.core-BdiNtuYK.js +4 -0
  123. package/dist/static/assets/mermaid.core-Cy3kC-2x.js +42 -0
  124. package/dist/static/assets/mindmap-definition-QFDTVHPH-DibAS34Z.js +96 -0
  125. package/dist/static/assets/ordinal-DtR4qwUh.js +1 -0
  126. package/dist/static/assets/packet-4T2RLAQJ-QWjI5ifX.js +1 -0
  127. package/dist/static/assets/path-fybaL0A-.js +1 -0
  128. package/dist/static/assets/pie-ZZUOXDRM-CCpZfmHW.js +1 -0
  129. package/dist/static/assets/pieDiagram-DEJITSTG-DE3IRdo2.js +30 -0
  130. package/dist/static/assets/quadrantDiagram-34T5L4WZ-BnFzq8uS.js +7 -0
  131. package/dist/static/assets/radar-PYXPWWZC-DJRfpCAG.js +1 -0
  132. package/dist/static/assets/reduce-D9Ymtwj-.js +1 -0
  133. package/dist/static/assets/requirementDiagram-MS252O5E-4JH5mfMt.js +84 -0
  134. package/dist/static/assets/rolldown-runtime-C_s2cVnS.js +1 -0
  135. package/dist/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  136. package/dist/static/assets/sankeyDiagram-XADWPNL6-BBM3bCVp.js +10 -0
  137. package/dist/static/assets/sequenceDiagram-FGHM5R23-Ngkhph4n.js +157 -0
  138. package/dist/static/assets/src-D3QavEJ4.js +1 -0
  139. package/dist/static/assets/stateDiagram-FHFEXIEX-B8QHUbFP.js +1 -0
  140. package/dist/static/assets/stateDiagram-v2-QKLJ7IA2-8s677m33.js +1 -0
  141. package/dist/static/assets/timeline-definition-GMOUNBTQ-Cj_jCa6v.js +120 -0
  142. package/dist/static/assets/treeView-SZITEDCU-BYIf12Kb.js +1 -0
  143. package/dist/static/assets/treemap-W4RFUUIX-ChTAE-ps.js +1 -0
  144. package/dist/static/assets/vennDiagram-DHZGUBPP-Nv73eNL-.js +34 -0
  145. package/dist/static/assets/wardley-RL74JXVD-D4JZq5aY.js +1 -0
  146. package/dist/static/assets/wardleyDiagram-NUSXRM2D-D4_-w6kd.js +20 -0
  147. package/dist/static/assets/xychartDiagram-5P7HB3ND-BWrW2XAn.js +7 -0
  148. package/dist/static/icons/apple-touch-icon.png +0 -0
  149. package/dist/static/icons/icon-192.png +0 -0
  150. package/dist/static/icons/icon-512.png +0 -0
  151. package/dist/static/index.html +46 -0
  152. package/dist/static/manifest.webmanifest +28 -0
  153. package/dist/static/offline.html +83 -0
  154. package/dist/static/sw.js +75 -0
  155. package/package.json +107 -0
  156. package/public/icons/apple-touch-icon.png +0 -0
  157. package/public/icons/icon-192.png +0 -0
  158. package/public/icons/icon-512.png +0 -0
  159. package/public/manifest.webmanifest +28 -0
  160. package/public/offline.html +83 -0
  161. package/public/sw.js +75 -0
@@ -0,0 +1,83 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
+ <meta name="theme-color" content="#1a1a1a" />
7
+ <title>Pi Web is offline</title>
8
+ <style>
9
+ :root {
10
+ color-scheme: dark;
11
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
12
+ background: #1a1a1a;
13
+ color: #e8e8e8;
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ body {
21
+ min-height: 100dvh;
22
+ margin: 0;
23
+ display: grid;
24
+ place-items: center;
25
+ padding: 32px;
26
+ }
27
+
28
+ main {
29
+ width: min(100%, 420px);
30
+ text-align: center;
31
+ }
32
+
33
+ img {
34
+ width: 88px;
35
+ height: 88px;
36
+ margin-bottom: 24px;
37
+ }
38
+
39
+ h1 {
40
+ margin: 0 0 10px;
41
+ font-size: 22px;
42
+ font-weight: 650;
43
+ letter-spacing: 0;
44
+ }
45
+
46
+ p {
47
+ margin: 0;
48
+ color: #9ca3af;
49
+ font-size: 14px;
50
+ line-height: 1.6;
51
+ }
52
+
53
+ button {
54
+ margin-top: 24px;
55
+ min-height: 40px;
56
+ padding: 0 18px;
57
+ border: 1px solid #3a3a3a;
58
+ border-radius: 6px;
59
+ background: #242424;
60
+ color: #e8e8e8;
61
+ font: inherit;
62
+ cursor: pointer;
63
+ }
64
+
65
+ button:hover {
66
+ background: #2e2e2e;
67
+ }
68
+
69
+ button:focus-visible {
70
+ outline: 2px solid #60a5fa;
71
+ outline-offset: 3px;
72
+ }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <main>
77
+ <img src="/icons/icon-192.png" alt="" />
78
+ <h1>Pi Web is offline</h1>
79
+ <p>Reconnect to the local Pi Web server, then try again.</p>
80
+ <button type="button" onclick="location.reload()">Try again</button>
81
+ </main>
82
+ </body>
83
+ </html>
@@ -0,0 +1,75 @@
1
+ const CACHE_PREFIX = "pi-web";
2
+ const CACHE_VERSION = new URL(self.location.href).searchParams.get("v") || "dev";
3
+ const STATIC_CACHE = `${CACHE_PREFIX}-static-${CACHE_VERSION}`;
4
+ const OFFLINE_URL = "/offline.html";
5
+ const PRECACHE_URLS = [
6
+ OFFLINE_URL,
7
+ "/manifest.webmanifest",
8
+ "/icons/icon-192.png",
9
+ "/icons/icon-512.png",
10
+ "/icons/apple-touch-icon.png",
11
+ ];
12
+
13
+ self.addEventListener("install", (event) => {
14
+ event.waitUntil(
15
+ caches
16
+ .open(STATIC_CACHE)
17
+ .then((cache) => cache.addAll(PRECACHE_URLS))
18
+ .then(() => self.skipWaiting()),
19
+ );
20
+ });
21
+
22
+ self.addEventListener("activate", (event) => {
23
+ event.waitUntil(
24
+ caches
25
+ .keys()
26
+ .then((keys) =>
27
+ Promise.all(
28
+ keys
29
+ .filter((key) => key.startsWith(`${CACHE_PREFIX}-`) && key !== STATIC_CACHE)
30
+ .map((key) => caches.delete(key)),
31
+ ),
32
+ )
33
+ .then(() => self.clients.claim()),
34
+ );
35
+ });
36
+
37
+ self.addEventListener("fetch", (event) => {
38
+ const { request } = event;
39
+ if (request.method !== "GET") return;
40
+
41
+ const url = new URL(request.url);
42
+ if (url.origin !== self.location.origin) return;
43
+
44
+ // Session data and live agent traffic must always come from the local server.
45
+ if (url.pathname.startsWith("/api/") || url.pathname === "/sw.js") return;
46
+
47
+ if (request.mode === "navigate") {
48
+ event.respondWith(
49
+ fetch(request).catch(async () => {
50
+ const fallback = await caches.match(OFFLINE_URL);
51
+ return fallback ?? Response.error();
52
+ }),
53
+ );
54
+ return;
55
+ }
56
+
57
+ const isStaticAsset =
58
+ url.pathname.startsWith("/_next/static/") || PRECACHE_URLS.includes(url.pathname);
59
+
60
+ if (isStaticAsset) {
61
+ event.respondWith(cacheFirst(request));
62
+ }
63
+ });
64
+
65
+ async function cacheFirst(request) {
66
+ const cached = await caches.match(request);
67
+ if (cached) return cached;
68
+
69
+ const response = await fetch(request);
70
+ if (response.ok && response.type === "basic") {
71
+ const cache = await caches.open(STATIC_CACHE);
72
+ await cache.put(request, response.clone());
73
+ }
74
+ return response;
75
+ }
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "@rainmanhhh/pi-web",
3
+ "version": "0.8.7",
4
+ "description": "Web UI for the pi coding agent (fork of @agegr/pi-web)",
5
+ "homepage": "https://gitee.com/dsxbygzzl/pi-web#readme",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://gitee.com/dsxbygzzl/pi-web.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://gitee.com/dsxbygzzl/pi-web/issues"
12
+ },
13
+ "author": "rainmanhhh",
14
+ "license": "MIT",
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org"
18
+ },
19
+ "engines": {
20
+ "node": ">=22.19.0"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "public",
25
+ "package.json"
26
+ ],
27
+ "bin": {
28
+ "pi-web": "dist/server.mjs"
29
+ },
30
+ "dependencies": {
31
+ "@earendil-works/pi-agent-core": "0.84.1",
32
+ "@earendil-works/pi-ai": "0.84.1",
33
+ "@earendil-works/pi-coding-agent": "0.84.1",
34
+ "@earendil-works/pi-tui": "0.84.1",
35
+ "@hono/node-server": "^2.1.0",
36
+ "class-variance-authority": "^0.7.1",
37
+ "clsx": "^2.1.1",
38
+ "hono": "^4.13.1",
39
+ "lucide-react": "^1.31.0",
40
+ "proper-lockfile": "4.1.2",
41
+ "radix-ui": "^1.6.7",
42
+ "react": "^19.2.4",
43
+ "react-dom": "^19.2.4",
44
+ "shadcn": "^4.17.0",
45
+ "streamdown": "2.5.0",
46
+ "tailwind-merge": "^3.6.0",
47
+ "tw-animate-css": "^1.4.0",
48
+ "undici": "8.9.0"
49
+ },
50
+ "devDependencies": {
51
+ "@lobehub/icons": "^5.6.0",
52
+ "@playwright/test": "^1.62.1",
53
+ "@tailwindcss/postcss": "^4.2.2",
54
+ "@testing-library/dom": "^10.4.1",
55
+ "@testing-library/react": "^16.3.2",
56
+ "@types/node": "^25",
57
+ "@types/node-notifier": "^8.0.5",
58
+ "@types/proper-lockfile": "4.1.4",
59
+ "@types/react": "^19",
60
+ "@types/react-dom": "^19",
61
+ "@types/react-syntax-highlighter": "^15.5.13",
62
+ "@vitejs/plugin-react": "^6.0.5",
63
+ "biome": "^0.3.3",
64
+ "commander": "^15.0.0",
65
+ "husky": "^9.1.7",
66
+ "jiti": "^2.7.0",
67
+ "jscpd": "^5.0.14",
68
+ "jsdom": "^30.0.1",
69
+ "katex": "^0.16.47",
70
+ "lint-staged": "^17.3.0",
71
+ "mammoth": "^1.12.0",
72
+ "mermaid": "^11.14.0",
73
+ "node-notifier": "^10.0.1",
74
+ "oxlint": "^1.78.0",
75
+ "postcss": "^8",
76
+ "react-markdown": "^10.1.0",
77
+ "react-syntax-highlighter": "^16.1.1",
78
+ "rehype-katex": "^7.0.1",
79
+ "rehype-raw": "^7.0.0",
80
+ "rehype-sanitize": "^6.0.0",
81
+ "remark-gfm": "^4.0.1",
82
+ "remark-math": "^6.0.0",
83
+ "tailwindcss": "^4.2.2",
84
+ "typescript": "^7.0.2",
85
+ "vite": "^8.2.1",
86
+ "vite-plugin-svgr": "^5.2.0",
87
+ "vitest": "^4.1.10"
88
+ },
89
+ "type": "module",
90
+ "scripts": {
91
+ "dev": "vite",
92
+ "dev:lan": "vite --host 0.0.0.0",
93
+ "mb": "bun run --env-file=.env.manual api",
94
+ "mf": "bun run --env-file=.env.manual dev -- --port 3001",
95
+ "api": "bun run server/main.ts",
96
+ "api:node": "bun run build:server && node dist/server.mjs",
97
+ "build:server": "bun build server/main.ts --target node --outfile dist/server.mjs --minify --external \"@earendil-works/*\" --define \"process.env.PI_WEB_PACKAGED=1\"",
98
+ "e2e:stop": "bun run scripts/e2e-stop.mjs",
99
+ "build": "vite build",
100
+ "lint": "oxlint --fix",
101
+ "jscpd": "jscpd --config .jscpd.json",
102
+ "check": "tsc --noEmit",
103
+ "format": "biome check --write .",
104
+ "test:e2e": "playwright test",
105
+ "test:unit": "vitest run"
106
+ }
107
+ }
Binary file
Binary file
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "/",
3
+ "name": "Pi Web",
4
+ "short_name": "Pi Web",
5
+ "description": "Local web interface for the pi coding agent",
6
+ "start_url": "/",
7
+ "scope": "/",
8
+ "display": "standalone",
9
+ "background_color": "#000000",
10
+ "theme_color": "#000000",
11
+ "orientation": "any",
12
+ "categories": ["developer", "productivity"],
13
+ "lang": "en",
14
+ "icons": [
15
+ {
16
+ "src": "/icons/icon-192.png",
17
+ "sizes": "192x192",
18
+ "type": "image/png",
19
+ "purpose": "any"
20
+ },
21
+ {
22
+ "src": "/icons/icon-512.png",
23
+ "sizes": "512x512",
24
+ "type": "image/png",
25
+ "purpose": "any"
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,83 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
+ <meta name="theme-color" content="#1a1a1a" />
7
+ <title>Pi Web is offline</title>
8
+ <style>
9
+ :root {
10
+ color-scheme: dark;
11
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
12
+ background: #1a1a1a;
13
+ color: #e8e8e8;
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ body {
21
+ min-height: 100dvh;
22
+ margin: 0;
23
+ display: grid;
24
+ place-items: center;
25
+ padding: 32px;
26
+ }
27
+
28
+ main {
29
+ width: min(100%, 420px);
30
+ text-align: center;
31
+ }
32
+
33
+ img {
34
+ width: 88px;
35
+ height: 88px;
36
+ margin-bottom: 24px;
37
+ }
38
+
39
+ h1 {
40
+ margin: 0 0 10px;
41
+ font-size: 22px;
42
+ font-weight: 650;
43
+ letter-spacing: 0;
44
+ }
45
+
46
+ p {
47
+ margin: 0;
48
+ color: #9ca3af;
49
+ font-size: 14px;
50
+ line-height: 1.6;
51
+ }
52
+
53
+ button {
54
+ margin-top: 24px;
55
+ min-height: 40px;
56
+ padding: 0 18px;
57
+ border: 1px solid #3a3a3a;
58
+ border-radius: 6px;
59
+ background: #242424;
60
+ color: #e8e8e8;
61
+ font: inherit;
62
+ cursor: pointer;
63
+ }
64
+
65
+ button:hover {
66
+ background: #2e2e2e;
67
+ }
68
+
69
+ button:focus-visible {
70
+ outline: 2px solid #60a5fa;
71
+ outline-offset: 3px;
72
+ }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <main>
77
+ <img src="/icons/icon-192.png" alt="" />
78
+ <h1>Pi Web is offline</h1>
79
+ <p>Reconnect to the local Pi Web server, then try again.</p>
80
+ <button type="button" onclick="location.reload()">Try again</button>
81
+ </main>
82
+ </body>
83
+ </html>
package/public/sw.js ADDED
@@ -0,0 +1,75 @@
1
+ const CACHE_PREFIX = "pi-web";
2
+ const CACHE_VERSION = new URL(self.location.href).searchParams.get("v") || "dev";
3
+ const STATIC_CACHE = `${CACHE_PREFIX}-static-${CACHE_VERSION}`;
4
+ const OFFLINE_URL = "/offline.html";
5
+ const PRECACHE_URLS = [
6
+ OFFLINE_URL,
7
+ "/manifest.webmanifest",
8
+ "/icons/icon-192.png",
9
+ "/icons/icon-512.png",
10
+ "/icons/apple-touch-icon.png",
11
+ ];
12
+
13
+ self.addEventListener("install", (event) => {
14
+ event.waitUntil(
15
+ caches
16
+ .open(STATIC_CACHE)
17
+ .then((cache) => cache.addAll(PRECACHE_URLS))
18
+ .then(() => self.skipWaiting()),
19
+ );
20
+ });
21
+
22
+ self.addEventListener("activate", (event) => {
23
+ event.waitUntil(
24
+ caches
25
+ .keys()
26
+ .then((keys) =>
27
+ Promise.all(
28
+ keys
29
+ .filter((key) => key.startsWith(`${CACHE_PREFIX}-`) && key !== STATIC_CACHE)
30
+ .map((key) => caches.delete(key)),
31
+ ),
32
+ )
33
+ .then(() => self.clients.claim()),
34
+ );
35
+ });
36
+
37
+ self.addEventListener("fetch", (event) => {
38
+ const { request } = event;
39
+ if (request.method !== "GET") return;
40
+
41
+ const url = new URL(request.url);
42
+ if (url.origin !== self.location.origin) return;
43
+
44
+ // Session data and live agent traffic must always come from the local server.
45
+ if (url.pathname.startsWith("/api/") || url.pathname === "/sw.js") return;
46
+
47
+ if (request.mode === "navigate") {
48
+ event.respondWith(
49
+ fetch(request).catch(async () => {
50
+ const fallback = await caches.match(OFFLINE_URL);
51
+ return fallback ?? Response.error();
52
+ }),
53
+ );
54
+ return;
55
+ }
56
+
57
+ const isStaticAsset =
58
+ url.pathname.startsWith("/_next/static/") || PRECACHE_URLS.includes(url.pathname);
59
+
60
+ if (isStaticAsset) {
61
+ event.respondWith(cacheFirst(request));
62
+ }
63
+ });
64
+
65
+ async function cacheFirst(request) {
66
+ const cached = await caches.match(request);
67
+ if (cached) return cached;
68
+
69
+ const response = await fetch(request);
70
+ if (response.ok && response.type === "basic") {
71
+ const cache = await caches.open(STATIC_CACHE);
72
+ await cache.put(request, response.clone());
73
+ }
74
+ return response;
75
+ }