@rexvane/piweb 0.3.24 → 0.3.26
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 -1
- package/.next/app-path-routes-manifest.json +11 -11
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +5 -5
- package/.next/react-loadable-manifest.json +13 -20
- package/.next/required-server-files.js +2 -1
- package/.next/required-server-files.json +2 -1
- package/.next/routes-manifest.json +6 -8
- package/.next/server/app/_global-error/page.js +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/agent/[id]/events/route.js +2 -2
- package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/[id]/route.js +1 -1
- package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/[id]/tree/route.js +1 -1
- package/.next/server/app/api/agent/[id]/tree/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/new/route.js +1 -1
- package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/resources/route.js +1 -0
- package/.next/server/app/api/agent/resources/route.js.nft.json +1 -0
- package/.next/server/app/api/agent/resources/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/config/route.js +1 -1
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/files/route.js +1 -1
- package/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/route.js +1 -1
- package/.next/server/app/api/fs/route.js.nft.json +1 -1
- package/.next/server/app/api/git/route.js +4 -4
- package/.next/server/app/api/git/route.js.nft.json +1 -1
- package/.next/server/app/api/github/route.js +4 -4
- package/.next/server/app/api/github/route.js.nft.json +1 -1
- package/.next/server/app/api/growth/route.js +1 -1
- package/.next/server/app/api/growth/route.js.nft.json +1 -1
- package/.next/server/app/api/health/route.js +1 -1
- package/.next/server/app/api/models/defaults/route.js +1 -1
- package/.next/server/app/api/models/defaults/route.js.nft.json +1 -1
- package/.next/server/app/api/models/route.js +1 -1
- package/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/server/app/api/pi-settings/route.js +1 -1
- package/.next/server/app/api/pi-settings/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/route.js +1 -1
- package/.next/server/app/api/plugins/route.js.nft.json +1 -1
- package/.next/server/app/api/prompts/route.js +1 -1
- package/.next/server/app/api/prompts/route.js.nft.json +1 -1
- package/.next/server/app/api/remote/route.js +4 -3
- package/.next/server/app/api/security/route.js +1 -1
- package/.next/server/app/api/security/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/import/route.js +2 -2
- package/.next/server/app/api/sessions/import/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +2 -2
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/update/route.js +2 -2
- package/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/server/app/api/version/route.js +1 -1
- package/.next/server/app/api/version/route.js.nft.json +1 -1
- package/.next/server/app/api/web-auth/route.js +2 -2
- package/.next/server/app/api/workspaces/route.js +1 -1
- package/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/.next/server/app/icon.svg/route.js +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +6 -7
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -7
- package/.next/server/app/index.segments/_full.segment.rsc +6 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -3
- package/.next/server/app/login/page.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +3 -3
- package/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +11 -11
- package/.next/server/chunks/3924.js +3 -3
- package/.next/server/chunks/538.js +1 -1
- package/.next/server/chunks/620.js +1 -0
- package/.next/server/chunks/6229.js +1 -1
- package/.next/server/chunks/7496.js +1 -1
- package/.next/server/chunks/7662.js +2 -2
- package/.next/server/chunks/8686.js +1 -1
- package/.next/server/functions-config-manifest.json +1 -2
- package/.next/server/instrumentation.js.nft.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/preview-props.json +3 -3
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/QJCtqgDKzGS2BdKABd9ch/_buildManifest.js +1 -0
- package/.next/static/chunks/2577.86c8538fbf05a8b2.js +1 -0
- package/.next/static/chunks/2716.fa561519675a3ff1.js +1 -0
- package/.next/static/chunks/2906.8a0e09bb47605cf1.js +1 -0
- package/.next/static/chunks/4673.ea36e55005c0f82f.js +1 -0
- package/.next/static/chunks/4686-4dc565817a160351.js +1 -0
- package/.next/static/chunks/4778.0d2c5d75b791d352.js +1 -0
- package/.next/static/chunks/{618.949981da99be7182.js → 618.9a22656b863f242b.js} +2 -2
- package/.next/static/chunks/app/_global-error/page-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/events/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/tree/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/agent/new/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/agent/resources/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/config/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/files/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/fs/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/git/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/github/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/growth/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/health/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/models/defaults/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/models/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/pi-settings/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/plugins/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/prompts/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/remote/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/security/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/export/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/sessions/import/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/skills/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/update/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/version/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/web-auth/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/api/workspaces/route-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/app/page-71f2d3b3ed864b3d.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-f2d93969c0bcf406.js +1 -0
- package/.next/static/chunks/webpack-ffc09b5fcc8aaa6d.js +1 -0
- package/.next/static/css/014eb1f21414e615.css +1 -0
- package/.next/static/css/56b129a13637fcfd.css +1 -0
- package/.next/static/css/7e3caf797e4cb19a.css +1 -0
- package/.next/types/app/api/agent/{[id]/side-chat → resources}/route.ts +3 -3
- package/.next/types/routes.d.ts +2 -2
- package/.next/types/validator.ts +9 -9
- package/README.md +1 -1
- package/next.config.ts +1 -1
- package/package.json +9 -9
- package/scripts/apply-global.mjs +87 -0
- package/scripts/launcher.mjs +21 -0
- package/scripts/testing/prepare-sdk-tools.mjs +19 -0
- package/src/app/api/agent/new/route.ts +2 -1
- package/src/app/api/agent/resources/route.ts +18 -0
- package/src/app/api/models/route.ts +22 -1
- package/src/app/api/plugins/route.ts +3 -2
- package/src/app/api/prompts/route.ts +3 -2
- package/src/app/api/remote/route.ts +22 -4
- package/src/app/api/sessions/[id]/export/route.ts +3 -1
- package/src/app/api/skills/route.ts +3 -2
- package/src/app/globals.css +1002 -1765
- package/src/components/AppShell.tsx +128 -93
- package/src/components/ChatInput.tsx +177 -98
- package/src/components/ChatWindow.tsx +189 -56
- package/src/components/ContextMeter.tsx +33 -9
- package/src/components/CustomSelect.module.css +142 -0
- package/src/components/CustomSelect.tsx +157 -0
- package/src/components/DrawerPanel.tsx +1 -1
- package/src/components/ExtensionUI.tsx +9 -3
- package/src/components/FileViewer.tsx +24 -21
- package/src/components/GitPanel.tsx +35 -13
- package/src/components/GrowthTree.tsx +6 -2
- package/src/components/ImageViewer.tsx +72 -0
- package/src/components/MarkdownBlock.tsx +67 -96
- package/src/components/ModelSelector.tsx +36 -39
- package/src/components/PiMark.tsx +76 -41
- package/src/components/PreviewImage.tsx +33 -0
- package/src/components/ProjectPanel.tsx +8 -5
- package/src/components/PromptPanel.tsx +85 -20
- package/src/components/ProviderSetupModal.module.css +12 -11
- package/src/components/ProviderSetupModal.tsx +107 -36
- package/src/components/RemoteSection.tsx +53 -2
- package/src/components/SessionImportSection.tsx +30 -15
- package/src/components/SessionSidebar.tsx +72 -62
- package/src/components/SettingsPanel.tsx +49 -151
- package/src/components/TrajectoryAnalyzer.module.css +26 -11
- package/src/components/TrajectoryView.tsx +11 -3
- package/src/components/chat/markdown-actions.tsx +23 -0
- package/src/components/composer/ComposerFiles.tsx +224 -0
- package/src/components/composer/ComposerImages.tsx +59 -127
- package/src/hooks/usePiWeb.ts +47 -2
- package/src/i18n.tsx +62 -80
- package/src/lib/agent-manager.ts +365 -33
- package/src/lib/chat/file-path.ts +54 -0
- package/src/lib/chat/skill-expansion.ts +51 -0
- package/src/lib/extension-ui.ts +25 -1
- package/src/lib/font.ts +37 -39
- package/src/lib/git-service.ts +4 -2
- package/src/lib/growth-turns.ts +3 -1
- package/src/lib/model-draft.ts +69 -2
- package/src/lib/models-service.ts +53 -3
- package/src/lib/pi.ts +2 -2
- package/src/lib/remote/assets.json +1 -1
- package/src/lib/remote/supervisor.ts +48 -5
- package/src/lib/security-service.ts +2 -1
- package/src/lib/session-reader.ts +25 -13
- package/src/lib/session-retention.ts +11 -8
- package/src/lib/skills-service.ts +2 -1
- package/src/lib/slash-command-token.ts +14 -0
- package/src/lib/trajectory.ts +111 -15
- package/src/lib/types.ts +28 -3
- package/src/lib/update-service.ts +29 -9
- package/src/lib/workspace-store.ts +36 -1
- package/.next/server/app/api/agent/[id]/side-chat/route.js +0 -5
- package/.next/server/app/api/agent/[id]/side-chat/route.js.nft.json +0 -1
- package/.next/server/app/api/agent/[id]/side-chat/route_client-reference-manifest.js +0 -1
- package/.next/server/chunks/3421.js +0 -1
- package/.next/static/chunks/2716.44fdf1b21454b961.js +0 -1
- package/.next/static/chunks/4673.e261707dce391be7.js +0 -1
- package/.next/static/chunks/4686-0cd87513f9ea3538.js +0 -1
- package/.next/static/chunks/4778.eddd3a5813f85824.js +0 -1
- package/.next/static/chunks/7411.5f79671208209b13.js +0 -1
- package/.next/static/chunks/8552.25c39ef4c995eba0.js +0 -1
- package/.next/static/chunks/app/_global-error/page-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/events/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/side-chat/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/tree/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/agent/new/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/config/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/files/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/fs/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/git/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/github/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/growth/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/health/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/models/defaults/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/models/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/pi-settings/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/plugins/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/prompts/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/remote/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/security/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/export/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/sessions/import/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/skills/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/update/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/version/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/web-auth/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/api/workspaces/route-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/app/page-dc3cb41d91c7432e.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-cbaaee0d7aacb85a.js +0 -1
- package/.next/static/chunks/webpack-2ac3d76b81895f5b.js +0 -1
- package/.next/static/css/08815507594e8b8d.css +0 -1
- package/.next/static/css/9fc559c2c4ad1d0f.css +0 -1
- package/.next/static/css/c6e2227c36ec2fd6.css +0 -1
- package/.next/static/css/f15a853af8b5127f.css +0 -1
- package/.next/static/lvKCJmjFj8LuqSojRVLRF/_buildManifest.js +0 -1
- package/src/app/api/agent/[id]/side-chat/route.ts +0 -77
- package/src/components/side-chat/SideChatPanel.module.css +0 -131
- package/src/components/side-chat/SideChatPanel.tsx +0 -189
- package/src/components/side-chat/icons.tsx +0 -8
- package/src/components/side-chat/request-history.ts +0 -29
- package/src/components/side-chat/store.ts +0 -248
- package/src/lib/chat/stream-settings.ts +0 -192
- package/src/lib/side-chat/context.ts +0 -123
- package/src/lib/side-chat/service.ts +0 -191
- package/src/lib/side-chat/types.ts +0 -61
- /package/.next/static/{lvKCJmjFj8LuqSojRVLRF → QJCtqgDKzGS2BdKABd9ch}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";exports.id=6229,exports.ids=[6229],exports.modules={66229:(a,b,c)=>{c.a(a,async(a,d)=>{try{c.d(b,{GW:()=>
|
|
1
|
+
"use strict";exports.id=6229,exports.ids=[6229],exports.modules={66229:(a,b,c)=>{c.a(a,async(a,d)=>{try{c.d(b,{GW:()=>v,deleteSession:()=>w,lx:()=>x});var e=c(73024),f=c(51455),g=c.n(f),h=c(76760),i=c.n(h),j=c(80481),k=c(75430),l=c(28686),m=c(87982),n=c(62433),o=c(777),p=a([k,l,m,n]);function q(a){return Number.isFinite(a)&&864e13>=Math.abs(a)}async function r(a,b){try{var c;let d,f,g=null,h=0,i="";for await(let b of(0,j.createInterface)({input:(0,e.createReadStream)(a,{encoding:"utf8"}),crlfDelay:1/0})){let a;if(!b.trim())continue;try{a=JSON.parse(b)}catch{continue}if(!g){if(a?.type!=="session")return null;g=a;continue}if(a?.type==="session_info"&&(d="string"==typeof a.name&&a.name.trim()?a.name.trim():void 0),a?.type!=="message")continue;h+=1;let c=a.message;if(!c||"string"!=typeof c.role||!("content"in c)||"user"!==c.role&&"assistant"!==c.role)continue;let e="number"==typeof c.timestamp?c.timestamp:new Date(a.timestamp).getTime();if(q(e)&&(f=Math.max(f??0,e)),!i&&"user"===c.role){let a=c.content;i=(0,o.K)("string"==typeof a?a:Array.isArray(a)?a.filter(a=>a?.type==="text").map(a=>a.text).join(" "):"")}}if(!g)return null;let k="string"==typeof g.timestamp?new Date(g.timestamp).getTime():0/0,l=q(k)?new Date(k):b.mtime,m=f&&f>0?new Date(f):l;return{path:(c={path:a,name:d,cwd:"string"==typeof g.cwd?g.cwd:"",created:l,modified:m,messageCount:h,firstMessage:function(a){if(a.length<=300)return a;let b=300,c=a.charCodeAt(b-1);return c>=55296&&c<=56319&&(b-=1),`${a.slice(0,b)}…`}(i)||"(no messages)"}).path,name:c.name,cwd:c.cwd,created:c.created.toISOString(),modified:c.modified.toISOString(),messageCount:c.messageCount,firstMessage:c.firstMessage}}catch{return null}}[k,l,m,n]=p.then?(await p)():p;let y=new Map,z=null,A=null,B=!1,C=null;async function s(){let a=i().join((0,m.$M)(),"piweb-session-index.json");if(A!==a){A=a,y.clear();try{let b=JSON.parse(await g().readFile(a,"utf8"));if(b?.version!==4||!b.entries||"object"!=typeof b.entries||Array.isArray(b.entries))return;for(let[a,c]of Object.entries(b.entries)){if(!Array.isArray(c)||3!==c.length)continue;let[b,d,e]=c;"number"==typeof b&&"number"==typeof d&&y.set(a,{mtimeMs:b,size:d,summary:e&&"object"==typeof e?e:null})}}catch{}}}async function t(){if(!B)return;B=!1;let a=A;if(!a)return;let b={};for(let[a,c]of[...y.entries()].sort((a,b)=>b[1].mtimeMs-a[1].mtimeMs).slice(0,5e3))b[a]=[c.mtimeMs,c.size,c.summary];try{await g().mkdir(i().dirname(a),{recursive:!0});let c=`${a}.${process.pid}.tmp`;try{await g().writeFile(c,JSON.stringify({version:4,entries:b}),"utf8"),await g().rename(c,a)}finally{await g().rm(c,{force:!0}).catch(()=>void 0)}}catch{}}async function u(){let a=i().join((0,m.$M)(),"sessions"),b=[],c=[];try{c=await g().readdir(a,{withFileTypes:!0})}catch{return[]}await Promise.all(c.filter(a=>a.isDirectory()||a.isSymbolicLink()).map(async c=>{try{for(let d of(await g().readdir(i().join(a,c.name))))d.endsWith(".jsonl")&&b.push(i().join(a,c.name,d))}catch{}}));let d=new Set,e=[],f=!1;for(let a=0;a<b.length;a+=16)await Promise.all(b.slice(a,a+16).map(async a=>{d.add(a);let b=await g().stat(a).catch(()=>null);if(!b?.isFile())return;let c=y.get(a);if(c&&c.mtimeMs===b.mtimeMs&&c.size===b.size){c.summary&&e.push(c.summary);return}let h=await r(a,b);y.set(a,{mtimeMs:b.mtimeMs,size:b.size,summary:h}),f=!0,h&&e.push(h)}));for(let a of y.keys())d.has(a)||(y.delete(a),f=!0);return f&&(B=!0,C||(C=setTimeout(()=>{C=null,t()},1500),C.unref?.())),e}let D=null;async function v(a){let b;if(D&&Date.now()-D.at<1200?b=D.list:(await s(),z??=u().finally(()=>{z=null}),b=await z,D={at:Date.now(),list:b},(0,l.yn)()),a?.trim()){let c=a.trim().toLowerCase();b=b.filter(a=>a.name?.toLowerCase().includes(c)||a.firstMessage.toLowerCase().includes(c)||a.cwd.toLowerCase().includes(c))}return b.sort((a,b)=>b.modified.localeCompare(a.modified)||a.path.localeCompare(b.path)),b}async function w(a){let b=i().join((0,m.$M)(),"sessions"),c=await g().realpath(b).catch(()=>i().resolve(b)),d=i().resolve(a);if(".jsonl"!==i().extname(d).toLowerCase()||!(0,n.CN)(b,d)&&!(0,n.CN)(c,d))throw new n.BV("session path is outside the Pi session store");let e=await g().realpath(d).catch(a=>{if("ENOENT"===a.code)return d;throw a});if(e!==d&&!(0,n.CN)(c,e))throw new n.BV("session path escapes the Pi session store");try{await g().unlink(d)}catch(a){if("ENOENT"!==a.code)throw a}}async function x(a){let b=k.SessionManager.open(a),c=[];try{c=(0,l.nK)(b)}catch{c=[]}let d="";try{d=b.getSessionName?.()??""}catch{d=""}return{cwd:b.getCwd(),name:d,messages:c}}d()}catch(a){d(a)}})}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
exports.id=7496,exports.ids=[7496],exports.modules={104:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23)),Promise.resolve().then(c.t.bind(c,60440,23)),Promise.resolve().then(c.t.bind(c,84342,23)),Promise.resolve().then(c.t.bind(c,82265,23)),Promise.resolve().then(c.t.bind(c,35421,23)),Promise.resolve().then(c.t.bind(c,61335,23)),Promise.resolve().then(c.t.bind(c,70664,23)),Promise.resolve().then(c.bind(c,74661))},1096:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23))},8e3:(a,b,c)=>{"use strict";c.d(b,{N:()=>e,h:()=>f});var d=c(48249);function e({size:a=18,className:b,style:c}){return(0,d.jsxs)("svg",{width:a,height:a,viewBox:"165.29 165.29 469.43 469.43","aria-hidden":!0,className:b,style:{color:"var(--dsw-label-primary)",display:"block",flex:"none",...c},children:[(0,d.jsx)("path",{fill:"currentColor",fillRule:"evenodd",d:"M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"}),(0,d.jsx)("path",{fill:"currentColor",d:"M517.36 400 H634.72 V634.72 H517.36 Z"})]})}function f({compact:a=!1}){return a?(0,d.jsx)(e,{size:18}):(0,d.jsxs)("div",{className:"inline-flex items-center select-none",style:{color:"var(--dsw-label-primary)",gap:6},children:[(0,d.jsx)(e,{size:17}),(0,d.jsx)("span",{className:"inline-flex items-center",style:{fontSize:16.5,fontWeight:600,letterSpacing:"-0.02em",color:"var(--dsw-label-primary)",lineHeight:1},children:"pi"}),(0,d.jsx)("span",{className:"inline-flex items-center justify-center font-bold",style:{fontSize:9.5,letterSpacing:"0.06em",height:15,paddingLeft:4.5,paddingRight:4.5,borderRadius:4,background:"var(--dsw-label-primary)",color:"var(--dsw-bg-base)",lineHeight:1,textTransform:"uppercase"},children:"HARNESS"})]})}},18874:()=>{},23635:()=>{},36552:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23)),Promise.resolve().then(c.t.bind(c,15098,23)),Promise.resolve().then(c.t.bind(c,47644,23)),Promise.resolve().then(c.t.bind(c,33859,23)),Promise.resolve().then(c.t.bind(c,98099,23)),Promise.resolve().then(c.t.bind(c,16237,23)),Promise.resolve().then(c.t.bind(c,98562,23)),Promise.resolve().then(c.t.bind(c,36675,23))},36593:()=>{},55091:(a,b,c)=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0}),Object.defineProperty(b,"default",{enumerable:!0,get:function(){return f}});let d=c(5735),e=c(22675);function f(){return(0,d.jsx)(e.HTTPAccessErrorFallback,{status:404,message:"This page could not be found."})}("function"==typeof b.default||"object"==typeof b.default&&null!==b.default)&&void 0===b.default.__esModule&&(Object.defineProperty(b.default,"__esModule",{value:!0}),Object.assign(b.default,b),a.exports=b.default)},59645:(a,b,c)=>{"use strict";function d(){return[{type:"image/svg+xml",sizes:"any",url:"/icon.svg?779ce17318f43f72"}]}c.r(b),c.d(b,{default:()=>d})},60587:()=>{},61135:()=>{},76537:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>g,metadata:()=>e,viewport:()=>f});var d=c(5735);c(18874),c(36593),c(61135);let e={title:"pi",description:"Web UI for the pi coding agent"},f={width:"device-width",initialScale:1,themeColor:[{media:"(prefers-color-scheme: light)",color:"#fcfbf9"},{media:"(prefers-color-scheme: dark)",color:"#2e3440"}]};function g({children:a}){return(0,d.jsx)("html",{lang:"zh-CN",suppressHydrationWarning:!0,children:(0,d.jsx)("body",{suppressHydrationWarning:!0,children:a})})}},78335:()=>{},87944:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23))},93961:(a,b,c)=>{"use strict";c.d(b,{I18nProvider:()=>i,s:()=>j});var d=c(48249),e=c(67484);let f={confirm:"确认",cancel:"取消",delete:"删除",rename:"重命名",renameSession:"重命名会话",renameWorkspace:"重命名工作区",search:"搜索",save:"保存",close:"关闭",error:"出错",copy:"复制",copyFailed:"复制失败",externalImage:"外部图片,点击加载",chatWidthHandle:"拖动调整对话宽度",editMessage:"编辑这条消息",sendEdit:"重新发送",editMessageFailed:"编辑重发失败",export:"导出",settings:"设置",newChat:"新会话",reconnecting:"连接中断,正在重连…",sessionListLoadFailed:"会话列表加载失败",retry:"重试",compacting:"正在压缩上下文…",compactionComplete:"上下文压缩完成",compactionFailed:"上下文压缩失败",pickWorkspaceFirst:"请先选择工作区",capacityFields:"容量",contextWindowLabel:"上下文窗口",maxTokensLabel:"最大输出",capacityHint:"留空按 pi 缺省(128K / 16K)\xb7 支持 256K / 2M 写法",visionLabel:"视觉",visionHint:"该模型能否接收图片。未声明时 pi 按纯文本处理:你贴的截图会被换成一行占位文字(提示语还会说成「模型不支持图像」)",visionUnset:"未声明",visionInputText:"文本",visionInputTextHint:"pi 总是接受文本输入;贴图能不能发由「图片」决定",visionInputImage:"图片",visionInputImageHint:"勾上表示该模型能收图(写进 models.json 的 input);不勾则按纯文本处理",visionOn:"有视觉",visionOff:"纯文本",imagePreview:"点击放大预览",imageViewer:"图片预览",imageClearAll:"清空图片",imagePrev:"上一张",imageNext:"下一张",chipExpandMore:"展开 {n}",chipCollapse:"收起",modelAuditTitle:"{n} 个模型没写能力字段",modelAuditDesc:"没写的字段,pi 会按上下文 {ctx}、输出上限 {out}、纯文本处理。端点没报的值不会替你猜:照模型的真实规格填上(支持 256K / 1M 写法),保存时只补空着的格子,已写的值不改。",modelAuditColModel:"模型",modelAuditColContext:"上下文",modelAuditColOutput:"输出上限",modelAuditColVision:"视觉",modelAuditVisionQuick:"视觉一起设:",modelAuditVisionOn:"都有视觉",modelAuditVisionOff:"都是纯文本",modelAuditSave:"保存 {n} 个模型",modelAuditSaveIdle:"填好后保存",capacityInvalid:"第 {n} 行:容量需为数字(可用 K/M)",discoverEmpty:"远端没有返回可识别的模型",candidateTitle:"发现 {count} 个模型,勾选要添加的",candidateAll:"全选",candidatePicked:"已选 {n} 个",candidateAdopt:"添加 {n} 个",candidateInCatalog:"已在目录中",runningTool:"Running {name}…",thinkingLive:"Thinking",stepRunning:"Running",stepRan:"已运行",stepRead:"读取",stepSearched:"搜索",stepEdited:"编辑了",stepWrote:"写入了",resultRead:"读取了 {n} 行",resultFound:"找到 {n} 处",resultWrote:"{n} 行",sumThought:"思考了 {d}",sumRan:"运行了 {n} 条命令",sumRan1:"运行了 {n} 条命令",sumRead:"读了 {n} 个文件",sumRead1:"读了 {n} 个文件",sumSearched:"搜索了 {n} 次",sumSearched1:"搜索了 {n} 次",sumJoin:",",toolLines:"{n} 行",toolMatches:"{n} 个匹配",toolExit:"退出码 {code}",toolWritten:"已写入",diffSummary:"+{add} −{del} 行",deletedFile:"已删除 {path}",backToBottom:"回到底部",modeSteer:"插话",modeQueue:"排队",sendSteer:"插话:当前工具跑完就送达",sendQueue:"排队:本轮结束后发送",queueEdit:"↑ 取回编辑",queueDrop:"丢弃",viewInTrajectory:"在轨迹中查看",turnRanFor:"耗时 {duration}",durationSeconds:"{seconds} 秒",durationMinutes:"{minutes} 分 {seconds} 秒",clockMd:"{m}月{d}日",clockYmd:"{y}年{m}月{d}日",turnUsageTitle:"本回合用量",filesPanel:"文件",outline:"大纲",moreActions:"更多",filesFilter:"筛选文件…",filesShowAll:"显示 node_modules 等",filesHideNoise:"隐藏 node_modules 等",fileReference:"引用到输入框",fileOpenEditor:"在编辑器中打开",fileChangedByPi:"本会话中被 pi 修改",fileRenderMarkdown:"渲染",fileRawSource:"源码",gitUnavailable:"未找到 git 命令,请确认已安装并加入 PATH。",gitUpstream:"上游 {name}",gitNoUpstream:"无上游分支",gitConflict:"冲突",gitAskCommit:"让 pi 提交",gitDetails:"Git 详情",gitAskCommitPrompt:"请检查当前工作区的变更,把相关改动分组提交,写清晰的 commit message。",gitDiffEmpty:"没有差异",gitDiffTruncated:"差异过长,已截断",gitBinary:"二进制文件,不显示差异",gitStagedDiff:"暂存区差异",gitWorktreeDiff:"工作区差异",gitNoCommits:"尚无提交",gitBack:"返回",gitPanel:"Git",panelRefresh:"刷新",panelLoading:"加载中…",filesEmpty:"空目录",filesBack:"返回",fileBinary:"二进制文件,不提供预览",filePreviewTruncated:"文件较大,仅显示前 256 KB",entriesTruncated:"目录条目过多,仅显示前 2000 项",gitNotRepo:"此工作区不是 Git 仓库。",gitDetached:"分离头指针",gitAhead:"领先 {n}",gitBehind:"落后 {n}",gitStaged:"已暂存",gitUnstaged:"未暂存",gitUntracked:"未跟踪",gitNoChanges:"工作区干净,没有变更",gitStatusUnknown:"Git 状态读取失败,无法确认是否有变更",gitRecentCommits:"最近提交",gitStagingArea:"暂存区",gitWorkingTree:"工作区",gitGithubAccount:"GitHub 账号",gitGithubUnknown:"未识别到 GitHub 账号",toolNoOutput:"无输出",toolFailed:"失败",thinkingClamped:"当前模型不支持「{requested}」,已改为「{level}」",modelError:"模型返回错误",modelErrorTimes:"连续 {n} 次",modelErrorRateLimit:"限流:请求过于频繁,稍等片刻再试",modelErrorBilling:"余额或配额不足",modelErrorAuth:"鉴权失败:检查该供应商的 API Key",modelErrorNotFound:"模型不存在或当前 Key 无权访问",modelErrorContext:"上下文超出模型窗口,可用 /compact 压缩后重试",modelErrorTimeout:"请求超时",modelErrorServer:"供应商服务端出错或过载",modelErrorModeration:"请求内容被供应商审核拦截(敏感词),换措辞或新开会话试试",modelErrorNetwork:"网络连接失败",turnAborted:"已中止",moreLines:"还有 {n} 行",commandLines:"{n} 行脚本",thinkLabel:"思考",expandOutput:"展开全部输出",expandDiff:"展开改动",collapseOutput:"收起",workspaces:"工作区",pickFolderTitle:"选择工作区文件夹",pickFolderUp:"上一级",pickFolderConfirm:"选择此文件夹",pickFolderEmpty:"此目录下没有子文件夹",pickFolderTruncated:"只列出前 {n} 个文件夹",pickFolderLoading:"读取中…",searchSessions:"搜索会话...",addWorkspace:"添加工作区",groupBy:"分组方式",sortBy:"排序方式",byWorkspace:"按工作区",flatList:"单列表",manualOrder:"按创建时间",recentUpdated:"最近更新",newSessionHere:"在此工作区新会话",removeWorkspace:"从列表移除",deleteWorkspace:"删除工作区",deleteWorkspaceConfirm:"将把“{name}”从工作区列表中移除。文件夹与会话记录会保留,其会话将显示在“未分组”下。",deleteWorkspacePending:"正在删除工作区…",workspaceNameConflict:"已存在名为“{name}”的工作区。",ungrouped:"未分组",forkSession:"在新对话中分支",archiveSession:"归档会话",unarchiveSession:"取消归档",archivedSessions:"已归档",deleteAllSessions:"删除全部会话",deleteAllConfirm:"删除此工作区的全部会话?不可恢复。",contextInject:"上下文注入",autoCompact:"自动压缩",settingsLoading:"正在读取设置…",settingsLoadFailed:"设置读取失败;未显示默认值。请重试。",settingsSaveFailed:"设置未保存,请检查输入或网络后重试。",settingsRetry:"重试",autoCompactDesc:"上下文超出阈值时自动压缩历史",reserveTokens:"保留 Token",keepRecentTokens:"近期保留",autoRetry:"自动重试",autoRetryDesc:"请求失败后的自动重试",maxRetries:"最大重试次数",baseDelayMs:"初始延迟 (ms)",reloadExtensions:"重载全部扩展",cycleModel:"循环切换模型",cycleModelHint:"循环模型(Shift 点击切换到前一个)",branches:"分支",noBranches:"暂无可跳转的分支节点",oauthLogin:"OAuth 登录",authMethod:"认证方式",webAuth:"访问认证",webAuthTokenOn:"已启用(启动令牌)",loginTokenTitle:"这个实例用启动令牌登录",loginTokenDesc:"请打开启动 PiWeb 时终端里打印的登录链接(形如 …/?token=…),或在已登录的电脑上打开 设置 → 远程连接,复制带令牌的地址。令牌每次重启都会更换;打开一次后浏览器会记住 30 天。",logout:"退出登录",authMethodApiKey:"API 密钥",oauthDevicePrompt:"请在浏览器中完成授权",oauthOpenAuth:"打开授权页面",oauthDeviceCode:"设备码",oauthCodeCopied:"已复制",usageQuotaLabel:"API 配额",usageRequests:"请求",usageRefresh:"刷新配额",usageProbe:"检测配额",usageProbing:"检测中…",usageProbeDisclosure:"检测会向 xAI 发送一次可能计费的最小请求。",usageProbeFailed:"配额检测失败,未获得用量信息。",usagePlan:"套餐",usageQuotaRemaining:"额度剩余",queryingQuota:"正在查询额度…",usageReadOnlyDisclosure:"读取提供商的只读用量端点,不消耗额度。",usageReset:"刷新时间",usageWindowWeekly:"周限",usageWindowMonthly:"月限",usageWindowHours:"{n} 小时",usageWindowDays:"{n} 天",usageWindowRolling:"滚动窗口",usageWindowChat:"对话",usageWindowCompletions:"补全",usageWindowPremium:"高级请求",usageVariantOpus:"Opus",usageVariantCode:"代码",usageBalanceGranted:"赠金",usageBalanceToppedUp:"充值",usageBalanceVoucher:"代金券",usageBalanceCash:"现金",usageBalanceUsed:"已用",usageBalanceLimit:"上限",oauthWait:"等待授权…",oauthCancel:"取消登录",noSessions:"暂无会话",startWith:"新建工作区",inputPlaceholder:"给 pi 发消息…",thinking:"思考",thinkingOff:"关闭",model:"模型",selectModel:"选择模型",triggerLoading:"正在加载模型…",blockedComposer:"当前模型不可用,请先选择模型",emptyModels:"没有可用的模型。",emptyEfforts:"当前模型未提供推理等级。",thinkingUnsupported:"此模型不支持",thinkingUnsupportedHint:'模型没有声明推理能力。自定义模型请在 ~/.pi/agent/models.json 里给该模型加 "reasoning": true(可选 thinkingLevelMap 指定档位)',toolReadonly:"Read Only",toolStandard:"Workspace Write",toolFull:"Full access",stop:"停止",send:"发送",imageAttachment:"图片附件",imageTooLarge:"单张图片不能超过 20 MB",imageCountLimit:"一次最多添加 20 张图片",imageTypeUnsupported:"仅支持 JPEG、PNG、WebP 和 GIF 图片",dropToAttach:"松开添加附件",dropToAttachHint:"图片直接附到消息;其他文件(压缩包/文档等)保存后以路径引用,模型可用工具读取",dropLimits:"图片 ≤ 20MB \xb7 最多 20 张 \xb7 其他文件 ≤ 100MB \xb7 最多 16 个",uploading:"正在上传…",uploadFailed:"上传失败",uploadTooLarge:"单个文件不能超过 100 MB",uploadCountLimit:"一次最多添加 16 个文件",attachmentLine:"附件:{path}({size})",cmdMenu:"命令",slashCatalog:"命令与技能",skillType:"技能",cmdCompact:"压缩更早的对话历史",cmdExport:"下载本会话日志",cmdModel:"选择本会话使用的模型",cmdNew:"新建会话",cmdFork:"分叉会话",cmdReload:"重载扩展、技能与提示模板(pi /reload)",promptType:"模板",extensionCmdType:"扩展",cmdUnknown:"没有这个命令:/{name}。可用命令见输入框的 / 菜单",extensionDialogTag:"扩展",extensionStatus:"扩展状态",contextUsed:"上下文已用",contextUnknown:"上下文用量未知",contextEstimated:"上下文估算",contextMeasured:"上下文用量",contextBackground:"Main Conversation",contextApiInput:"最近请求输入(API)",contextChars:"字符",contextSystem:"系统提示词",contextMessages:"对话消息",contextTools:"工具",promptPanel:"提示词来源",promptRefresh:"刷新",promptLoading:"加载中…",promptColdHint:"会话尚未启动:先列出磁盘上的提示词文件;打开会话后才会出现「组装后的系统提示词」与工具定义。",promptOriginProject:"项目",promptOriginAgent:"个人",promptOriginPackage:"包",promptOriginExtension:"扩展",promptKindSystem:"系统提示词文件",promptKindAppend:"追加提示词",promptKindAgents:"项目记忆(AGENTS.md)",promptKindSkill:"技能提示词",promptKindTemplate:"提示模板",promptKindTool:"工具提示词",promptKindAssembled:"系统提示词",promptKindCompacted:"压缩摘要",promptCompactedKey:"进入上下文的压缩摘要",promptGuidelines:"提示词指南",promptParameters:"参数定义",promptAssembledKey:"当前生效的系统提示词",promptToolBuiltin:"内置",promptToolExtension:"扩展",contextSystemPrompt:"System Prompt",contextSystemTools:"System Tools",contextCustomTools:"Custom Tools",contextMemory:"Memory(AGENTS.md)",contextSkills:"Skills",contextUserMessages:"User Messages",contextAgentText:"Agent Text",contextAgentThinking:"Agent Thinking",contextAgentToolCall:"Agent Tool Call",contextToolOutput:"Tool Output",contextCompacted:"Compacted Data",contextAutoCompactBuffer:"Auto-Compact Buffer",contextFreeSpace:"Free Space",contextColdHint:"会话还没启动,System Prompt 和工具定义要启动后才算得出",contextCountNow:"现在统计",contextCounting:"统计中…",contextWindowEdit:"修改",contextWindowBuiltin:"pi 内置目录:{value}",contextWindowUseBuiltin:"填入",contextWindowScope:"改的是这个模型的全局配置(models.json),pi 终端和其它会话一起生效",contextWindowOverBuiltin:"比内置目录大:超过模型实际上限时,请求会被上游拒绝(400)",contextWindowNoBuiltin:"填模型实际支持的上限;填大了,请求会被上游拒绝(400)",contextWindowInvalid:"填正整数,可带 K / M(如 200K)",mentionFiles:"@ 引用文件 / 文件夹",mentionHint:"↑↓ 选择 \xb7 Enter 引用 \xb7 Esc 关闭",mentionNoMatch:"没有匹配的文件",mentionTruncated:"候选已截断",mentionDiskSource:"目录遍历",mentionDiskSourceHint:"当前工作区不是 git 仓库(或没装 git):候选来自目录遍历,会跳过 node_modules、构建产物等目录;列为 git 仓库后候选会自动按 .gitignore 过滤",turns:"轮次",toolCalls:"工具调用",cost:"花费",duration:"耗时",cacheHits:"缓存命中",statsCounts:"{turns} 轮 \xb7 {steps} 步",ttftAverage:"首 token 平均",inputTokens:"输入",outputTokens:"输出",tabChat:"对话",tabTrajectory:"轨迹",sessionLog:"Session log",sessionDetails:"会话详情",exportJsonl:"导出 JSONL",trajTimeline:"时间轴",trajModeSeq:"等距",trajModeTime:"时间",trajModeDur:"间隔",trajEmpty:"本会话还没有轨迹记录",trajSearchPlaceholder:"搜索轨迹",trajNoMatch:"没有匹配的轨迹记录",trajInput:"输入",trajModel:"模型",trajTools:"工具",trajOutput:"输出",trajThink:"思考",trajTime:"时间",trajTurn:"轮次",trajSystem:"系统",trajSession:"会话",trajSummary:"摘要",trajPreview:"预览",trajRaw:"原始",trajSource:"来源",trajStatus:"状态",trajCompleted:"已完成",trajFailed:"失败",trajStarted:"开始时间",trajTokens:"Token 用量",trajNoContent:"此记录没有可显示的内容",encodingLossWarning:"这段历史工具输出在写入时已经损坏,无法恢复的行已隐藏。当前 Pi SDK 已对新的 PowerShell 输出强制使用 UTF-8。",ttft:"首 token",decode:"解码",inspector:"记录详情",setGeneral:"通用设置",setModels:"模型",enterBehavior:"繁忙时 Enter 键行为",enterBehaviorDesc:"仅在 pi 运行时生效;Ctrl/Cmd+Enter 用另一种方式发送",enterQueue:"排队:本轮结束后发送",enterSteer:"插话:当前工具跑完就送达",setSkills:"技能",importSessions:"导入会话",importDesc:"把本机 Codex / Claude Code / Grok / ZCode / dsh / opencode 的对话无损导入成 pi 会话:文本、思考、工具调用与结果、时间戳、用量都保留。源项目目录还在本机就导回原工作区,否则落到下面选的兜底工作区。只读源数据,不修改源工具的任何文件。",importRescan:"重新扫描",importScanning:"扫描中…",importSourceClaude:"Claude Code",importSourceCodex:"Codex",importSourceGrok:"Grok",importSourceZcode:"ZCode",importSourceDsh:"dsh",importSourceOpencode:"opencode",importSourceError:"{source} 扫描失败:{message}",importGroupCount:"{n} 条 \xb7 已导入 {imported}",importPickSource:"选择来源",importLimitHint:"每个来源只列最近 {n} 条对话(更早的会话不扫描,省时省资源)",importLimitHintTooltip:"看更早的会话:把 src/lib/session-import/index.ts 里的 SCAN_LIMIT_PER_SOURCE 调大",importSelectAll:"全选本组",importSelectNone:"清空本组",importClearSelection:"清空选择",importRun:"导入所选 ({n})",importRunning:"导入中…",importFallbackWorkspace:"兜底工作区",importFallbackHint:"原项目目录已不在本机时落到这里",importWhereGoes:"导入去向",importGoesOriginal:"回到原工作区",importGoesFallback:"原目录已不在,用兜底工作区",importAlready:"已导入",importUntitled:"(无标题)",importNoProject:"(无项目目录)",importMessages:"{n} 条消息",importEmpty:"没有找到可导入的本地会话",importReportSummary:"成功 {imported} \xb7 跳过 {skipped} \xb7 失败 {failed}",drawerPanel:"右侧抽屉",drawerSections:"抽屉入口",drawerPrompts:"提示词",sideChat:"旁聊",sideChatModel:"旁聊模型",sideChatFollowMain:"跟随主会话",sideChatNew:"新旁聊",sideChatHistory:"旁聊记录",sideChatMessages:"旁聊消息",sideChatQuestion:"旁聊提问",sideChatPlaceholder:"读到哪里有疑问,就在这里问…",sideChatEmpty:"边读边问,主会话停在原处",sideChatHint:"参考主会话,问答独立。记录仅保存在此浏览器。",sideChatPickSession:"打开一个主会话后,就可以旁聊",sideChatAnswering:"正在回答…",sideChatContextTruncated:"背景较长,本次仅参考了部分主会话或旁聊记录。",sideChatLengthLimited:"已达到本次输出上限,可以继续追问。",sideChatStorageFailed:"浏览器未能保存旁聊记录,请先保留需要的内容。",setPlugins:"插件",setRemote:"远程连接",remoteBuiltin:"内置插件",remoteLanTitle:"局域网入口",remoteLanHint:"同一个 WiFi 下的设备直接打开下面地址即可,手机排版已适配。默认开启。链接带登录令牌:点「复制」发到手机,打开就直接登录;令牌即凭据,别发给别人。",remotePublicTitle:"公网入口",remotePublicHint:"开启后任何浏览器都能打开,无需安装客户端。地址由 Cloudflare 随机分配,每次启动都会变。链接同样带登录令牌。",remoteLinkCopied:"已复制(含令牌)",remoteStart:"开启远程连接",remoteStop:"关闭",remoteWorking:"启动中…",remoteRunning:"运行中",remoteStopped:"未开启",remotePending:"地址已生成,生效中…",remoteEngineMissing:"找不到 cloudflared。请安装后重试,或用 PIWEB_CLOUDFLARED 指定它的路径。",remoteFailed:"操作失败",remoteBlockedAuth:"认证没开,远程连接不可用:开出去就是一个免密入口。请用 piweb 启动器启动,或设 PI_WEB_AUTH=1。",remoteBlockedDev:"开发模式只服务本机,远程连接不可用。请先构建,再用生产模式启动。",remoteSessionsTitle:"已登录的设备",remoteSessionsHint:"手机、别的电脑登录后一直有效(30 天)。设备丢了或链接被别人拿到时,可以让所有设备(包括这台)都要重新用启动令牌登录。",remoteSignOutAll:"让所有设备重新登录",remoteSignOutAllConfirm:"再点一次确认",appearance:"外观",appearanceMode:"亮暗模式",themeLight:"浅色",themeDark:"深色",themeSystem:"跟随系统",themeSilverSteel:"银钢",themeLimestoneCoal:"石灰与煤炭",themeLinenMoss:"亚麻与苔绿",themeNordPaper:"北欧纸墨",themePebrel:"Pebrel",themeDsh:"海与墨",fontSize:"正文字号",fontUiSize:"界面字体",fontUiSizeDesc:"侧栏、按钮、标签等界面文字",fontChatSize:"对话字体",fontChatSizeDesc:"消息正文、用户气泡与输入框",fontUiFamily:"界面字体族",fontUiFamilyDesc:"侧栏、按钮、标签等界面文字使用的字体",fontMonoFamily:"代码字体族",fontMonoFamilyDesc:"代码块、diff、行内代码使用的等宽字体",fontCustom:"自定义…",fontCustomPlaceholder:"输入字体栈,如 Fira Code, monospace",language:"界面语言",openConfigFile:"打开配置文件",providerAuthOk:"已配置",providerReady:"请求认证可用",authUnavailable:"凭据不可用",credentialSource:"凭据:{source}",authSourceRuntime:"运行时",authSourceEnvironment:"环境变量",authSourceCommand:"models.json 命令",authSourceProvider:"Provider 配置",apiKey:"API Key",apiKeyStored:"已保存;留空保持不变",providerIdImmutable:"Provider ID 创建后不可修改;如需更名,请删除后重建。",modelConfigReopen:"模型配置已保存并立即生效;正在回答的会话在本轮结束后生效。",customModelIdentityNotice:"自定义模型 ID 只是发往该 API 地址的路由名;PiWeb 不会自动下载、接入或识别本机 Ollama 模型。",customApiKeyHint:"可留空改用 auth.json;指向本机/私网的无鉴权服务(Ollama 等)保存时自动填占位值。",modelsTitle:"模型",modelsDesc:"填入各提供方的 API 密钥即可使用其模型。",addProvider:"添加提供方",addCustomProvider:"添加自定义提供方",customProviderTitle:"自定义提供方",edit:"编辑",customBadge:"自定义",providerLabel:"提供方",apiType:"API 类型",modelsList:"模型(每行一个 ID)",baseUrl:"Base URL",apiAddress:"API 地址",apiProtocol:"API 协议",apiKeyOptional:"输入 API 密钥,或留空使用环境认证",customSettings:"自定义设置",providerDefault:"提供方默认",selectProvider:"选择提供方",searchProviders:"搜索提供方名称或 ID",noProviderMatches:"没有匹配的提供方",modelCount:"{count} 个模型",providerId:"Provider ID",providerIdHint:"以小写字母开头的标识,在请求中唯一标识该提供方,并用于派生凭据名。",providerIdInvalid:"只能使用小写字母、数字和单个连字符分段。",providerIdTaken:"该 Provider ID 已存在。",displayName:"显示名称",displayNameOptional:"显示名称(可选)",modelCatalog:"模型目录",discoverModels:"获取可用模型",allowPrivateDiscovery:"允许本机/私网",allowPrivateHint:"模型地址指向本机或私有网络(如 Ollama、LM Studio、one-api 本地网关)时勾选,本次探测放行;发消息不受此限制",discoveringModels:"获取中...",autoDiscovering:"正在自动识别模型…",autoDiscovered:"已自动识别 {n} 个模型(端点报了容量与视觉的已一并填好)",autoDiscoverFailed:"自动识别失败,可点「获取可用模型」重试",usingDefaultModels:"正在使用 Pi SDK 默认模型 \xb7 {count} 个",customModelsRequired:"至少添加一个可发送的模型 ID",modelCatalogEmptyBuiltin:"未添加覆盖模型;模型选择器会继续实时使用 Pi SDK 的官方模型目录。",modelCatalogEmptyCustom:"模型选择器中将不显示任何模型;请至少添加一个模型 ID。",catalogOverrideHint:"与内置目录同 ID 的行只覆盖填写的字段,推理、价格、思考档位等沿用内置值。",addModel:"添加模型",modelId:"模型 ID",createProvider:"创建提供方",saving:"保存中...",setKey:"保存 Key",removeKey:"移除 Key",removeOAuth:"移除 OAuth",confirmRemoveOAuth:"确定移除“{name}”的 OAuth 登录吗?移除后需重新登录才能使用。",confirmRemoveProvider:"确定删除提供方“{name}”及其配置吗?",confirmRemoveKey:"确定移除“{name}”的已保存密钥吗?",customProviders:"自定义 Provider(models.json)",toolsSection:"工具启用情况",toolsSectionDesc:"三档预设决定新会话的默认工具;打开会话后可逐个启停当前会话的工具(仅本会话生效)。",toolsCurrentSession:"当前会话",toolsActiveCount:"{n}/{total} 已启用",toolsNoSession:"打开一个会话后,这里会显示可用工具并支持逐个启停。",securityToolPreset:"权限",securityToolPresetDesc:"切换当前会话工具集;Workspace Write 包含 bash,并非文件系统沙箱",securityTrust:"项目信任",securityTrustDesc:"首次进入含 .pi/ 资源的项目时是否自动信任(写入 pi settings.json)",trustAsk:"每次询问",trustAlways:"总是信任",trustNever:"从不信任",versionPiweb:"PiWeb 版本",versionPiwebDesc:"本 Web 应用的版本;启动时自动检查,有新版本在这里直接更新(点版本号打开仓库)",versionPi:"Pi 版本",versionPiDesc:"pi 智能体内核的版本;启动时自动检查,有新版本在这里直接更新(点版本号打开仓库)",checkUpdate:"检查更新",checkingUpdate:"检查中…",upToDate:"已是最新",updateTo:"更新到 {v}",updatingNow:"更新中…",updatedTo:"已更新到 {v},重启 PiWeb 后生效",updateFailed:"更新失败",updateManualHint:"先停止 piweb,再执行上面的命令(Windows 无法替换运行中的安装目录)",updateCopied:"已复制",updateBusy:"有会话正在运行,等它结束再更新",updateCommits:"main 新增 {n} 个提交",updateNoticeTitle:"有新版本",updateNoticeUpdatingTitle:"正在更新…",updateNoticeDoneTitle:"更新完成",updateNoticeUpdate:"更新",updateNoticeLater:"稍后",updateNoticeOk:"知道了",updateNoticeUpdated:"已更新到 {v}",updateRunCommandHint:"先停掉 piweb,再在终端运行:",updateRestartHint:"重启 PiWeb 后生效:在运行 piweb 的终端按 Ctrl+C,再重新运行 piweb",skillsDesc:"关闭后技能不会出现在系统提示中,仅可通过 /skill:名称 手动调用",confirmDeleteSkill:"确定删除技能“{name}”吗?将删除其所在技能目录,不可恢复。",deleteSkillHint:"删除技能目录",skillDeletePackageHint:"包技能请用禁用管理",scopeGlobal:"全局",scopeProject:"项目",scopePackage:"包",viewSkillFile:"查看 SKILL.md",packages:"已安装的 pi 包",packagesEmpty:"尚未安装任何 pi 包",addPackage:"安装 pi 包",addPackagePlaceholder:"npm:包名 / git:https://… / 本地路径",installLocal:"安装到当前项目(-l)",install:"安装",uninstall:"卸载",confirmUninstallPackage:"确定卸载“{source}”吗?",update:"更新",pluginConfig:"插件配置",pluginList:"插件列表",pluginPageDesc:"配置和查看本部署已安装的插件。",searchPlugins:"搜索插件",enabled:"已启用",disabled:"已停用",enablePlugin:"启用",disablePlugin:"停用",updating:"正在更新...",uninstalling:"正在卸载...",updateSuccess:"更新成功",uninstallSuccess:"已卸载",extensionsEmpty:"没有已加载的扩展",extensionLoadError:"加载失败",resourceDiagnostics:"资源诊断",installing:"正在安装…",installSuccess:"已安装并加载",reloadedSessions:"已重载:{loaders} 个加载器 \xb7 {sessions} 个会话",projectTrustBanner:"此项目含 .pi/ 扩展或技能,pi 需要你的信任才会加载并执行它们",projectTrustBannerNever:"此项目的 .pi/ 扩展与技能已被设为不信任,不会加载",projectTrustAllow:"信任并加载",projectTrustDeny:"不信任",projectTrustForget:"重新询问",projectTrustTrusted:"项目已信任",projectTrustUntrusted:"项目未信任",resources:"携带",toastSaved:"已保存",toastError:"操作失败",running:"运行中",projectPanel:"项目",growthScopeRound:"本轮",growthScopeSession:"本会话累计",growthOnlyChanges:"只看改动",growthPickRound:"选择轮次",growthRoundJump:"输入轮号...",growthRoundJumpHint:"输入轮号后按回车跳到该轮",growthPrev:"上一轮",growthNext:"下一轮",growthRoundPosition:"第 {current}/{total} 轮",growthRecordNow:"立即记录:把当前改动记为「你的修改」",growthRecordNone:"没有新的改动",growthNoRounds:"还没有记录。发一条消息让 pi 开始工作,每一轮的改动会出现在这里。",growthLoading:"正在读取记录…",growthNoChangesRound:"本轮无文件改动",growthNoSession:"打开或新建一个会话后,这里会显示项目的生长过程。",growthUnavailable:"机器上找不到 git,项目生长功能不可用",growthUnavailableFallback:"生长记录不可用(找不到可用的 git),已显示当前目录结构",growthConsentTitle:"要为这个工作区开启生长记录吗?",growthConsentNotGit:"生长记录会把 pi 每一轮的改动存成 git 提交,方便回看和对比。这个目录还不是 git 仓库,开启后会在这里执行 git init(新建 .git 目录)。",growthConsentNested:"生长记录会把 pi 每一轮的改动存成 git 提交,方便回看和对比。这个目录是另一个仓库({parent})的子目录,开启后会在这里再建一个嵌套的 git 仓库,外层仓库会把它当成一个子仓库看待。",growthConsentNote:"记录挂在专用引用 refs/piweb/rounds/… 上,不动分支和暂存区。选择会按工作区记住。",growthConsentAllow:"开启并建仓库",growthConsentDecline:"不记录",growthRoundLabel:"第 {n} 轮",growthKindUser:"你的修改",growthRoundFiles:"{n} 个文件",growthJumpToChat:"在对话里看",growthRunning:"本轮进行中…",growthStatusAborted:"已中止",growthStatusError:"出错",growthStatD:"删除",growthPending:"生成中",growthLazyDir:"当前磁盘条目,不在所选这一轮的记录中",growthTruncated:"这一轮变更过多,只显示前 2000 条",chatRoundChanged:"本轮改了 {n} 个文件",chatRoundNoChanges:"本轮没有改动文件",chatRoundShow:"在项目栏里查看这一轮",growthExpandAll:"展开全部",growthCollapseAll:"收起全部",growthFilter:"筛选…",viewerModeDiff:"变更",viewerModeContent:"内容",viewerModeRender:"渲染",viewerFold:"折叠未改动",viewerUnfold:"展开未改动",viewerFoldedLines:"\xb7\xb7\xb7 {n} 行未改动 \xb7\xb7\xb7",viewerPrevChange:"上一处改动",viewerNextChange:"下一处改动",viewerFullscreen:"全屏",viewerExitFullscreen:"退出全屏",viewerQuickOpen:"输入文件名打开…",viewerQuickOpenEmpty:"没有匹配的文件",viewerNoChanges:"这一范围内此文件没有变化",viewerDeleted:"此文件在本轮被删除,显示的是删除前的内容",viewerHistorical:"此文件已不在当前快照中,显示最近一次记录的内容",viewerMissing:"此文件已不在当前快照或磁盘中",viewerPatchTruncated:"差异过大,已截断",viewerCloseTab:"关闭页签",viewerNotInSnapshot:"此文件不在快照里(超过 1MB 或被排除),显示磁盘上的当前内容",viewerLoadFailed:"加载失败",viewerEmpty:"从左侧树里选择一个文件",viewerOpenFolder:"打开文件夹预览",viewerDirHint:"文件夹:共 {n} 项(已按 .gitignore 过滤)",viewerDirMore:"加载更多",streamStyleTitle:"流式输出样式",streamStyleDesc:"回答逐字出现的方式;改完立刻生效,正在流出的回答也一并换",streamStyleSmooth:"平滑",streamStyleSmoothDesc:"匀速长出,不跳字",streamStyleTypewriter:"打字机",streamStyleTypewriterDesc:"固定节奏逐字敲出",streamStyleFade:"渐显",streamStyleFadeDesc:"整词推进,段落柔和淡入",streamStyleInstant:"即时",streamStyleInstantDesc:"立即显示,不做平滑",streamSpeedTitle:"推进速度",streamSpeedDesc:"平滑 / 打字机 / 渐显的节奏快慢;即时样式不受影响",streamSpeed1:"慢",streamSpeed2:"较慢",streamSpeed3:"标准",streamSpeed4:"快",streamSpeed5:"极快",streamCaretTitle:"打字光标",streamCaretDesc:"流式期间在文字末尾显示闪烁光标"},g={zh:f,en:{confirm:"Confirm",cancel:"Cancel",delete:"Delete",rename:"Rename",renameSession:"Rename session",renameWorkspace:"Rename workspace",search:"Search",save:"Save",close:"Close",error:"Error",copy:"Copy",copyFailed:"Copy failed",externalImage:"External image — click to load",chatWidthHandle:"Drag to resize the conversation",editMessage:"Edit this message",sendEdit:"Send again",editMessageFailed:"Edit and resend failed",export:"Export",settings:"Settings",newChat:"New session",reconnecting:"Connection lost, reconnecting…",sessionListLoadFailed:"Failed to load sessions",retry:"Retry",compacting:"Compacting context…",compactionComplete:"Context compaction complete",compactionFailed:"Context compaction failed",pickWorkspaceFirst:"Select a workspace first",capacityFields:"Capacities",contextWindowLabel:"Context window",maxTokensLabel:"Max output",capacityHint:"blank = pi default (128K / 16K) \xb7 256K / 2M accepted",visionLabel:"Vision",visionHint:"Whether this model accepts images. Left unset, pi treats it as text-only and replaces pasted screenshots with a placeholder line.",visionUnset:"Not declared",visionInputText:"Text",visionInputTextHint:"pi always accepts text; whether images can be sent is decided by the Image box",visionInputImage:"Image",visionInputImageHint:"Checked means this model accepts images (written into models.json input); unchecked is treated as text-only",visionOn:"Vision",visionOff:"Text only",imagePreview:"Click to preview",imageViewer:"Image preview",imageClearAll:"Clear images",imagePrev:"Previous image",imageNext:"Next image",chipExpandMore:"Show {n} more",chipCollapse:"Collapse",modelAuditTitle:"{n} models don't declare their capabilities",modelAuditDesc:"For fields left out, pi assumes a {ctx} context window, {out} max output and text-only input. Values the endpoint didn't report are never guessed: fill in the model's real limits (256K / 1M accepted). Saving only fills empty cells and never changes values already set.",modelAuditColModel:"Model",modelAuditColContext:"Context",modelAuditColOutput:"Max output",modelAuditColVision:"Vision",modelAuditVisionQuick:"Set vision for all:",modelAuditVisionOn:"All vision",modelAuditVisionOff:"All text only",modelAuditSave:"Save {n} models",modelAuditSaveIdle:"Fill in, then save",capacityInvalid:"Row {n}: capacity must be a number (K/M ok)",discoverEmpty:"No recognizable models returned",candidateTitle:"Found {count} models — pick ones to add",candidateAll:"Select all",candidatePicked:"{n} selected",candidateAdopt:"Add {n}",candidateInCatalog:"Already in catalog",runningTool:"Running {name}…",thinkingLive:"Thinking",stepRunning:"Running",stepRan:"Ran",stepRead:"Read",stepSearched:"Searched",stepEdited:"Edited",stepWrote:"Wrote",resultRead:"Read {n} lines",resultFound:"Found {n} matches",resultWrote:"{n} lines",sumThought:"Thought for {d}",sumRan:"ran {n} shell commands",sumRan1:"ran {n} shell command",sumRead:"read {n} files",sumRead1:"read {n} file",sumSearched:"searched {n} times",sumSearched1:"searched once",sumJoin:", ",toolLines:"{n} lines",toolMatches:"{n} matches",toolExit:"exit {code}",toolWritten:"written",diffSummary:"+{add} −{del} lines",deletedFile:"deleted {path}",backToBottom:"Back to bottom",modeSteer:"steer",modeQueue:"queue",sendSteer:"Steer: delivered after the current tool call",sendQueue:"Queue: sent after this turn ends",queueEdit:"↑ Edit queued",queueDrop:"Discard",viewInTrajectory:"View in trajectory",turnRanFor:"ran for {duration}",durationSeconds:"{seconds}s",durationMinutes:"{minutes}m {seconds}s",clockMd:"{m}/{d}",clockYmd:"{y}/{m}/{d}",turnUsageTitle:"Turn usage",filesPanel:"Files",outline:"Outline",moreActions:"More",filesFilter:"Filter files…",filesShowAll:"Show node_modules etc.",filesHideNoise:"Hide node_modules etc.",fileReference:"Reference in composer",fileOpenEditor:"Open in editor",fileChangedByPi:"Modified by pi in this session",fileRenderMarkdown:"Render",fileRawSource:"Source",gitUnavailable:"git command not found. Install it and make sure it is on PATH.",gitUpstream:"upstream {name}",gitNoUpstream:"no upstream",gitConflict:"Conflicts",gitAskCommit:"Ask pi to commit",gitDetails:"Git details",gitAskCommitPrompt:"Review the current changes, group related edits into commits, and write clear commit messages.",gitDiffEmpty:"No differences",gitDiffTruncated:"Diff truncated",gitBinary:"Binary file, no diff shown",gitStagedDiff:"Staged diff",gitWorktreeDiff:"Working tree diff",gitNoCommits:"No commits yet",gitBack:"Back",gitPanel:"Git",panelRefresh:"Refresh",panelLoading:"Loading…",filesEmpty:"Empty directory",filesBack:"Back",fileBinary:"Binary file, no preview",filePreviewTruncated:"Large file, showing first 256 KB only",entriesTruncated:"Too many entries, showing first 2000",gitNotRepo:"This workspace is not a Git repository.",gitDetached:"detached HEAD",gitAhead:"ahead {n}",gitBehind:"behind {n}",gitStaged:"Staged",gitUnstaged:"Unstaged",gitUntracked:"Untracked",gitNoChanges:"Working tree clean",gitStatusUnknown:"Git status unavailable; changes could not be determined",gitRecentCommits:"Recent commits",gitStagingArea:"Staging area",gitWorkingTree:"Working tree",gitGithubAccount:"GitHub account",gitGithubUnknown:"No GitHub account detected",toolNoOutput:"no output",toolFailed:"failed",thinkingClamped:'This model does not support "{requested}"; using "{level}" instead',modelError:"Model returned an error",modelErrorTimes:"{n} times in a row",modelErrorRateLimit:"Rate limited: too many requests, wait a moment and retry",modelErrorBilling:"Insufficient balance or quota",modelErrorAuth:"Authentication failed: check this provider's API key",modelErrorNotFound:"Model not found or not accessible with this key",modelErrorContext:"Context exceeds the model window; try /compact and retry",modelErrorTimeout:"Request timed out",modelErrorServer:"Provider server error or overloaded",modelErrorModeration:"Request blocked by the provider's content filter (sensitive words); rephrase or start a new session",modelErrorNetwork:"Network connection failed",turnAborted:"Aborted",moreLines:"{n} more lines",commandLines:"{n}-line script",thinkLabel:"Thought",expandOutput:"Show full output",expandDiff:"Show changes",collapseOutput:"Collapse",workspaces:"Workspaces",pickFolderTitle:"Choose a workspace folder",pickFolderUp:"Parent folder",pickFolderConfirm:"Use this folder",pickFolderEmpty:"No subfolders here",pickFolderTruncated:"Showing the first {n} folders",pickFolderLoading:"Loading…",searchSessions:"Search sessions...",addWorkspace:"Add workspace",groupBy:"Group by",sortBy:"Sort by",byWorkspace:"Workspace",flatList:"Flat list",manualOrder:"Created",recentUpdated:"Recently updated",newSessionHere:"New session here",removeWorkspace:"Remove from list",deleteWorkspace:"Delete workspace",deleteWorkspaceConfirm:'Remove "{name}" from the workspace list. Folders and session records will be retained, and its sessions will be displayed under "Ungrouped".',deleteWorkspacePending:"Deleting workspace...",workspaceNameConflict:'A workspace named "{name}" already exists.',ungrouped:"Ungrouped",forkSession:"Fork session",archiveSession:"Archive session",unarchiveSession:"Unarchive",archivedSessions:"Archived",deleteAllSessions:"Delete all sessions",deleteAllConfirm:"Delete ALL sessions in this workspace? This cannot be undone.",contextInject:"Context",autoCompact:"Auto compaction",settingsLoading:"Loading settings…",settingsLoadFailed:"Settings could not be loaded. Defaults are not shown; please retry.",settingsSaveFailed:"Settings were not saved. Check the value or connection and retry.",settingsRetry:"Retry",autoCompactDesc:"Automatically compact history when context exceeds the threshold",reserveTokens:"Reserve tokens",keepRecentTokens:"Keep recent",autoRetry:"Auto retry",autoRetryDesc:"Automatically retry failed requests",maxRetries:"Max retries",baseDelayMs:"Initial delay (ms)",reloadExtensions:"Reload all extensions",cycleModel:"Cycle model",cycleModelHint:"Cycle model (Shift-click for previous)",branches:"Branches",noBranches:"No branch points available",oauthLogin:"OAuth login",authMethod:"Authentication",webAuth:"Access authentication",webAuthTokenOn:"Enabled (launch token)",loginTokenTitle:"This instance signs in with a launch token",loginTokenDesc:"Open the login link printed in the terminal when PiWeb started (…/?token=…), or copy a link from Settings → Remote access on a signed-in computer. The token changes on every restart; once opened, the browser remembers it for 30 days.",logout:"Sign out",authMethodApiKey:"API key",oauthDevicePrompt:"Finish authorization in your browser",oauthOpenAuth:"Open authorization page",oauthDeviceCode:"Device code",oauthCodeCopied:"Copied",usageQuotaLabel:"API quota",usageRequests:"Requests",usageRefresh:"Refresh quota",usageProbe:"Check quota",usageProbing:"Checking…",usageProbeDisclosure:"Checking sends one minimal request to xAI that may be billed.",usageProbeFailed:"Quota check failed; no usage data was returned.",usagePlan:"Plan",usageQuotaRemaining:"Remaining quota",queryingQuota:"Querying quota…",usageReadOnlyDisclosure:"Reads the provider's read-only usage endpoint; consumes no quota.",usageReset:"Resets",usageWindowWeekly:"Weekly",usageWindowMonthly:"Monthly",usageWindowHours:"{n}h",usageWindowDays:"{n}d",usageWindowRolling:"Rolling",usageWindowChat:"Chat",usageWindowCompletions:"Completions",usageWindowPremium:"Premium requests",usageVariantOpus:"Opus",usageVariantCode:"Code",usageBalanceGranted:"Granted",usageBalanceToppedUp:"Topped up",usageBalanceVoucher:"Voucher",usageBalanceCash:"Cash",usageBalanceUsed:"Used",usageBalanceLimit:"Limit",oauthWait:"Waiting for authorization…",oauthCancel:"Cancel login",noSessions:"No sessions yet",startWith:"New workspace",inputPlaceholder:"Message pi…",thinking:"Thinking",thinkingOff:"Off",model:"Model",selectModel:"Select model",triggerLoading:"Loading models…",blockedComposer:"This model is unavailable — select one to continue",emptyModels:"No models available.",emptyEfforts:"This model provides no reasoning effort levels.",thinkingUnsupported:"Not supported by this model",thinkingUnsupportedHint:'The model does not declare reasoning support. For custom models, add "reasoning": true (optionally a thinkingLevelMap) to the model in ~/.pi/agent/models.json',toolReadonly:"Read Only",toolStandard:"Workspace Write",toolFull:"Full access",stop:"Stop",send:"Send",imageAttachment:"Image attachment",imageTooLarge:"Each image must be 20 MB or smaller",imageCountLimit:"You can attach up to 20 images",imageTypeUnsupported:"Only JPEG, PNG, WebP, and GIF images are supported",dropToAttach:"Drop to attach",dropToAttachHint:"Images attach to the message; other files (archives, documents) are saved and referenced by path for the agent to read",dropLimits:"Images ≤ 20MB \xb7 up to 20 \xb7 Other files ≤ 100MB \xb7 up to 16",uploading:"Uploading…",uploadFailed:"Upload failed",uploadTooLarge:"Each file must be 100 MB or smaller",uploadCountLimit:"You can attach up to 16 files",attachmentLine:"Attachment: {path} ({size})",cmdMenu:"Commands",slashCatalog:"Commands and skills",skillType:"Skill",cmdCompact:"Compact older conversation history",cmdExport:"Download this session log",cmdModel:"Select the model for this session",cmdNew:"Start a new session",cmdFork:"Fork this session",cmdReload:"Reload extensions, skills and prompt templates (pi /reload)",promptType:"Template",extensionCmdType:"Extension",cmdUnknown:"Unknown command: /{name}. See the / menu in the composer for available commands",extensionDialogTag:"Extension",extensionStatus:"Extension status",contextUsed:"context used",contextUnknown:"Context usage unknown",contextEstimated:"estimated context usage",contextMeasured:"context usage",contextBackground:"Main Conversation",contextApiInput:"Last request input (API)",contextChars:"chars",contextSystem:"System prompt",contextMessages:"Messages",contextTools:"Tools",promptPanel:"Prompt sources",promptRefresh:"Refresh",promptLoading:"Loading…",promptColdHint:"Session not started yet: disk files are listed now; the assembled system prompt and tool definitions appear once the session is running.",promptOriginProject:"project",promptOriginAgent:"user",promptOriginPackage:"package",promptOriginExtension:"extension",promptKindSystem:"System prompt file",promptKindAppend:"Appended prompt",promptKindAgents:"Project memory (AGENTS.md)",promptKindSkill:"Skill prompts",promptKindTemplate:"Prompt templates",promptKindTool:"Tool prompts",promptKindAssembled:"System prompt",promptKindCompacted:"Compaction summary",promptCompactedKey:"Compaction summary in context",promptGuidelines:"Prompt guidelines",promptParameters:"Parameter schema",promptAssembledKey:"Effective system prompt",promptToolBuiltin:"builtin",promptToolExtension:"extension",contextSystemPrompt:"System Prompt",contextSystemTools:"System Tools",contextCustomTools:"Custom Tools",contextMemory:"Memory (AGENTS.md)",contextSkills:"Skills",contextUserMessages:"User Messages",contextAgentText:"Agent Text",contextAgentThinking:"Agent Thinking",contextAgentToolCall:"Agent Tool Call",contextToolOutput:"Tool Output",contextCompacted:"Compacted Data",contextAutoCompactBuffer:"Auto-Compact Buffer",contextFreeSpace:"Free Space",contextColdHint:"Session not started yet — System Prompt and tool definitions are counted once it starts",contextCountNow:"Count now",contextCounting:"Counting…",contextWindowEdit:"Edit",contextWindowBuiltin:"pi built-in catalog: {value}",contextWindowUseBuiltin:"Use",contextWindowScope:"Changes this model's global config (models.json); the pi terminal and other sessions use it too",contextWindowOverBuiltin:"Larger than the built-in catalog: requests past the model's real limit are rejected upstream (400)",contextWindowNoBuiltin:"Enter the model's real limit; a larger value gets requests rejected upstream (400)",contextWindowInvalid:"Enter a positive integer; K / M allowed (e.g. 200K)",mentionFiles:"@ reference files / folders",mentionHint:"↑↓ select \xb7 Enter reference \xb7 Esc close",mentionNoMatch:"No matching files",mentionTruncated:"list truncated",mentionDiskSource:"directory scan",mentionDiskSourceHint:"This workspace is not a git repository (or git is missing): candidates come from a directory scan that skips node_modules and build output; in a git repository they follow .gitignore automatically",turns:"turns",toolCalls:"tool calls",cost:"cost",duration:"duration",cacheHits:"cache hits",statsCounts:"{turns} turns \xb7 {steps} steps",ttftAverage:"TTFT avg",inputTokens:"Input",outputTokens:"Output",tabChat:"Chat",tabTrajectory:"Trajectory",sessionLog:"Session log",sessionDetails:"Session details",exportJsonl:"Export JSONL",trajTimeline:"Timeline",trajModeSeq:"Sequence",trajModeTime:"Time",trajModeDur:"Duration",trajEmpty:"No trajectory records yet",trajSearchPlaceholder:"Search trajectory",trajNoMatch:"No matching trajectory records",trajInput:"Input",trajModel:"Model",trajTools:"Tools",trajOutput:"Output",trajThink:"Think",trajTime:"Time",trajTurn:"Turn",trajSystem:"System",trajSession:"Session",trajSummary:"Summary",trajPreview:"Preview",trajRaw:"Raw",trajSource:"Source",trajStatus:"Status",trajCompleted:"Completed",trajFailed:"Failed",trajStarted:"Started",trajTokens:"Token usage",trajNoContent:"This record has no displayable content",encodingLossWarning:"This historical tool output was already damaged when saved. Unrecoverable lines are hidden; the current Pi SDK forces new PowerShell output to UTF-8.",ttft:"TTFT",decode:"Decode",inspector:"Record inspector",setGeneral:"General",setModels:"Models",enterBehavior:"Enter while busy",enterBehaviorDesc:"Only while pi is running; Ctrl/Cmd+Enter sends the other way",enterQueue:"Queue: sent after this turn ends",enterSteer:"Steer: delivered after the current tool call",setSkills:"Skills",importSessions:"Import sessions",importDesc:"Losslessly import conversations from Codex / Claude Code / Grok / ZCode / dsh / opencode on this machine into pi sessions: text, thinking, tool calls and results, timestamps and usage are all kept. If the original project directory still exists locally the session lands in that workspace; otherwise it falls back to the workspace selected below. Source data is only read, never modified.",importRescan:"Rescan",importScanning:"Scanning...",importSourceClaude:"Claude Code",importSourceCodex:"Codex",importSourceGrok:"Grok",importSourceZcode:"ZCode",importSourceDsh:"dsh",importSourceOpencode:"opencode",importSourceError:"{source} scan failed: {message}",importGroupCount:"{n} sessions \xb7 {imported} imported",importPickSource:"Choose a source",importLimitHint:"Only the {n} most recent conversations per source are scanned",importLimitHintTooltip:"To see older sessions, raise SCAN_LIMIT_PER_SOURCE in src/lib/session-import/index.ts",importSelectAll:"Select group",importSelectNone:"Clear group",importClearSelection:"Clear",importRun:"Import selected ({n})",importRunning:"Importing...",importFallbackWorkspace:"Fallback workspace",importFallbackHint:"Used when the original project folder is gone",importWhereGoes:"Destination",importGoesOriginal:"Back to its original workspace",importGoesFallback:"Original folder is gone — uses the fallback workspace",importAlready:"Imported",importUntitled:"(untitled)",importNoProject:"(no project directory)",importMessages:"{n} messages",importEmpty:"No importable local sessions found",importReportSummary:"Imported {imported} \xb7 skipped {skipped} \xb7 failed {failed}",drawerPanel:"Drawer",drawerSections:"Drawer sections",drawerPrompts:"Prompts",sideChat:"Side chat",sideChatModel:"Side-chat model",sideChatFollowMain:"Follow main chat",sideChatNew:"New side chat",sideChatHistory:"Side-chat history",sideChatMessages:"Side-chat messages",sideChatQuestion:"Side-chat question",sideChatPlaceholder:"Ask about anything you're reading…",sideChatEmpty:"Ask as you read. Keep your place.",sideChatHint:"Uses the main chat as background. Separate answers, saved only in this browser.",sideChatPickSession:"Open a main conversation to start a side chat",sideChatAnswering:"Answering…",sideChatContextTruncated:"The background is long; this answer uses part of the main or side-chat history.",sideChatLengthLimited:"This answer reached its output limit. You can ask it to continue.",sideChatStorageFailed:"Your browser could not save the side chat. Keep a copy of anything you need.",setPlugins:"Plugins",setRemote:"Remote access",remoteBuiltin:"Built-in plugin",remoteLanTitle:"Local network",remoteLanHint:"Devices on the same Wi-Fi can open the address below; the mobile layout is already applied. On by default. Links carry the login token: copy one to your phone and it signs in directly. The token is a credential — don't share it.",remotePublicTitle:"Public access",remotePublicHint:"Once on, any browser can open it with nothing to install. Cloudflare assigns a random address that changes on every start. The link carries the login token too.",remoteLinkCopied:"Copied (with token)",remoteStart:"Turn on",remoteStop:"Turn off",remoteWorking:"Starting…",remoteRunning:"Running",remoteStopped:"Off",remotePending:"Address created, taking effect…",remoteEngineMissing:"cloudflared not found. Install it and retry, or point PIWEB_CLOUDFLARED at it.",remoteFailed:"Action failed",remoteBlockedAuth:"Remote access is unavailable because authentication is off — it would be an open, password-free entry. Start with the piweb launcher, or set PI_WEB_AUTH=1.",remoteBlockedDev:"Development mode serves this machine only, so remote access is unavailable. Build first, then start in production mode.",remoteSessionsTitle:"Signed-in devices",remoteSessionsHint:"Phones and other computers stay signed in for 30 days. If a device is lost or a link leaked, make every device (including this one) sign in again with the launch token.",remoteSignOutAll:"Sign out all devices",remoteSignOutAllConfirm:"Click again to confirm",appearance:"Appearance",appearanceMode:"Light / Dark",themeLight:"Light",themeDark:"Dark",themeSystem:"System",themeSilverSteel:"Silver & Steel",themeLimestoneCoal:"Limestone & Coal",themeLinenMoss:"Linen & Moss",themeNordPaper:"Nord & Paper",themePebrel:"Pebrel",themeDsh:"Sea & Ink",fontSize:"Font size",fontUiSize:"UI font size",fontUiSizeDesc:"Sidebar, buttons, labels and other UI text",fontChatSize:"Chat font size",fontChatSizeDesc:"Message body, user bubbles and the composer",fontUiFamily:"UI font family",fontUiFamilyDesc:"Font used by the sidebar, buttons, labels and other UI text",fontMonoFamily:"Code font family",fontMonoFamilyDesc:"Monospace font used by code blocks, diffs and inline code",fontCustom:"Custom…",fontCustomPlaceholder:"Font stack, e.g. Fira Code, monospace",language:"Language",openConfigFile:"Open config file",providerAuthOk:"Configured",providerReady:"Request authentication ready",authUnavailable:"Credentials unavailable",credentialSource:"Credential: {source}",authSourceRuntime:"runtime",authSourceEnvironment:"environment",authSourceCommand:"models.json command",authSourceProvider:"provider config",apiKey:"API Key",apiKeyStored:"Saved; leave blank to keep it",providerIdImmutable:"A Provider ID cannot be changed after creation. Delete and recreate it to rename it.",modelConfigReopen:"Model configuration saved and applied. Sessions that are answering pick it up after the current turn.",customModelIdentityNotice:"A custom model ID is only a route name sent to that API endpoint. PiWeb does not automatically download, attach, or identify local Ollama models.",customApiKeyHint:"Leave blank to use auth.json. Keyless local/private services (Ollama etc.) get a placeholder key automatically on save.",modelsTitle:"Models",modelsDesc:"Enter an API key for each provider to use its models.",addProvider:"Add provider",addCustomProvider:"Add custom provider",customProviderTitle:"Custom provider",edit:"Edit",customBadge:"Custom",providerLabel:"Provider",apiType:"API type",modelsList:"Models (one ID per line)",baseUrl:"Base URL",apiAddress:"API address",apiProtocol:"API protocol",apiKeyOptional:"Enter an API key, or leave blank to use environment authentication",customSettings:"Custom settings",providerDefault:"Provider default",selectProvider:"Select provider",searchProviders:"Search provider name or ID",noProviderMatches:"No matching providers",modelCount:"{count} models",providerId:"Provider ID",providerIdHint:"A lowercase identifier that uniquely identifies this provider in requests and derives its credential name.",providerIdInvalid:"Use lowercase letters, numbers, and single hyphen-separated segments only.",providerIdTaken:"This Provider ID already exists.",displayName:"Display name",displayNameOptional:"Display name (optional)",modelCatalog:"Model catalog",discoverModels:"Fetch available models",allowPrivateDiscovery:"Allow local/private",allowPrivateHint:"Check this when the model address points to loopback or a private network (Ollama, LM Studio, one-api gateways) to allow this probe; chat requests are not affected",discoveringModels:"Fetching...",autoDiscovering:"Detecting models…",autoDiscovered:"Detected {n} models (capacity and vision filled in where the endpoint reports them)",autoDiscoverFailed:"Automatic detection failed — use the button to retry",usingDefaultModels:"Using Pi SDK default models \xb7 {count}",customModelsRequired:"Add at least one model ID that can be sent",modelCatalogEmptyBuiltin:"No model overrides. The model selector will continue using Pi SDK's live official catalog.",modelCatalogEmptyCustom:"No models will appear in the selector. Add at least one model ID.",catalogOverrideHint:"Rows matching a built-in model ID only override the fields you fill in; reasoning, pricing and thinking levels stay built-in.",addModel:"Add model",modelId:"Model ID",createProvider:"Create provider",saving:"Saving...",setKey:"Save key",removeKey:"Remove key",removeOAuth:"Remove OAuth",confirmRemoveOAuth:'Remove the OAuth login for "{name}"? You will need to log in again to use it.',confirmRemoveProvider:'Delete provider "{name}" and its configuration?',confirmRemoveKey:'Remove the saved key for "{name}"?',customProviders:"Custom providers (models.json)",toolsSection:"Tools",toolsSectionDesc:"The preset picks the default tools for new sessions; with a session open you can toggle its tools individually (current session only).",toolsCurrentSession:"Current session",toolsActiveCount:"{n}/{total} enabled",toolsNoSession:"Open a session to see and toggle its available tools.",securityToolPreset:"Permission",securityToolPresetDesc:"Switch the current tool set; Workspace Write includes bash and is not a filesystem sandbox",securityTrust:"Project trust",securityTrustDesc:"Auto-trust projects containing .pi/ resources (writes pi settings.json)",trustAsk:"Ask every time",trustAlways:"Always trust",trustNever:"Never trust",versionPiweb:"PiWeb version",versionPiwebDesc:"Version of this web app; checked at startup and updatable right here (click the version to open the repo)",versionPi:"Pi version",versionPiDesc:"Version of the pi agent engine; checked at startup and updatable right here (click the version to open the repo)",checkUpdate:"Check for updates",checkingUpdate:"Checking…",upToDate:"Up to date",updateTo:"Update to {v}",updatingNow:"Updating…",updatedTo:"Updated to {v}; restart PiWeb to apply",updateFailed:"Update failed",updateManualHint:"Stop piweb, then run the command above (Windows cannot replace a running installation)",updateCopied:"Copied",updateBusy:"A session is running; update after it finishes",updateCommits:"{n} new commits on main",updateNoticeTitle:"Update available",updateNoticeUpdatingTitle:"Updating…",updateNoticeDoneTitle:"Update installed",updateNoticeUpdate:"Update",updateNoticeLater:"Later",updateNoticeOk:"Got it",updateNoticeUpdated:"Updated to {v}",updateRunCommandHint:"Stop piweb, then run in a terminal:",updateRestartHint:"Restart PiWeb to apply: press Ctrl+C in the terminal running piweb, then run piweb again",skillsDesc:"Disabled skills are hidden from the system prompt and only callable via /skill:name",confirmDeleteSkill:'Delete skill "{name}"? Its skill directory will be removed and cannot be recovered.',deleteSkillHint:"Delete the skill directory",skillDeletePackageHint:"package skill: use disable",scopeGlobal:"Global",scopeProject:"Project",scopePackage:"Package",viewSkillFile:"View SKILL.md",packages:"Installed pi packages",packagesEmpty:"No pi packages installed",addPackage:"Install pi package",addPackagePlaceholder:"npm:pkg / git:https://… / local path",installLocal:"Install into current project (-l)",install:"Install",uninstall:"Uninstall",confirmUninstallPackage:'Uninstall "{source}"?',update:"Update",pluginConfig:"Plugin config",pluginList:"Plugin list",pluginPageDesc:"Configure and view installed plugins for this deployment.",searchPlugins:"Search plugins",enabled:"Enabled",disabled:"Disabled",enablePlugin:"Enable",disablePlugin:"Disable",updating:"Updating...",uninstalling:"Uninstalling...",updateSuccess:"Updated successfully",uninstallSuccess:"Uninstalled",extensionsEmpty:"No loaded extensions",extensionLoadError:"Failed to load",resourceDiagnostics:"Resource diagnostics",installing:"Installing…",installSuccess:"Installed and loaded",reloadedSessions:"Reloaded: {loaders} loaders \xb7 {sessions} sessions",projectTrustBanner:"This project has .pi/ extensions or skills; pi loads and runs them only if you trust the project",projectTrustBannerNever:"This project's .pi/ extensions and skills are marked untrusted and will not load",projectTrustAllow:"Trust and load",projectTrustDeny:"Do not trust",projectTrustForget:"Ask again",projectTrustTrusted:"Project trusted",projectTrustUntrusted:"Project not trusted",resources:"carries",toastSaved:"Saved",toastError:"Operation failed",running:"Running",projectPanel:"Project",growthScopeRound:"This round",growthScopeSession:"Session total",growthOnlyChanges:"Changes only",growthPickRound:"Select round",growthRoundJump:"Enter round number...",growthRoundJumpHint:"Type a round number and press Enter to jump",growthPrev:"Previous round",growthNext:"Next round",growthRoundPosition:"Round {current}/{total}",growthRecordNow:'Record now: save the current changes as "Your changes"',growthRecordNone:"No new changes",growthNoRounds:"Nothing recorded yet. Send pi a message and each round's changes will show up here.",growthLoading:"Loading history…",growthNoChangesRound:"No file changes in this round",growthNoSession:"Open or start a session to watch the project grow here.",growthUnavailable:"git was not found on this machine; project growth is unavailable",growthUnavailableFallback:"Growth history is unavailable (no usable git); showing the current directory structure",growthConsentTitle:"Turn on growth history for this workspace?",growthConsentNotGit:"Growth history saves each pi turn's changes as git commits so you can review and compare them. This folder is not a git repository yet; turning it on runs git init here (creates a .git folder).",growthConsentNested:"Growth history saves each pi turn's changes as git commits so you can review and compare them. This folder is inside another repository ({parent}); turning it on creates a nested git repository here, which the outer repository will see as a sub-repository.",growthConsentNote:"Commits live on a private ref (refs/piweb/rounds/…) and never touch your branches or index. The choice is remembered per workspace.",growthConsentAllow:"Turn on and create repository",growthConsentDecline:"Don't record",growthRoundLabel:"Round {n}",growthKindUser:"Your changes",growthRoundFiles:"{n} files",growthJumpToChat:"Show in chat",growthRunning:"Round in progress…",growthStatusAborted:"Aborted",growthStatusError:"Error",growthStatD:"Deleted",growthPending:"Writing…",growthLazyDir:"Current disk entry, not recorded in the selected round",growthTruncated:"Too many changes in this round; showing the first 2000",chatRoundChanged:"This round changed {n} files",chatRoundNoChanges:"No file changes this round",chatRoundShow:"Show this round in the project panel",growthExpandAll:"Expand all",growthCollapseAll:"Collapse all",growthFilter:"Filter…",viewerModeDiff:"Changes",viewerModeContent:"Content",viewerModeRender:"Rendered",viewerFold:"Fold unchanged",viewerUnfold:"Show unchanged",viewerFoldedLines:"\xb7\xb7\xb7 {n} unchanged lines \xb7\xb7\xb7",viewerPrevChange:"Previous change",viewerNextChange:"Next change",viewerFullscreen:"Fullscreen",viewerExitFullscreen:"Exit fullscreen",viewerQuickOpen:"Type a file name to open…",viewerQuickOpenEmpty:"No matching files",viewerNoChanges:"No changes to this file in this scope",viewerDeleted:"This file was deleted in this round; showing its last content",viewerHistorical:"This file is no longer in the current snapshot; showing its last recorded content",viewerMissing:"This file is no longer in the current snapshot or on disk",viewerPatchTruncated:"Diff too large; truncated",viewerCloseTab:"Close tab",viewerNotInSnapshot:"Not in the snapshot (over 1MB or excluded); showing the current content from disk",viewerLoadFailed:"Failed to load",viewerEmpty:"Pick a file from the tree on the left",viewerOpenFolder:"Preview folder",viewerDirHint:"Folder: {n} items (ignored files hidden)",viewerDirMore:"Load more",streamStyleTitle:"Streaming text",streamStyleDesc:"How the answer appears while it arrives; applies to the stream already running",streamStyleSmooth:"Smooth",streamStyleSmoothDesc:"Even pace, no jumps",streamStyleTypewriter:"Typewriter",streamStyleTypewriterDesc:"Fixed cadence, character by character",streamStyleFade:"Fade in",streamStyleFadeDesc:"Whole words, paragraphs fade in",streamStyleInstant:"Instant",streamStyleInstantDesc:"Show immediately, no smoothing",streamSpeedTitle:"Streaming speed",streamSpeedDesc:"Cadence for Smooth / Typewriter / Fade in; Instant ignores it",streamSpeed1:"Slow",streamSpeed2:"Relaxed",streamSpeed3:"Standard",streamSpeed4:"Fast",streamSpeed5:"Fastest",streamCaretTitle:"Typing caret",streamCaretDesc:"Blinking caret at the end of the text while streaming"}},h=(0,e.createContext)({lang:"zh",setLang:()=>{},t:f});function i({children:a}){let[b,c]=(0,e.useState)("zh"),f=(0,e.useCallback)(a=>{c(a),localStorage.setItem("piweb.lang",a)},[]);return(0,d.jsx)(h.Provider,{value:{lang:b,setLang:f,t:g[b]},children:a})}function j(){return(0,e.useContext)(h)}},96487:()=>{}};
|
|
1
|
+
exports.id=7496,exports.ids=[7496],exports.modules={104:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23)),Promise.resolve().then(c.t.bind(c,60440,23)),Promise.resolve().then(c.t.bind(c,84342,23)),Promise.resolve().then(c.t.bind(c,82265,23)),Promise.resolve().then(c.t.bind(c,35421,23)),Promise.resolve().then(c.t.bind(c,61335,23)),Promise.resolve().then(c.t.bind(c,70664,23)),Promise.resolve().then(c.bind(c,74661))},1096:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23))},8e3:(a,b,c)=>{"use strict";c.d(b,{N:()=>e,h:()=>f});var d=c(48249);function e({size:a=20,className:b,style:c}){return(0,d.jsxs)("svg",{width:a,height:a,viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,className:b,style:{display:"block",flex:"none",...c},children:[(0,d.jsx)("defs",{children:(0,d.jsxs)("linearGradient",{id:"isx-pi-grad",x1:"0%",y1:"0%",x2:"100%",y2:"100%",children:[(0,d.jsx)("stop",{offset:"0%",stopColor:"#02defc"}),(0,d.jsx)("stop",{offset:"50%",stopColor:"#7ffe00"}),(0,d.jsx)("stop",{offset:"100%",stopColor:"#fc0197"})]})}),(0,d.jsx)("path",{d:"M3.75 6.75C3.75 5.92 4.42 5.25 5.25 5.25H18.75C19.58 5.25 20.25 5.92 20.25 6.75C20.25 7.58 19.58 8.25 18.75 8.25H5.25C4.42 8.25 3.75 7.58 3.75 6.75Z",fill:"currentColor"}),(0,d.jsx)("path",{d:"M8.25 7.5V15.5C8.25 17.16 6.91 18.5 5.25 18.5C4.42 18.5 3.75 17.83 3.75 17C3.75 16.17 4.42 15.5 5.25 15.5C5.66 15.5 6 15.16 6 14.75V7.5H8.25Z",fill:"currentColor"}),(0,d.jsx)("path",{d:"M15 7.5V14.5C15 15.88 16.12 17 17.5 17C18.33 17 19 17.67 19 18.5C19 19.33 18.33 20 17.5 20C14.46 20 12.75 17.54 12.75 14.5V7.5H15Z",fill:"currentColor"})]})}function f({compact:a=!1}){return a?(0,d.jsx)("div",{className:"flex items-center justify-center rounded-[10px] border border-white/10 transition-transform duration-200 hover:scale-105",style:{width:32,height:32,background:"var(--dsw-bg-elevated)",boxShadow:"0 2px 8px rgba(0,0,0,0.18)"},children:(0,d.jsx)(e,{size:18,style:{color:"var(--dsw-label-primary)"}})}):(0,d.jsxs)("div",{className:"group inline-flex cursor-pointer select-none items-center gap-2.5 transition-transform duration-200",style:{color:"var(--dsw-label-primary)"},children:[(0,d.jsx)("div",{className:"relative flex items-center justify-center rounded-[9px] border transition-all duration-300 group-hover:scale-105",style:{width:28,height:28,background:"var(--dsw-bg-elevated)",borderColor:"var(--dsw-border-l3)",boxShadow:"0 2px 10px rgba(0,0,0,0.12)"},children:(0,d.jsx)(e,{size:16,style:{color:"var(--dsw-label-primary)"}})}),(0,d.jsxs)("div",{className:"flex items-baseline gap-0.5",children:[(0,d.jsx)("span",{style:{fontSize:16.5,fontWeight:700,letterSpacing:"-0.03em",color:"var(--dsw-label-primary)",lineHeight:1},children:"Pi"}),(0,d.jsx)("span",{style:{fontSize:16.5,fontWeight:600,letterSpacing:"-0.02em",background:"var(--isx-line-gradient)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent",lineHeight:1},children:"Web"})]})]})}},18874:()=>{},23635:()=>{},36552:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23)),Promise.resolve().then(c.t.bind(c,15098,23)),Promise.resolve().then(c.t.bind(c,47644,23)),Promise.resolve().then(c.t.bind(c,33859,23)),Promise.resolve().then(c.t.bind(c,98099,23)),Promise.resolve().then(c.t.bind(c,16237,23)),Promise.resolve().then(c.t.bind(c,98562,23)),Promise.resolve().then(c.t.bind(c,36675,23))},36593:()=>{},55091:(a,b,c)=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0}),Object.defineProperty(b,"default",{enumerable:!0,get:function(){return f}});let d=c(5735),e=c(22675);function f(){return(0,d.jsx)(e.HTTPAccessErrorFallback,{status:404,message:"This page could not be found."})}("function"==typeof b.default||"object"==typeof b.default&&null!==b.default)&&void 0===b.default.__esModule&&(Object.defineProperty(b.default,"__esModule",{value:!0}),Object.assign(b.default,b),a.exports=b.default)},59645:(a,b,c)=>{"use strict";function d(){return[{type:"image/svg+xml",sizes:"any",url:"/icon.svg?779ce17318f43f72"}]}c.r(b),c.d(b,{default:()=>d})},60587:()=>{},61135:()=>{},76537:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>g,metadata:()=>e,viewport:()=>f});var d=c(5735);c(18874),c(36593),c(61135);let e={title:"pi",description:"Web UI for the pi coding agent"},f={width:"device-width",initialScale:1,themeColor:[{media:"(prefers-color-scheme: light)",color:"#fcfbf9"},{media:"(prefers-color-scheme: dark)",color:"#2e3440"}]};function g({children:a}){return(0,d.jsx)("html",{lang:"zh-CN",suppressHydrationWarning:!0,children:(0,d.jsx)("body",{suppressHydrationWarning:!0,children:a})})}},78335:()=>{},87944:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23))},93961:(a,b,c)=>{"use strict";c.d(b,{I18nProvider:()=>i,s:()=>j});var d=c(48249),e=c(67484);let f={confirm:"确认",cancel:"取消",delete:"删除",rename:"重命名",renameSession:"重命名会话",renameWorkspace:"重命名工作区",search:"搜索",save:"保存",close:"关闭",error:"出错",copy:"复制",copyFailed:"复制失败",externalImage:"外部图片,点击加载",chatWidthHandle:"拖动调整对话宽度",editMessage:"编辑这条消息",sendEdit:"重新发送",editMessageFailed:"编辑重发失败",export:"导出",settings:"设置",newChat:"新会话",reconnecting:"连接中断,正在重连…",sessionListLoadFailed:"会话列表加载失败",retry:"重试",compacting:"正在压缩上下文…",compactionComplete:"上下文压缩完成",compactionFailed:"上下文压缩失败",compactedTitle:"上下文已压缩",compactedTitleTokens:"上下文已压缩 \xb7 压缩前约 {tokens} tokens",compactedHint:"以上内容模型只看得到摘要",branchSummaryTitle:"分支摘要",branchSummaryHint:"切换分支时,离开的那条分支以摘要形式发给模型",showSummary:"查看摘要",hideSummary:"收起摘要",externalSessionReloaded:"终端在这个会话里写了 {n} 条新内容,已重新载入",externalSessionWriting:"终端也在写这个会话({n} 条)。两边同时写会分叉,这一轮结束后自动重新载入",pickWorkspaceFirst:"请先选择工作区",capacityFields:"容量",contextWindowLabel:"上下文窗口",maxTokensLabel:"最大输出",capacityHint:"留空按 pi 缺省(128K / 16K)\xb7 支持 256K / 2M 写法",visionLabel:"视觉",visionHint:"该模型能否接收图片。未声明时 pi 按纯文本处理:你贴的截图会被换成一行占位文字(提示语还会说成「模型不支持图像」)",visionUnset:"未声明",visionInputText:"文本",visionInputTextHint:"pi 总是接受文本输入;贴图能不能发由「图片」决定",visionInputImage:"图片",visionInputImageHint:"勾上表示该模型能收图(写进 models.json 的 input);不勾则按纯文本处理",visionOn:"有视觉",visionOff:"纯文本",reasoningLabel:"推理",reasoningHint:"该模型是否支持推理(思考档位)。未声明时 pi 按不支持处理,模型选择器里的思考档位会整个消失",reasoningUnset:"未声明",reasoningOn:"支持推理",reasoningOff:"不支持",imagePreview:"点击放大预览",imageViewer:"图片预览",imageClearAll:"清空图片",filesClearAll:"清空文件",imagePrev:"上一张",imageNext:"下一张",chipExpandMore:"展开 {n}",chipCollapse:"收起",modelAuditTitle:"{n} 个模型没写能力字段",modelAuditDesc:"没写的字段,pi 会按上下文 {ctx}、输出上限 {out}、纯文本处理。端点没报的值不会替你猜:照模型的真实规格填上(支持 256K / 1M 写法),保存时只补空着的格子,已写的值不改。",modelAuditColModel:"模型",modelAuditColContext:"上下文",modelAuditColOutput:"输出上限",modelAuditColVision:"视觉",modelAuditVisionQuick:"视觉一起设:",modelAuditVisionOn:"都有视觉",modelAuditVisionOff:"都是纯文本",modelAuditSave:"保存 {n} 个模型",modelAuditSaveIdle:"填好后保存",capacityInvalid:"第 {n} 行:容量需为数字(可用 K/M)",discoverEmpty:"远端没有返回可识别的模型",candidateTitle:"发现 {count} 个模型,勾选要添加的",candidateAll:"全选",candidatePicked:"已选 {n} 个",candidateAdopt:"添加 {n} 个",candidateInCatalog:"已在目录中",runningTool:"Running {name}…",thinkingLive:"Thinking",stepRunning:"Running",stepRan:"已运行",stepRead:"读取",stepSearched:"搜索",stepEdited:"编辑了",stepWrote:"写入了",skillStep:"使用技能",skillStepTitle:"技能",resultRead:"读取了 {n} 行",resultFound:"找到 {n} 处",resultWrote:"{n} 行",sumThought:"思考了 {d}",sumRan:"运行了 {n} 条命令",sumRan1:"运行了 {n} 条命令",sumRead:"读了 {n} 个文件",sumRead1:"读了 {n} 个文件",sumSearched:"搜索了 {n} 次",sumSearched1:"搜索了 {n} 次",sumJoin:",",toolLines:"{n} 行",toolMatches:"{n} 个匹配",toolExit:"退出码 {code}",toolWritten:"已写入",diffSummary:"+{add} −{del} 行",deletedFile:"已删除 {path}",backToBottom:"回到底部",modeSteer:"插话",modeQueue:"排队",sendSteer:"插话:当前工具跑完就送达",sendQueue:"排队:本轮结束后发送",queueEdit:"↑ 取回编辑",queueDrop:"丢弃",viewInTrajectory:"在轨迹中查看",turnRanFor:"耗时 {duration}",durationSeconds:"{seconds} 秒",durationMinutes:"{minutes} 分 {seconds} 秒",clockMd:"{m}月{d}日",clockYmd:"{y}年{m}月{d}日",turnUsageTitle:"本回合用量",filesPanel:"文件",outline:"大纲",moreActions:"更多",filesFilter:"筛选文件…",filesShowAll:"显示 node_modules 等",filesHideNoise:"隐藏 node_modules 等",fileReference:"引用到输入框",fileOpenEditor:"在编辑器中打开",fileChangedByPi:"本会话中被 pi 修改",fileRenderMarkdown:"渲染",fileRawSource:"源码",gitUnavailable:"未找到 git 命令,请确认已安装并加入 PATH。",gitUpstream:"上游 {name}",gitNoUpstream:"无上游分支",gitConflict:"冲突",gitAskCommit:"让 pi 提交",gitDetails:"Git 详情",gitAskCommitPrompt:"请检查当前工作区的变更,把相关改动分组提交,写清晰的 commit message。",gitDiffEmpty:"没有差异",gitDiffTruncated:"差异过长,已截断",gitBinary:"二进制文件,不显示差异",gitStagedDiff:"暂存区差异",gitWorktreeDiff:"工作区差异",gitNoCommits:"尚无提交",gitBack:"返回",gitPanel:"Git",panelRefresh:"刷新",panelLoading:"加载中…",filesEmpty:"空目录",filesBack:"返回",fileBinary:"二进制文件,不提供预览",filePreviewTruncated:"文件较大,仅显示前 256 KB",entriesTruncated:"目录条目过多,仅显示前 2000 项",gitNotRepo:"此工作区不是 Git 仓库。",gitDetached:"分离头指针",gitAhead:"领先 {n}",gitBehind:"落后 {n}",gitStaged:"已暂存",gitUnstaged:"未暂存",gitUntracked:"未跟踪",gitNoChanges:"工作区干净,没有变更",gitStatusUnknown:"Git 状态读取失败,无法确认是否有变更",gitRecentCommits:"最近提交",gitStagingArea:"暂存区",gitWorkingTree:"工作区",gitGithubAccount:"GitHub 账号",gitGithubUnknown:"未识别到 GitHub 账号",toolNoOutput:"无输出",toolFailed:"失败",thinkingClamped:"当前模型不支持「{requested}」,已改为「{level}」",modelError:"模型返回错误",modelErrorTimes:"连续 {n} 次",modelErrorRateLimit:"限流:请求过于频繁,稍等片刻再试",modelErrorBilling:"余额或配额不足",modelErrorAuth:"鉴权失败:检查该供应商的 API Key",modelErrorNotFound:"模型不存在或当前 Key 无权访问",modelErrorContext:"上下文超出模型窗口,可用 /compact 压缩后重试",modelErrorTimeout:"请求超时",modelErrorServer:"供应商服务端出错或过载",modelErrorModeration:"请求内容被供应商审核拦截(敏感词),换措辞或新开会话试试",modelErrorNetwork:"网络连接失败",turnAborted:"已中止",moreLines:"还有 {n} 行",commandLines:"{n} 行脚本",thinkLabel:"思考",expandOutput:"展开全部输出",expandDiff:"展开改动",collapseOutput:"收起",workspaces:"工作区",pickFolderTitle:"选择工作区文件夹",pickFolderUp:"上一级",pickFolderConfirm:"选择此文件夹",pickFolderEmpty:"此目录下没有子文件夹",pickFolderTruncated:"只列出前 {n} 个文件夹",pickFolderLoading:"读取中…",searchSessions:"搜索会话...",addWorkspace:"添加工作区",groupBy:"分组方式",sortBy:"排序方式",byWorkspace:"按工作区",flatList:"单列表",manualOrder:"按创建时间",recentUpdated:"最近更新",newSessionHere:"在此工作区新会话",removeWorkspace:"从列表移除",deleteWorkspace:"删除工作区",deleteWorkspaceConfirm:"将把“{name}”从工作区列表中移除。文件夹与会话记录会保留,其会话将显示在“未分组”下。",deleteWorkspacePending:"正在删除工作区…",workspaceNameConflict:"已存在名为“{name}”的工作区。",ungrouped:"未分组",forkSession:"在新对话中分支",archiveSession:"归档会话",unarchiveSession:"取消归档",archivedSessions:"已归档",archiveRetentionHint:"归档满 30 天自动删除",archiveRetentionDetail:"归档的会话从归档那天起保留 30 天,之后自动删除;归档后又用过的,从最后一次使用起算。打开中的会话不会被删。",deleteAllSessions:"删除全部会话",deleteAllConfirm:"删除此工作区的全部会话?不可恢复。",contextInject:"上下文注入",autoCompact:"自动压缩",settingsLoading:"正在读取设置…",settingsLoadFailed:"设置读取失败;未显示默认值。请重试。",settingsSaveFailed:"设置未保存,请检查输入或网络后重试。",settingsRetry:"重试",autoCompactDesc:"上下文超出阈值时自动压缩历史",reserveTokens:"保留 Token",keepRecentTokens:"近期保留",autoRetry:"自动重试",autoRetryDesc:"请求失败后的自动重试",maxRetries:"最大重试次数",baseDelayMs:"初始延迟 (ms)",reloadExtensions:"重载全部扩展",cycleModel:"循环切换模型",cycleModelHint:"循环模型(Shift 点击切换到前一个)",branches:"分支",noBranches:"暂无可跳转的分支节点",oauthLogin:"OAuth 登录",authMethod:"认证方式",webAuth:"访问认证",webAuthTokenOn:"已启用(启动令牌)",loginTokenTitle:"这个实例用启动令牌登录",loginTokenDesc:"请打开启动 PiWeb 时终端里打印的登录链接(形如 …/?token=…),或在已登录的电脑上打开 设置 → 远程连接,复制带令牌的地址。令牌每次重启都会更换;打开一次后浏览器会记住 30 天。",logout:"退出登录",authMethodApiKey:"API 密钥",oauthDevicePrompt:"请在浏览器中完成授权",oauthOpenAuth:"打开授权页面",oauthDeviceCode:"设备码",oauthCodeCopied:"已复制",usageQuotaLabel:"API 配额",usageRequests:"请求",usageRefresh:"刷新配额",usageProbe:"检测配额",usageProbing:"检测中…",usageProbeDisclosure:"检测会向 xAI 发送一次可能计费的最小请求。",usageProbeFailed:"配额检测失败,未获得用量信息。",usagePlan:"套餐",usageQuotaRemaining:"额度剩余",queryingQuota:"正在查询额度…",usageReadOnlyDisclosure:"读取提供商的只读用量端点,不消耗额度。",usageReset:"刷新时间",usageWindowWeekly:"周限",usageWindowMonthly:"月限",usageWindowHours:"{n} 小时",usageWindowDays:"{n} 天",usageWindowRolling:"滚动窗口",usageWindowChat:"对话",usageWindowCompletions:"补全",usageWindowPremium:"高级请求",usageVariantOpus:"Opus",usageVariantCode:"代码",usageBalanceGranted:"赠金",usageBalanceToppedUp:"充值",usageBalanceVoucher:"代金券",usageBalanceCash:"现金",usageBalanceUsed:"已用",usageBalanceLimit:"上限",oauthWait:"等待授权…",oauthCancel:"取消登录",noSessions:"暂无会话",startWith:"新建工作区",inputPlaceholder:"给 pi 发消息…",thinking:"思考",thinkingOff:"关闭",model:"模型",selectModel:"选择模型",triggerLoading:"正在加载模型…",blockedComposer:"当前模型不可用,请先选择模型",emptyModels:"没有可用的模型。",emptyEfforts:"当前模型未提供推理等级。",thinkingUnsupported:"此模型不支持",thinkingUnsupportedHint:'模型没有声明推理能力。自定义模型请在 ~/.pi/agent/models.json 里给该模型加 "reasoning": true(可选 thinkingLevelMap 指定档位)',toolReadonly:"Read Only",toolStandard:"Workspace Write",toolFull:"Full access",stop:"停止",send:"发送",imageAttachment:"图片附件",imageTooLarge:"单张图片不能超过 20 MB",imageCountLimit:"一次最多添加 20 张图片",imageTypeUnsupported:"仅支持 JPEG、PNG、WebP 和 GIF 图片",dropToAttach:"松开添加附件",dropToAttachHint:"图片直接附到消息;其他文件(压缩包/文档等)保存后以路径引用,模型可用工具读取",dropLimits:"图片 ≤ 20MB \xb7 最多 20 张 \xb7 其他文件 ≤ 100MB \xb7 最多 16 个",uploading:"正在上传…",uploadFailed:"上传失败",uploadTooLarge:"单个文件不能超过 100 MB",uploadCountLimit:"一次最多添加 16 个文件",attachmentLine:"附件:{path}({size})",cmdMenu:"命令",slashCatalog:"命令与技能",skillType:"技能",cmdCompact:"压缩更早的对话历史",cmdExport:"下载本会话日志",cmdModel:"选择本会话使用的模型",cmdNew:"新建会话",cmdFork:"分叉会话",cmdReload:"重载扩展、技能与提示模板(pi /reload)",promptType:"模板",extensionCmdType:"扩展",cmdUnknown:"没有这个命令:/{name}。可用命令见输入框的 / 菜单",extensionDialogTag:"扩展",extensionStatus:"扩展状态",contextUsed:"上下文已用",contextUnknown:"上下文用量未知",contextEstimated:"上下文估算",contextMeasured:"上下文用量",contextApiInput:"最近请求输入(API)",contextChars:"字符",contextSystem:"系统提示词",contextMessages:"对话消息",contextTools:"工具",promptPanel:"提示词来源",promptRefresh:"刷新",promptLoading:"加载中…",promptColdHint:"会话尚未启动:先列出磁盘上的提示词文件;打开会话后才会出现「组装后的系统提示词」与工具定义。",promptOriginProject:"项目",promptOriginAgent:"个人",promptOriginPackage:"包",promptOriginExtension:"扩展",promptKindSystem:"系统提示词文件",promptKindAppend:"追加提示词",promptKindAgents:"项目记忆(AGENTS.md)",promptKindSkill:"技能提示词",promptKindTemplate:"提示模板",promptKindTool:"工具提示词",promptKindAssembled:"系统提示词",promptKindCompacted:"压缩摘要",promptCompactedKey:"进入上下文的压缩摘要",promptGuidelines:"提示词指南",promptParameters:"参数定义",promptAssembledKey:"当前生效的系统提示词",promptToolBuiltin:"内置",promptToolExtension:"扩展",contextSystemPrompt:"System Prompt",contextSystemTools:"System Tools",contextCustomTools:"Custom Tools",contextMemory:"Memory(AGENTS.md)",contextSkills:"Skills",contextUserMessages:"User Messages",contextAgentText:"Agent Text",contextAgentThinking:"Agent Thinking",contextAgentToolCall:"Agent Tool Call",contextToolOutput:"Tool Output",contextCompacted:"Compacted Data",contextAutoCompactBuffer:"Auto-Compact Buffer",contextFreeSpace:"Free Space",contextColdHint:"会话还没启动,System Prompt 和工具定义要启动后才算得出",contextCountNow:"现在统计",contextCounting:"统计中…",contextWindowEdit:"修改",contextWindowBuiltin:"pi 内置目录:{value}",contextWindowUseBuiltin:"填入",contextWindowScope:"改的是这个模型的全局配置(models.json),pi 终端和其它会话一起生效",contextWindowOverBuiltin:"比内置目录大:超过模型实际上限时,请求会被上游拒绝(400)",contextWindowNoBuiltin:"填模型实际支持的上限;填大了,请求会被上游拒绝(400)",contextWindowInvalid:"填正整数,可带 K / M(如 200K)",mentionFiles:"@ 引用文件 / 文件夹",mentionHint:"↑↓ 选择 \xb7 Enter 引用 \xb7 Esc 关闭",mentionNoMatch:"没有匹配的文件",mentionTruncated:"候选已截断",mentionDiskSource:"目录遍历",mentionDiskSourceHint:"当前工作区不是 git 仓库(或没装 git):候选来自目录遍历,会跳过 node_modules、构建产物等目录;列为 git 仓库后候选会自动按 .gitignore 过滤",turns:"轮次",toolCalls:"工具调用",cost:"花费",duration:"耗时",cacheHits:"缓存命中",statsCounts:"{turns} 轮 \xb7 {steps} 步",ttftAverage:"首 token 平均",inputTokens:"输入",outputTokens:"输出",tabChat:"对话",tabTrajectory:"轨迹",sessionLog:"Session log",sessionDetails:"会话详情",exportJsonl:"导出 JSONL",trajTimeline:"时间轴",trajModeSeq:"等距",trajModeTime:"时间",trajModeDur:"间隔",trajEmpty:"本会话还没有轨迹记录",trajSearchPlaceholder:"搜索轨迹",trajNoMatch:"没有匹配的轨迹记录",trajInput:"输入",trajModel:"模型",trajTools:"工具",trajOutput:"输出",trajThink:"思考",trajTime:"时间",trajTurn:"轮次",trajSystem:"系统",trajSession:"会话",trajSummary:"摘要",trajPreview:"预览",trajRaw:"原始",trajSource:"来源",trajStatus:"状态",trajCompleted:"已完成",trajFailed:"失败",trajStarted:"开始时间",trajTokens:"Token 用量",trajNoContent:"此记录没有可显示的内容",encodingLossWarning:"这段历史工具输出在写入时已经损坏,无法恢复的行已隐藏。当前 Pi SDK 已对新的 PowerShell 输出强制使用 UTF-8。",ttft:"首 token",decode:"解码",inspector:"记录详情",setGeneral:"通用设置",setModels:"模型",enterBehavior:"繁忙时 Enter 键行为",enterBehaviorDesc:"仅在 pi 运行时生效;Ctrl/Cmd+Enter 用另一种方式发送",enterQueue:"排队:本轮结束后发送",enterSteer:"插话:当前工具跑完就送达",setSkills:"技能",importSessions:"导入会话",importDesc:"把本机 Codex / Claude Code / Grok / ZCode / dsh / opencode 的对话无损导入成 pi 会话:文本、思考、工具调用与结果、时间戳、用量都保留。源项目目录还在本机就导回原工作区,否则落到下面选的兜底工作区。只读源数据,不修改源工具的任何文件。",importRescan:"重新扫描",importScanning:"扫描中…",importSourceClaude:"Claude Code",importSourceCodex:"Codex",importSourceGrok:"Grok",importSourceZcode:"ZCode",importSourceDsh:"dsh",importSourceOpencode:"opencode",importSourceError:"{source} 扫描失败:{message}",importGroupCount:"{n} 条 \xb7 已导入 {imported}",importPickSource:"选择来源",importLimitHint:"每个来源只列最近 {n} 条对话(更早的会话不扫描,省时省资源)",importLimitHintTooltip:"看更早的会话:把 src/lib/session-import/index.ts 里的 SCAN_LIMIT_PER_SOURCE 调大",importSelectAll:"全选本组",importSelectNone:"清空本组",importClearSelection:"清空选择",importRun:"导入所选 ({n})",importRunning:"导入中…",importFallbackWorkspace:"兜底工作区",importFallbackHint:"原项目目录已不在本机时落到这里",importWhereGoes:"导入去向",importGoesOriginal:"回到原工作区",importGoesFallback:"原目录已不在,用兜底工作区",importAlready:"已导入",importUntitled:"(无标题)",importNoProject:"(无项目目录)",importMessages:"{n} 条消息",importEmpty:"没有找到可导入的本地会话",importReportSummary:"成功 {imported} \xb7 跳过 {skipped} \xb7 失败 {failed}",drawerPanel:"右侧抽屉",drawerSections:"抽屉入口",drawerPrompts:"提示词",setPlugins:"插件",setRemote:"远程连接",remoteBuiltin:"内置插件",remotePluginToggle:"启用内置远程连接插件",remotePluginOn:"已启用",remotePluginOff:"已关闭",remotePluginHint:"关闭后不再注入手机排版、也不能开公网入口;局域网入口保留为纯转发,你自己的插件或自建反代指向同一个端口照旧可用。",remoteLanPlain:"纯转发(未注入手机排版)",remotePublicNeedsPlugin:"需要先启用内置插件",remoteLanTitle:"局域网入口",remoteLanHint:"同一个 WiFi 下的设备直接打开下面地址即可,手机排版已适配。默认开启。链接带登录令牌:点「复制」发到手机,打开就直接登录;令牌即凭据,别发给别人。",remotePublicTitle:"公网入口",remotePublicHint:"开启后任何浏览器都能打开,无需安装客户端。地址由 Cloudflare 随机分配,每次启动都会变。链接同样带登录令牌。",remoteLinkCopied:"已复制(含令牌)",remoteStart:"开启远程连接",remoteStop:"关闭",remoteWorking:"启动中…",remoteRunning:"运行中",remoteStopped:"未开启",remotePending:"地址已生成,生效中…",remoteEngineMissing:"找不到 cloudflared。请安装后重试,或用 PIWEB_CLOUDFLARED 指定它的路径。",remoteFailed:"操作失败",remoteBlockedAuth:"认证没开,远程连接不可用:开出去就是一个免密入口。请用 piweb 启动器启动,或设 PI_WEB_AUTH=1。",remoteBlockedDev:"开发模式只服务本机,远程连接不可用。请先构建,再用生产模式启动。",remoteSessionsTitle:"已登录的设备",remoteSessionsHint:"手机、别的电脑登录后一直有效(30 天)。设备丢了或链接被别人拿到时,可以让所有设备(包括这台)都要重新用启动令牌登录。",remoteSignOutAll:"让所有设备重新登录",remoteSignOutAllConfirm:"再点一次确认",appearance:"外观",appearanceMode:"亮暗模式",themeLight:"浅色",themeDark:"深色",themeSystem:"跟随系统",themeSilverSteel:"银钢",themeLimestoneCoal:"石灰与煤炭",themeLinenMoss:"亚麻与苔绿",themeNordPaper:"北欧纸墨",themePebrel:"Pebrel",themeDsh:"海与墨",fontSize:"正文字号",fontUiSize:"界面字体",fontUiSizeDesc:"侧栏、按钮、标签等界面文字",fontChatSize:"对话字体",fontChatSizeDesc:"消息正文、用户气泡与输入框",fontUiFamily:"界面字体族",fontUiFamilyDesc:"侧栏、按钮、标签等界面文字使用的字体",fontCustom:"自定义…",fontCustomPlaceholder:"输入字体栈,如 Fira Code, monospace",language:"界面语言",openConfigFile:"打开配置文件",providerAuthOk:"已配置",providerReady:"请求认证可用",authUnavailable:"凭据不可用",credentialSource:"凭据:{source}",authSourceRuntime:"运行时",authSourceEnvironment:"环境变量",authSourceCommand:"models.json 命令",authSourceProvider:"Provider 配置",apiKey:"API Key",apiKeyStored:"已保存;留空保持不变",providerIdImmutable:"Provider ID 创建后不可修改;如需更名,请删除后重建。",modelConfigReopen:"模型配置已保存并立即生效;正在回答的会话在本轮结束后生效。",customModelIdentityNotice:"自定义模型 ID 只是发往该 API 地址的路由名;PiWeb 不会自动下载、接入或识别本机 Ollama 模型。",customApiKeyHint:"可留空改用 auth.json;指向本机/私网的无鉴权服务(Ollama 等)保存时自动填占位值。",customHeaders:"自定义请求头",customHeadersHint:"需要额外认证头的网关在这里填;探测模型目录与发消息都会带上。值支持 $ENV 或 ${ENV} 读环境变量、!命令 取命令输出,与 models.json 的写法一致。",customHeaderName:"名字,如 X-Api-Version",customHeaderValue:"值,如 $MY_GATEWAY_TOKEN",customHeaderAdd:"添加请求头",modelsTitle:"模型",modelsDesc:"填入各提供方的 API 密钥即可使用其模型。",addProvider:"添加提供方",addCustomProvider:"添加自定义提供方",customProviderTitle:"自定义提供方",edit:"编辑",customBadge:"自定义",providerLabel:"提供方",apiType:"API 类型",modelsList:"模型(每行一个 ID)",baseUrl:"Base URL",apiAddress:"API 地址",apiProtocol:"API 协议",apiKeyOptional:"输入 API 密钥,或留空使用环境认证",customSettings:"自定义设置",providerDefault:"提供方默认",selectProvider:"选择提供方",searchProviders:"搜索提供方名称或 ID",noProviderMatches:"没有匹配的提供方",modelCount:"{count} 个模型",providerId:"Provider ID",providerIdHint:"以小写字母开头的标识,在请求中唯一标识该提供方,并用于派生凭据名。",providerIdInvalid:"只能使用小写字母、数字和单个连字符分段。",providerIdTaken:"该 Provider ID 已存在。",displayName:"显示名称",displayNameOptional:"显示名称(可选)",modelCatalog:"模型目录",discoverModels:"获取可用模型",discoveringModels:"获取中...",autoDiscovering:"正在自动识别模型…",autoDiscovered:"已自动识别 {n} 个模型(端点报了容量与视觉的已一并填好)",autoDiscoverFailed:"自动识别失败,可点「获取可用模型」重试",usingDefaultModels:"正在使用 Pi SDK 默认模型 \xb7 {count} 个",customModelsRequired:"至少添加一个可发送的模型 ID",modelCatalogEmptyBuiltin:"未添加覆盖模型;模型选择器会继续实时使用 Pi SDK 的官方模型目录。",modelCatalogEmptyCustom:"模型选择器中将不显示任何模型;请至少添加一个模型 ID。",catalogOverrideHint:"与内置目录同 ID 的行只覆盖填写的字段,推理、价格、思考档位等沿用内置值。",addModel:"添加模型",modelId:"模型 ID",createProvider:"创建提供方",saving:"保存中...",setKey:"保存 Key",removeKey:"移除 Key",removeOAuth:"移除 OAuth",confirmRemoveOAuth:"确定移除“{name}”的 OAuth 登录吗?移除后需重新登录才能使用。",confirmRemoveProvider:"确定删除提供方“{name}”及其配置吗?",confirmRemoveKey:"确定移除“{name}”的已保存密钥吗?",customProviders:"自定义 Provider(models.json)",toolsSection:"工具启用情况",toolsSectionDesc:"三档预设决定新会话的默认工具;打开会话后可逐个启停当前会话的工具(仅本会话生效)。",toolsCurrentSession:"当前会话",toolsActiveCount:"{n}/{total} 已启用",toolsNoSession:"打开一个会话后,这里会显示可用工具并支持逐个启停。",securityToolPreset:"权限",securityToolPresetDesc:"切换当前会话工具集;Workspace Write 包含 bash,并非文件系统沙箱",securityTrust:"项目信任",securityTrustDesc:"首次进入含 .pi/ 资源的项目时是否自动信任(写入 pi settings.json)",trustAsk:"每次询问",trustAlways:"总是信任",trustNever:"从不信任",versionPiweb:"PiWeb 版本",versionPiwebDesc:"本 Web 应用的版本;启动时自动检查,有新版本在这里直接更新(点版本号打开仓库)",versionPi:"Pi 版本",versionPiDesc:"pi 智能体内核的版本;启动时自动检查,有新版本在这里直接更新(点版本号打开仓库)",checkUpdate:"检查更新",checkingUpdate:"检查中…",upToDate:"已是最新",updateTo:"更新到 {v}",updatingNow:"更新中…",updatedTo:"已更新到 {v},重启 PiWeb 后生效",updateFailed:"更新失败",updateManualHint:"先停止 piweb,再执行上面的命令(Windows 无法替换运行中的安装目录)",updateCopied:"已复制",updateBusy:"有会话正在运行,等它结束再更新",updateCommits:"main 新增 {n} 个提交",updateNoticeTitle:"有新版本",updateNoticeUpdatingTitle:"正在更新…",updateNoticeDoneTitle:"更新完成",updateNoticeUpdate:"更新",updateNoticeLater:"稍后",updateNoticeOk:"知道了",updateNoticeUpdated:"已更新到 {v}",updateRunCommandHint:"先停掉 piweb,再在终端运行:",updateRestartHint:"重启 PiWeb 后生效:在运行 piweb 的终端按 Ctrl+C,再重新运行 piweb",skillsDesc:"关闭后技能不会出现在系统提示中,仅可通过 /skill:名称 手动调用",confirmDeleteSkill:"确定删除技能“{name}”吗?将删除其所在技能目录,不可恢复。",deleteSkillHint:"删除技能目录",skillDeletePackageHint:"包技能请用禁用管理",scopeGlobal:"全局",scopeProject:"项目",scopePackage:"包",viewSkillFile:"查看 SKILL.md",packages:"已安装的 pi 包",packagesEmpty:"尚未安装任何 pi 包",addPackage:"安装 pi 包",addPackagePlaceholder:"npm:包名 / git:https://… / 本地路径",installLocal:"安装到当前项目(-l)",install:"安装",uninstall:"卸载",confirmUninstallPackage:"确定卸载“{source}”吗?",update:"更新",updateNeedsEnable:"已停用的插件要先启用才能更新",pluginConfig:"插件配置",pluginList:"插件列表",pluginPageDesc:"配置和查看本部署已安装的插件。",searchPlugins:"搜索插件",enabled:"已启用",disabled:"已停用",enablePlugin:"启用",disablePlugin:"停用",updating:"正在更新...",uninstalling:"正在卸载...",updateSuccess:"更新成功",uninstallSuccess:"已卸载",extensionsEmpty:"没有已加载的扩展",extensionLoadError:"加载失败",resourceDiagnostics:"资源诊断",installing:"正在安装…",installSuccess:"已安装并加载",reloadedSessions:"已重载:{loaders} 个加载器 \xb7 {sessions} 个会话",projectTrustBanner:"此项目含 .pi/ 扩展或技能,pi 需要你的信任才会加载并执行它们",projectTrustBannerNever:"此项目的 .pi/ 扩展与技能已被设为不信任,不会加载",projectTrustAllow:"信任并加载",projectTrustDeny:"不信任",projectTrustForget:"重新询问",projectTrustTrusted:"项目已信任",projectTrustUntrusted:"项目未信任",resources:"携带",toastSaved:"已保存",toastError:"操作失败",running:"运行中",projectPanel:"项目",growthScopeRound:"本轮",growthScopeSession:"本会话累计",growthOnlyChanges:"只看改动",growthPickRound:"选择轮次",growthRoundJump:"输入轮号...",growthRoundJumpHint:"输入轮号后按回车跳到该轮",growthPrev:"上一轮",growthNext:"下一轮",growthRoundPosition:"第 {current}/{total} 轮",growthRecordNow:"立即记录:把当前改动记为「你的修改」",growthRecordNone:"没有新的改动",growthNoRounds:"还没有记录。发一条消息让 pi 开始工作,每一轮的改动会出现在这里。",growthLoading:"正在读取记录…",growthNoChangesRound:"本轮无文件改动",growthNoSession:"打开或新建一个会话后,这里会显示项目的生长过程。",growthUnavailable:"机器上找不到 git,项目生长功能不可用",growthUnavailableFallback:"生长记录不可用(找不到可用的 git),已显示当前目录结构",growthConsentTitle:"要为这个工作区开启生长记录吗?",growthConsentNotGit:"生长记录会把 pi 每一轮的改动存成 git 提交,方便回看和对比。这个目录还不是 git 仓库,开启后会在这里执行 git init(新建 .git 目录)。",growthConsentNested:"生长记录会把 pi 每一轮的改动存成 git 提交,方便回看和对比。这个目录是另一个仓库({parent})的子目录,开启后会在这里再建一个嵌套的 git 仓库,外层仓库会把它当成一个子仓库看待。",growthConsentNote:"记录挂在专用引用 refs/piweb/rounds/… 上,不动分支和暂存区。选择会按工作区记住。",growthConsentAllow:"开启并建仓库",growthConsentDecline:"不记录",growthRoundLabel:"第 {n} 轮",growthKindUser:"你的修改",growthRoundFiles:"{n} 个文件",growthJumpToChat:"在对话里看",growthRunning:"本轮进行中…",growthStatusAborted:"已中止",growthStatusError:"出错",growthStatD:"删除",growthPending:"生成中",growthLazyDir:"当前磁盘条目,不在所选这一轮的记录中",growthTruncated:"这一轮变更过多,只显示前 2000 条",chatRoundChanged:"本轮改了 {n} 个文件",chatRoundNoChanges:"本轮没有改动文件",chatRoundShow:"在项目栏里查看这一轮",growthExpandAll:"展开全部",growthCollapseAll:"收起全部",growthFilter:"筛选…",viewerModeDiff:"变更",viewerModeContent:"内容",viewerModeRender:"渲染",viewerFold:"折叠未改动",viewerUnfold:"展开未改动",viewerFoldedLines:"\xb7\xb7\xb7 {n} 行未改动 \xb7\xb7\xb7",viewerPrevChange:"上一处改动",viewerNextChange:"下一处改动",viewerFullscreen:"全屏",viewerExitFullscreen:"退出全屏",viewerQuickOpen:"输入文件名打开…",viewerQuickOpenEmpty:"没有匹配的文件",viewerNoChanges:"这一范围内此文件没有变化",viewerDeleted:"此文件在本轮被删除,显示的是删除前的内容",viewerHistorical:"此文件已不在当前快照中,显示最近一次记录的内容",viewerMissing:"此文件已不在当前快照或磁盘中",viewerPatchTruncated:"差异过大,已截断",viewerCloseTab:"关闭页签",viewerNotInSnapshot:"此文件不在快照里(超过 1MB 或被排除),显示磁盘上的当前内容",viewerLoadFailed:"加载失败",viewerEmpty:"从左侧树里选择一个文件",viewerOpenFolder:"打开文件夹预览",viewerDirHint:"文件夹:共 {n} 项(已按 .gitignore 过滤)",viewerDirMore:"加载更多"},g={zh:f,en:{confirm:"Confirm",cancel:"Cancel",delete:"Delete",rename:"Rename",renameSession:"Rename session",renameWorkspace:"Rename workspace",search:"Search",save:"Save",close:"Close",error:"Error",copy:"Copy",copyFailed:"Copy failed",externalImage:"External image — click to load",chatWidthHandle:"Drag to resize the conversation",editMessage:"Edit this message",sendEdit:"Send again",editMessageFailed:"Edit and resend failed",export:"Export",settings:"Settings",newChat:"New session",reconnecting:"Connection lost, reconnecting…",sessionListLoadFailed:"Failed to load sessions",retry:"Retry",compacting:"Compacting context…",compactionComplete:"Context compaction complete",compactionFailed:"Context compaction failed",compactedTitle:"Context compacted",compactedTitleTokens:"Context compacted \xb7 about {tokens} tokens before",compactedHint:"The model only sees a summary of everything above",branchSummaryTitle:"Branch summary",branchSummaryHint:"The branch you left is sent to the model as a summary",showSummary:"Show summary",hideSummary:"Hide summary",externalSessionReloaded:"The terminal added {n} new entries to this session — reloaded",externalSessionWriting:"The terminal is also writing to this session ({n} entries). Writing from both sides forks it; it reloads after this turn",pickWorkspaceFirst:"Select a workspace first",capacityFields:"Capacities",contextWindowLabel:"Context window",maxTokensLabel:"Max output",capacityHint:"blank = pi default (128K / 16K) \xb7 256K / 2M accepted",visionLabel:"Vision",visionHint:"Whether this model accepts images. Left unset, pi treats it as text-only and replaces pasted screenshots with a placeholder line.",visionUnset:"Not declared",visionInputText:"Text",visionInputTextHint:"pi always accepts text; whether images can be sent is decided by the Image box",visionInputImage:"Image",visionInputImageHint:"Checked means this model accepts images (written into models.json input); unchecked is treated as text-only",visionOn:"Vision",visionOff:"Text only",reasoningLabel:"Reasoning",reasoningHint:"Whether this model supports reasoning. Left unset, pi treats it as unsupported and the thinking levels disappear from the model picker.",reasoningUnset:"Not declared",reasoningOn:"Reasoning",reasoningOff:"No reasoning",imagePreview:"Click to preview",imageViewer:"Image preview",imageClearAll:"Clear images",filesClearAll:"Clear files",imagePrev:"Previous image",imageNext:"Next image",chipExpandMore:"Show {n} more",chipCollapse:"Collapse",modelAuditTitle:"{n} models don't declare their capabilities",modelAuditDesc:"For fields left out, pi assumes a {ctx} context window, {out} max output and text-only input. Values the endpoint didn't report are never guessed: fill in the model's real limits (256K / 1M accepted). Saving only fills empty cells and never changes values already set.",modelAuditColModel:"Model",modelAuditColContext:"Context",modelAuditColOutput:"Max output",modelAuditColVision:"Vision",modelAuditVisionQuick:"Set vision for all:",modelAuditVisionOn:"All vision",modelAuditVisionOff:"All text only",modelAuditSave:"Save {n} models",modelAuditSaveIdle:"Fill in, then save",capacityInvalid:"Row {n}: capacity must be a number (K/M ok)",discoverEmpty:"No recognizable models returned",candidateTitle:"Found {count} models — pick ones to add",candidateAll:"Select all",candidatePicked:"{n} selected",candidateAdopt:"Add {n}",candidateInCatalog:"Already in catalog",runningTool:"Running {name}…",thinkingLive:"Thinking",stepRunning:"Running",stepRan:"Ran",stepRead:"Read",stepSearched:"Searched",stepEdited:"Edited",stepWrote:"Wrote",skillStep:"Used skill",skillStepTitle:"Skill",resultRead:"Read {n} lines",resultFound:"Found {n} matches",resultWrote:"{n} lines",sumThought:"Thought for {d}",sumRan:"ran {n} shell commands",sumRan1:"ran {n} shell command",sumRead:"read {n} files",sumRead1:"read {n} file",sumSearched:"searched {n} times",sumSearched1:"searched once",sumJoin:", ",toolLines:"{n} lines",toolMatches:"{n} matches",toolExit:"exit {code}",toolWritten:"written",diffSummary:"+{add} −{del} lines",deletedFile:"deleted {path}",backToBottom:"Back to bottom",modeSteer:"steer",modeQueue:"queue",sendSteer:"Steer: delivered after the current tool call",sendQueue:"Queue: sent after this turn ends",queueEdit:"↑ Edit queued",queueDrop:"Discard",viewInTrajectory:"View in trajectory",turnRanFor:"ran for {duration}",durationSeconds:"{seconds}s",durationMinutes:"{minutes}m {seconds}s",clockMd:"{m}/{d}",clockYmd:"{y}/{m}/{d}",turnUsageTitle:"Turn usage",filesPanel:"Files",outline:"Outline",moreActions:"More",filesFilter:"Filter files…",filesShowAll:"Show node_modules etc.",filesHideNoise:"Hide node_modules etc.",fileReference:"Reference in composer",fileOpenEditor:"Open in editor",fileChangedByPi:"Modified by pi in this session",fileRenderMarkdown:"Render",fileRawSource:"Source",gitUnavailable:"git command not found. Install it and make sure it is on PATH.",gitUpstream:"upstream {name}",gitNoUpstream:"no upstream",gitConflict:"Conflicts",gitAskCommit:"Ask pi to commit",gitDetails:"Git details",gitAskCommitPrompt:"Review the current changes, group related edits into commits, and write clear commit messages.",gitDiffEmpty:"No differences",gitDiffTruncated:"Diff truncated",gitBinary:"Binary file, no diff shown",gitStagedDiff:"Staged diff",gitWorktreeDiff:"Working tree diff",gitNoCommits:"No commits yet",gitBack:"Back",gitPanel:"Git",panelRefresh:"Refresh",panelLoading:"Loading…",filesEmpty:"Empty directory",filesBack:"Back",fileBinary:"Binary file, no preview",filePreviewTruncated:"Large file, showing first 256 KB only",entriesTruncated:"Too many entries, showing first 2000",gitNotRepo:"This workspace is not a Git repository.",gitDetached:"detached HEAD",gitAhead:"ahead {n}",gitBehind:"behind {n}",gitStaged:"Staged",gitUnstaged:"Unstaged",gitUntracked:"Untracked",gitNoChanges:"Working tree clean",gitStatusUnknown:"Git status unavailable; changes could not be determined",gitRecentCommits:"Recent commits",gitStagingArea:"Staging area",gitWorkingTree:"Working tree",gitGithubAccount:"GitHub account",gitGithubUnknown:"No GitHub account detected",toolNoOutput:"no output",toolFailed:"failed",thinkingClamped:'This model does not support "{requested}"; using "{level}" instead',modelError:"Model returned an error",modelErrorTimes:"{n} times in a row",modelErrorRateLimit:"Rate limited: too many requests, wait a moment and retry",modelErrorBilling:"Insufficient balance or quota",modelErrorAuth:"Authentication failed: check this provider's API key",modelErrorNotFound:"Model not found or not accessible with this key",modelErrorContext:"Context exceeds the model window; try /compact and retry",modelErrorTimeout:"Request timed out",modelErrorServer:"Provider server error or overloaded",modelErrorModeration:"Request blocked by the provider's content filter (sensitive words); rephrase or start a new session",modelErrorNetwork:"Network connection failed",turnAborted:"Aborted",moreLines:"{n} more lines",commandLines:"{n}-line script",thinkLabel:"Thought",expandOutput:"Show full output",expandDiff:"Show changes",collapseOutput:"Collapse",workspaces:"Workspaces",pickFolderTitle:"Choose a workspace folder",pickFolderUp:"Parent folder",pickFolderConfirm:"Use this folder",pickFolderEmpty:"No subfolders here",pickFolderTruncated:"Showing the first {n} folders",pickFolderLoading:"Loading…",searchSessions:"Search sessions...",addWorkspace:"Add workspace",groupBy:"Group by",sortBy:"Sort by",byWorkspace:"Workspace",flatList:"Flat list",manualOrder:"Created",recentUpdated:"Recently updated",newSessionHere:"New session here",removeWorkspace:"Remove from list",deleteWorkspace:"Delete workspace",deleteWorkspaceConfirm:'Remove "{name}" from the workspace list. Folders and session records will be retained, and its sessions will be displayed under "Ungrouped".',deleteWorkspacePending:"Deleting workspace...",workspaceNameConflict:'A workspace named "{name}" already exists.',ungrouped:"Ungrouped",forkSession:"Fork session",archiveSession:"Archive session",unarchiveSession:"Unarchive",archivedSessions:"Archived",archiveRetentionHint:"Deleted 30 days after archiving",archiveRetentionDetail:"Archived sessions are kept for 30 days from the day they were archived, then deleted automatically. If you use one after archiving, the 30 days restart from its last use. Open sessions are never deleted.",deleteAllSessions:"Delete all sessions",deleteAllConfirm:"Delete ALL sessions in this workspace? This cannot be undone.",contextInject:"Context",autoCompact:"Auto compaction",settingsLoading:"Loading settings…",settingsLoadFailed:"Settings could not be loaded. Defaults are not shown; please retry.",settingsSaveFailed:"Settings were not saved. Check the value or connection and retry.",settingsRetry:"Retry",autoCompactDesc:"Automatically compact history when context exceeds the threshold",reserveTokens:"Reserve tokens",keepRecentTokens:"Keep recent",autoRetry:"Auto retry",autoRetryDesc:"Automatically retry failed requests",maxRetries:"Max retries",baseDelayMs:"Initial delay (ms)",reloadExtensions:"Reload all extensions",cycleModel:"Cycle model",cycleModelHint:"Cycle model (Shift-click for previous)",branches:"Branches",noBranches:"No branch points available",oauthLogin:"OAuth login",authMethod:"Authentication",webAuth:"Access authentication",webAuthTokenOn:"Enabled (launch token)",loginTokenTitle:"This instance signs in with a launch token",loginTokenDesc:"Open the login link printed in the terminal when PiWeb started (…/?token=…), or copy a link from Settings → Remote access on a signed-in computer. The token changes on every restart; once opened, the browser remembers it for 30 days.",logout:"Sign out",authMethodApiKey:"API key",oauthDevicePrompt:"Finish authorization in your browser",oauthOpenAuth:"Open authorization page",oauthDeviceCode:"Device code",oauthCodeCopied:"Copied",usageQuotaLabel:"API quota",usageRequests:"Requests",usageRefresh:"Refresh quota",usageProbe:"Check quota",usageProbing:"Checking…",usageProbeDisclosure:"Checking sends one minimal request to xAI that may be billed.",usageProbeFailed:"Quota check failed; no usage data was returned.",usagePlan:"Plan",usageQuotaRemaining:"Remaining quota",queryingQuota:"Querying quota…",usageReadOnlyDisclosure:"Reads the provider's read-only usage endpoint; consumes no quota.",usageReset:"Resets",usageWindowWeekly:"Weekly",usageWindowMonthly:"Monthly",usageWindowHours:"{n}h",usageWindowDays:"{n}d",usageWindowRolling:"Rolling",usageWindowChat:"Chat",usageWindowCompletions:"Completions",usageWindowPremium:"Premium requests",usageVariantOpus:"Opus",usageVariantCode:"Code",usageBalanceGranted:"Granted",usageBalanceToppedUp:"Topped up",usageBalanceVoucher:"Voucher",usageBalanceCash:"Cash",usageBalanceUsed:"Used",usageBalanceLimit:"Limit",oauthWait:"Waiting for authorization…",oauthCancel:"Cancel login",noSessions:"No sessions yet",startWith:"New workspace",inputPlaceholder:"Message pi…",thinking:"Thinking",thinkingOff:"Off",model:"Model",selectModel:"Select model",triggerLoading:"Loading models…",blockedComposer:"This model is unavailable — select one to continue",emptyModels:"No models available.",emptyEfforts:"This model provides no reasoning effort levels.",thinkingUnsupported:"Not supported by this model",thinkingUnsupportedHint:'The model does not declare reasoning support. For custom models, add "reasoning": true (optionally a thinkingLevelMap) to the model in ~/.pi/agent/models.json',toolReadonly:"Read Only",toolStandard:"Workspace Write",toolFull:"Full access",stop:"Stop",send:"Send",imageAttachment:"Image attachment",imageTooLarge:"Each image must be 20 MB or smaller",imageCountLimit:"You can attach up to 20 images",imageTypeUnsupported:"Only JPEG, PNG, WebP, and GIF images are supported",dropToAttach:"Drop to attach",dropToAttachHint:"Images attach to the message; other files (archives, documents) are saved and referenced by path for the agent to read",dropLimits:"Images ≤ 20MB \xb7 up to 20 \xb7 Other files ≤ 100MB \xb7 up to 16",uploading:"Uploading…",uploadFailed:"Upload failed",uploadTooLarge:"Each file must be 100 MB or smaller",uploadCountLimit:"You can attach up to 16 files",attachmentLine:"Attachment: {path} ({size})",cmdMenu:"Commands",slashCatalog:"Commands and skills",skillType:"Skill",cmdCompact:"Compact older conversation history",cmdExport:"Download this session log",cmdModel:"Select the model for this session",cmdNew:"Start a new session",cmdFork:"Fork this session",cmdReload:"Reload extensions, skills and prompt templates (pi /reload)",promptType:"Template",extensionCmdType:"Extension",cmdUnknown:"Unknown command: /{name}. See the / menu in the composer for available commands",extensionDialogTag:"Extension",extensionStatus:"Extension status",contextUsed:"context used",contextUnknown:"Context usage unknown",contextEstimated:"estimated context usage",contextMeasured:"context usage",contextApiInput:"Last request input (API)",contextChars:"chars",contextSystem:"System prompt",contextMessages:"Messages",contextTools:"Tools",promptPanel:"Prompt sources",promptRefresh:"Refresh",promptLoading:"Loading…",promptColdHint:"Session not started yet: disk files are listed now; the assembled system prompt and tool definitions appear once the session is running.",promptOriginProject:"project",promptOriginAgent:"user",promptOriginPackage:"package",promptOriginExtension:"extension",promptKindSystem:"System prompt file",promptKindAppend:"Appended prompt",promptKindAgents:"Project memory (AGENTS.md)",promptKindSkill:"Skill prompts",promptKindTemplate:"Prompt templates",promptKindTool:"Tool prompts",promptKindAssembled:"System prompt",promptKindCompacted:"Compaction summary",promptCompactedKey:"Compaction summary in context",promptGuidelines:"Prompt guidelines",promptParameters:"Parameter schema",promptAssembledKey:"Effective system prompt",promptToolBuiltin:"builtin",promptToolExtension:"extension",contextSystemPrompt:"System Prompt",contextSystemTools:"System Tools",contextCustomTools:"Custom Tools",contextMemory:"Memory (AGENTS.md)",contextSkills:"Skills",contextUserMessages:"User Messages",contextAgentText:"Agent Text",contextAgentThinking:"Agent Thinking",contextAgentToolCall:"Agent Tool Call",contextToolOutput:"Tool Output",contextCompacted:"Compacted Data",contextAutoCompactBuffer:"Auto-Compact Buffer",contextFreeSpace:"Free Space",contextColdHint:"Session not started yet — System Prompt and tool definitions are counted once it starts",contextCountNow:"Count now",contextCounting:"Counting…",contextWindowEdit:"Edit",contextWindowBuiltin:"pi built-in catalog: {value}",contextWindowUseBuiltin:"Use",contextWindowScope:"Changes this model's global config (models.json); the pi terminal and other sessions use it too",contextWindowOverBuiltin:"Larger than the built-in catalog: requests past the model's real limit are rejected upstream (400)",contextWindowNoBuiltin:"Enter the model's real limit; a larger value gets requests rejected upstream (400)",contextWindowInvalid:"Enter a positive integer; K / M allowed (e.g. 200K)",mentionFiles:"@ reference files / folders",mentionHint:"↑↓ select \xb7 Enter reference \xb7 Esc close",mentionNoMatch:"No matching files",mentionTruncated:"list truncated",mentionDiskSource:"directory scan",mentionDiskSourceHint:"This workspace is not a git repository (or git is missing): candidates come from a directory scan that skips node_modules and build output; in a git repository they follow .gitignore automatically",turns:"turns",toolCalls:"tool calls",cost:"cost",duration:"duration",cacheHits:"cache hits",statsCounts:"{turns} turns \xb7 {steps} steps",ttftAverage:"TTFT avg",inputTokens:"Input",outputTokens:"Output",tabChat:"Chat",tabTrajectory:"Trajectory",sessionLog:"Session log",sessionDetails:"Session details",exportJsonl:"Export JSONL",trajTimeline:"Timeline",trajModeSeq:"Sequence",trajModeTime:"Time",trajModeDur:"Duration",trajEmpty:"No trajectory records yet",trajSearchPlaceholder:"Search trajectory",trajNoMatch:"No matching trajectory records",trajInput:"Input",trajModel:"Model",trajTools:"Tools",trajOutput:"Output",trajThink:"Think",trajTime:"Time",trajTurn:"Turn",trajSystem:"System",trajSession:"Session",trajSummary:"Summary",trajPreview:"Preview",trajRaw:"Raw",trajSource:"Source",trajStatus:"Status",trajCompleted:"Completed",trajFailed:"Failed",trajStarted:"Started",trajTokens:"Token usage",trajNoContent:"This record has no displayable content",encodingLossWarning:"This historical tool output was already damaged when saved. Unrecoverable lines are hidden; the current Pi SDK forces new PowerShell output to UTF-8.",ttft:"TTFT",decode:"Decode",inspector:"Record inspector",setGeneral:"General",setModels:"Models",enterBehavior:"Enter while busy",enterBehaviorDesc:"Only while pi is running; Ctrl/Cmd+Enter sends the other way",enterQueue:"Queue: sent after this turn ends",enterSteer:"Steer: delivered after the current tool call",setSkills:"Skills",importSessions:"Import sessions",importDesc:"Losslessly import conversations from Codex / Claude Code / Grok / ZCode / dsh / opencode on this machine into pi sessions: text, thinking, tool calls and results, timestamps and usage are all kept. If the original project directory still exists locally the session lands in that workspace; otherwise it falls back to the workspace selected below. Source data is only read, never modified.",importRescan:"Rescan",importScanning:"Scanning...",importSourceClaude:"Claude Code",importSourceCodex:"Codex",importSourceGrok:"Grok",importSourceZcode:"ZCode",importSourceDsh:"dsh",importSourceOpencode:"opencode",importSourceError:"{source} scan failed: {message}",importGroupCount:"{n} sessions \xb7 {imported} imported",importPickSource:"Choose a source",importLimitHint:"Only the {n} most recent conversations per source are scanned",importLimitHintTooltip:"To see older sessions, raise SCAN_LIMIT_PER_SOURCE in src/lib/session-import/index.ts",importSelectAll:"Select group",importSelectNone:"Clear group",importClearSelection:"Clear",importRun:"Import selected ({n})",importRunning:"Importing...",importFallbackWorkspace:"Fallback workspace",importFallbackHint:"Used when the original project folder is gone",importWhereGoes:"Destination",importGoesOriginal:"Back to its original workspace",importGoesFallback:"Original folder is gone — uses the fallback workspace",importAlready:"Imported",importUntitled:"(untitled)",importNoProject:"(no project directory)",importMessages:"{n} messages",importEmpty:"No importable local sessions found",importReportSummary:"Imported {imported} \xb7 skipped {skipped} \xb7 failed {failed}",drawerPanel:"Drawer",drawerSections:"Drawer sections",drawerPrompts:"Prompts",setPlugins:"Plugins",setRemote:"Remote access",remoteBuiltin:"Built-in plugin",remotePluginToggle:"Enable the built-in remote access plugin",remotePluginOn:"Enabled",remotePluginOff:"Disabled",remotePluginHint:"When disabled, PiWeb stops injecting the mobile layout and cannot open the public tunnel. The local-network entry stays as a plain forwarder, so your own plugin or reverse proxy can keep pointing at the same port.",remoteLanPlain:"plain forwarding (no mobile layout injected)",remotePublicNeedsPlugin:"Enable the built-in plugin first",remoteLanTitle:"Local network",remoteLanHint:"Devices on the same Wi-Fi can open the address below; the mobile layout is already applied. On by default. Links carry the login token: copy one to your phone and it signs in directly. The token is a credential — don't share it.",remotePublicTitle:"Public access",remotePublicHint:"Once on, any browser can open it with nothing to install. Cloudflare assigns a random address that changes on every start. The link carries the login token too.",remoteLinkCopied:"Copied (with token)",remoteStart:"Turn on",remoteStop:"Turn off",remoteWorking:"Starting…",remoteRunning:"Running",remoteStopped:"Off",remotePending:"Address created, taking effect…",remoteEngineMissing:"cloudflared not found. Install it and retry, or point PIWEB_CLOUDFLARED at it.",remoteFailed:"Action failed",remoteBlockedAuth:"Remote access is unavailable because authentication is off — it would be an open, password-free entry. Start with the piweb launcher, or set PI_WEB_AUTH=1.",remoteBlockedDev:"Development mode serves this machine only, so remote access is unavailable. Build first, then start in production mode.",remoteSessionsTitle:"Signed-in devices",remoteSessionsHint:"Phones and other computers stay signed in for 30 days. If a device is lost or a link leaked, make every device (including this one) sign in again with the launch token.",remoteSignOutAll:"Sign out all devices",remoteSignOutAllConfirm:"Click again to confirm",appearance:"Appearance",appearanceMode:"Light / Dark",themeLight:"Light",themeDark:"Dark",themeSystem:"System",themeSilverSteel:"Silver & Steel",themeLimestoneCoal:"Limestone & Coal",themeLinenMoss:"Linen & Moss",themeNordPaper:"Nord & Paper",themePebrel:"Pebrel",themeDsh:"Sea & Ink",fontSize:"Font size",fontUiSize:"UI font size",fontUiSizeDesc:"Sidebar, buttons, labels and other UI text",fontChatSize:"Chat font size",fontChatSizeDesc:"Message body, user bubbles and the composer",fontUiFamily:"UI font family",fontUiFamilyDesc:"Font used by the sidebar, buttons, labels and other UI text",fontCustom:"Custom…",fontCustomPlaceholder:"Font stack, e.g. Fira Code, monospace",language:"Language",openConfigFile:"Open config file",providerAuthOk:"Configured",providerReady:"Request authentication ready",authUnavailable:"Credentials unavailable",credentialSource:"Credential: {source}",authSourceRuntime:"runtime",authSourceEnvironment:"environment",authSourceCommand:"models.json command",authSourceProvider:"provider config",apiKey:"API Key",apiKeyStored:"Saved; leave blank to keep it",providerIdImmutable:"A Provider ID cannot be changed after creation. Delete and recreate it to rename it.",modelConfigReopen:"Model configuration saved and applied. Sessions that are answering pick it up after the current turn.",customModelIdentityNotice:"A custom model ID is only a route name sent to that API endpoint. PiWeb does not automatically download, attach, or identify local Ollama models.",customApiKeyHint:"Leave blank to use auth.json. Keyless local/private services (Ollama etc.) get a placeholder key automatically on save.",customHeaders:"Custom headers",customHeadersHint:"For gateways that need extra auth headers. They are sent for both model discovery and chat requests. Values accept $ENV / ${ENV} for environment variables and a leading !command, the same syntax as models.json.",customHeaderName:"Name, e.g. X-Api-Version",customHeaderValue:"Value, e.g. $MY_GATEWAY_TOKEN",customHeaderAdd:"Add header",modelsTitle:"Models",modelsDesc:"Enter an API key for each provider to use its models.",addProvider:"Add provider",addCustomProvider:"Add custom provider",customProviderTitle:"Custom provider",edit:"Edit",customBadge:"Custom",providerLabel:"Provider",apiType:"API type",modelsList:"Models (one ID per line)",baseUrl:"Base URL",apiAddress:"API address",apiProtocol:"API protocol",apiKeyOptional:"Enter an API key, or leave blank to use environment authentication",customSettings:"Custom settings",providerDefault:"Provider default",selectProvider:"Select provider",searchProviders:"Search provider name or ID",noProviderMatches:"No matching providers",modelCount:"{count} models",providerId:"Provider ID",providerIdHint:"A lowercase identifier that uniquely identifies this provider in requests and derives its credential name.",providerIdInvalid:"Use lowercase letters, numbers, and single hyphen-separated segments only.",providerIdTaken:"This Provider ID already exists.",displayName:"Display name",displayNameOptional:"Display name (optional)",modelCatalog:"Model catalog",discoverModels:"Fetch available models",discoveringModels:"Fetching...",autoDiscovering:"Detecting models…",autoDiscovered:"Detected {n} models (capacity and vision filled in where the endpoint reports them)",autoDiscoverFailed:"Automatic detection failed — use the button to retry",usingDefaultModels:"Using Pi SDK default models \xb7 {count}",customModelsRequired:"Add at least one model ID that can be sent",modelCatalogEmptyBuiltin:"No model overrides. The model selector will continue using Pi SDK's live official catalog.",modelCatalogEmptyCustom:"No models will appear in the selector. Add at least one model ID.",catalogOverrideHint:"Rows matching a built-in model ID only override the fields you fill in; reasoning, pricing and thinking levels stay built-in.",addModel:"Add model",modelId:"Model ID",createProvider:"Create provider",saving:"Saving...",setKey:"Save key",removeKey:"Remove key",removeOAuth:"Remove OAuth",confirmRemoveOAuth:'Remove the OAuth login for "{name}"? You will need to log in again to use it.',confirmRemoveProvider:'Delete provider "{name}" and its configuration?',confirmRemoveKey:'Remove the saved key for "{name}"?',customProviders:"Custom providers (models.json)",toolsSection:"Tools",toolsSectionDesc:"The preset picks the default tools for new sessions; with a session open you can toggle its tools individually (current session only).",toolsCurrentSession:"Current session",toolsActiveCount:"{n}/{total} enabled",toolsNoSession:"Open a session to see and toggle its available tools.",securityToolPreset:"Permission",securityToolPresetDesc:"Switch the current tool set; Workspace Write includes bash and is not a filesystem sandbox",securityTrust:"Project trust",securityTrustDesc:"Auto-trust projects containing .pi/ resources (writes pi settings.json)",trustAsk:"Ask every time",trustAlways:"Always trust",trustNever:"Never trust",versionPiweb:"PiWeb version",versionPiwebDesc:"Version of this web app; checked at startup and updatable right here (click the version to open the repo)",versionPi:"Pi version",versionPiDesc:"Version of the pi agent engine; checked at startup and updatable right here (click the version to open the repo)",checkUpdate:"Check for updates",checkingUpdate:"Checking…",upToDate:"Up to date",updateTo:"Update to {v}",updatingNow:"Updating…",updatedTo:"Updated to {v}; restart PiWeb to apply",updateFailed:"Update failed",updateManualHint:"Stop piweb, then run the command above (Windows cannot replace a running installation)",updateCopied:"Copied",updateBusy:"A session is running; update after it finishes",updateCommits:"{n} new commits on main",updateNoticeTitle:"Update available",updateNoticeUpdatingTitle:"Updating…",updateNoticeDoneTitle:"Update installed",updateNoticeUpdate:"Update",updateNoticeLater:"Later",updateNoticeOk:"Got it",updateNoticeUpdated:"Updated to {v}",updateRunCommandHint:"Stop piweb, then run in a terminal:",updateRestartHint:"Restart PiWeb to apply: press Ctrl+C in the terminal running piweb, then run piweb again",skillsDesc:"Disabled skills are hidden from the system prompt and only callable via /skill:name",confirmDeleteSkill:'Delete skill "{name}"? Its skill directory will be removed and cannot be recovered.',deleteSkillHint:"Delete the skill directory",skillDeletePackageHint:"package skill: use disable",scopeGlobal:"Global",scopeProject:"Project",scopePackage:"Package",viewSkillFile:"View SKILL.md",packages:"Installed pi packages",packagesEmpty:"No pi packages installed",addPackage:"Install pi package",addPackagePlaceholder:"npm:pkg / git:https://… / local path",installLocal:"Install into current project (-l)",install:"Install",uninstall:"Uninstall",confirmUninstallPackage:'Uninstall "{source}"?',update:"Update",updateNeedsEnable:"Enable this plugin before updating it",pluginConfig:"Plugin config",pluginList:"Plugin list",pluginPageDesc:"Configure and view installed plugins for this deployment.",searchPlugins:"Search plugins",enabled:"Enabled",disabled:"Disabled",enablePlugin:"Enable",disablePlugin:"Disable",updating:"Updating...",uninstalling:"Uninstalling...",updateSuccess:"Updated successfully",uninstallSuccess:"Uninstalled",extensionsEmpty:"No loaded extensions",extensionLoadError:"Failed to load",resourceDiagnostics:"Resource diagnostics",installing:"Installing…",installSuccess:"Installed and loaded",reloadedSessions:"Reloaded: {loaders} loaders \xb7 {sessions} sessions",projectTrustBanner:"This project has .pi/ extensions or skills; pi loads and runs them only if you trust the project",projectTrustBannerNever:"This project's .pi/ extensions and skills are marked untrusted and will not load",projectTrustAllow:"Trust and load",projectTrustDeny:"Do not trust",projectTrustForget:"Ask again",projectTrustTrusted:"Project trusted",projectTrustUntrusted:"Project not trusted",resources:"carries",toastSaved:"Saved",toastError:"Operation failed",running:"Running",projectPanel:"Project",growthScopeRound:"This round",growthScopeSession:"Session total",growthOnlyChanges:"Changes only",growthPickRound:"Select round",growthRoundJump:"Enter round number...",growthRoundJumpHint:"Type a round number and press Enter to jump",growthPrev:"Previous round",growthNext:"Next round",growthRoundPosition:"Round {current}/{total}",growthRecordNow:'Record now: save the current changes as "Your changes"',growthRecordNone:"No new changes",growthNoRounds:"Nothing recorded yet. Send pi a message and each round's changes will show up here.",growthLoading:"Loading history…",growthNoChangesRound:"No file changes in this round",growthNoSession:"Open or start a session to watch the project grow here.",growthUnavailable:"git was not found on this machine; project growth is unavailable",growthUnavailableFallback:"Growth history is unavailable (no usable git); showing the current directory structure",growthConsentTitle:"Turn on growth history for this workspace?",growthConsentNotGit:"Growth history saves each pi turn's changes as git commits so you can review and compare them. This folder is not a git repository yet; turning it on runs git init here (creates a .git folder).",growthConsentNested:"Growth history saves each pi turn's changes as git commits so you can review and compare them. This folder is inside another repository ({parent}); turning it on creates a nested git repository here, which the outer repository will see as a sub-repository.",growthConsentNote:"Commits live on a private ref (refs/piweb/rounds/…) and never touch your branches or index. The choice is remembered per workspace.",growthConsentAllow:"Turn on and create repository",growthConsentDecline:"Don't record",growthRoundLabel:"Round {n}",growthKindUser:"Your changes",growthRoundFiles:"{n} files",growthJumpToChat:"Show in chat",growthRunning:"Round in progress…",growthStatusAborted:"Aborted",growthStatusError:"Error",growthStatD:"Deleted",growthPending:"Writing…",growthLazyDir:"Current disk entry, not recorded in the selected round",growthTruncated:"Too many changes in this round; showing the first 2000",chatRoundChanged:"This round changed {n} files",chatRoundNoChanges:"No file changes this round",chatRoundShow:"Show this round in the project panel",growthExpandAll:"Expand all",growthCollapseAll:"Collapse all",growthFilter:"Filter…",viewerModeDiff:"Changes",viewerModeContent:"Content",viewerModeRender:"Rendered",viewerFold:"Fold unchanged",viewerUnfold:"Show unchanged",viewerFoldedLines:"\xb7\xb7\xb7 {n} unchanged lines \xb7\xb7\xb7",viewerPrevChange:"Previous change",viewerNextChange:"Next change",viewerFullscreen:"Fullscreen",viewerExitFullscreen:"Exit fullscreen",viewerQuickOpen:"Type a file name to open…",viewerQuickOpenEmpty:"No matching files",viewerNoChanges:"No changes to this file in this scope",viewerDeleted:"This file was deleted in this round; showing its last content",viewerHistorical:"This file is no longer in the current snapshot; showing its last recorded content",viewerMissing:"This file is no longer in the current snapshot or on disk",viewerPatchTruncated:"Diff too large; truncated",viewerCloseTab:"Close tab",viewerNotInSnapshot:"Not in the snapshot (over 1MB or excluded); showing the current content from disk",viewerLoadFailed:"Failed to load",viewerEmpty:"Pick a file from the tree on the left",viewerOpenFolder:"Preview folder",viewerDirHint:"Folder: {n} items (ignored files hidden)",viewerDirMore:"Load more"}},h=(0,e.createContext)({lang:"zh",setLang:()=>{},t:f});function i({children:a}){let[b,c]=(0,e.useState)("zh"),f=(0,e.useCallback)(a=>{c(a),localStorage.setItem("piweb.lang",a)},[]);return(0,d.jsx)(h.Provider,{value:{lang:b,setLang:f,t:g[b]},children:a})}function j(){return(0,e.useContext)(h)}},96487:()=>{}};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
exports.id=7662,exports.ids=[7662],exports.modules={909:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{lX:()=>
|
|
2
|
-
`,"utf8"),await g.sync()}finally{await g.close()}await e.rename(f,d)}finally{await e.rm(f,{force:!0})}}async function p(a){let b,c=(0,k.V6)(a,u);try{b=await e.open(c,"wx",384)}catch(a){if("EEXIST"===a.code)throw Error(`an update/build is already running (${c}); after an interrupted build, confirm its process tree has stopped before removing this lock and retrying npm run build:release`);throw a}try{await b.writeFile(JSON.stringify({pid:process.pid,startedAt:new Date().toISOString()}))}catch(a){throw await b.close(),await e.unlink(c),a}return async()=>{await b.close(),await e.unlink(c)}}async function q(a,b){let c=b.slice(`${k.Dy}/`.length);await o(a,v,{extends:"../tsconfig.json",compilerOptions:{tsBuildInfoFile:`./${c}.tsbuildinfo`},include:["../next-env.d.ts","../*.ts","../*.mts","../src/**/*.ts","../src/**/*.tsx","../tests/**/*.ts","../tests/**/*.tsx",`./${c}/types/**/*.ts`,`./${c}/dev/types/**/*.ts`],exclude:["../node_modules","../pi","../dsh","../bin"]})}async function r(a=process.cwd(),b=process.env){let d=(0,k.f6)(a),e=(0,k.Qz)(d,b.PIWEB_BUILD_DIR);if(!e.startsWith(`${k.Dy}/`))throw Error("release requires an isolated build output");let f=(0,i.createRequire)(g.join(d,"package.json")),h=await c(99082)((0,j.pathToFileURL)(f.resolve("next/dist/server/config.js")).href),l="function"==typeof h.default?h.default:h.default.default,{PHASE_PRODUCTION_BUILD:m}=f("next/constants"),n=await l(m,d,{silent:!0});if(n.distDir!==e||n.typescript?.tsconfigPath!==v||n.typescript?.ignoreBuildErrors)throw Error("Next config does not honor the isolated release directory/typecheck; refusing to build over the serving output")}async function s({root:a,env:b,run:c,signal:d},f=async()=>{}){await (0,n.nF)({root:a,env:b,run:c,signal:d},{assertIdle:f}),await c("npm",["run","sync:provider-icons"],{cwd:a,env:b,timeoutMs:6e4,signal:d});let h=JSON.parse(await e.readFile(g.join(a,"node_modules",n.V0,"package.json"),"utf8"));if("string"!=typeof h.version||!h.version)throw Error("Pi engine package version is missing");return h.version}async function t({root:b=a,env:c=process.env,run:d=l.d,beforePrepare:f,prepare:i,signal:j}={}){let m,n=(0,k.f6)(b),r=(0,k.V6)(n,k.Dy);await e.mkdir(r,{recursive:!0}),(0,k.V6)(n,k.Dy);let s=await p(n),u=!1;try{await f?.(),j?.throwIfAborted();let a=(0,k.Qz)(n,`${k.Dy}/${Date.now().toString(36)}-${(0,h.randomUUID)()}`);await e.mkdir((0,k.V6)(n,a)),m={schema:1,state:"building",buildDir:a,startedAt:new Date().toISOString()},await o(n,k.Op,m),u=!0;let b={...c,PI_WEB_ROOT:n,PIWEB_BUILD_DIR:a,PYTHONUTF8:c.PYTHONUTF8??"1",PYTHONIOENCODING:c.PYTHONIOENCODING??"utf-8"};delete b.PI_WEB_DEV,delete b.NODE_ENV,await i?.({root:n,buildDir:a,env:b,run:d,signal:j}),j?.throwIfAborted(),(0,k.f6)(n),await q(n,a),await d(process.execPath,[g.join(n,"scripts","release.mjs"),"--verify-config"],{cwd:n,env:b,timeoutMs:6e4,signal:j}),await d("npm",["run","check"],{cwd:n,env:b,timeoutMs:6e5,signal:j}),j?.throwIfAborted();let l=(0,k.kI)(n,a),p=JSON.parse(await e.readFile(g.join(n,"package.json"),"utf8")).version;if("string"!=typeof p||!p)throw Error("PiWeb package version is missing");return await o(n,k.Op,{...m,...l,state:"ready",version:p,finishedAt:new Date().toISOString()}),{...l,version:p,needsRestart:!0}}catch(a){if(u)try{await o(n,k.Op,{...m,state:"failed",finishedAt:new Date().toISOString()})}catch{}throw a}finally{await s()}}if((0,m.e)("file:///home/runner/work/PiWeb/PiWeb/scripts/release.mjs")){let a=new AbortController,b=()=>a.abort();process.once("SIGINT",b),process.once("SIGTERM",b);try{if(3===process.argv.length&&"--verify-config"===process.argv[2])await r();else{let b=3===process.argv.length&&"--update-pi"===process.argv[2];if(process.argv.length>2&&!b)throw Error("Usage: node scripts/release.mjs [--update-pi]");console.log("[piweb] Checking and building an isolated release; the existing server is not restarted."),b&&console.log("[piweb] Pi dependency update: use a maintenance window with no active sessions; node_modules is shared.");let c=await t({signal:a.signal,prepare:b?async a=>{await s(a)}:void 0});console.log(`[piweb] Release ready: ${c.buildDir} (${c.buildId}). Restart PiWeb manually when idle to use it.`)}}catch(a){console.error(`[piweb] Release failed: ${a instanceof Error?a.message:a}`),process.exitCode=1}finally{process.off("SIGINT",b),process.off("SIGTERM",b)}}d()}catch(a){d(a)}},1)},47516:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{Eb:()=>j}),c(51455);var e=c(76760),f=c.n(e),g=c(89721),h=a([g]);function i(a){let b=f().resolve(a);return"win32"===process.platform?b.toLowerCase():b}function j(a,b){return i(a)===i(b)}g=(h.then?(await h)():h)[0],d()}catch(a){d(a)}})},47662:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.r(b),c.d(b,{ensureStartupCheck:()=>k,markUpdated:()=>m,recordCheck:()=>l,resetStartupCheck:()=>n,startupCheckEnabled:()=>i,updateNoticeLine:()=>j});var e=c(77598),f=c(909),g=a([f]);f=(g.then?(await g)():g)[0];let o="piweb.update.startup",p=["piweb","pi"],q={piweb:"PiWeb",pi:"Pi"};function h(){let a=globalThis,b=Symbol.for(o),c=a[b];if(c)return c;let d={startId:(0,e.randomUUID)(),results:{},pending:null,started:!1};return a[b]=d,d}function i(a=process.env){return"0"!==a.PI_WEB_UPDATE_CHECK}function j(a){let b,c=[];for(let d of p){let e=a[d];!e||"error"in e||!e.canUpdate||(c.push(e.latest===e.current&&e.behind?`${q[d]}(main 新增 ${e.behind} 个提交)`:`${q[d]} ${e.current} → ${e.latest}`),!e.selfUpdate&&e.command&&(b=e.command))}if(!c.length)return null;let d=`[更新] 有新版本:${c.join("、")}。打开 设置 → 通用 点「更新」`;return b?`${d};PiWeb 要先停掉 piweb 再运行:${b}`:d}async function k({check:a=f.lX,log:b=console.log,env:c=process.env}={}){let d;if(!i(c))return null;let e=h();return e.started||(e.started=!0,e.pending=(async()=>{await Promise.all(p.map(async b=>{try{let c=await a(b);e.results[b]||(e.results[b]=c)}catch(a){e.results[b]||(e.results[b]={error:a instanceof Error?a.message:String(a)})}}));let c=j(e.results);c&&b(c)})()),await e.pending,{startId:(d=h()).startId,results:{...d.results}}}function l(a,b){h().results[a]=b}function m(a,b){let c=h(),d=c.results[a],e=!d||"error"in d?{current:"",latest:b,canUpdate:!1,selfUpdate:!0}:d;c.results[a]={...e,latest:b||e.latest,canUpdate:!1,updatedTo:b||e.latest}}function n(){delete globalThis[Symbol.for(o)]}d()}catch(a){d(a)}})},63168:(a,b,c)=>{"use strict";function d(a){let b=a.trim().replace(/^v/i,"").match(/^(\d+)\.(\d+)(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?/);return b?{nums:[Number(b[1]),Number(b[2]),Number(b[3]??0)],pre:b[4]?b[4].split("."):[]}:null}function e(a,b){let c=d(a),e=d(b);if(!c||!e)return!1;for(let a=0;a<3;a+=1)if(c.nums[a]!==e.nums[a])return c.nums[a]>e.nums[a];if(!c.pre.length||!e.pre.length)return 0===c.pre.length&&e.pre.length>0;let f=Math.max(c.pre.length,e.pre.length);for(let a=0;a<f;a+=1){let b=c.pre[a],d=e.pre[a];if(void 0===b)break;if(void 0===d)return!0;let f=/^\d+$/.test(b),g=/^\d+$/.test(d);if(f&&g){if(Number(b)!==Number(d))return Number(b)>Number(d);continue}if(f!==g)return g;if(b!==d)return b>d}return!1}c.d(b,{U:()=>e})},74158:(a,b,c)=>{"use strict";c.d(b,{V:()=>e});var d=c(76760);let e=(c.n(d))().resolve(process.env.PI_WEB_ROOT??process.cwd())},80373:(a,b,c)=>{"use strict";c(73024),c(76760)},89721:(a,b,c)=>{"use strict";c.a(a,async(a,b)=>{try{c(76760),c(73024),c(39642);var d=c(75430);c(80373);var e=a([d]);d=(e.then?(await e)():e)[0],process.env.PYTHONUTF8??="1",process.env.PYTHONIOENCODING??="utf-8",Promise.resolve(),(0,d.createCodemodeExtension)(),(0,d.createToolSearchExtension)(),(0,d.createMcpExtension)(),b()}catch(a){b(a)}})},90053:a=>{"use strict";a.exports={rE:"0.3.
|
|
1
|
+
exports.id=7662,exports.ids=[7662],exports.modules={909:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{lX:()=>A});var e=c(51455),f=c.n(e),g=c(73024),h=c(76760),i=c.n(h),j=c(45348),k=c(11377),l=c(5243),m=c(98011),n=c(63168),o=c(47516),p=c(3912),q=c(74158),r=a([j,o,p]);[j,o,p]=r.then?(await r)():r;class w extends Error{}function s(a){if("piweb"!==a&&"pi"!==a)throw Error("unknown target")}let x="@rexvane/piweb";function t(a){return i().resolve(a).split(/[\\/]/).includes("node_modules")}function u(a=process.platform,b){if("win32"!==a)return!0;if(!b)return!1;try{let a=(0,g.realpathSync)(process.cwd()),c=(0,g.realpathSync)(b),d=i().relative(c,a);return""!==d&&(d.startsWith("..")||i().isAbsolute(d))}catch{return!1}}let y=`npm install -g ${x}@latest`;async function v(a){let b=JSON.parse(await f().readFile(a,"utf8"));if("string"!=typeof b.version||!b.version)throw Error(`no version field in ${a}`);return b.version}let z=function({root:a=q.V,run:b=m.d,versions:c=p.Y,env:d=process.env,platform:e=process.platform}={}){let g=!1,h={...d};async function r(){return(0,l.f6)(a)}async function z(a,c){if(!u(e,a))throw Error(`This PiWeb cannot replace itself while serving. Stop piweb, then run: ${y}`);await c();let d=(c,d)=>b("npm",c,{cwd:a,env:h,timeoutMs:d}),f=i().join(a,"package.json"),g=await v(f);await d(["install","-g",`${x}@latest`,"--no-audit","--no-fund"],6e5),await c(),(0,l.f6)(a);let j=await v(f);if(j===g){let a=(await d(["view",`${x}@latest`,"version"],3e4)).trim().split(/\r?\n/)[0];if((0,n.U)(a,g))throw Error(`npm updated a different copy of ${x}; this installation is not the global package. Update it the way it was installed.`)}return{...(0,l.kI)(a,".next"),version:j,needsRestart:!0}}async function A(a,c){await (0,k.nF)({root:a,env:h,run:b},{omitDev:!0,assertIdle:c}),await c(),(0,l.f6)(a);let d=await v(i().join(a,"node_modules",j.V0,"package.json"));return{...(0,l.kI)(a,".next"),version:d,needsRestart:!0}}return{checkForUpdate:async function(a){if(s(a),g)throw new w("an update is already running");let d=await r(),f=(a,c,e)=>b(a,c,{cwd:d,env:h,timeoutMs:e}),{piWeb:i,piEngine:k}=await c();if("pi"===a){let a=(await f("npm",["view",j.V0,"version"],3e4)).trim().split(/\r?\n/)[0];return{current:k,latest:a,canUpdate:(0,n.U)(a,k),selfUpdate:!0}}if(t(d)){let a=(await f("npm",["view",x,"version"],3e4)).trim().split(/\r?\n/)[0];if(!a)throw Error(`cannot read the published version of ${x}`);let b=u(e,d);return{current:i,latest:a,canUpdate:(0,n.U)(a,i),selfUpdate:b,...b?{}:{command:y}}}await f("git",["fetch","origin","main","--tags"],3e4);let l=Number((await f("git",["rev-list","--count","HEAD..origin/main"],15e3)).trim());if(!Number.isSafeInteger(l)||l<0)throw Error("invalid upstream commit count");let m=JSON.parse(await f("git",["show","origin/main:package.json"],15e3));if(!["piweb","pi-web","@rexvane/piweb"].includes(String(m.name))||"string"!=typeof m.version||!m.version)throw Error("upstream is not a PiWeb package");return{current:i,latest:m.version,behind:l,canUpdate:(0,n.U)(m.version,i)||l>0,selfUpdate:!0}},runUpdate:async function(a,{assertIdle:c=async()=>{}}={}){if(s(a),g)throw new w("an update is already running");g=!0;try{let e=await r();if(t(e))return"piweb"===a?await z(e,c):await A(e,c);let g="";return{...await (0,j.vn)({root:e,env:d,run:b,beforePrepare:async()=>{if(await c(),"piweb"===a){let a=a=>b("git",a,{cwd:e,env:h,timeoutMs:15e3}),c=(await a(["rev-parse","--show-toplevel"])).trim(),d=await f().realpath(c).catch(()=>i().resolve(c));if(!(0,o.Eb)(d,e))throw Error("refusing to update: PiWeb is not the Git installation root");if((await a(["status","--porcelain","--untracked-files=no"])).trim())throw Error("PiWeb has local tracked changes; preserve them before updating (no files were reset)")}await c()},prepare:async d=>{let{env:f,signal:h}=d,k=(a,c,d)=>b(a,c,{cwd:e,env:f,timeoutMs:d,signal:h});"pi"===a?g=await (0,j.eh)(d,c):(await c(),await k("git",["pull","--ff-only","origin","main"],12e4),(0,l.f6)(e),await c(),await k("npm",["install","--no-audit","--no-fund"],6e5),g=await v(i().join(e,"package.json")))}}),version:g,needsRestart:!0}}finally{g=!1}}}}(),A=z.checkForUpdate;z.runUpdate,d()}catch(a){d(a)}})},3912:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{Y:()=>h});var e=c(75430),f=c(90053),g=a([e]);function h(){return Promise.resolve({piWeb:f.rE,piEngine:e.VERSION})}e=(g.then?(await g)():g)[0],d()}catch(a){d(a)}})},5243:(a,b,c)=>{"use strict";c.d(b,{Dy:()=>f,Op:()=>g,Qz:()=>i,V6:()=>j,f6:()=>k,kI:()=>m});var d=c(73024),e=c(76760);let f=".next-releases",g=`${f}/active.json`,h=/^\.next-releases\/[A-Za-z0-9_-]{1,100}$/;function i(a,b){let c=void 0===b?".next":b;if("string"!=typeof c||".next"!==c&&!h.test(c))throw Error("PIWEB_BUILD_DIR must be .next or .next-releases/<safe-id>");return j(a,c),c}function j(a,b){if("string"!=typeof b||!b||b.includes("\\")||b.includes(":"))throw Error("invalid project-relative path");let c=b.split("/");if(c.some(a=>!a||"."===a||".."===a))throw Error("invalid project-relative path");let f=d.realpathSync(a),g=f;for(let a of c){let c;g=e.join(g,a);try{c=d.lstatSync(g)}catch(a){if("ENOENT"===a.code)break;throw a}if(c.isSymbolicLink())throw Error(`refusing linked deployment path: ${b}`);let h=d.realpathSync(g),i=e.relative(f,h);if(".."===i||i.startsWith(`..${e.sep}`)||e.isAbsolute(i))throw Error(`deployment path escapes installation: ${b}`)}return e.join(f,...c)}function k(a){let b=d.realpathSync(a),c=j(b,"package.json"),e=JSON.parse(d.readFileSync(c,"utf8"));if(!["piweb","pi-web","@rexvane/piweb"].includes(e?.name))throw Error(`refusing to update outside the PiWeb installation: ${b}`);return b}function l(a,b,c=1048576){let e=j(a,b),f=d.statSync(e);if(!f.isFile()||f.size>c)throw Error(`invalid deployment file: ${b}`);return d.readFileSync(e,"utf8")}function m(a,b){let c=i(a,b),e=l(a,`${c}/BUILD_ID`,1024).trim();if(!e||/\s/.test(e))throw Error(`invalid BUILD_ID in ${c}`);let f=JSON.parse(function(a,b){try{return l(a,`${b}/required-server-files.json`)}catch(a){if("ENOENT"===a.code)throw Error(function(a,b="required-server-files.json"){return`incomplete production build in ${a}: ${b} is missing. Reinstall with \`npm install -g @rexvane/piweb@latest\`, or rebuild this installation with \`npm rebuild -g piweb\`.`}(b));throw a}}(a,c));if(f?.version!==1||f.config?.distDir?.replaceAll("\\","/")!==c)throw Error(`build output does not match ${c}`);if(!Array.isArray(f.files)||!f.files.length)throw Error(`incomplete build in ${c}`);let g=new Set(f.files.map(a=>"string"==typeof a?a.replaceAll("\\","/"):""));for(let a of["BUILD_ID","routes-manifest.json","build-manifest.json","prerender-manifest.json","server/app-paths-manifest.json"])g.add(`${c}/${a}`);for(let b of g){if(!b.startsWith(`${c}/`))throw Error(`invalid required build file: ${b}`);let e=j(a,b);if(!d.statSync(e).isFile())throw Error(`missing required build file: ${b}`)}return{buildDir:c,buildId:e}}},11377:(a,b,c)=>{"use strict";c.d(b,{V0:()=>d,nF:()=>f});let d="@earendil-works/pi-coding-agent",e=Object.freeze([d,"@earendil-works/pi-ai","@earendil-works/pi-agent-core","@earendil-works/pi-codemode","@earendil-works/pi-mcp","@earendil-works/pi-telemetry","@earendil-works/pi-tui","@earendil-works/chord"]);async function f({root:a,env:b,run:c,signal:g},{omitDev:h=!1,assertIdle:i=async()=>{}}={}){await i();let j=(await c("npm",["view",d+"@latest","version"],{cwd:a,env:b,timeoutMs:3e4,signal:g})).trim(),k=function(a){if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(a))throw Error("Pi runtime requires an exact version; received "+JSON.stringify(a));return e.map(b=>b+"@"+a)}(j);return await i(),await c("npm",["install","--save-exact",...k,...h?["--omit=dev"]:[],"--no-audit","--no-fund"],{cwd:a,env:b,timeoutMs:6e5,signal:g}),j}},18931:(a,b,c)=>{"use strict";c.d(b,{e:()=>f});var d=c(73024),e=c(73136);function f(a){if(!process.argv[1])return!1;try{return d.realpathSync(process.argv[1])===d.realpathSync((0,e.fileURLToPath)(a))}catch{return!1}}},39642:(a,b,c)=>{"use strict";c(73024),c(51455),c(76760)},45348:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{V0:()=>n.V0,eh:()=>s,vn:()=>t});var e=c(51455),f=c(73024),g=c(76760),h=c(77598),i=c(98995),j=c(73136),k=c(5243),l=c(98011),m=c(18931),n=c(11377);let a=function({env:a=process.env,cwd:b=process.cwd(),moduleUrl:c}={}){if(a.PI_WEB_ROOT)return g.resolve(a.PI_WEB_ROOT);if("string"==typeof c)try{let a=g.resolve(g.dirname((0,j.fileURLToPath)(c)),"..");if((0,f.existsSync)(g.join(a,"scripts","release.mjs")))return a}catch{}return g.resolve(b)}({moduleUrl:"file:///home/runner/work/PiWeb/PiWeb/scripts/release.mjs"}),u=`${k.Dy}/update.lock`,v=`${k.Dy}/tsconfig.json`;async function o(a,b,c){let d=(0,k.V6)(a,b),f=(0,k.V6)(a,`${b}.${(0,h.randomUUID)()}.tmp`),g=await e.open(f,"wx",384);try{try{await g.writeFile(`${JSON.stringify(c,null,2)}
|
|
2
|
+
`,"utf8"),await g.sync()}finally{await g.close()}await e.rename(f,d)}finally{await e.rm(f,{force:!0})}}async function p(a){let b,c=(0,k.V6)(a,u);try{b=await e.open(c,"wx",384)}catch(a){if("EEXIST"===a.code)throw Error(`an update/build is already running (${c}); after an interrupted build, confirm its process tree has stopped before removing this lock and retrying npm run build:release`);throw a}try{await b.writeFile(JSON.stringify({pid:process.pid,startedAt:new Date().toISOString()}))}catch(a){throw await b.close(),await e.unlink(c),a}return async()=>{await b.close(),await e.unlink(c)}}async function q(a,b){let c=b.slice(`${k.Dy}/`.length);await o(a,v,{extends:"../tsconfig.json",compilerOptions:{tsBuildInfoFile:`./${c}.tsbuildinfo`},include:["../next-env.d.ts","../*.ts","../*.mts","../src/**/*.ts","../src/**/*.tsx","../tests/**/*.ts","../tests/**/*.tsx",`./${c}/types/**/*.ts`,`./${c}/dev/types/**/*.ts`],exclude:["../node_modules","../pi","../dsh","../bin"]})}async function r(a=process.cwd(),b=process.env){let d=(0,k.f6)(a),e=(0,k.Qz)(d,b.PIWEB_BUILD_DIR);if(!e.startsWith(`${k.Dy}/`))throw Error("release requires an isolated build output");let f=(0,i.createRequire)(g.join(d,"package.json")),h=await c(99082)((0,j.pathToFileURL)(f.resolve("next/dist/server/config.js")).href),l="function"==typeof h.default?h.default:h.default.default,{PHASE_PRODUCTION_BUILD:m}=f("next/constants"),n=await l(m,d,{silent:!0});if(n.distDir!==e||n.typescript?.tsconfigPath!==v||n.typescript?.ignoreBuildErrors)throw Error("Next config does not honor the isolated release directory/typecheck; refusing to build over the serving output")}async function s({root:a,env:b,run:c,signal:d},f=async()=>{}){await (0,n.nF)({root:a,env:b,run:c,signal:d},{assertIdle:f}),await c("npm",["run","sync:provider-icons"],{cwd:a,env:b,timeoutMs:6e4,signal:d});let h=JSON.parse(await e.readFile(g.join(a,"node_modules",n.V0,"package.json"),"utf8"));if("string"!=typeof h.version||!h.version)throw Error("Pi engine package version is missing");return h.version}async function t({root:b=a,env:c=process.env,run:d=l.d,beforePrepare:f,prepare:i,signal:j}={}){let m,n=(0,k.f6)(b),r=(0,k.V6)(n,k.Dy);await e.mkdir(r,{recursive:!0}),(0,k.V6)(n,k.Dy);let s=await p(n),u=!1;try{await f?.(),j?.throwIfAborted();let a=(0,k.Qz)(n,`${k.Dy}/${Date.now().toString(36)}-${(0,h.randomUUID)()}`);await e.mkdir((0,k.V6)(n,a)),m={schema:1,state:"building",buildDir:a,startedAt:new Date().toISOString()},await o(n,k.Op,m),u=!0;let b={...c,PI_WEB_ROOT:n,PIWEB_BUILD_DIR:a,PYTHONUTF8:c.PYTHONUTF8??"1",PYTHONIOENCODING:c.PYTHONIOENCODING??"utf-8"};delete b.PI_WEB_DEV,delete b.NODE_ENV,await i?.({root:n,buildDir:a,env:b,run:d,signal:j}),j?.throwIfAborted(),(0,k.f6)(n),await q(n,a),await d(process.execPath,[g.join(n,"scripts","release.mjs"),"--verify-config"],{cwd:n,env:b,timeoutMs:6e4,signal:j}),await d("npm",["run","check"],{cwd:n,env:b,timeoutMs:6e5,signal:j}),j?.throwIfAborted();let l=(0,k.kI)(n,a),p=JSON.parse(await e.readFile(g.join(n,"package.json"),"utf8")).version;if("string"!=typeof p||!p)throw Error("PiWeb package version is missing");return await o(n,k.Op,{...m,...l,state:"ready",version:p,finishedAt:new Date().toISOString()}),{...l,version:p,needsRestart:!0}}catch(a){if(u)try{await o(n,k.Op,{...m,state:"failed",finishedAt:new Date().toISOString()})}catch{}throw a}finally{await s()}}if((0,m.e)("file:///home/runner/work/PiWeb/PiWeb/scripts/release.mjs")){let a=new AbortController,b=()=>a.abort();process.once("SIGINT",b),process.once("SIGTERM",b);try{if(3===process.argv.length&&"--verify-config"===process.argv[2])await r();else{let b=3===process.argv.length&&"--update-pi"===process.argv[2];if(process.argv.length>2&&!b)throw Error("Usage: node scripts/release.mjs [--update-pi]");console.log("[piweb] Checking and building an isolated release; the existing server is not restarted."),b&&console.log("[piweb] Pi dependency update: use a maintenance window with no active sessions; node_modules is shared.");let c=await t({signal:a.signal,prepare:b?async a=>{await s(a)}:void 0});console.log(`[piweb] Release ready: ${c.buildDir} (${c.buildId}). Restart PiWeb manually when idle to use it.`)}}catch(a){console.error(`[piweb] Release failed: ${a instanceof Error?a.message:a}`),process.exitCode=1}finally{process.off("SIGINT",b),process.off("SIGTERM",b)}}d()}catch(a){d(a)}},1)},47516:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{Eb:()=>j}),c(51455);var e=c(76760),f=c.n(e),g=c(89721),h=a([g]);function i(a){let b=f().resolve(a);return"win32"===process.platform?b.toLowerCase():b}function j(a,b){return i(a)===i(b)}g=(h.then?(await h)():h)[0],d()}catch(a){d(a)}})},47662:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.r(b),c.d(b,{ensureStartupCheck:()=>k,markUpdated:()=>m,recordCheck:()=>l,resetStartupCheck:()=>n,startupCheckEnabled:()=>i,updateNoticeLine:()=>j});var e=c(77598),f=c(909),g=a([f]);f=(g.then?(await g)():g)[0];let o="piweb.update.startup",p=["piweb","pi"],q={piweb:"PiWeb",pi:"Pi"};function h(){let a=globalThis,b=Symbol.for(o),c=a[b];if(c)return c;let d={startId:(0,e.randomUUID)(),results:{},pending:null,started:!1};return a[b]=d,d}function i(a=process.env){return"0"!==a.PI_WEB_UPDATE_CHECK}function j(a){let b,c=[];for(let d of p){let e=a[d];!e||"error"in e||!e.canUpdate||(c.push(e.latest===e.current&&e.behind?`${q[d]}(main 新增 ${e.behind} 个提交)`:`${q[d]} ${e.current} → ${e.latest}`),!e.selfUpdate&&e.command&&(b=e.command))}if(!c.length)return null;let d=`[更新] 有新版本:${c.join("、")}。打开 设置 → 通用 点「更新」`;return b?`${d};PiWeb 要先停掉 piweb 再运行:${b}`:d}async function k({check:a=f.lX,log:b=console.log,env:c=process.env}={}){let d;if(!i(c))return null;let e=h();return e.started||(e.started=!0,e.pending=(async()=>{await Promise.all(p.map(async b=>{try{let c=await a(b);e.results[b]||(e.results[b]=c)}catch(a){e.results[b]||(e.results[b]={error:a instanceof Error?a.message:String(a)})}}));let c=j(e.results);c&&b(c)})()),await e.pending,{startId:(d=h()).startId,results:{...d.results}}}function l(a,b){h().results[a]=b}function m(a,b){let c=h(),d=c.results[a],e=!d||"error"in d?{current:"",latest:b,canUpdate:!1,selfUpdate:!0}:d;c.results[a]={...e,latest:b||e.latest,canUpdate:!1,updatedTo:b||e.latest}}function n(){delete globalThis[Symbol.for(o)]}d()}catch(a){d(a)}})},63168:(a,b,c)=>{"use strict";function d(a){let b=a.trim().replace(/^v/i,"").match(/^(\d+)\.(\d+)(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?/);return b?{nums:[Number(b[1]),Number(b[2]),Number(b[3]??0)],pre:b[4]?b[4].split("."):[]}:null}function e(a,b){let c=d(a),e=d(b);if(!c||!e)return!1;for(let a=0;a<3;a+=1)if(c.nums[a]!==e.nums[a])return c.nums[a]>e.nums[a];if(!c.pre.length||!e.pre.length)return 0===c.pre.length&&e.pre.length>0;let f=Math.max(c.pre.length,e.pre.length);for(let a=0;a<f;a+=1){let b=c.pre[a],d=e.pre[a];if(void 0===b)break;if(void 0===d)return!0;let f=/^\d+$/.test(b),g=/^\d+$/.test(d);if(f&&g){if(Number(b)!==Number(d))return Number(b)>Number(d);continue}if(f!==g)return g;if(b!==d)return b>d}return!1}c.d(b,{U:()=>e})},74158:(a,b,c)=>{"use strict";c.d(b,{V:()=>e});var d=c(76760);let e=(c.n(d))().resolve(process.env.PI_WEB_ROOT??process.cwd())},80373:(a,b,c)=>{"use strict";c(73024),c(76760)},89721:(a,b,c)=>{"use strict";c.a(a,async(a,b)=>{try{c(76760),c(73024),c(39642);var d=c(75430);c(80373);var e=a([d]);d=(e.then?(await e)():e)[0],process.env.PYTHONUTF8??="1",process.env.PYTHONIOENCODING??="utf-8",Promise.resolve(),(0,d.createCodemodeExtension)(),(0,d.createToolSearchExtension)(),(0,d.createMcpExtension)(),b()}catch(a){b(a)}})},90053:a=>{"use strict";a.exports={rE:"0.3.26"}},98011:(a,b,c)=>{"use strict";c.d(b,{d:()=>f});var d=c(31421);async function e(a){if(!a.pid)return void a.kill();if("win32"!==process.platform){try{process.kill(-a.pid,"SIGKILL")}catch{a.kill("SIGKILL")}return}await new Promise(b=>{let c=(0,d.spawn)("taskkill",["/PID",String(a.pid),"/T","/F"],{stdio:"ignore",windowsHide:!0}),e=setTimeout(()=>{a.kill(),c.kill(),b()},1e4),f=()=>{clearTimeout(e),b()};c.once("error",()=>{a.kill(),f()}),c.once("close",f)})}function f(a,b,{cwd:c,env:g=process.env,timeoutMs:h=6e5,signal:i}){return new Promise((f,j)=>{if(i?.aborted)return void j(Error("release cancelled"));let k="win32"===process.platform&&"npm"===a,l=(0,d.spawn)(k?g.ComSpec||"cmd.exe":a,k?["/d","/c","npm",...b]:b,{cwd:c,env:g,windowsHide:!0,detached:"win32"!==process.platform,stdio:["ignore","pipe","pipe"]}),m="",n="",o=!1,p=!1,q=()=>{clearTimeout(u),i?.removeEventListener("abort",t)},r=a=>{p||(p=!0,q(),j(a))},s=a=>{p||o||(o=!0,e(l).then(()=>r(Error(a)),r))},t=()=>s("release cancelled; command process tree terminated"),u=setTimeout(()=>s(`timeout after ${Math.round(h/1e3)}s: ${a} ${b.join(" ")}`),h);i?.addEventListener("abort",t,{once:!0}),i?.aborted&&t(),l.stdout.on("data",a=>{m=(m+a).slice(-262144)}),l.stderr.on("data",a=>{n=(n+a).slice(-262144)}),l.once("error",a=>{o||r(a)}),l.once("close",a=>{if(!o&&!p){if(0!==a)return void r(Error((n||m||`exit code ${a}`).trim().slice(-1e3)));p=!0,q(),f(m)}})})}},99082:a=>{function b(a){return Promise.resolve().then(()=>{var b=Error("Cannot find module '"+a+"'");throw b.code="MODULE_NOT_FOUND",b})}b.keys=()=>[],b.resolve=b,b.id=99082,a.exports=b}};
|