@pananfly/pi-web 0.8.1
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/.next/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +46 -0
- package/.next/build-manifest.json +20 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +68 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +138 -0
- package/.next/react-loadable-manifest.json +2367 -0
- package/.next/required-server-files.js +350 -0
- package/.next/required-server-files.json +350 -0
- package/.next/routes-manifest.json +348 -0
- package/.next/server/app/_global-error/page.js +32 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_global-error.html +1 -0
- package/.next/server/app/_global-error.meta +16 -0
- package/.next/server/app/_global-error.rsc +14 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +14 -0
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +16 -0
- package/.next/server/app/_not-found.rsc +19 -0
- package/.next/server/app/_not-found.segments/_full.segment.rsc +19 -0
- package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
- package/.next/server/app/_not-found.segments/_index.segment.rsc +6 -0
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +5 -0
- package/.next/server/app/api/agent/[id]/bash-output/route.js +1 -0
- package/.next/server/app/api/agent/[id]/bash-output/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/[id]/bash-output/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/agent/[id]/events/route.js +3 -0
- package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/[id]/events/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/agent/[id]/route.js +1 -0
- package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/agent/new/route.js +1 -0
- package/.next/server/app/api/agent/new/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/new/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/agent/running/events/route.js +3 -0
- package/.next/server/app/api/agent/running/events/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/running/events/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/all-providers/route.js +1 -0
- package/.next/server/app/api/auth/all-providers/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/all-providers/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -0
- package/.next/server/app/api/auth/api-key/[provider]/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/api-key/[provider]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/login/[provider]/route.js +3 -0
- package/.next/server/app/api/auth/login/[provider]/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/login/[provider]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/login/route.js +1 -0
- package/.next/server/app/api/auth/login/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/logout/[provider]/route.js +1 -0
- package/.next/server/app/api/auth/logout/[provider]/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/logout/[provider]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/logout/route.js +1 -0
- package/.next/server/app/api/auth/logout/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/providers/route.js +1 -0
- package/.next/server/app/api/auth/providers/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/providers/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/refresh/route.js +1 -0
- package/.next/server/app/api/auth/refresh/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/status/route.js +1 -0
- package/.next/server/app/api/auth/status/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/verify/route.js +1 -0
- package/.next/server/app/api/auth/verify/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/verify/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/cwd/validate/route.js +1 -0
- package/.next/server/app/api/cwd/validate/route.js.nft.json +1 -0
- package/.next/server/app/api/cwd/validate/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/default-cwd/route.js +1 -0
- package/.next/server/app/api/default-cwd/route.js.nft.json +1 -0
- package/.next/server/app/api/default-cwd/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/file-index/route.js +1 -0
- package/.next/server/app/api/file-index/route.js.nft.json +1 -0
- package/.next/server/app/api/file-index/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/files/[...path]/route.js +49 -0
- package/.next/server/app/api/files/[...path]/route.js.nft.json +1 -0
- package/.next/server/app/api/files/[...path]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/diff/route.js +6 -0
- package/.next/server/app/api/git/diff/route.js.nft.json +1 -0
- package/.next/server/app/api/git/diff/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/status/route.js +6 -0
- package/.next/server/app/api/git/status/route.js.nft.json +1 -0
- package/.next/server/app/api/git/status/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/home/route.js +1 -0
- package/.next/server/app/api/home/route.js.nft.json +1 -0
- package/.next/server/app/api/home/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/models/route.js +1 -0
- package/.next/server/app/api/models/route.js.nft.json +1 -0
- package/.next/server/app/api/models/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/models-config/route.js +1 -0
- package/.next/server/app/api/models-config/route.js.nft.json +1 -0
- package/.next/server/app/api/models-config/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/models-config/test/route.js +1 -0
- package/.next/server/app/api/models-config/test/route.js.nft.json +1 -0
- package/.next/server/app/api/models-config/test/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/plugins/route.js +1 -0
- package/.next/server/app/api/plugins/route.js.nft.json +1 -0
- package/.next/server/app/api/plugins/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/auto-name/route.js +10 -0
- package/.next/server/app/api/sessions/[id]/auto-name/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/auto-name/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/context/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/context/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/export/route.js +54 -0
- package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/export/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/state/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/state/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/state/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/route.js +1 -0
- package/.next/server/app/api/sessions/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/check/route.js +1 -0
- package/.next/server/app/api/skills/check/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/check/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/install/route.js +1 -0
- package/.next/server/app/api/skills/install/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/install/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/route.js +6 -0
- package/.next/server/app/api/skills/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/search/route.js +1 -0
- package/.next/server/app/api/skills/search/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/search/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/update/route.js +1 -0
- package/.next/server/app/api/skills/update/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/update/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/route.js +1 -0
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -0
- package/.next/server/app/favicon.ico/route.js +1 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/index.html +1 -0
- package/.next/server/app/index.meta +14 -0
- package/.next/server/app/index.rsc +18 -0
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
- package/.next/server/app/index.segments/_full.segment.rsc +18 -0
- package/.next/server/app/index.segments/_head.segment.rsc +6 -0
- package/.next/server/app/index.segments/_index.segment.rsc +6 -0
- package/.next/server/app/index.segments/_tree.segment.rsc +5 -0
- package/.next/server/app/login/page.js +2 -0
- package/.next/server/app/login/page.js.nft.json +1 -0
- package/.next/server/app/login/page_client-reference-manifest.js +1 -0
- package/.next/server/app/login.html +1 -0
- package/.next/server/app/login.meta +15 -0
- package/.next/server/app/login.rsc +20 -0
- package/.next/server/app/login.segments/_full.segment.rsc +20 -0
- package/.next/server/app/login.segments/_head.segment.rsc +6 -0
- package/.next/server/app/login.segments/_index.segment.rsc +6 -0
- package/.next/server/app/login.segments/_tree.segment.rsc +5 -0
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +6 -0
- package/.next/server/app/login.segments/login.segment.rsc +5 -0
- package/.next/server/app/page.js +73 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +46 -0
- package/.next/server/chunks/1069.js +23 -0
- package/.next/server/chunks/1089.js +1 -0
- package/.next/server/chunks/1130.js +79 -0
- package/.next/server/chunks/1207.js +36 -0
- package/.next/server/chunks/1515.js +1 -0
- package/.next/server/chunks/1570.js +24 -0
- package/.next/server/chunks/1605.js +1 -0
- package/.next/server/chunks/1707.js +93 -0
- package/.next/server/chunks/1792.js +38 -0
- package/.next/server/chunks/1813.js +1 -0
- package/.next/server/chunks/2018.js +148 -0
- package/.next/server/chunks/2106.js +1 -0
- package/.next/server/chunks/2155.js +34 -0
- package/.next/server/chunks/2185.js +5 -0
- package/.next/server/chunks/2190.js +1 -0
- package/.next/server/chunks/2325.js +82 -0
- package/.next/server/chunks/2349.js +1 -0
- package/.next/server/chunks/2394.js +1 -0
- package/.next/server/chunks/2434.js +1 -0
- package/.next/server/chunks/2744.js +1 -0
- package/.next/server/chunks/2815.js +1 -0
- package/.next/server/chunks/2871.js +8 -0
- package/.next/server/chunks/2903.js +1 -0
- package/.next/server/chunks/319.js +45 -0
- package/.next/server/chunks/3252.js +115 -0
- package/.next/server/chunks/3379.js +1 -0
- package/.next/server/chunks/3770.js +1 -0
- package/.next/server/chunks/3894.js +1 -0
- package/.next/server/chunks/4030.js +86 -0
- package/.next/server/chunks/4286.js +1 -0
- package/.next/server/chunks/4309.js +1 -0
- package/.next/server/chunks/4338.js +64 -0
- package/.next/server/chunks/4367.js +1 -0
- package/.next/server/chunks/4372.js +1 -0
- package/.next/server/chunks/4424.js +215 -0
- package/.next/server/chunks/4485.js +1 -0
- package/.next/server/chunks/46.js +62 -0
- package/.next/server/chunks/4674.js +1 -0
- package/.next/server/chunks/4741.js +18 -0
- package/.next/server/chunks/4742.js +80 -0
- package/.next/server/chunks/4796.js +104 -0
- package/.next/server/chunks/4980.js +1 -0
- package/.next/server/chunks/5029.js +1 -0
- package/.next/server/chunks/5198.js +90 -0
- package/.next/server/chunks/5318.js +1 -0
- package/.next/server/chunks/5461.js +1 -0
- package/.next/server/chunks/5582.js +3 -0
- package/.next/server/chunks/5598.js +1 -0
- package/.next/server/chunks/5627.js +1 -0
- package/.next/server/chunks/6219.js +41 -0
- package/.next/server/chunks/6337.js +1 -0
- package/.next/server/chunks/6429.js +1 -0
- package/.next/server/chunks/6476.js +27 -0
- package/.next/server/chunks/6509.js +153 -0
- package/.next/server/chunks/6949.js +1 -0
- package/.next/server/chunks/6953.js +1 -0
- package/.next/server/chunks/703.js +1 -0
- package/.next/server/chunks/7152.js +1 -0
- package/.next/server/chunks/7181.js +160 -0
- package/.next/server/chunks/7233.js +1 -0
- package/.next/server/chunks/7307.js +1 -0
- package/.next/server/chunks/7434.js +77 -0
- package/.next/server/chunks/7561.js +1 -0
- package/.next/server/chunks/7872.js +1 -0
- package/.next/server/chunks/7914.js +226 -0
- package/.next/server/chunks/8267.js +24 -0
- package/.next/server/chunks/8294.js +1 -0
- package/.next/server/chunks/835.js +1 -0
- package/.next/server/chunks/8645.js +141 -0
- package/.next/server/chunks/9081.js +1 -0
- package/.next/server/chunks/9169.js +1 -0
- package/.next/server/chunks/9280.js +255 -0
- package/.next/server/chunks/940.js +287 -0
- package/.next/server/chunks/9486.js +1 -0
- package/.next/server/chunks/9509.js +1 -0
- package/.next/server/functions-config-manifest.json +15 -0
- package/.next/server/instrumentation.js +1 -0
- package/.next/server/instrumentation.js.nft.json +1 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/middleware.js +18 -0
- package/.next/server/middleware.js.nft.json +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages-manifest.json +4 -0
- package/.next/server/prefetch-hints.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/050357b0.986bc6597f184c3b.js +62 -0
- package/.next/static/chunks/1212.c32f02f461182c5b.js +226 -0
- package/.next/static/chunks/127.394be8b7a579a747.js +8 -0
- package/.next/static/chunks/1327.09252bb80616cc3a.js +1 -0
- package/.next/static/chunks/1377.e883e13864574c26.js +36 -0
- package/.next/static/chunks/1390.3e7d84d187924556.js +104 -0
- package/.next/static/chunks/1438.d742ea00e0f072ca.js +27 -0
- package/.next/static/chunks/1474.605367a77b6161a0.js +115 -0
- package/.next/static/chunks/1576.93e0666990c12243.js +38 -0
- package/.next/static/chunks/1951.4b73bf47740c2bfb.js +160 -0
- package/.next/static/chunks/2081.47b6e9391094055f.js +1 -0
- package/.next/static/chunks/2178.2adcd2b51553bd50.js +1 -0
- package/.next/static/chunks/2217.4bf1455eb89bdd9b.js +1 -0
- package/.next/static/chunks/2325.23caf22075e51aa5.js +1 -0
- package/.next/static/chunks/2356.52627097a8b56ec1.js +1 -0
- package/.next/static/chunks/2418.b5d9e177e10a686e.js +1 -0
- package/.next/static/chunks/249.973d23a3940a5fc9.js +1 -0
- package/.next/static/chunks/2554.ca4cb2f8bc69f32e.js +86 -0
- package/.next/static/chunks/2566.505384571dedf726.js +79 -0
- package/.next/static/chunks/2619.9aac8983f30c7c8a.js +1 -0
- package/.next/static/chunks/2646.c653cac657d7b035.js +215 -0
- package/.next/static/chunks/2784.3d8e0d20edb71dcd.js +64 -0
- package/.next/static/chunks/2821.934bcf60fbdc28c6.js +1 -0
- package/.next/static/chunks/2847.b66f6d92e4f5e495.js +23 -0
- package/.next/static/chunks/2866.4ecb766127917d99.js +1 -0
- package/.next/static/chunks/28f0fb3b.5f2b0099c24fbe32.js +122 -0
- package/.next/static/chunks/3308.29d4f7078e26a916.js +73 -0
- package/.next/static/chunks/3316.5c51b238308a838b.js +34 -0
- package/.next/static/chunks/3341.6042c7cb7225d88d.js +41 -0
- package/.next/static/chunks/339.1a094bb1c6eaf9dc.js +1 -0
- package/.next/static/chunks/370.57cfa27da8567918.js +1 -0
- package/.next/static/chunks/3708.81252290870c8487.js +1 -0
- package/.next/static/chunks/3794-e569667691edc8f7.js +32 -0
- package/.next/static/chunks/3832.5d713641634c65b5.js +24 -0
- package/.next/static/chunks/4368.e43e952c5535cba6.js +80 -0
- package/.next/static/chunks/4424.fd0c93a807a333e1.js +1 -0
- package/.next/static/chunks/4866.d1060b4faf2ae1e2.js +1 -0
- package/.next/static/chunks/4bd1b696-e356ca5ba0218e27.js +1 -0
- package/.next/static/chunks/5020.9ac8d0dc8390bb6e.js +1 -0
- package/.next/static/chunks/5166.7d3648847337fe52.js +62 -0
- package/.next/static/chunks/5242.7b643c6b3394cac1.js +1 -0
- package/.next/static/chunks/5361.afc00ab2626bacbf.js +1 -0
- package/.next/static/chunks/5460.0337c14f29b9ff9a.js +90 -0
- package/.next/static/chunks/5521.cfdf2cfc6db31407.js +1 -0
- package/.next/static/chunks/5715.048f1bae2c41fa89.js +1 -0
- package/.next/static/chunks/6121.5b8cb3199531d194.js +1 -0
- package/.next/static/chunks/6294.24f510c0c3e3714c.js +1 -0
- package/.next/static/chunks/6467.b354ed428e3bef01.js +5 -0
- package/.next/static/chunks/66d203d7.3e90bc8f1f096a8e.js +153 -0
- package/.next/static/chunks/6787.a15de946178e8ef7.js +1 -0
- package/.next/static/chunks/7176.2979806e91c0df29.js +1 -0
- package/.next/static/chunks/7256.e07cf52d87d40252.js +1 -0
- package/.next/static/chunks/7543.89f7b805ed0f2901.js +1 -0
- package/.next/static/chunks/776.fe8e64ab3669a915.js +287 -0
- package/.next/static/chunks/8118.f905a690db2b859b.js +148 -0
- package/.next/static/chunks/8233.a465d18b04719c6d.js +141 -0
- package/.next/static/chunks/8249.7a48897e80a16391.js +1 -0
- package/.next/static/chunks/8311-95813758da2b283c.js +1 -0
- package/.next/static/chunks/8365.dc22e1ff76d04a3b.js +93 -0
- package/.next/static/chunks/8498.1083c36ddbbedd69.js +1 -0
- package/.next/static/chunks/8511.c7c064a8f58f1355.js +1 -0
- package/.next/static/chunks/869.7152372b662e31af.js +1 -0
- package/.next/static/chunks/8782.9ab86081b5661687.js +77 -0
- package/.next/static/chunks/8863.fa0320ea586efb3b.js +1 -0
- package/.next/static/chunks/8953.e5e7399c7952a1ff.js +1 -0
- package/.next/static/chunks/90542734.b75ad0df50bf68f5.js +1 -0
- package/.next/static/chunks/9165.02dc1f4804b94791.js +24 -0
- package/.next/static/chunks/934.9006461bd0548660.js +1 -0
- package/.next/static/chunks/9522.c7c6e9c330f9ba6b.js +1 -0
- package/.next/static/chunks/9667.c6d6228dd3c4861b.js +1 -0
- package/.next/static/chunks/9705.40a82b97f214e28b.js +1 -0
- package/.next/static/chunks/9793.4567af813117ad25.js +1 -0
- package/.next/static/chunks/app/_global-error/page-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/_not-found/page-3ea40c1a91b0cd39.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/bash-output/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/events/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/agent/new/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/agent/running/events/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/all-providers/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/api-key/[provider]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/login/[provider]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/[provider]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/providers/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/refresh/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/status/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/auth/verify/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/cwd/validate/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/default-cwd/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/file-index/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/files/[...path]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/git/diff/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/git/status/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/home/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/models/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/models-config/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/models-config/test/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/plugins/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/context/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/export/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/state/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/skills/check/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/skills/install/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/skills/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/skills/search/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/skills/update/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/app/layout-fc0dbec63c654527.js +1 -0
- package/.next/static/chunks/app/login/page-c7d96da038297463.js +1 -0
- package/.next/static/chunks/app/page-883e877df3335b30.js +72 -0
- package/.next/static/chunks/d2c09beb.4f5ff7197b5bbbea.js +1 -0
- package/.next/static/chunks/d3ac728e-7964f816a1ca64e5.js +1 -0
- package/.next/static/chunks/da12927c.00775c0e4542fd3e.js +82 -0
- package/.next/static/chunks/framework-711ef29bc66f648c.js +1 -0
- package/.next/static/chunks/main-app-6d3ca1bd083597b7.js +1 -0
- package/.next/static/chunks/main-b70eb01cb9d3de17.js +5 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/global-error-129b03c25e777d59.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-6270af0206ac74b6.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-bbd44e4ff13f4c9b.js +1 -0
- package/.next/static/css/88714c00e109ce28.css +1 -0
- package/.next/static/css/afdadd5192f321e7.css +1 -0
- package/.next/static/media/15605e25b523335c-s.woff2 +0 -0
- package/.next/static/media/1a3dce5cfb5f7760-s.woff2 +0 -0
- package/.next/static/media/1cdd02902f937a18-s.woff2 +0 -0
- package/.next/static/media/4c4b3b30b6bcb2be-s.woff2 +0 -0
- package/.next/static/media/641a7b8a5800ee0e-s.woff2 +0 -0
- package/.next/static/media/7deddc85b7ffd1dc-s.p.woff2 +0 -0
- package/.next/static/media/KaTeX_AMS-Regular.1608a09b.woff +0 -0
- package/.next/static/media/KaTeX_AMS-Regular.4aafdb68.ttf +0 -0
- package/.next/static/media/KaTeX_AMS-Regular.a79f1c31.woff2 +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Bold.b6770918.woff +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Bold.cce5b8ec.ttf +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Bold.ec17d132.woff2 +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Regular.07ef19e7.ttf +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Regular.55fac258.woff2 +0 -0
- package/.next/static/media/KaTeX_Caligraphic-Regular.dad44a7f.woff +0 -0
- package/.next/static/media/KaTeX_Fraktur-Bold.9f256b85.woff +0 -0
- package/.next/static/media/KaTeX_Fraktur-Bold.b18f59e1.ttf +0 -0
- package/.next/static/media/KaTeX_Fraktur-Bold.d42a5579.woff2 +0 -0
- package/.next/static/media/KaTeX_Fraktur-Regular.7c187121.woff +0 -0
- package/.next/static/media/KaTeX_Fraktur-Regular.d3c882a6.woff2 +0 -0
- package/.next/static/media/KaTeX_Fraktur-Regular.ed38e79f.ttf +0 -0
- package/.next/static/media/KaTeX_Main-Bold.b74a1a8b.ttf +0 -0
- package/.next/static/media/KaTeX_Main-Bold.c3fb5ac2.woff2 +0 -0
- package/.next/static/media/KaTeX_Main-Bold.d181c465.woff +0 -0
- package/.next/static/media/KaTeX_Main-BoldItalic.6f2bb1df.woff2 +0 -0
- package/.next/static/media/KaTeX_Main-BoldItalic.70d8b0a5.ttf +0 -0
- package/.next/static/media/KaTeX_Main-BoldItalic.e3f82f9d.woff +0 -0
- package/.next/static/media/KaTeX_Main-Italic.47373d1e.ttf +0 -0
- package/.next/static/media/KaTeX_Main-Italic.8916142b.woff2 +0 -0
- package/.next/static/media/KaTeX_Main-Italic.9024d815.woff +0 -0
- package/.next/static/media/KaTeX_Main-Regular.0462f03b.woff2 +0 -0
- package/.next/static/media/KaTeX_Main-Regular.7f51fe03.woff +0 -0
- package/.next/static/media/KaTeX_Main-Regular.b7f8fe9b.ttf +0 -0
- package/.next/static/media/KaTeX_Math-BoldItalic.572d331f.woff2 +0 -0
- package/.next/static/media/KaTeX_Math-BoldItalic.a879cf83.ttf +0 -0
- package/.next/static/media/KaTeX_Math-BoldItalic.f1035d8d.woff +0 -0
- package/.next/static/media/KaTeX_Math-Italic.5295ba48.woff +0 -0
- package/.next/static/media/KaTeX_Math-Italic.939bc644.ttf +0 -0
- package/.next/static/media/KaTeX_Math-Italic.f28c23ac.woff2 +0 -0
- package/.next/static/media/KaTeX_SansSerif-Bold.8c5b5494.woff2 +0 -0
- package/.next/static/media/KaTeX_SansSerif-Bold.94e1e8dc.ttf +0 -0
- package/.next/static/media/KaTeX_SansSerif-Bold.bf59d231.woff +0 -0
- package/.next/static/media/KaTeX_SansSerif-Italic.3b1e59b3.woff2 +0 -0
- package/.next/static/media/KaTeX_SansSerif-Italic.7c9bc82b.woff +0 -0
- package/.next/static/media/KaTeX_SansSerif-Italic.b4c20c84.ttf +0 -0
- package/.next/static/media/KaTeX_SansSerif-Regular.74048478.woff +0 -0
- package/.next/static/media/KaTeX_SansSerif-Regular.ba21ed5f.woff2 +0 -0
- package/.next/static/media/KaTeX_SansSerif-Regular.d4d7ba48.ttf +0 -0
- package/.next/static/media/KaTeX_Script-Regular.03e9641d.woff2 +0 -0
- package/.next/static/media/KaTeX_Script-Regular.07505710.woff +0 -0
- package/.next/static/media/KaTeX_Script-Regular.fe9cbbe1.ttf +0 -0
- package/.next/static/media/KaTeX_Size1-Regular.e1e279cb.woff +0 -0
- package/.next/static/media/KaTeX_Size1-Regular.eae34984.woff2 +0 -0
- package/.next/static/media/KaTeX_Size1-Regular.fabc004a.ttf +0 -0
- package/.next/static/media/KaTeX_Size2-Regular.57727022.woff +0 -0
- package/.next/static/media/KaTeX_Size2-Regular.5916a24f.woff2 +0 -0
- package/.next/static/media/KaTeX_Size2-Regular.d6b476ec.ttf +0 -0
- package/.next/static/media/KaTeX_Size3-Regular.9acaf01c.woff +0 -0
- package/.next/static/media/KaTeX_Size3-Regular.a144ef58.ttf +0 -0
- package/.next/static/media/KaTeX_Size3-Regular.b4230e7e.woff2 +0 -0
- package/.next/static/media/KaTeX_Size4-Regular.10d95fd3.woff2 +0 -0
- package/.next/static/media/KaTeX_Size4-Regular.7a996c9d.woff +0 -0
- package/.next/static/media/KaTeX_Size4-Regular.fbccdabe.ttf +0 -0
- package/.next/static/media/KaTeX_Typewriter-Regular.6258592b.woff +0 -0
- package/.next/static/media/KaTeX_Typewriter-Regular.a8709e36.woff2 +0 -0
- package/.next/static/media/KaTeX_Typewriter-Regular.d97aaf4a.ttf +0 -0
- package/.next/static/media/ec14413c594b3356-s.p.woff2 +0 -0
- package/.next/static/rNxNXXmbOkkvQk0-VdhVR/_buildManifest.js +1 -0
- package/.next/static/rNxNXXmbOkkvQk0-VdhVR/_ssgManifest.js +1 -0
- package/.next/trace +6 -0
- package/.next/trace-build +1 -0
- package/.next/types/app/api/agent/[id]/bash-output/route.ts +351 -0
- package/.next/types/app/api/agent/[id]/events/route.ts +351 -0
- package/.next/types/app/api/agent/[id]/route.ts +351 -0
- package/.next/types/app/api/agent/new/route.ts +351 -0
- package/.next/types/app/api/agent/running/events/route.ts +351 -0
- package/.next/types/app/api/auth/all-providers/route.ts +351 -0
- package/.next/types/app/api/auth/api-key/[provider]/route.ts +351 -0
- package/.next/types/app/api/auth/login/[provider]/route.ts +351 -0
- package/.next/types/app/api/auth/login/route.ts +351 -0
- package/.next/types/app/api/auth/logout/[provider]/route.ts +351 -0
- package/.next/types/app/api/auth/logout/route.ts +351 -0
- package/.next/types/app/api/auth/providers/route.ts +351 -0
- package/.next/types/app/api/auth/refresh/route.ts +351 -0
- package/.next/types/app/api/auth/status/route.ts +351 -0
- package/.next/types/app/api/auth/verify/route.ts +351 -0
- package/.next/types/app/api/cwd/validate/route.ts +351 -0
- package/.next/types/app/api/default-cwd/route.ts +351 -0
- package/.next/types/app/api/file-index/route.ts +351 -0
- package/.next/types/app/api/files/[...path]/route.ts +351 -0
- package/.next/types/app/api/git/diff/route.ts +351 -0
- package/.next/types/app/api/git/status/route.ts +351 -0
- package/.next/types/app/api/home/route.ts +351 -0
- package/.next/types/app/api/models/route.ts +351 -0
- package/.next/types/app/api/models-config/route.ts +351 -0
- package/.next/types/app/api/models-config/test/route.ts +351 -0
- package/.next/types/app/api/plugins/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/auto-name/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/context/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/entries/[entryId]/thinking/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/export/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/route.ts +351 -0
- package/.next/types/app/api/sessions/[id]/state/route.ts +351 -0
- package/.next/types/app/api/sessions/route.ts +351 -0
- package/.next/types/app/api/skills/check/route.ts +351 -0
- package/.next/types/app/api/skills/install/route.ts +351 -0
- package/.next/types/app/api/skills/route.ts +351 -0
- package/.next/types/app/api/skills/search/route.ts +351 -0
- package/.next/types/app/api/skills/update/route.ts +351 -0
- package/.next/types/app/api/worktrees/route.ts +351 -0
- package/.next/types/app/layout.ts +87 -0
- package/.next/types/app/login/page.ts +87 -0
- package/.next/types/app/page.ts +87 -0
- package/.next/types/cache-life.d.ts +145 -0
- package/.next/types/package.json +1 -0
- package/.next/types/routes.d.ts +112 -0
- package/.next/types/validator.ts +430 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/README.zh-CN.md +136 -0
- package/bin/pi-web-options.js +45 -0
- package/bin/pi-web.js +343 -0
- package/lib/auth-cli.js +115 -0
- package/next.config.ts +37 -0
- package/package.json +79 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Pi Web
|
|
2
|
+
|
|
3
|
+
[English](./README.md)
|
|
4
|
+
|
|
5
|
+
[pi 编程智能体](https://github.com/badlogic/pi-mono) 的本地网页界面。它会读取本机的 pi 会话文件,在浏览器里提供会话管理、实时对话、模型配置、技能管理和项目文件预览。
|
|
6
|
+
|
|
7
|
+
## 快速开始
|
|
8
|
+
|
|
9
|
+
**无需安装,直接运行:**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @agegr/pi-web@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**或全局安装后使用:**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @agegr/pi-web
|
|
19
|
+
pi-web
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
启动后打开 [http://localhost:30141](http://localhost:30141)。命令行版本会在服务就绪后尝试自动打开浏览器。
|
|
23
|
+
|
|
24
|
+
**可选参数:**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pi-web --port 8080 # 自定义端口
|
|
28
|
+
pi-web --hostname 127.0.0.1 # 仅本机访问
|
|
29
|
+
pi-web -p 8080 -H 127.0.0.1 # 组合使用
|
|
30
|
+
pi-web --no-open # 不自动打开浏览器
|
|
31
|
+
|
|
32
|
+
PORT=8080 pi-web # 也支持环境变量
|
|
33
|
+
PI_WEB_NO_OPEN=1 pi-web # 适用于后台服务或开机自启
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## HTTP 代理
|
|
37
|
+
|
|
38
|
+
Pi Web 的服务端模型请求和 API 请求会读取标准的 `HTTP_PROXY`、`HTTPS_PROXY` 和 `NO_PROXY` 环境变量。
|
|
39
|
+
|
|
40
|
+
macOS 或 Linux:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
HTTP_PROXY=http://127.0.0.1:7890 \
|
|
44
|
+
HTTPS_PROXY=http://127.0.0.1:7890 \
|
|
45
|
+
NO_PROXY=localhost,127.0.0.1 \
|
|
46
|
+
npx @agegr/pi-web@latest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Windows PowerShell:
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
$env:HTTP_PROXY = "http://127.0.0.1:7890"
|
|
53
|
+
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
|
|
54
|
+
$env:NO_PROXY = "localhost,127.0.0.1"
|
|
55
|
+
npx @agegr/pi-web@latest
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 功能介绍
|
|
59
|
+
|
|
60
|
+
- **把历史工作接回来**:打开网页就能按项目找到以前的 pi 对话,不必在终端里翻文件或记住会话路径。
|
|
61
|
+
- **放心试不同方向**:可以从某条历史消息重新开始,也可以复制出一条独立的新路线,探索方案时不怕弄乱原来的对话。
|
|
62
|
+
- **跨分支工作**:在侧边栏切换 Git worktree,让新会话和 Explorer 跟随你选择的 checkout。
|
|
63
|
+
- **边聊边看项目文件**:左侧浏览项目文件,右侧打开源码、文档、图片、音频和 PDF;文件变化会自动刷新,适合边让 agent 改边检查结果。
|
|
64
|
+
- **随时掌握会话状态**:在顶部就能看到上下文占用、花费、压缩结果和系统提示,长会话不再像黑箱。
|
|
65
|
+
- **少离开当前界面**:模型、登录/API key、模型测试和技能开关都能在网页里处理,配置 agent 时不用在多个工具之间来回切换。
|
|
66
|
+
|
|
67
|
+
## 注意事项
|
|
68
|
+
|
|
69
|
+
- **数据目录**:默认读取 `~/.pi/agent/sessions` 下的会话文件。可通过环境变量 `PI_CODING_AGENT_DIR` 指定其他 pi agent 目录。
|
|
70
|
+
- **会话文件**:路径形如 `~/.pi/agent/sessions/<编码后的工作目录>/<时间戳>_<uuid>.jsonl`。
|
|
71
|
+
- **模型配置**:Models 面板读写 pi agent 目录下的 `models.json`,模型列表和默认模型由 pi 的配置解析得到。
|
|
72
|
+
- **文件访问**:文件浏览和预览面向当前选择的项目目录,以及会话中已出现过的工作目录。
|
|
73
|
+
- **Git worktree**:什么时候显示切换器、新建目录在哪里、删除会影响什么,见 [Pi Web 里的 Worktree](./docs/worktrees.zh-CN.md)。
|
|
74
|
+
- **Fork 与会话内分支不同**:Fork 会创建新的 `.jsonl` 文件;“Edit from here” 是同一会话文件里的分支。
|
|
75
|
+
|
|
76
|
+
## 开发
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install
|
|
80
|
+
npm run dev
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
本地开发端口为 [http://localhost:30141](http://localhost:30141)。
|
|
84
|
+
|
|
85
|
+
常用检查:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
node_modules/.bin/tsc --noEmit
|
|
89
|
+
npm run lint
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
开发时不要运行 `next build` / `npm run build`,它会写入 `.next/`,容易影响正在运行的 dev server。发布流程再执行构建。
|
|
93
|
+
|
|
94
|
+
## 项目结构
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
app/
|
|
98
|
+
api/
|
|
99
|
+
agent/ # 创建/驱动 AgentSession,提供 SSE 事件流
|
|
100
|
+
auth/ # OAuth 和 API key 管理
|
|
101
|
+
cwd/validate/ # 自定义工作目录校验
|
|
102
|
+
default-cwd/ # 获取 pi 默认工作目录
|
|
103
|
+
files/ # 文件列表、读取、预览、watch
|
|
104
|
+
home/ # 当前用户 home 目录
|
|
105
|
+
models/ # 可用模型、默认模型、thinking levels
|
|
106
|
+
models-config/ # 读写 models.json、测试模型
|
|
107
|
+
sessions/ # 会话读取、重命名、删除、上下文、HTML 导出
|
|
108
|
+
skills/ # skills 列表、搜索、安装、启停
|
|
109
|
+
components/
|
|
110
|
+
AppShell.tsx # 主布局、URL 状态、顶部面板、文件标签
|
|
111
|
+
SessionSidebar.tsx # 项目选择、会话树、Explorer
|
|
112
|
+
ChatWindow.tsx # 消息区、SSE、拖拽图片、minimap
|
|
113
|
+
ChatInput.tsx # 输入栏、模型/工具/thinking/compact/slash controls
|
|
114
|
+
MessageView.tsx # 消息、thinking、tool call/result 渲染
|
|
115
|
+
ModelsConfig.tsx # 模型和认证配置面板
|
|
116
|
+
SkillsConfig.tsx # 技能管理面板
|
|
117
|
+
FileExplorer.tsx # 文件树
|
|
118
|
+
FileViewer.tsx # 源码、diff、图片、音频、PDF、DOCX 预览
|
|
119
|
+
lib/
|
|
120
|
+
http-dispatcher.ts # 服务端 fetch 的 HTTP(S) 代理配置
|
|
121
|
+
rpc-manager.ts # AgentSessionWrapper 生命周期和全局 registry
|
|
122
|
+
session-reader.ts # 解析 .jsonl 会话文件和分支上下文
|
|
123
|
+
normalize.ts # 规范化 toolCall 字段名
|
|
124
|
+
file-access.ts # 文件读取安全边界
|
|
125
|
+
file-paths.ts # 文件路径编码/相对路径工具
|
|
126
|
+
markdown.ts # Markdown/Mermaid/KaTeX 插件配置
|
|
127
|
+
pi-types.ts # pi 相关类型
|
|
128
|
+
hooks/
|
|
129
|
+
useAgentSession.ts # 会话加载、发送命令、SSE 状态机
|
|
130
|
+
useAudio.ts # 完成提示音
|
|
131
|
+
useDragDrop.ts # 图片拖拽
|
|
132
|
+
useTheme.ts # 主题切换
|
|
133
|
+
bin/
|
|
134
|
+
pi-web.js # npm CLI 入口
|
|
135
|
+
instrumentation.ts # 初始化服务端 HTTP dispatcher
|
|
136
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
4
|
+
const { parseArgs } = require("util");
|
|
5
|
+
|
|
6
|
+
const TRUE_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
7
|
+
|
|
8
|
+
function isEnabled(value) {
|
|
9
|
+
return typeof value === "string" && TRUE_VALUES.has(value.trim().toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function parseLaunchOptions(args = process.argv.slice(2), env = process.env) {
|
|
13
|
+
const { values: cliArgs } = parseArgs({
|
|
14
|
+
args,
|
|
15
|
+
options: {
|
|
16
|
+
port: { type: "string", short: "p" },
|
|
17
|
+
hostname: { type: "string", short: "H" },
|
|
18
|
+
"no-open": { type: "boolean" },
|
|
19
|
+
auth: { type: "boolean" },
|
|
20
|
+
"no-auth": { type: "boolean" },
|
|
21
|
+
dev: { type: "boolean" },
|
|
22
|
+
},
|
|
23
|
+
strict: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Determine auth mode: CLI flag > env var > default (false)
|
|
27
|
+
let authEnabled = false;
|
|
28
|
+
if (cliArgs.auth) {
|
|
29
|
+
authEnabled = true;
|
|
30
|
+
} else if (cliArgs["no-auth"]) {
|
|
31
|
+
authEnabled = false;
|
|
32
|
+
} else if (isEnabled(env.PI_WEB_AUTH)) {
|
|
33
|
+
authEnabled = true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
port: cliArgs.port ?? env.PORT ?? "30141",
|
|
38
|
+
hostname: cliArgs.hostname ?? env.HOSTNAME ?? null,
|
|
39
|
+
openBrowser: !cliArgs["no-open"] && !isEnabled(env.PI_WEB_NO_OPEN),
|
|
40
|
+
authEnabled,
|
|
41
|
+
dev: cliArgs.dev ?? false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = { parseLaunchOptions };
|
package/bin/pi-web.js
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
7
|
+
const path = require("path");
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
11
|
+
const readline = require("readline");
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
13
|
+
const { parseLaunchOptions } = require("./pi-web-options");
|
|
14
|
+
|
|
15
|
+
const pkgDir = path.join(__dirname, "..");
|
|
16
|
+
const nextDir = path.join(pkgDir, ".next");
|
|
17
|
+
|
|
18
|
+
// Resolve next's CLI entry directly to avoid relying on .bin symlinks (which
|
|
19
|
+
// may not exist when installed via npx).
|
|
20
|
+
let nextBin;
|
|
21
|
+
try {
|
|
22
|
+
nextBin = require.resolve("next/dist/bin/next", { paths: [pkgDir] });
|
|
23
|
+
} catch {
|
|
24
|
+
// Fallback: locate next package root and derive the bin path manually.
|
|
25
|
+
try {
|
|
26
|
+
const nextPkg = require.resolve("next/package.json", { paths: [pkgDir] });
|
|
27
|
+
nextBin = path.join(path.dirname(nextPkg), "dist", "bin", "next");
|
|
28
|
+
} catch {
|
|
29
|
+
nextBin = path.join(pkgDir, "node_modules", "next", "dist", "bin", "next");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { port, hostname, openBrowser, authEnabled, dev } = parseLaunchOptions();
|
|
34
|
+
|
|
35
|
+
async function setupAuth() {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
37
|
+
const auth = require("../lib/auth-cli");
|
|
38
|
+
const config = auth.getAuthConfig();
|
|
39
|
+
|
|
40
|
+
if (config) {
|
|
41
|
+
console.log("Auth already configured.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log("\nPi Web - Authentication Setup");
|
|
46
|
+
console.log("==============================\n");
|
|
47
|
+
|
|
48
|
+
const rl = readline.createInterface({
|
|
49
|
+
input: process.stdin,
|
|
50
|
+
output: process.stdout,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const username = await question("Enter username: ");
|
|
57
|
+
const password = await question("Enter password: ");
|
|
58
|
+
const confirmPassword = await question("Confirm password: ");
|
|
59
|
+
|
|
60
|
+
if (password !== confirmPassword) {
|
|
61
|
+
console.error("Passwords do not match.");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const validation = auth.validatePasswordStrength(password);
|
|
66
|
+
if (!validation.valid) {
|
|
67
|
+
console.error(`Invalid password: ${validation.error}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log("\n✓ Password meets requirements.\n");
|
|
72
|
+
|
|
73
|
+
const passwordHash = await auth.hashPassword(password);
|
|
74
|
+
const totpSecret = auth.generateTOTPSecret();
|
|
75
|
+
|
|
76
|
+
console.log("Generating 2FA secret...");
|
|
77
|
+
console.log("Scan this QR code with your authenticator app:\n");
|
|
78
|
+
|
|
79
|
+
// Generate QR code as ASCII art
|
|
80
|
+
const totpUri = auth.generateTOTPDatauri(totpSecret);
|
|
81
|
+
const qrCode = await auth.generateQRCode(totpUri);
|
|
82
|
+
console.log(qrCode);
|
|
83
|
+
console.log(`\nTOTP URI: ${totpUri}\n`);
|
|
84
|
+
|
|
85
|
+
const code = await question("Enter 2FA code to verify: ");
|
|
86
|
+
|
|
87
|
+
const valid = auth.verifyTOTP(totpSecret.base32, code);
|
|
88
|
+
if (!valid) {
|
|
89
|
+
console.error("Invalid 2FA code.");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log("✓ 2FA verified. Authentication enabled.\n");
|
|
94
|
+
|
|
95
|
+
auth.saveAuthConfig({
|
|
96
|
+
username,
|
|
97
|
+
passwordHash,
|
|
98
|
+
totpSecret: totpSecret.base32,
|
|
99
|
+
totpEnabled: true,
|
|
100
|
+
createdAt: new Date().toISOString(),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
console.log(`✓ auth.json created at ${auth.getAuthConfigPath()}\n`);
|
|
104
|
+
} finally {
|
|
105
|
+
rl.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function setup2FA() {
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
111
|
+
const auth = require("../lib/auth-cli");
|
|
112
|
+
const config = auth.getAuthConfig();
|
|
113
|
+
|
|
114
|
+
if (!config) {
|
|
115
|
+
console.error("No auth configured. Run with --auth first.");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log("\nPi Web - 2FA Reset");
|
|
120
|
+
console.log("===================\n");
|
|
121
|
+
|
|
122
|
+
const rl = readline.createInterface({
|
|
123
|
+
input: process.stdin,
|
|
124
|
+
output: process.stdout,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const password = await question("Enter password to verify identity: ");
|
|
131
|
+
|
|
132
|
+
const valid = await auth.verifyPassword(password, config.passwordHash);
|
|
133
|
+
if (!valid) {
|
|
134
|
+
console.error("Invalid password.");
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log("✓ Password verified.\n");
|
|
139
|
+
|
|
140
|
+
const totpSecret = auth.generateTOTPSecret();
|
|
141
|
+
|
|
142
|
+
console.log("Generating new 2FA secret...");
|
|
143
|
+
console.log("Scan this QR code with your authenticator app:\n");
|
|
144
|
+
|
|
145
|
+
const totpUri = auth.generateTOTPDatauri(totpSecret);
|
|
146
|
+
const qrCode = await auth.generateQRCode(totpUri);
|
|
147
|
+
console.log(qrCode);
|
|
148
|
+
console.log(`\nTOTP URI: ${totpUri}\n`);
|
|
149
|
+
|
|
150
|
+
const code = await question("Enter 2FA code to verify: ");
|
|
151
|
+
|
|
152
|
+
const validCode = auth.verifyTOTP(totpSecret.base32, code);
|
|
153
|
+
if (!validCode) {
|
|
154
|
+
console.error("Invalid 2FA code.");
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log("✓ 2FA verified and updated.\n");
|
|
159
|
+
|
|
160
|
+
auth.saveAuthConfig({
|
|
161
|
+
...config,
|
|
162
|
+
totpSecret: totpSecret.base32,
|
|
163
|
+
totpEnabled: true,
|
|
164
|
+
});
|
|
165
|
+
} finally {
|
|
166
|
+
rl.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function reset2FA() {
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
172
|
+
const auth = require("../lib/auth-cli");
|
|
173
|
+
const config = auth.getAuthConfig();
|
|
174
|
+
|
|
175
|
+
if (!config) {
|
|
176
|
+
console.error("No auth configured.");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log("\nPi Web - 2FA Reset");
|
|
181
|
+
console.log("===================\n");
|
|
182
|
+
|
|
183
|
+
const rl = readline.createInterface({
|
|
184
|
+
input: process.stdin,
|
|
185
|
+
output: process.stdout,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
const password = await question("Enter password to verify identity: ");
|
|
192
|
+
|
|
193
|
+
const valid = await auth.verifyPassword(password, config.passwordHash);
|
|
194
|
+
if (!valid) {
|
|
195
|
+
console.error("Invalid password.");
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log("✓ Password verified.\n");
|
|
200
|
+
|
|
201
|
+
auth.saveAuthConfig({
|
|
202
|
+
...config,
|
|
203
|
+
totpSecret: "",
|
|
204
|
+
totpEnabled: false,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
console.log("✓ 2FA has been reset. You will need to set it up again on next --auth start.\n");
|
|
208
|
+
} finally {
|
|
209
|
+
rl.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function resetPassword() {
|
|
214
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
215
|
+
const auth = require("../lib/auth-cli");
|
|
216
|
+
const config = auth.getAuthConfig();
|
|
217
|
+
|
|
218
|
+
if (!config) {
|
|
219
|
+
console.error("No auth configured.");
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log("\nPi Web - Password Reset");
|
|
224
|
+
console.log("======================\n");
|
|
225
|
+
|
|
226
|
+
const rl = readline.createInterface({
|
|
227
|
+
input: process.stdin,
|
|
228
|
+
output: process.stdout,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const currentPassword = await question("Enter current password: ");
|
|
235
|
+
|
|
236
|
+
const valid = await auth.verifyPassword(currentPassword, config.passwordHash);
|
|
237
|
+
if (!valid) {
|
|
238
|
+
console.error("Invalid password.");
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log("✓ Password verified.\n");
|
|
243
|
+
|
|
244
|
+
const newPassword = await question("Enter new password: ");
|
|
245
|
+
const confirmPassword = await question("Confirm new password: ");
|
|
246
|
+
|
|
247
|
+
if (newPassword !== confirmPassword) {
|
|
248
|
+
console.error("Passwords do not match.");
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const validation = auth.validatePasswordStrength(newPassword);
|
|
253
|
+
if (!validation.valid) {
|
|
254
|
+
console.error(`Invalid password: ${validation.error}`);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const passwordHash = await auth.hashPassword(newPassword);
|
|
259
|
+
|
|
260
|
+
auth.saveAuthConfig({
|
|
261
|
+
...config,
|
|
262
|
+
passwordHash,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
console.log("✓ Password updated successfully.\n");
|
|
266
|
+
} finally {
|
|
267
|
+
rl.close();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (!fs.existsSync(nextDir)) {
|
|
272
|
+
console.error("Build artifacts not found. Please report this issue.");
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const args = process.argv.slice(2);
|
|
277
|
+
|
|
278
|
+
if (args.includes("setup-2fa")) {
|
|
279
|
+
setup2FA().catch(console.error);
|
|
280
|
+
process.exit(0);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (args.includes("reset-2fa")) {
|
|
284
|
+
reset2FA().catch(console.error);
|
|
285
|
+
process.exit(0);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (args.includes("reset-password")) {
|
|
289
|
+
resetPassword().catch(console.error);
|
|
290
|
+
process.exit(0);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (authEnabled) {
|
|
294
|
+
setupAuth().then(() => {
|
|
295
|
+
startServer();
|
|
296
|
+
}).catch(console.error);
|
|
297
|
+
} else {
|
|
298
|
+
startServer();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function startServer() {
|
|
302
|
+
const nextCommand = dev ? "dev" : "start";
|
|
303
|
+
const nextArgs = [nextCommand, "-p", port];
|
|
304
|
+
if (hostname) nextArgs.push("-H", hostname);
|
|
305
|
+
|
|
306
|
+
// Always run next's JS entry with node directly — avoids .bin symlink issues
|
|
307
|
+
// and path-with-spaces problems on Windows when shell: true is used.
|
|
308
|
+
const child = spawn(process.execPath, [nextBin, ...nextArgs], {
|
|
309
|
+
cwd: pkgDir,
|
|
310
|
+
stdio: ["inherit", "pipe", "inherit"],
|
|
311
|
+
env: {
|
|
312
|
+
...process.env,
|
|
313
|
+
PI_WEB_AUTH: authEnabled ? "true" : "false",
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
let browserOpened = false;
|
|
318
|
+
const url = `http://${hostname ?? "localhost"}:${port}`;
|
|
319
|
+
|
|
320
|
+
child.stdout.on("data", (chunk) => {
|
|
321
|
+
const text = chunk.toString();
|
|
322
|
+
process.stdout.write(text);
|
|
323
|
+
if (openBrowser && !browserOpened && text.includes("Ready")) {
|
|
324
|
+
browserOpened = true;
|
|
325
|
+
const isWindows = process.platform === "win32";
|
|
326
|
+
const isMac = process.platform === "darwin";
|
|
327
|
+
const openCmd = isWindows ? "start" : isMac ? "open" : "xdg-open";
|
|
328
|
+
const opener = spawn(openCmd, [url], {
|
|
329
|
+
shell: isWindows,
|
|
330
|
+
stdio: "ignore",
|
|
331
|
+
detached: true,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
opener.on("error", (error) => {
|
|
335
|
+
console.warn(`Could not open browser automatically: ${error.message}`);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
opener.unref();
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
343
|
+
}
|
package/lib/auth-cli.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
4
|
+
const bcrypt = require("bcryptjs");
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
6
|
+
const OTPAuth = require("otpauth");
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
10
|
+
const path = require("path");
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
12
|
+
const qrcode = require("qrcode-terminal");
|
|
13
|
+
|
|
14
|
+
const BCRYPT_COST = 12;
|
|
15
|
+
|
|
16
|
+
function getAuthConfigPath() {
|
|
17
|
+
return path.join(process.env.HOME || "~", ".pi", "agent", "auth.json");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getAuthConfig() {
|
|
21
|
+
const configPath = getAuthConfigPath();
|
|
22
|
+
if (!fs.existsSync(configPath)) return null;
|
|
23
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
24
|
+
// Check if auth fields are present
|
|
25
|
+
if (!config.username || !config.passwordHash || !config.totpSecret || config.totpEnabled === undefined) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return config;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveAuthConfig(config) {
|
|
32
|
+
const configPath = getAuthConfigPath();
|
|
33
|
+
const dir = path.dirname(configPath);
|
|
34
|
+
if (!fs.existsSync(dir)) {
|
|
35
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function hashPassword(password) {
|
|
41
|
+
return bcrypt.hash(password, BCRYPT_COST);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function verifyPassword(password, hash) {
|
|
45
|
+
return bcrypt.compare(password, hash);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function validatePasswordStrength(password) {
|
|
49
|
+
if (password.length < 8) {
|
|
50
|
+
return { valid: false, error: "Password must be at least 8 characters" };
|
|
51
|
+
}
|
|
52
|
+
if (!/[A-Z]/.test(password)) {
|
|
53
|
+
return { valid: false, error: "Password must contain at least one uppercase letter" };
|
|
54
|
+
}
|
|
55
|
+
if (!/[a-z]/.test(password)) {
|
|
56
|
+
return { valid: false, error: "Password must contain at least one lowercase letter" };
|
|
57
|
+
}
|
|
58
|
+
if (!/[0-9]/.test(password)) {
|
|
59
|
+
return { valid: false, error: "Password must contain at least one number" };
|
|
60
|
+
}
|
|
61
|
+
if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) {
|
|
62
|
+
return { valid: false, error: "Password must contain at least one special character" };
|
|
63
|
+
}
|
|
64
|
+
return { valid: true };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function generateTOTPSecret() {
|
|
68
|
+
return new OTPAuth.Secret({ size: 20 });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function generateTOTPDatauri(secret) {
|
|
72
|
+
const totp = new OTPAuth.TOTP({
|
|
73
|
+
issuer: "Pi Web",
|
|
74
|
+
label: "admin",
|
|
75
|
+
algorithm: "SHA1",
|
|
76
|
+
digits: 6,
|
|
77
|
+
period: 30,
|
|
78
|
+
secret,
|
|
79
|
+
});
|
|
80
|
+
return totp.toString();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function generateQRCode(text) {
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
qrcode.generate(text, { small: true }, (qr) => {
|
|
86
|
+
resolve(qr);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function verifyTOTP(secret, token) {
|
|
92
|
+
const totp = new OTPAuth.TOTP({
|
|
93
|
+
issuer: "Pi Web",
|
|
94
|
+
label: "admin",
|
|
95
|
+
algorithm: "SHA1",
|
|
96
|
+
digits: 6,
|
|
97
|
+
period: 30,
|
|
98
|
+
secret: OTPAuth.Secret.fromBase32(secret),
|
|
99
|
+
});
|
|
100
|
+
const delta = totp.validate({ token, window: 1 });
|
|
101
|
+
return delta !== null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
getAuthConfigPath,
|
|
106
|
+
getAuthConfig,
|
|
107
|
+
saveAuthConfig,
|
|
108
|
+
hashPassword,
|
|
109
|
+
verifyPassword,
|
|
110
|
+
validatePasswordStrength,
|
|
111
|
+
generateTOTPSecret,
|
|
112
|
+
generateTOTPDatauri,
|
|
113
|
+
generateQRCode,
|
|
114
|
+
verifyTOTP,
|
|
115
|
+
};
|
package/next.config.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
const { version } = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8")) as { version: string };
|
|
6
|
+
let piVersion = "unknown";
|
|
7
|
+
try {
|
|
8
|
+
const piPkgPath = join(__dirname, "node_modules/@earendil-works/pi-coding-agent/package.json");
|
|
9
|
+
piVersion = (JSON.parse(readFileSync(piPkgPath, "utf8")) as { version: string }).version;
|
|
10
|
+
} catch { /* package not found, use default */ }
|
|
11
|
+
|
|
12
|
+
const nextConfig: NextConfig = {
|
|
13
|
+
serverExternalPackages: [
|
|
14
|
+
"undici",
|
|
15
|
+
"@earendil-works/pi-coding-agent",
|
|
16
|
+
"@earendil-works/pi-agent-core",
|
|
17
|
+
"@earendil-works/pi-ai",
|
|
18
|
+
"@earendil-works/pi-tui",
|
|
19
|
+
],
|
|
20
|
+
allowedDevOrigins: ['192.168.*.*', '[2408:8256:1a]'],
|
|
21
|
+
async headers() {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
source: "/",
|
|
25
|
+
headers: [
|
|
26
|
+
{ key: "Cache-Control", value: "private, no-cache, max-age=0, must-revalidate" },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
},
|
|
31
|
+
env: {
|
|
32
|
+
NEXT_PUBLIC_APP_VERSION: version,
|
|
33
|
+
NEXT_PUBLIC_PI_VERSION: piVersion,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default nextConfig;
|