@jetcrab/pi-desk 1.1.13-dev → 1.1.16
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/package.json +2 -2
- package/src/app/api/model-settings/preview/route.ts +1 -0
- package/src/client/l2_biz/settings/hooks/l2-use-model-provider-settings.ts +54 -10
- package/src/client/l2_biz/settings/hooks/l2-use-model-settings.ts +37 -9
- package/src/client/l2_biz/settings/l2-model-settings-biz.ts +26 -12
- package/src/client/l2_biz/settings/views/l2-model-provider-settings.tsx +3 -2
- package/src/client/l2_biz/settings/views/l2-model-replacement-preview.tsx +34 -0
- package/src/client/l4_foundation/ui/l4-confirm-dialog.tsx +9 -1
- package/src/common/l2_biz/model-settings/l2-model-settings-contract.ts +23 -1
- package/src/common/l2_biz/settings/l2-settings-messages.ts +8 -0
- package/src/server/l1_entry/api/l1-model-settings-preview-route.ts +32 -0
- package/src/server/l2_biz/model-settings/l2-model-settings.ts +9 -0
- package/src/server/l2_biz/plugin-management/l2-plugin-management.ts +159 -52
- package/src/server/l4_foundation/model-settings/l4-model-settings-store.ts +161 -38
- package/src/server/l4_foundation/model-settings/l4-model-settings-types.ts +11 -0
- package/src/server/l4_foundation/model-settings/l4-model-settings.ts +1 -0
- package/src/server/l4_foundation/pi/l4-pi-package-maintenance-runner.mts +56 -65
- package/src/server/l4_foundation/pi/l4-pi-package-maintenance.ts +2 -0
- package/src/server/l4_foundation/pi/l4-pi-package-reinstall-runner.mts +49 -0
- package/src/server/l4_foundation/pi/l4-pi-package-root-consistency.ts +6 -2
- package/src/server/l4_foundation/pi/l4-pi-plugin-probe.ts +3 -1
- package/src/server/l4_foundation/pi/l4-pi-runner-process.ts +9 -0
- package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
- package/temp/build/pi-desk/release/.next/app-path-routes-manifest.json +1 -0
- package/temp/build/pi-desk/release/.next/build-manifest.json +2 -2
- package/temp/build/pi-desk/release/.next/prerender-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/required-server-files.js +3 -3
- package/temp/build/pi-desk/release/.next/required-server-files.json +3 -3
- package/temp/build/pi-desk/release/.next/routes-manifest.json +6 -0
- package/temp/build/pi-desk/release/.next/server/app/_global-error/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_not-found/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth/login/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth/logout/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/context/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/images/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/messages/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-check/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-catalog/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route.js +1 -0
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route_client-reference-manifest.js +1 -0
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directories/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-entries/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/models/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/session-user-messages/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/sessions/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/search/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/apply/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/batch/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/enabled-set/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/reload/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/update/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/reveal/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/search/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skills/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/task-center/images/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/task-center/messages/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree-entry/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/branch/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/sort/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/favicon.ico/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/page.js +16 -16
- package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app-paths-manifest.json +1 -0
- package/temp/build/pi-desk/release/.next/server/chunks/35985.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/50520.js +5 -5
- package/temp/build/pi-desk/release/.next/server/chunks/78262.js +3 -3
- package/temp/build/pi-desk/release/.next/server/chunks/82499.js +4 -4
- package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
- package/temp/build/pi-desk/release/.next/server/server-reference-manifest.json +1 -1
- package/temp/build/pi-desk/release/.next/static/DqamF28k0ShQLbNVzXDIj/_buildManifest.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{api/auth-settings/get/route-5137efe26947191b.js → _global-error/page-9969fe0baa238786.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/{api/auth-settings/replace/route-5137efe26947191b.js → _not-found/page-9969fe0baa238786.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{_global-error/page-5137efe26947191b.js → api/auth-settings/get/route-9969fe0baa238786.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/{_not-found/page-5137efe26947191b.js → api/auth-settings/replace/route-9969fe0baa238786.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{layout-358978b7cfe69a5f.js → layout-c0e1c5cef8620cf8.js} +2 -2
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-0069319a4fb97211.js +158 -0
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9969fe0baa238786.js +1 -0
- package/temp/build/pi-desk/release/.next/static/css/6427d02b6edf406f.css +1 -0
- package/temp/build/pi-desk/release/.next/trace-build +1 -1
- package/temp/build/pi-desk/release/.next/static/YdOQ7klRBI5tJb5NpDVLW/_buildManifest.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-cc05e71bf51adb57.js +0 -158
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-5137efe26947191b.js +0 -1
- package/temp/build/pi-desk/release/.next/static/css/095a062e18f96657.css +0 -1
- /package/temp/build/pi-desk/release/.next/static/{YdOQ7klRBI5tJb5NpDVLW → DqamF28k0ShQLbNVzXDIj}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{48923:(e,t,i)=>{Promise.resolve().then(i.t.bind(i,97876,23)),Promise.resolve().then(i.bind(i,64282)),Promise.resolve().then(i.t.bind(i,84178,23))},64282:(e,t,i)=>{"use strict";i.d(t,{L1AppProviders:()=>tg});var s=i(7962);let o={currentHead:"当前 HEAD",localBranch:"本地分支",remoteBranch:"远程分支 \xb7 本地记录",retry:"重试",compareDirect:"直接比较",loadingCommits:"读取提交…",commitList:"Git 提交列表",noCommitMessage:"(无提交说明)",noMatchingCommits:"没有匹配的提交",noCommits:"没有提交记录",scanLimit:"历史扫描达到上限,请选择更具体的分支或提交。",loadedLimit:"已加载 2000 条,请缩小查询范围。",loadMoreCommits:"加载更多提交",backCommits:"返回提交列表",commitChanges:"提交变更",cumulativeChanges:"累计变更",loadedFiles:"已加载 {{count}} 个文件",backCumulative:"返回累计变更",loadingChanges:"读取变更…",noDiff:"没有文件差异",loadMoreFiles:"加载更多文件",changesLimit:"变更文件超过显示上限。",commitDetails:"提交详情",copySha:"复制提交SHA",compareParent:"比较父提交",parentCommit:"父提交 {{count}} \xb7 {{oid}}",mergeBaseToTarget:"共同祖先 → 目标提交",baseToTarget:"基准提交 → 目标提交",emptyRevision:"空版本",selectCommit:"选择提交查看详情",historyAndCompare:"Git 历史与比较",viewMode:"Git 查看方式",historyMode:"提交记录",compareMode:"分支比较",selectRepository:"查看仓库",viewBranch:"查看分支",baseBranch:"基准分支",chooseBase:"选择基准分支",targetBranch:"目标分支",comparison:"比较方式",introducedChanges:"本分支引入的变更",directComparison:"两个版本直接比较",filterAuthor:"按提交用户筛选",author:"提交用户",searchCommits:"搜索提交说明或 SHA",refreshGit:"刷新Git记录",localRecord:"本地记录",refUnavailable:"引用不可用",aheadBehind:"领先 {{ahead}} \xb7 落后 {{behind}}",chooseBaseBranch:"选择基准分支",restoreGit:"还原Git区域",maximizeGit:"最大化Git区域",collapseGit:"收起Git区域",copyFailed:"复制失败",findingGit:"正在识别 Git 仓库…",noGit:"未发现 Git 仓库",collapseDirectory:"收起目录",expandDirectory:"展开目录",previewDescription:"只读项目文件和 Git 历史预览",gitRecords:"Git 记录",refreshPreview:"刷新项目预览",restoreWindow:"还原预览窗口",maximizeWindow:"最大化预览窗口",closePreview:"关闭项目预览",previewArea:"项目预览区域",files:"文件",code:"代码",changeFiles:"提交变更文件",viewDiff:"查看差异",gitStatus:"Git 状态 {{status}}",viewDiffPath:"查看差异 {{path}}",historyDiffAncestor:"共同祖先 {{left}} ↔ {{target}}",historyDiffDirect:"{{left}} ↔ {{target}}",historyReadFailed:"读取 Git 历史失败"};var r=i(46782),n=i(74577),a=i(31343),l=i(67796),c=i(93540),d=i(82639),h=i(74052),u=i(90740),p=i(69266),g=i(33550);function m({children:e}){let{wrapLines:t}=(0,g.TX)();return(0,p.useEffect)(()=>{let e=document.documentElement;e.dataset.piDeskCodeWrap=String(t),e.style.setProperty("--pi-desk-code-white-space",t?"pre-wrap":"pre"),e.style.setProperty("--pi-desk-code-overflow-wrap",t?"anywhere":"normal")},[t]),(0,s.jsx)(s.Fragment,{children:e})}var f=i(5816),v=i(78121),y=i(51821);function b(){let{pendingLocale:e}=(0,f.i)(),{t}=(0,v.Bd)("common"),i=(0,y.G)(),s=(0,p.useRef)(null);return(0,p.useEffect)(()=>{if(!e){s.current=null;return}s.current!==e&&(s.current=e,i.show({level:"info",title:t("languagePendingNotice")}))},[e,t,i]),null}var w=i(32892),C=i(48708),S=i(5011),k=i(42515),P=i(91399),x=i(38979),D=i(9626),R=i(99739);x.Yj().min(32).max(128).regex(/^[A-Za-z0-9_-]+$/);let j="/api/plugins/host-runtime/v1";Object.freeze({imports:Object.freeze({react:`${j}/base.js`,"react/jsx-runtime":`${j}/base.js`,"react/jsx-dev-runtime":`${j}/base.js`,"react-dom":`${j}/base.js`,"react-dom/client":`${j}/base.js`,"@jetcrab/pi-desk-sdk/react/base":`${j}/base.js`,"@jetcrab/pi-desk-sdk/react/markdown":`${j}/markdown.js`})}),x.eu("v1");let I=x.Ik({pluginName:R.tv,url:x.Yj().regex(/^\/api\/plugins\/browser-resources\/[A-Za-z0-9_-]{32,128}\/entry\.js$/,"Browser Entry URL 无效")}).strict(),M=x.Ik({}).strict(),E=x.Ik({entries:x.YO(I)}).strict(),N=Object.freeze({list:(0,D.Vc)({path:"plugins/browser-entries/list",inputSchema:M,outputSchema:E})}),T=x.Yj().trim().min(1).max(32768),A=x.Ik({text:x.Yj(),truncated:x.zM()}).strict(),F=x.KC([x.Ik({type:x.eu("text_append"),text:x.Yj().min(1)}).strict(),x.Ik({type:x.eu("snapshot"),snapshot:A}).strict(),x.Ik({type:x.eu("unavailable")}).strict()]),L=x.Ik({pluginName:R.tv,path:T}).strict(),z=x.Ik({snapshot:A}).strict(),O=x.Ik({}).strict(),B=x.Ik({pluginName:R.tv,path:T,event:F}).strict(),U=Object.freeze({watch:(0,D.Vc)({path:"plugins/logs/watch",inputSchema:L,outputSchema:z}),unwatch:(0,D.Vc)({path:"plugins/logs/unwatch",inputSchema:L,outputSchema:O}),event:(0,D._G)({path:"plugins/logs/event",bodySchema:B})});var q=i(95826),G=i(267);let H=x.gM("scope",[x.Ik({scope:x.eu("global")}).strict(),x.Ik({scope:x.eu("session"),source:G.R}).strict()]),_=x.Ik({pluginName:R.tv,target:H,event:R.f7,data:R.Dz}).strict(),$=(0,D._G)({path:"plugins/push",bodySchema:_});var W=i(79137),V=i(67765);function J(e,t,i){let s=e=>{console.error("[Pi Desk][PluginHost] 插件回调执行失败",{pluginName:i,phase:t,message:e instanceof Error?e.message:String(e)})};try{let t=e();"object"==typeof t&&null!==t&&"then"in t&&"function"==typeof t.then&&Promise.resolve(t).catch(s)}catch(e){s(e)}}async function Y(e,t,i){let s,o=Promise.resolve().then(i).catch(i=>{console.error("[Pi Desk][PluginHost] 插件资源清理失败",{pluginName:e,phase:t,message:i instanceof Error?i.message:String(i)})});try{await Promise.race([o,new Promise(i=>{s=setTimeout(()=>{console.warn("[Pi Desk][PluginHost] 插件资源清理超时",{pluginName:e,phase:t,timeoutMs:1500}),i()},1500)})])}finally{void 0!==s&&clearTimeout(s)}}let K={text:"",truncated:!1,loading:!0,error:null};function Q(e,t){if(t.text!==e.snapshot.text||t.truncated!==e.snapshot.truncated||t.loading!==e.snapshot.loading||t.error!==e.snapshot.error){e.snapshot=t;for(let t of[...e.listeners])J(t,`log:${e.path}`)}}class Z{constructor(e,t){this.channel=e,this.connection=t,this.records=new Map,this.connectionEpoch=0,this.disposed=!1,this.unsubscribeEvents=e.subscribe(e=>this.handleEvent(e)),this.unsubscribeConnection=t.subscribe(()=>this.handleConnectionChange())}open(e){if(this.disposed)throw Error("Plugin log host has been disposed");let t=e.trim();if(!t)throw Error("日志路径不能为空");let i=this.records.get(t);i||(i={path:t,references:0,observed:!1,blockedByError:!1,refreshRequested:!1,syncRequested:!1,syncPromise:null,snapshot:{...K},listeners:new Set},this.records.set(t,i)),i.references+=1,this.requestSync(i);let s=!0;return{getSnapshot:()=>i.snapshot,subscribe:e=>{if(!s)throw Error("Plugin log handle has been disposed");return i.listeners.add(e),()=>{i.listeners.delete(e)}},retry:()=>{s&&!this.disposed&&(i.blockedByError=!1,i.refreshRequested=!0,Q(i,{...i.snapshot,loading:!0,error:null}),this.requestSync(i))},dispose:()=>{s&&(s=!1,i.references-=1,this.requestSync(i))}}}dispose(){if(!this.disposed){for(let e of(this.disposed=!0,this.unsubscribeEvents(),this.unsubscribeConnection(),this.records.values()))e.observed&&"ready"===this.connection.getSnapshot().status&&this.channel.unwatch(e.path).catch(()=>void 0),e.listeners.clear();this.records.clear()}}handleConnectionChange(){if(this.disposed)return;this.connectionEpoch+=1;let e="ready"===this.connection.getSnapshot().status;for(let t of this.records.values())t.observed=!1,t.blockedByError=!1,t.refreshRequested=e,t.references>0&&Q(t,{...t.snapshot,loading:!0,error:e?null:t.snapshot.error}),this.requestSync(t)}handleEvent(e){if(this.disposed)return;let t=this.records.get(e.path);if(t&&0!==t.references){if("text_append"===e.event.type)return void Q(t,{...t.snapshot,text:t.snapshot.text+e.event.text,loading:!1,error:null});if("snapshot"===e.event.type)return void Q(t,{...e.event.snapshot,loading:!1,error:null});t.observed=!1,t.blockedByError=!0,Q(t,{...t.snapshot,loading:!1,error:"日志暂不可用"})}}requestSync(e){this.disposed||(e.syncRequested=!0,e.syncPromise||(e.syncPromise=(async()=>{for(;e.syncRequested&&!this.disposed;)e.syncRequested=!1,await this.reconcileRecord(e)})().finally(()=>{e.syncPromise=null,e.syncRequested&&!this.disposed&&this.requestSync(e)})))}async reconcileRecord(e){if(this.records.get(e.path)!==e)return;let t="ready"===this.connection.getSnapshot().status;if(!(e.references>0&&t&&!e.blockedByError)){if(e.observed&&t){let t=this.connectionEpoch;try{await this.channel.unwatch(e.path)}catch{}t===this.connectionEpoch&&(e.observed=!1)}else e.observed=!1;0!==e.references||e.observed||this.records.delete(e.path);return}if(e.observed&&!e.refreshRequested)return;e.refreshRequested=!1,Q(e,{...e.snapshot,loading:!0,error:null});let i=this.connectionEpoch;try{let t=await this.channel.watch(e.path);if(this.disposed||i!==this.connectionEpoch||this.records.get(e.path)!==e)return;e.observed=!0,e.blockedByError=!1,Q(e,{...t,loading:!1,error:null})}catch(t){if(i!==this.connectionEpoch||"ready"!==this.connection.getSnapshot().status){e.syncRequested=!0;return}e.observed=!1,e.blockedByError=!0,Q(e,{...e.snapshot,loading:!1,error:t instanceof Error&&t.message?t.message:"读取日志失败"})}finally{(0===e.references||e.syncRequested)&&(e.syncRequested=!0)}}}function X(e){if(null!==e&&"object"==typeof e){for(let t of Object.values(e))X(t);Object.freeze(e)}return e}let ee=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,et=/^[a-z0-9]+(?:-[a-z0-9]+)*\/[a-z0-9]+(?:-[a-z0-9]+)*$/,ei=new Set(["plugin","server","rocket","settings","panel","message","terminal","file","folder","bot","wrench","database","globe"]),es=new Set(["application","composer-panel","settings-page","message-view","session-sidebar-tab"]);function eo(e,t){return`${e}\u0000${t}`}function er(e,t,i){return`${e}\u0000${eo(t,i)}`}function en(e){return import(e)}function ea(){return"u"<typeof document?{mode:"light"}:((0,h.Is)(),Object.freeze({mode:document.documentElement.classList.contains("dark")?"dark":"light"}))}function el(e,t){return e.workId===t.workId&&e.sessionId===t.sessionId&&e.branchId===t.branchId}function ec(e){return{source:{workId:e.workId,sessionId:e.sessionId,branchId:e.branchId},cwd:e.cwd,status:e.status}}function ed(e,t){let i=e.trim();if(!i||i.length>100)throw Error(`${t} must contain 1-100 characters`);return i}function eh(e){if("string"!=typeof e)throw Error("Contribution name 必须是字符串");let t=e.trim();if(!t||t.length>64||!ee.test(t))throw Error("Contribution name 必须是 1-64 字符的小写 kebab-case");return t}function eu(e){if(void 0!==e){if(!e||"object"!=typeof e||Array.isArray(e))throw Error("Contribution icon 无效");if("builtin"===e.type){if(2!==Object.keys(e).length||"string"!=typeof e.name||!ei.has(e.name))throw Error("Contribution builtin icon 无效");return{type:"builtin",name:e.name}}if("svg"===e.type){let t="string"==typeof e.content?e.content.trim():"";if(2!==Object.keys(e).length||!t||t.length>16384)throw Error("Contribution SVG icon 无效");return{type:"svg",content:t}}throw Error("Contribution icon type 无效")}}class ep{constructor(e,t=en,i=()=>void 0){this.transport=e,this.entryImporter=t,this.notifyPlugin=i,this.entryDescriptors=[],this.entryDescriptorsByPlugin=new Map,this.entryStates=new Map,this.ownersByPlugin=new Map,this.registrations=new Map,this.contributionLoadStates=new Map,this.browserDescriptors=[],this.registrySnapshot={revision:0,descriptors:this.browserDescriptors},this.messageViewResolutions=new Map,this.logHosts=new Map,this.registryListeners=new Set,this.workSessionListeners=new Set,this.connectionListeners=new Set,this.themeListeners=new Set,this.globalPluginStates={},this.workSessions=[],this.workSessionCreate=null,this.workSessionGoTo=null,this.projectPreview=null,this.terminalOpen=null,this.workSessionFilePreview=null,this.workSessionFileReveal=null,this.imageReader=null,this.connectionSnapshot={status:"disconnected",error:null},this.themeSnapshot={mode:"light"},this.refreshPromise=null,this.refreshPending=!1,this.entriesMaintaining=!1,this.entriesInitialized=!1,this.entryListError=null,this.applicationResolveController=null,this.applicationResolveEpoch=0,this.applicationVisibility=new Map,this.disposed=!1,this.unsubscribePush=e.subscribePush(e=>this.dispatchPush(e));const s=()=>{let e=ea();e.mode!==this.themeSnapshot.mode&&(this.themeSnapshot=e,this.notify(this.themeListeners))};this.themeSnapshot=ea(),this.unsubscribeTheme=(0,h.Cy)(s);const o=window.matchMedia("(prefers-color-scheme: dark)");o.addEventListener("change",s),this.removeSystemThemeListener=()=>o.removeEventListener("change",s)}subscribeRegistry(e){return this.registryListeners.add(e),()=>this.registryListeners.delete(e)}getBrowserDescriptors(){return this.browserDescriptors}getRegisteredBrowserDescriptors(){return[...this.ownersByPlugin.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({pluginName:e,contributions:[...t.registrations.values()].sort((e,t)=>{let i=e.kind.localeCompare(t.kind);return 0===i?e.contributionName.localeCompare(t.contributionName):i}).map(e=>structuredClone(e.descriptor))}))}getRegistrySnapshot(){return this.registrySnapshot}areEntriesInitialized(){return this.entriesInitialized}isRefreshingEntries(){return this.entriesMaintaining||null!==this.refreshPromise}setEntriesMaintaining(e){this.disposed||this.entriesMaintaining===e||(this.entriesMaintaining=e,this.publishRegistryChange())}getEntryListError(){return this.entryListError}getEntryState(e){return this.entryStates.get(e)??{status:"unloaded"}}getFailedEntries(){return[...this.entryStates.entries()].flatMap(([e,t])=>"failed"===t.status?[{pluginName:e,error:t.error}]:[])}getContributionLoadState(e,t,i){return this.contributionLoadStates.get(er(e,t,i))??{status:"unloaded"}}getMessageViewResolution(e){return this.messageViewResolutions.get(e)??null}bindWorkSessionCreate(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionCreate)throw Error("Workbench WorkSession 创建能力已经绑定");this.workSessionCreate=e;let t=!0;return()=>{t&&(t=!1,this.workSessionCreate===e&&(this.workSessionCreate=null))}}bindWorkSessionGoTo(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionGoTo)throw Error("Workbench WorkSession 前往能力已经绑定");this.workSessionGoTo=e;let t=!0;return()=>{t&&(t=!1,this.workSessionGoTo===e&&(this.workSessionGoTo=null))}}bindTerminalOpen(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if(this.terminalOpen)throw Error("终端创建能力已经绑定");return this.terminalOpen=e,()=>{this.terminalOpen===e&&(this.terminalOpen=null)}}bindProjectPreview(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if(this.projectPreview)throw Error("项目预览能力已经绑定");return this.projectPreview=e,()=>{this.projectPreview===e&&(this.projectPreview=null)}}previewProject(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if("string"!=typeof e||!e.trim())throw Error("项目预览需要有效目录");if(!this.projectPreview)throw Error("项目预览尚未准备好");this.projectPreview(e.trim())}bindWorkSessionFilePreview(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionFilePreview)throw Error("Workbench 文件预览能力已经绑定");this.workSessionFilePreview=e;let t=!0;return()=>{t&&(t=!1,this.workSessionFilePreview===e&&(this.workSessionFilePreview=null))}}bindImageReader(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.imageReader)throw Error("Workbench 图片读取能力已经绑定");return this.imageReader=e,()=>{this.imageReader===e&&(this.imageReader=null)}}bindWorkSessionFileReveal(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionFileReveal)throw Error("Workbench 文件定位能力已经绑定");this.workSessionFileReveal=e;let t=!0;return()=>{t&&(t=!1,this.workSessionFileReveal===e&&(this.workSessionFileReveal=null))}}replaceGlobalPluginStates(e){let t=X(structuredClone(e)),i=[...new Set([...Object.keys(this.globalPluginStates),...Object.keys(t)])].filter(e=>JSON.stringify(this.globalPluginStates[e]??null)!==JSON.stringify(t[e]??null));if(0!==i.length){for(let e of(this.globalPluginStates=t,i)){let t=this.ownersByPlugin.get(e);t&&this.notify(t.globalStateListeners)}this.entriesInitialized&&i.some(e=>[...this.ownersByPlugin.get(e)?.registrations.values()??[]].some(e=>"application"===e.kind&&e.resolve))&&this.scheduleApplicationResolution()}}async dispatchNotificationEvent(e,t){let i=this.entryStates.get(t.pluginName);if(i?.status!=="ready")throw Error(`插件 Browser Entry 尚未就绪:${t.pluginName}`);let s=i.runtime.owner,o=s.notificationEventListeners.get(t.name);if(!o)throw Error(`插件未注册通知事件:${t.pluginName}/${t.name}`);if(await o({notificationId:e,data:structuredClone(t.data)}),!s.active)throw Error("Browser Entry 已失效")}replaceWorkSessions(e){var t;let i=X(e.map(ec));t=this.workSessions,!(t.length===i.length&&t.every((e,t)=>void 0!==i[t]&&el(e.source,i[t].source)&&e.cwd===i[t].cwd&&e.status===i[t].status))&&(this.workSessions=i,this.notify(this.workSessionListeners),this.entriesInitialized&&this.scheduleApplicationResolution())}markConnecting(){this.replaceConnection({status:"connecting",error:null})}markReady(){this.replaceConnection({status:"ready",error:null})}markDisconnected(e=null){this.setEntriesMaintaining(!1),this.replaceConnection({status:"disconnected",error:e})}async refreshEntries(){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");return this.refreshPromise?this.refreshPending=!0:(this.entriesInitialized||this.replaceEntriesInitialized(!1),this.refreshPromise=(async()=>{try{do{this.refreshPending=!1;let e=await this.transport.listBrowserEntries();if(this.disposed||this.entriesMaintaining||(await this.replaceEntries(e),this.disposed))return;this.replaceEntriesInitialized(!0),this.replaceEntryListError(null)}while(this.refreshPending&&!this.disposed)}catch(e){throw this.replaceEntriesInitialized(!0),this.replaceEntryListError(e instanceof Error?e.message:String(e)),this.rebuildRegistry(),e}})().finally(()=>{this.refreshPromise=null,this.disposed||this.publishRegistryChange()}),this.publishRegistryChange()),this.refreshPromise}retryEntry(e){return this.entryStates.get(e)?.status==="failed"&&(this.entryStates.delete(e),this.publishRegistryChange()),this.loadEntry(e).then(async e=>(await this.resolveApplications(),e))}retryContribution(e,t,i){let s=er(e,t,i);this.contributionLoadStates.get(s)?.status==="failed"&&(this.contributionLoadStates.delete(s),this.publishRegistryChange());let o=this.registrations.get(s);return o?this.loadContribution(o):Promise.reject(new W.qj({pluginName:e,contributionName:i,phase:"registration",message:"插件 Contribution 不存在"}))}async mountContribution(e){let t=er(e.pluginName,e.kind,e.contributionName),i=this.registrations.get(t);if(!i)throw new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"registration",message:"插件 Contribution 不存在"});let s=new AbortController,o=new Promise(e=>{s.signal.addEventListener("abort",()=>e(),{once:!0})}),r=e.target;if("session-sidebar-tab"===r.kind&&r.setHeaderActions){let t=r.setHeaderActions,o=[];s.signal.addEventListener("abort",()=>{o=[],t([])},{once:!0}),r={...r,setHeaderActions:r=>{if(s.signal.aborted||!i.owner.active)return;if(!Array.isArray(r))throw Error("侧栏操作必须为数组");let n=r.map(t=>{let r=ed(t.label,"Sidebar action label"),a=eu(t.icon),l=!0===t.disabled,c=!0===t.busy,d=t.onSelect;if("function"!=typeof d)throw Error("侧栏操作缺少 onSelect 回调");let h=!1;return{label:r,icon:a,disabled:l,busy:c,onSelect:()=>{s.signal.aborted||!i.owner.active||o!==n||l||c||h||(h=!0,J(async()=>{try{await d()}catch(e){throw!s.signal.aborted&&i.owner.active&&i.owner.host.notify({level:"error",title:r,description:e instanceof Error?e.message:String(e)}),e}finally{h=!1}},`sidebar-action:${r}`,e.pluginName))}}});o=n,t(n)}}}let n=Promise.resolve().then(async()=>{if(s.signal.aborted)throw Error("插件视图已关闭");let t=await this.loadContribution(i);if(s.signal.aborted||!i.owner.active)throw Error("插件视图已失效");let o=t.mount,n=await o({container:e.container,target:r,host:i.owner.host,signal:s.signal});if(void 0!==n&&"function"!=typeof n)throw Error("Contribution mount must return void or a disposer");return n??null}),a=null,l=()=>a||(i.owner.mounts.delete(l),e.signal?.removeEventListener("abort",c),s.abort(),a=Y(e.pluginName,`mount:${e.contributionName}`,async()=>{let e=await n.catch(()=>null);await e?.()})),c=()=>{l()};i.owner.mounts.add(l),e.signal?.addEventListener("abort",c,{once:!0}),e.signal?.aborted&&c();try{if(await Promise.race([n,o]),s.signal.aborted||!i.owner.active)throw Error("插件视图已失效");return l}catch(t){if(await l(),t instanceof W.qj)throw t;throw new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"mount",message:t instanceof Error?t.message:String(t),cause:t})}}async dispose(){if(this.disposed)return;this.disposed=!0,this.applicationResolveController?.abort(),this.applicationResolveController=null,this.unsubscribePush(),this.unsubscribeTheme(),this.removeSystemThemeListener();let e=[...this.ownersByPlugin.values()].reverse();for(let t of(this.ownersByPlugin.clear(),await Promise.all(e.map(e=>this.disposeEntryOwner(e))),this.entriesMaintaining=!1,this.entryStates.clear(),this.entryDescriptorsByPlugin.clear(),this.entryDescriptors=[],this.registrations.clear(),this.contributionLoadStates.clear(),this.browserDescriptors=[],this.messageViewResolutions.clear(),this.applicationVisibility.clear(),this.logHosts.values()))t.dispose();this.logHosts.clear(),this.globalPluginStates={},this.workSessionCreate=null,this.workSessionGoTo=null,this.workSessionFilePreview=null,this.workSessionFileReveal=null,this.imageReader=null,this.projectPreview=null,this.terminalOpen=null,this.registryListeners.clear(),this.workSessionListeners.clear(),this.connectionListeners.clear(),this.themeListeners.clear()}async replaceEntries(e){var t;let i=[...e].sort((e,t)=>e.pluginName.localeCompare(t.pluginName)),s=new Map;for(let e of i){if(s.has(e.pluginName))throw Error(`重复 Plugin Browser Entry:${e.pluginName}`);s.set(e.pluginName,e)}for(let[e,t]of this.entryDescriptorsByPlugin){let i=s.get(e);i?.url!==t.url&&this.disposeEntry(e)}if(this.disposed)return;for(let[e,t]of(this.entryDescriptorsByPlugin.clear(),s))this.entryDescriptorsByPlugin.set(e,t);let o=(t=this.entryDescriptors,JSON.stringify(t)!==JSON.stringify(i));this.entryDescriptors=structuredClone(i),await Promise.allSettled(i.map(e=>this.loadEntry(e.pluginName))),await this.resolveApplications(),o&&this.publishRegistryChange()}loadEntry(e){if(this.disposed)return Promise.reject(Error("Plugin Host Runtime has been disposed"));let t=this.entryDescriptorsByPlugin.get(e);if(!t)return Promise.reject(Error(`Plugin Browser Entry 不存在:${e}`));let i=this.entryStates.get(e);if(i?.status==="ready")return Promise.resolve(i.runtime);if(i?.status==="loading")return i.promise;if(i?.status==="failed")return Promise.reject(i.error);let s=this.initializeEntry(t).then(i=>(this.disposed||this.entryDescriptorsByPlugin.get(e)?.url!==t.url?i.dispose():(this.entryStates.set(e,{status:"ready",runtime:i}),this.ownersByPlugin.set(e,i.owner),this.commitRegistrations(i.owner),this.rebuildRegistry()),this.publishRegistryChange(),i),i=>{let s=i instanceof Error?i:new W.qj({pluginName:e,phase:"entry-import",message:String(i)});throw this.disposed||this.entryDescriptorsByPlugin.get(e)?.url!==t.url||(this.entryStates.set(e,{status:"failed",error:s}),this.rebuildRegistry(),this.publishRegistryChange()),s});return this.entryStates.set(e,{status:"loading",promise:s}),this.publishRegistryChange(),s}async initializeEntry(e){let t;try{t=await this.entryImporter(e.url)}catch(t){throw new W.qj({pluginName:e.pluginName,phase:"entry-import",message:t instanceof Error?t.message:"Browser Entry import 失败",cause:t})}if(this.disposed||this.entryDescriptorsByPlugin.get(e.pluginName)?.url!==e.url)throw Error("Browser Entry 已失效");if("function"!=typeof t.default)throw new W.qj({pluginName:e.pluginName,phase:"entry-factory",message:"Browser Entry 必须 default-export defineBrowserEntry(...)"});let i={descriptor:e,registrations:new Map,pushListeners:new Set,notificationEventListeners:new Map,globalStateListeners:new Set,subscriptionDisposers:new Set,mounts:new Set,disposer:null,registrationOpen:!0,active:!0},s=Object.assign(i,{host:this.createBrowserHost(i)});try{let i=t.default(this.createBrowserFacade(e.pluginName,s));if(s.registrationOpen=!1,"object"==typeof i&&null!==i&&"function"==typeof Reflect.get(i,"then"))throw J(async()=>{let t=await i;"function"==typeof t&&await Y(e.pluginName,"entry-factory",async()=>{await t()})},"entry-factory",e.pluginName),Error("Browser Entry factory must register synchronously");if(void 0!==i&&"function"!=typeof i)throw Error("Browser Entry factory must return void or a disposer");s.disposer=i??null}catch(t){throw s.registrationOpen=!1,await this.disposeEntryOwner(s),new W.qj({pluginName:e.pluginName,phase:"entry-factory",message:t instanceof Error?t.message:String(t),cause:t})}return{pluginName:e.pluginName,owner:s,dispose:()=>this.disposeEntryOwner(s)}}createBrowserFacade(e,t){return{name:e,host:t.host,notifications:{onEvent:(i,s)=>{if(!t.active)throw Error("Browser Entry owner is no longer active");let o=eh(i);if(t.notificationEventListeners.has(o))throw Error(`Browser Notification Event 重复:${e}/${o}`);return t.notificationEventListeners.set(o,s),()=>{t.notificationEventListeners.get(o)===s&&t.notificationEventListeners.delete(o)}}},notify:i=>{t.active&&this.notifyPlugin(e,structuredClone(i))},registerContribution:(i,s,o)=>{if(!t.active||!t.registrationOpen)throw Error("Browser Entry registration phase has ended");if(!es.has(i))throw Error(`Browser Contribution kind 无效:${String(i)}`);let r=this.createRegistration(e,i,s,o,t),n=eo(i,r.contributionName);if(t.registrations.has(n))throw Error(`Browser Contribution 重复:${e}/${i}/${r.contributionName}`);t.registrations.set(n,r)},onPush:e=>{if(!t.active)throw Error("Browser Entry owner is no longer active");return t.pushListeners.add(e),()=>{t.pushListeners.delete(e)}}}}createRegistration(e,t,i,s,o){let r=eh(i);if(!s||"object"!=typeof s||"function"!=typeof s.load)throw Error(`Browser Contribution 必须提供 load():${t}/${r}`);if("application"===t){let i=ed(s.label,"Application label"),n=eu(s.icon),a=s.chrome??"host";if("host"!==a&&"none"!==a)throw Error("Application chrome 必须是 host 或 none");if(void 0!==s.resolve&&"function"!=typeof s.resolve)throw Error("Application resolve 必须是函数");return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:i,title:ed(s.title??i,"Application title"),...n?{icon:n}:{},chrome:a},load:s.load,resolve:s.resolve,owner:o}}if("composer-panel"===t){let i=eu(s.icon);return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:ed(s.label,"Composer Panel label"),...i?{icon:i}:{}},load:s.load,owner:o}}if("settings-page"===t){let i=eu(s.icon);return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:ed(s.label,"Settings Page label"),...i?{icon:i}:{}},load:s.load,owner:o}}if("message-view"===t)return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,viewKey:function(e){if("string"!=typeof e)throw Error("Message View viewKey 必须是字符串");let t=e.trim();if(t.length<3||t.length>129||!et.test(t))throw Error("Message View viewKey 必须是 plugin-name/view-name");return t}(s.viewKey),priority:function(e){if(!Number.isSafeInteger(e))throw Error("Message View priority must be a safe integer");return e}(s.priority)},load:s.load,owner:o};let n=eu(s.icon);return{pluginName:e,kind:"session-sidebar-tab",contributionName:r,descriptor:{kind:"session-sidebar-tab",contributionName:r,label:ed(s.label,"Session Sidebar Tab label"),...n?{icon:n}:{}},load:s.load,owner:o}}commitRegistrations(e){for(let t of e.registrations.values()){let e=er(t.pluginName,t.kind,t.contributionName);if(this.registrations.has(e))throw Error(`Browser Contribution Registry 重复:${e}`);this.registrations.set(e,t)}}loadContribution(e){let t=er(e.pluginName,e.kind,e.contributionName),i=this.contributionLoadStates.get(t);if(i?.status==="ready")return Promise.resolve(i.implementation);if(i?.status==="loading")return i.promise;if(i?.status==="failed")return Promise.reject(i.error);let s=Promise.resolve().then(e.load).then(i=>{if(!i||"function"!=typeof i.mount)throw Error("Lazy Contribution Module 必须导出 mount()");if(!e.owner.active||this.registrations.get(t)!==e)throw Error("Browser Contribution 已失效");return this.contributionLoadStates.set(t,{status:"ready",implementation:i}),this.publishRegistryChange(),i},e=>{throw e}).catch(i=>{let s=i instanceof Error?i:new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"contribution-load",message:String(i)});throw e.owner.active&&this.registrations.get(t)===e&&(this.contributionLoadStates.set(t,{status:"failed",error:s}),this.publishRegistryChange()),s});return this.contributionLoadStates.set(t,{status:"loading",promise:s}),this.publishRegistryChange(),s}async resolveApplications(){if(this.disposed)return;let e=new AbortController;this.applicationResolveController?.abort(),this.applicationResolveController=e;let t=++this.applicationResolveEpoch,i=[...this.registrations.values()].filter(e=>"application"===e.kind),s=new Map;if(await Promise.all(i.map(async t=>{let i=er(t.pluginName,t.kind,t.contributionName);if(!t.resolve)return void s.set(i,!0);try{let o=await t.resolve({workSessions:this.workSessions,host:t.owner.host,signal:e.signal});e.signal.aborted||s.set(i,!1!==o)}catch(o){if(e.signal.aborted)return;s.set(i,!1),console.warn("[Pi Desk][PluginHost] Application resolve 失败",{pluginName:t.pluginName,contributionName:t.contributionName,errorName:o instanceof Error?o.name:"UnknownError",message:o instanceof Error?o.message:String(o)})}})),!this.disposed&&!e.signal.aborted&&this.applicationResolveController===e&&this.applicationResolveEpoch===t){for(let[e,t]of(this.applicationVisibility.clear(),s))this.applicationVisibility.set(e,t);this.rebuildRegistry()}}scheduleApplicationResolution(){queueMicrotask(()=>{this.disposed||this.resolveApplications().catch(e=>{console.error("[Pi Desk][PluginHost] 刷新 Application 可见性失败",{errorName:e instanceof Error?e.name:"UnknownError",message:e instanceof Error?e.message:String(e)})})})}rebuildRegistry(){let e=[...this.ownersByPlugin.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({pluginName:e,contributions:[...t.registrations.values()].filter(e=>"application"!==e.kind||(this.applicationVisibility.get(er(e.pluginName,e.kind,e.contributionName))??!1)).sort((e,t)=>{let i=e.kind.localeCompare(t.kind);return 0===i?e.contributionName.localeCompare(t.contributionName):i}).map(e=>structuredClone(e.descriptor))}));JSON.stringify(this.browserDescriptors)!==JSON.stringify(e)&&(this.browserDescriptors=e,this.rebuildMessageViewResolutions(),this.publishRegistryChange())}rebuildMessageViewResolutions(){this.messageViewResolutions.clear();let e=new Map;for(let t of this.browserDescriptors)for(let i of t.contributions){if("message-view"!==i.kind)continue;let s=e.get(i.viewKey)??[];s.push({pluginName:t.pluginName,descriptor:i}),e.set(i.viewKey,s)}for(let[t,i]of e){let e=Math.max(...i.map(e=>e.descriptor.priority)),s=i.filter(t=>t.descriptor.priority===e);this.messageViewResolutions.set(t,1===s.length?{status:"winner",...s[0]}:{status:"conflict",viewKey:t,candidates:s})}}disposeEntry(e){this.entryDescriptorsByPlugin.delete(e),this.entryStates.delete(e);let t=this.ownersByPlugin.get(e);this.ownersByPlugin.delete(e),t&&this.disposeEntryOwner(t),this.rebuildRegistry()}async disposeEntryOwner(e){if(!e.active)return;for(let t of(e.active=!1,e.registrationOpen=!1,e.pushListeners.clear(),e.notificationEventListeners.clear(),e.globalStateListeners.clear(),e.subscriptionDisposers))J(t,"entry-subscription-dispose",e.descriptor.pluginName);e.subscriptionDisposers.clear();let t=this.logHosts.get(e.descriptor.pluginName);for(let i of(t===e.host.logs&&(this.logHosts.delete(e.descriptor.pluginName),J(()=>t.dispose(),"logs-dispose",e.descriptor.pluginName)),e.registrations.values())){let e=er(i.pluginName,i.kind,i.contributionName);this.registrations.get(e)===i&&(this.registrations.delete(e),this.contributionLoadStates.delete(e),this.applicationVisibility.delete(e))}let i=[...e.mounts].reverse();e.mounts.clear();let s=e.disposer;e.disposer=null,e.registrations.clear(),await Promise.all(i.map(e=>e())),s&&await Y(e.descriptor.pluginName,"entry-dispose",s)}previewWorkSessionFile(e,t,i){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("string"!=typeof t||!t.trim())throw Error("文件预览需要有效路径");let s=function(e){if(void 0!==e&&(null===e||"object"!=typeof e||Array.isArray(e)))throw Error("文件预览选项无效");let t=e?.mode;if(void 0===t||"session"===t||"expanded"===t||"standalone"===t)return t??"session";throw Error("文件预览模式无效")}(i),o=this.workSessions.find(t=>el(t.source,e));if(!o)throw Error("工作会话来源已变化");let r=this.workSessionFilePreview;if(!r)throw Error("Workbench 尚未准备好预览文件");r({source:structuredClone(o.source),cwd:o.cwd,path:t.trim(),mode:s,...i?.imagePaths===void 0?{}:{imagePaths:i.imagePaths}})}async revealWorkSessionFile(e,t){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("string"!=typeof t||!t.trim())throw Error("文件定位需要有效路径");let i=this.workSessions.find(t=>el(t.source,e));if(!i)throw Error("工作会话来源已变化");let s=this.workSessionFileReveal;if(!s)throw Error("Workbench 尚未准备好定位文件");await s({source:structuredClone(i.source),cwd:i.cwd,path:t.trim()})}async readImage(e,t,i){i.throwIfAborted();let s=V._g.parse(t),o=this.workSessions.find(t=>el(t.source,e));if(!o)throw Error("工作会话来源已变化");let r=this.imageReader;if(!r)throw Error("Workbench 尚未准备好读取图片");let n=await r({source:structuredClone(o.source),cwd:o.cwd,path:s},i);if(i.throwIfAborted(),!this.workSessions.some(t=>el(t.source,e)))throw Error("工作会话来源已变化");return n}async createWorkSession(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(!e||"string"!=typeof e.cwd||!e.cwd.trim())throw Error("创建工作会话需要有效 cwd");let t=this.workSessionCreate;if(!t)throw Error("Workbench 尚未准备好创建工作会话");return ec(await t(e.cwd.trim()))}async goToWorkSession(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("workId"in e){if("string"!=typeof e.workId||!e.workId.trim())throw Error("前往工作会话需要有效 workId")}else{if("string"!=typeof e.sessionId||!e.sessionId.trim())throw Error("前往工作会话需要有效 sessionId");if(void 0!==e.cwd&&("string"!=typeof e.cwd||!e.cwd.trim()))throw Error("cwd 必须是非空字符串")}let t=this.workSessionGoTo;if(!t)throw Error("Workbench 尚未准备好前往工作会话");return ec(await t(e))}createBrowserHost(e){let t=e.descriptor.pluginName,i=()=>{if(!e.active||this.disposed)throw Error("Browser Entry 已失效")},s=async e=>{i();let t=await e();return i(),t},o=this.transport.createPiDeskChannel(t),r=this.transport.pi,n=(s,o,r)=>{i();let n=()=>{e.active&&J(o,r,t)},a=()=>{s.delete(n),e.subscriptionDisposers.delete(a)};return s.add(n),e.subscriptionDisposers.add(a),a},a={getSnapshot:()=>(i(),this.connectionSnapshot),subscribe:e=>n(this.connectionListeners,e,"connection")},l=this.logHosts.get(t);return l||(l=new Z(this.transport.createLogChannel(t),{getSnapshot:()=>this.connectionSnapshot,subscribe:a.subscribe}),this.logHosts.set(t,l)),{settings:{getSnapshot:()=>(i(),(0,C.SJ)()),subscribe:s=>{i();let o=(0,C.ae)(()=>{e.active&&J(s,"settings",t)});return e.subscriptionDisposers.add(o),()=>{e.subscriptionDisposers.delete(o),o()}}},notify:e=>{i(),this.notifyPlugin(t,structuredClone(e))},locale:{getSnapshot:()=>(i(),(0,C.SJ)().region)},globalState:{getSnapshot:()=>(i(),this.globalPluginStates[t]??null),subscribe:t=>n(e.globalStateListeners,t,"global-state")},piDesk:{invokeGlobal:(e,t)=>s(()=>o.invokeGlobal(e,t)),invokeSession:(e,t,i)=>s(()=>o.invokeSession(e,t,i))},pi:{prompt:(e,t)=>s(()=>r.prompt(e,t)),commands:{list:e=>s(()=>r.commands.list(e)),execute:(e,t,i)=>s(()=>r.commands.execute(e,t,i))},tools:{list:e=>s(()=>r.tools.list(e))},bash:{execute:(e,t)=>s(()=>r.bash.execute(e,t)),abort:e=>s(()=>r.bash.abort(e))},interrupt:e=>s(()=>r.interrupt(e))},workSessions:{getSnapshot:()=>(i(),this.workSessions),subscribe:e=>n(this.workSessionListeners,e,"work-sessions"),create:e=>s(()=>this.createWorkSession(e)),goTo:e=>s(()=>this.goToWorkSession(e))},workSessionFiles:{preview:(e,t,s)=>{i(),this.previewWorkSessionFile(e,t,s)},reveal:(e,t)=>s(()=>this.revealWorkSessionFile(e,t)),readImage:(t,i,o)=>s(async()=>{let s=new AbortController,r=()=>s.abort();e.subscriptionDisposers.add(r);try{return await this.readImage(t,i,o?AbortSignal.any([o,s.signal]):s.signal)}finally{e.subscriptionDisposers.delete(r)}})},projects:{preview:e=>{i(),this.previewProject(e)}},terminals:{open:t=>s(async()=>{if(!t||"string"!=typeof t.cwd||!t.cwd.trim())throw Error("新建终端需要有效 cwd");let i=this.terminalOpen;if(!i)throw Error("终端创建能力尚未准备好");let s=new AbortController,o=()=>s.abort();e.subscriptionDisposers.add(o);try{await i(t.cwd,s.signal)}finally{e.subscriptionDisposers.delete(o)}})},logs:l,connection:a,theme:{getSnapshot:()=>(i(),this.themeSnapshot),subscribe:e=>n(this.themeListeners,e,"theme")}}}dispatchPush(e){let t=this.entryStates.get(e.pluginName);if(t?.status!=="ready")return;let i=t.runtime.owner;for(let t of[...i.pushListeners]){if(!i.active)break;J(()=>t(e),`push:${e.event}`,e.pluginName)}}replaceEntriesInitialized(e){this.entriesInitialized!==e&&(this.entriesInitialized=e,this.publishRegistryChange())}replaceEntryListError(e){this.entryListError!==e&&(this.entryListError=e,this.publishRegistryChange())}replaceConnection(e){(e.status!==this.connectionSnapshot.status||e.error!==this.connectionSnapshot.error)&&(this.connectionSnapshot=Object.freeze({...e}),this.notify(this.connectionListeners))}publishRegistryChange(){this.registrySnapshot={revision:this.registrySnapshot.revision+1,descriptors:this.browserDescriptors},this.notify(this.registryListeners)}notify(e){for(let t of[...e])J(t,"notify")}}var eg=i(31761),em=i(24925),ef=i(48155),ev=i(63013),ey=i(55079),eb=i(49667),ew=i(90680),eC=i(49362),eS=i(24863),ek=i(49762),eP=i(60278),ex=i(5464),eD=i(72282),eR=i(86963),ej=i(55945),eI=i(35842),eM=i(73068),eE=i(99084),eN=i(49426),eT=i(93119),eA=i(93320),eF=i(56592);class eL{constructor(e,t){this.cwd=e,this.reader=t,this.state={snapshot:{status:"idle",repositories:[],error:null},layout:"directory",changesOnly:!1,expandedRepositories:new Set},this.listeners=new Set,this.revision=0,this.request=null,this.disposed=!1,this.subscribe=e=>(this.listeners.add(e),()=>this.listeners.delete(e)),this.getRevision=()=>this.revision}getWorkspace(e){return e===this.cwd?this.state:null}ensureSnapshot(e){return e!==this.cwd||"ready"===this.state.snapshot.status||this.request?Promise.resolve():this.load(!1)}refreshSnapshot(e){return e===this.cwd?this.load(!0):Promise.resolve()}setLayout(e,t){this.state.layout=t,this.publish()}setChangesOnly(e,t){this.state.changesOnly=t,this.publish()}toggleRepository(e,t){let i=new Set(this.state.expandedRepositories);i.has(t)?i.delete(t):i.add(t),this.state.expandedRepositories=i,this.publish()}dispose(){this.disposed=!0,this.request?.abort(),this.request=null,this.listeners.clear()}async load(e){if(this.disposed)return;this.request?.abort();let t=new AbortController;this.request=t,this.state.snapshot={...this.state.snapshot,status:"loading",error:null},this.publish();try{let i=await this.reader.snapshot(t.signal,e);if(this.request!==t)return;this.state.snapshot={status:"ready",repositories:i.repositories,error:null}}catch(e){if(this.request!==t)return;this.state.snapshot={...this.state.snapshot,status:"error",error:e instanceof Error?e.message:"读取 Git 状态失败"}}this.request===t&&(this.request=null,this.publish())}publish(){if(!this.disposed)for(let e of(this.revision+=1,this.listeners))e()}}var ez=i(20476),eO=i(73230),eB=i(82075);function eU(e,t){return(0,eO.B)({msg:o[e],i18n:{key:`projectHistory:${e}`,...t?{params:t}:{}}})}function eq(){return{status:"idle",data:null,error:null}}class eG{constructor(e,t){this.reader=e,this.files=t,this.state={repositoryRoot:null,mode:"history",tip:"HEAD",base:"",target:"HEAD",strategy:"merge-base",query:"",author:"",authorSuggestions:[],selectedCommit:null,selectedChangePath:null,branches:eq(),log:eq(),changes:eq()},this.scroll={log:0,changes:0},this.listeners=new Set,this.requests=new Map,this.revision=0,this.disposed=!1,this.logPage=1,this.changesPage=1,this.range=null,this.selection=null,this.restoredCommit=null,this.restoredChangePath=null,this.restoredChangesScroll=null,this.queryTimer=null,this.collapsedDirectories=new Set,this.changeTree=(0,eB.OA)([]),this.changeRows=[],this.subscribe=e=>(this.listeners.add(e),()=>this.listeners.delete(e)),this.getRevision=()=>this.revision}getChangeRows(){return this.changeRows}restoreBrowsing(e){Object.assign(this.state,{repositoryRoot:e.repositoryRoot,mode:e.mode,tip:e.tip,base:e.base,target:e.target,strategy:e.strategy,query:e.query,author:e.author}),this.scroll.log=e.logScroll,this.restoredChangesScroll=e.changesScroll,this.restoredCommit=e.selectedCommit,this.restoredChangePath=e.selectedChangePath,null!==e.repositoryRoot&&(this.loadBranches(),this.reload())}selectChange(e){this.state.changes.data?.items.some(t=>t.path===e)&&(this.state.selectedChangePath=e,this.publish())}toggleChangeDirectory(e){let t=this.changeRows.find(t=>t.directory?.path===e);if(t?.directory){if(t.expanded)this.collapsedDirectories.add(e);else for(let e of t.directory.paths)this.collapsedDirectories.delete(e);this.rebuildChangeRows(),this.publish()}}setScroll(e,t){this.scroll[e]=t}setRepository(e){e!==this.state.repositoryRoot&&(this.cancel("branches"),this.state.repositoryRoot=e,this.state.tip=this.state.target="HEAD",this.state.base="",this.state.author="",this.state.authorSuggestions=[],this.state.branches=eq(),this.resetSelection(),this.loadBranches(),this.reload())}setMode(e){this.state.mode!==e&&(this.state.mode=e,this.resetSelection(),this.reload())}setRevision(e,t){this.state[e]!==t&&(this.state[e]=t,this.resetSelection(),this.reload())}setStrategy(e){this.state.strategy!==e&&(this.state.strategy=e,this.resetSelection(),this.reload())}setQuery(e){this.setLogFilter("query",e)}setAuthor(e){this.setLogFilter("author",e)}setLogFilter(e,t){this.state[e]=t,this.resetSelection(),this.queryTimer=setTimeout(()=>{this.queryTimer=null,this.reload()},220)}refresh(){this.resetSelection(),this.loadBranches(),this.reload()}async reload(){if(!this.disposed&&null!==this.state.repositoryRoot){if("compare"===this.state.mode)return this.state.base?void await this.loadChanges({base:this.state.base,target:this.state.target,strategy:this.state.strategy},1,!0):void this.publish();await this.loadLog(1)}}selectCommit(e,t){let i="string"==typeof e?e:e.oid;this.state.selectedCommit=i,this.scroll.changes=0,this.clearHistoricalDiff(),this.loadChanges({commit:i,...t?{parent:t}:{}},1)}showAggregate(){this.range&&(this.state.selectedCommit=null,this.clearHistoricalDiff(),this.loadChanges(this.range,1))}loadMoreLog(){"ready"===this.state.log.status&&this.state.log.data?.hasMore&&!(this.state.log.data.items.length>=2e3)&&this.loadLog(this.logPage+1)}loadMoreChanges(){this.selection&&"ready"===this.state.changes.status&&this.state.changes.data?.hasMore&&this.loadChanges(this.selection,this.changesPage+1)}openChange(e){if(null===this.state.repositoryRoot)return;let t=this.state.changes.data,i=t?.items.find(t=>t.path===e);if(!t||!i)return;this.state.selectedChangePath=e,this.publish();let{original:s,target:o}=t.comparison,r=s?s.slice(0,8):eU("emptyRevision"),n=eU(this.state.selectedCommit||"merge-base"!==this.state.strategy?"historyDiffDirect":"historyDiffAncestor",{left:r,target:o.slice(0,8)});this.files.openDiff(this.state.repositoryRoot,e,{baseCommit:s,targetCommit:o,...i.oldPath?{oldPath:i.oldPath}:{}},n)}dispose(){for(let e of(this.disposed=!0,this.queryTimer&&clearTimeout(this.queryTimer),this.requests.values()))e.abort();this.requests.clear(),this.resetChangeTree(),this.listeners.clear()}async loadBranches(){let e=this.state.repositoryRoot;if(null===e||this.disposed)return;let t=this.begin("branches");this.state.branches={status:"loading",data:this.state.branches.data,error:null},this.publish();try{let i=await this.reader.branches(e,t.signal);if(!this.current("branches",t))return;this.state.branches={status:"ready",data:i,error:null}}catch(e){if(!this.current("branches",t))return;this.state.branches={status:"error",data:null,error:this.error(e)}}this.requests.delete("branches"),this.publish()}async loadLog(e){let t=this.state.repositoryRoot;if(this.disposed||null===t)return;let i=e>1?this.state.log.data:null,s=i?.tip??("compare"===this.state.mode?this.range?.target:this.state.tip),o=i?.exclude??("compare"===this.state.mode?this.range?.base:void 0);if(!s)return;let r=this.begin("log");this.state.log={status:"loading",data:i,error:null},this.publish();try{let n=await this.reader.log(t,{tip:s,...o?{exclude:o}:{},query:this.state.query,...this.state.author.trim()?{author:this.state.author.trim()}:{},page:{index:e,size:50}},r.signal);if(!this.current("log",r))return;for(let{author:t}of(this.logPage=e,n.items))t&&this.state.authorSuggestions.length<200&&!this.state.authorSuggestions.includes(t)&&this.state.authorSuggestions.push(t);if(this.state.log={status:"ready",data:{...n,items:[...i?.items??[],...n.items].slice(0,2e3)},error:null},1===e&&n.items[0]){let e=n.items.find(e=>e.oid===this.restoredCommit);this.restoredCommit=null,e?(this.state.selectedCommit=e.oid,this.loadChanges({commit:e.oid},1)):"history"===this.state.mode&&this.selectCommit(n.items[0])}}catch(e){if(!this.current("log",r))return;this.state.log={status:"error",data:i,error:this.error(e)}}this.requests.delete("log"),this.publish()}async loadChanges(e,t,i=!1){let s=this.state.repositoryRoot;if(this.disposed||null===s)return;let o=this.begin("changes"),r=t>1?this.state.changes.data:null;1===t&&this.resetChangeTree(),this.selection=e,this.state.changes={status:"loading",data:r,error:null},this.publish();try{let n=await this.reader.changes(s,{selection:e,page:{index:t,size:200}},o.signal);if(!this.current("changes",o))return;this.changesPage=t;let a=[...r?.items??[],...n.items];this.state.changes={status:"ready",data:{...n,items:a},error:null},this.changeTree=(0,eB.OA)(a.map(e=>e.path)),null!==this.restoredChangesScroll&&(this.scroll.changes=this.restoredChangesScroll,this.restoredChangesScroll=null),this.rebuildChangeRows(),this.restoredChangePath&&a.some(e=>e.path===this.restoredChangePath)&&(this.state.selectedChangePath=this.restoredChangePath,this.restoredChangePath=null),this.selection="commit"in e?{commit:n.comparison.target,...n.commit?.selectedParent?{parent:n.commit.selectedParent}:{}}:{base:n.comparison.base,target:n.comparison.target,strategy:e.strategy},i&&"base"in this.selection&&(this.range=this.selection,this.loadLog(1))}catch(e){if(!this.current("changes",o))return;this.state.changes={status:"error",data:r,error:this.error(e)}}this.requests.delete("changes"),this.publish()}resetSelection(){this.restoredCommit=null,this.restoredChangePath=null,this.restoredChangesScroll=null,this.queryTimer&&clearTimeout(this.queryTimer),this.queryTimer=null,this.scroll.log=this.scroll.changes=0,this.cancel("log"),this.cancel("changes"),this.range=null,this.selection=null,this.state.selectedCommit=null,this.state.log=eq(),this.state.changes=eq(),this.resetChangeTree(),this.clearHistoricalDiff(),this.publish()}resetChangeTree(){this.collapsedDirectories.clear(),this.changeTree=(0,eB.OA)([]),this.changeRows=[],this.state.selectedChangePath=null,this.scroll.changes=0}rebuildChangeRows(){let e=Math.floor(this.scroll.changes/36),t=this.changeRows[e],i=this.scroll.changes%36;this.changeRows=(0,eB.qV)(this.changeTree,this.collapsedDirectories);let s=t?this.changeRows.findIndex(e=>e.key===t.key):-1;this.scroll.changes=s>=0?36*s+i:Math.min(this.scroll.changes,Math.max(0,(this.changeRows.length-1)*36))}clearHistoricalDiff(){this.files.state.activeDiff?.comparison&&this.files.closeDiff()}begin(e){this.cancel(e);let t=new AbortController;return this.requests.set(e,t),t}cancel(e){this.requests.get(e)?.abort(),this.requests.delete(e)}current(e,t){return!this.disposed&&this.requests.get(e)===t}error(e){return e instanceof Error?e.message:eU("historyReadFailed")}publish(){if(!this.disposed)for(let e of(this.revision+=1,this.listeners))e()}}var eH=i(14044),e_=i(57731),e$=i(35995),eW=i(15265),eV=i(74675),eJ=i(73429),eY=i(60471);function eK({items:e,label:t,scrollTop:i,onScroll:o,render:r,role:n="listbox",onKeyDown:a}){let l=(0,p.useRef)(null),[c,d]=(0,p.useState)({top:i,height:300});(0,p.useLayoutEffect)(()=>{let e=l.current;if(!e)return;e.scrollTop=i;let t=()=>d({top:e.scrollTop,height:e.clientHeight});t();let s=new ResizeObserver(t);return s.observe(e),()=>s.disconnect()},[]),(0,p.useLayoutEffect)(()=>{l.current&&(l.current.scrollTop=i)},[e,i]);let h=Math.max(0,Math.floor(c.top/36)-8),u=Math.min(e.length,Math.ceil((c.top+c.height)/36)+8);return(0,s.jsx)("div",{ref:l,role:n,tabIndex:"tree"===n?0:void 0,onKeyDown:a,"aria-label":t,className:"min-h-0 flex-1 overflow-auto overscroll-contain",onScroll:e=>{let t=e.currentTarget.scrollTop;d(e=>({...e,top:t})),o(t)},children:(0,s.jsx)("div",{style:{height:36*e.length,position:"relative"},children:(0,s.jsx)("div",{style:{position:"absolute",top:36*h,left:0,right:0},children:e.slice(h,u).map((e,t)=>r(e,h+t))})})})}var eQ=i(36670),eZ=i(50479),eX=i(66584),e0=i(60682);let e1={added:"A",modified:"M",deleted:"D",renamed:"R","type-changed":"T"};function e2({cwd:e,repositoryRoot:t,rows:i,changes:o,selectedPath:r,scrollTop:n,onScroll:a,onSelect:l,onToggle:c,onOpen:d,onReveal:h}){let{t:u}=(0,v.Bd)("projectHistory"),p=new Map(o.map(e=>[e.path,e]));return(0,s.jsx)(eK,{role:"tree",label:u("changeFiles"),items:i,scrollTop:n,onScroll:a,onKeyDown:e=>{if(e.defaultPrevented||!e.currentTarget.contains(e.target))return;let t=e.target instanceof Element?e.target.closest("[data-tree-key]"):null;if(e.target instanceof Element&&e.target.closest("button"))return;let s=t?i.findIndex(e=>e.key===t.dataset.treeKey):-1,o=i[s],r=s;if("ArrowDown"===e.key)r=Math.min(i.length-1,s+1);else if("ArrowUp"===e.key)r=Math.max(0,s-1);else if("Home"===e.key)r=0;else if("End"===e.key)r=i.length-1;else if("ArrowRight"===e.key&&o?.directory)o.expanded?r=Math.min(i.length-1,s+1):c(o.directory.path);else if("ArrowLeft"===e.key&&o){if(o.expanded&&o.directory)c(o.directory.path);else for(let e=s-1;e>=0;e-=1)if(i[e].depth<o.depth){r=e;break}}else{if("Enter"!==e.key&&" "!==e.key||!o)return;o.directory?c(o.directory.path):"Enter"===e.key?d(o.path):l(o.path)}e.preventDefault();let n=i[r];if(!n)return;let a=e.currentTarget;36*r<a.scrollTop?a.scrollTop=36*r:(r+1)*36>a.scrollTop+a.clientHeight&&(a.scrollTop=(r+1)*36-a.clientHeight),requestAnimationFrame(()=>{[...a.querySelectorAll("[data-tree-key]")].find(e=>e.dataset.treeKey===n.key)?.focus()})},render:i=>{let o=p.get(i.path),n=(0,eB._J)(t,i.path),a=i.directory;return(0,s.jsx)(e0.J,{cwd:e,path:n,type:i.type,historical:!0,expanded:i.expanded,onToggle:a?()=>c(a.path):void 0,onOpen:"file"===i.type?()=>d(i.path):void 0,openLabel:u("viewDiff"),oldPath:"file"===i.type&&o?.oldPath?(0,eB._J)(t,o.oldPath):void 0,onReveal:h,trigger:(0,s.jsxs)("div",{role:"treeitem",tabIndex:0,"aria-level":i.depth+1,"aria-expanded":i.expanded,"aria-selected":"file"===i.type&&r===i.path,"data-tree-key":i.key,className:(0,eN.cn)("flex h-9 min-w-0 cursor-pointer items-center gap-2 pr-2 text-sm outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring","file"===i.type&&r===i.path&&"bg-accent"),style:{paddingLeft:8+16*i.depth},title:o?.oldPath&&"file"===i.type?`${(0,eB._J)(t,o.oldPath)} → ${n}`:n,onClick:e=>{a?e.detail<2&&c(a.path):l(i.path)},onDoubleClick:()=>{"file"===i.type&&d(i.path)},children:[a?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(eQ.A,{className:(0,eN.cn)("size-4 shrink-0 text-muted-foreground",i.expanded&&"rotate-90")}),i.expanded?(0,s.jsx)(eZ.A,{className:"size-4 shrink-0 text-muted-foreground"}):(0,s.jsx)(eX.A,{className:"size-4 shrink-0 text-muted-foreground"})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"w-4 shrink-0"}),(0,s.jsx)("span",{className:(0,eN.cn)("w-4 shrink-0 font-mono text-xs",o?.status==="added"?"text-emerald-600 dark:text-emerald-400":o?.status==="deleted"?"text-red-600 dark:text-red-400":"text-blue-600 dark:text-blue-400"),"aria-label":u("gitStatus",{status:o?e1[o.status]:""}),children:o?e1[o.status]:""})]}),(0,s.jsxs)("span",{className:"min-w-0 flex-1 truncate",children:[i.label,"directory"===i.type&&p.has(i.path)?"/":""]}),"file"===i.type?(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":u("viewDiffPath",{path:i.path}),onDoubleClick:e=>e.stopPropagation(),onClick:e=>{e.stopPropagation(),d(i.path)},children:(0,s.jsx)(eP.A,{className:"size-4"})}):null]})},i.key)}})}function e4(e){let{state:t,repositories:i,projectName:o,narrow:r,scroll:n}=e,{t:a}=(0,v.Bd)("projectHistory"),{locale:l,timeZone:c}=(0,f.i)(),d=(0,p.useMemo)(()=>new Intl.DateTimeFormat("en"===l?"en-US":"zh-CN",{timeZone:c,month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[l,c]),h=(0,p.useMemo)(()=>new Intl.DateTimeFormat("en"===l?"en-US":"zh-CN",{timeZone:c,timeZoneName:"shortOffset",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[l,c]),u=(0,p.useId)(),{mobilePane:g,onMobilePane:m}=e,y=t.changes.data,b=`${t.repositoryRoot}:${y?.comparison.original}:${y?.comparison.target}`,w=t.selectedChangePath,C=[{value:"HEAD",label:a("currentHead")},...(t.branches.data?.local??[]).map(e=>({value:`refs/heads/${e}`,label:e,description:a("localBranch")})),...(t.branches.data?.remote??[]).map(e=>({value:`refs/remotes/${e}`,label:e,description:a("remoteBranch")}))],S=t.branches.data?.upstream,k=y?.commit,P=i=>i?(0,s.jsxs)("div",{role:"alert",className:"flex flex-wrap items-center gap-2 p-3 text-sm text-destructive",children:[(0,s.jsx)("span",{className:"min-w-0 flex-1 break-words",children:i}),(0,s.jsx)(eR.$,{size:"sm",variant:"outline",onClick:e.onRefresh,children:a("retry")}),"compare"===t.mode&&"merge-base"===t.strategy?(0,s.jsx)(eR.$,{size:"sm",variant:"outline",onClick:()=>e.onStrategy("direct"),children:a("compareDirect")}):null]}):null,x=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[P(t.log.error),"loading"===t.log.status?(0,s.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 text-xs text-muted-foreground",children:[(0,s.jsx)(eH.A,{className:"size-4 animate-spin"}),a("loadingCommits")]}):null,(0,s.jsx)(eK,{items:t.log.data?.items??[],label:a("commitList"),scrollTop:n.log,onScroll:t=>e.onScroll("log",t),render:i=>(0,s.jsxs)("button",{type:"button",role:"option","aria-selected":t.selectedCommit===i.oid,className:(0,eN.cn)("flex h-9 w-full items-center gap-3 border-b border-border/40 px-3 text-left text-sm outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",t.selectedCommit===i.oid&&"bg-accent"),onClick:()=>{var t;return t=i.oid,void(e.onCommit(t),r&&m("files"))},title:`${i.subject}
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{48923:(e,t,i)=>{Promise.resolve().then(i.t.bind(i,97876,23)),Promise.resolve().then(i.bind(i,64282)),Promise.resolve().then(i.t.bind(i,84178,23))},64282:(e,t,i)=>{"use strict";i.d(t,{L1AppProviders:()=>tg});var s=i(7962);let o={currentHead:"当前 HEAD",localBranch:"本地分支",remoteBranch:"远程分支 \xb7 本地记录",retry:"重试",compareDirect:"直接比较",loadingCommits:"读取提交…",commitList:"Git 提交列表",noCommitMessage:"(无提交说明)",noMatchingCommits:"没有匹配的提交",noCommits:"没有提交记录",scanLimit:"历史扫描达到上限,请选择更具体的分支或提交。",loadedLimit:"已加载 2000 条,请缩小查询范围。",loadMoreCommits:"加载更多提交",backCommits:"返回提交列表",commitChanges:"提交变更",cumulativeChanges:"累计变更",loadedFiles:"已加载 {{count}} 个文件",backCumulative:"返回累计变更",loadingChanges:"读取变更…",noDiff:"没有文件差异",loadMoreFiles:"加载更多文件",changesLimit:"变更文件超过显示上限。",commitDetails:"提交详情",copySha:"复制提交SHA",compareParent:"比较父提交",parentCommit:"父提交 {{count}} \xb7 {{oid}}",mergeBaseToTarget:"共同祖先 → 目标提交",baseToTarget:"基准提交 → 目标提交",emptyRevision:"空版本",selectCommit:"选择提交查看详情",historyAndCompare:"Git 历史与比较",viewMode:"Git 查看方式",historyMode:"提交记录",compareMode:"分支比较",selectRepository:"查看仓库",viewBranch:"查看分支",baseBranch:"基准分支",chooseBase:"选择基准分支",targetBranch:"目标分支",comparison:"比较方式",introducedChanges:"本分支引入的变更",directComparison:"两个版本直接比较",filterAuthor:"按提交用户筛选",author:"提交用户",searchCommits:"搜索提交说明或 SHA",refreshGit:"刷新Git记录",localRecord:"本地记录",refUnavailable:"引用不可用",aheadBehind:"领先 {{ahead}} \xb7 落后 {{behind}}",chooseBaseBranch:"选择基准分支",restoreGit:"还原Git区域",maximizeGit:"最大化Git区域",collapseGit:"收起Git区域",copyFailed:"复制失败",findingGit:"正在识别 Git 仓库…",noGit:"未发现 Git 仓库",collapseDirectory:"收起目录",expandDirectory:"展开目录",previewDescription:"只读项目文件和 Git 历史预览",gitRecords:"Git 记录",refreshPreview:"刷新项目预览",restoreWindow:"还原预览窗口",maximizeWindow:"最大化预览窗口",closePreview:"关闭项目预览",previewArea:"项目预览区域",files:"文件",code:"代码",changeFiles:"提交变更文件",viewDiff:"查看差异",gitStatus:"Git 状态 {{status}}",viewDiffPath:"查看差异 {{path}}",historyDiffAncestor:"共同祖先 {{left}} ↔ {{target}}",historyDiffDirect:"{{left}} ↔ {{target}}",historyReadFailed:"读取 Git 历史失败"};var r=i(46782),n=i(74577),a=i(31343),l=i(67796),c=i(93540),d=i(82639),h=i(74052),u=i(90740),p=i(69266),g=i(33550);function m({children:e}){let{wrapLines:t}=(0,g.TX)();return(0,p.useEffect)(()=>{let e=document.documentElement;e.dataset.piDeskCodeWrap=String(t),e.style.setProperty("--pi-desk-code-white-space",t?"pre-wrap":"pre"),e.style.setProperty("--pi-desk-code-overflow-wrap",t?"anywhere":"normal")},[t]),(0,s.jsx)(s.Fragment,{children:e})}var f=i(5816),v=i(78121),y=i(51821);function b(){let{pendingLocale:e}=(0,f.i)(),{t}=(0,v.Bd)("common"),i=(0,y.G)(),s=(0,p.useRef)(null);return(0,p.useEffect)(()=>{if(!e){s.current=null;return}s.current!==e&&(s.current=e,i.show({level:"info",title:t("languagePendingNotice")}))},[e,t,i]),null}var w=i(32892),C=i(48708),S=i(5011),k=i(42515),P=i(91399),x=i(38979),D=i(9626),j=i(99739);x.Yj().min(32).max(128).regex(/^[A-Za-z0-9_-]+$/);let R="/api/plugins/host-runtime/v1";Object.freeze({imports:Object.freeze({react:`${R}/base.js`,"react/jsx-runtime":`${R}/base.js`,"react/jsx-dev-runtime":`${R}/base.js`,"react-dom":`${R}/base.js`,"react-dom/client":`${R}/base.js`,"@jetcrab/pi-desk-sdk/react/base":`${R}/base.js`,"@jetcrab/pi-desk-sdk/react/markdown":`${R}/markdown.js`})}),x.eu("v1");let I=x.Ik({pluginName:j.tv,url:x.Yj().regex(/^\/api\/plugins\/browser-resources\/[A-Za-z0-9_-]{32,128}\/entry\.js$/,"Browser Entry URL 无效")}).strict(),M=x.Ik({}).strict(),E=x.Ik({entries:x.YO(I)}).strict(),N=Object.freeze({list:(0,D.Vc)({path:"plugins/browser-entries/list",inputSchema:M,outputSchema:E})}),T=x.Yj().trim().min(1).max(32768),A=x.Ik({text:x.Yj(),truncated:x.zM()}).strict(),F=x.KC([x.Ik({type:x.eu("text_append"),text:x.Yj().min(1)}).strict(),x.Ik({type:x.eu("snapshot"),snapshot:A}).strict(),x.Ik({type:x.eu("unavailable")}).strict()]),L=x.Ik({pluginName:j.tv,path:T}).strict(),z=x.Ik({snapshot:A}).strict(),O=x.Ik({}).strict(),B=x.Ik({pluginName:j.tv,path:T,event:F}).strict(),U=Object.freeze({watch:(0,D.Vc)({path:"plugins/logs/watch",inputSchema:L,outputSchema:z}),unwatch:(0,D.Vc)({path:"plugins/logs/unwatch",inputSchema:L,outputSchema:O}),event:(0,D._G)({path:"plugins/logs/event",bodySchema:B})});var q=i(95826),G=i(267);let H=x.gM("scope",[x.Ik({scope:x.eu("global")}).strict(),x.Ik({scope:x.eu("session"),source:G.R}).strict()]),_=x.Ik({pluginName:j.tv,target:H,event:j.f7,data:j.Dz}).strict(),$=(0,D._G)({path:"plugins/push",bodySchema:_});var W=i(79137),V=i(67765);function J(e,t,i){let s=e=>{console.error("[Pi Desk][PluginHost] 插件回调执行失败",{pluginName:i,phase:t,message:e instanceof Error?e.message:String(e)})};try{let t=e();"object"==typeof t&&null!==t&&"then"in t&&"function"==typeof t.then&&Promise.resolve(t).catch(s)}catch(e){s(e)}}async function Y(e,t,i){let s,o=Promise.resolve().then(i).catch(i=>{console.error("[Pi Desk][PluginHost] 插件资源清理失败",{pluginName:e,phase:t,message:i instanceof Error?i.message:String(i)})});try{await Promise.race([o,new Promise(i=>{s=setTimeout(()=>{console.warn("[Pi Desk][PluginHost] 插件资源清理超时",{pluginName:e,phase:t,timeoutMs:1500}),i()},1500)})])}finally{void 0!==s&&clearTimeout(s)}}let K={text:"",truncated:!1,loading:!0,error:null};function Q(e,t){if(t.text!==e.snapshot.text||t.truncated!==e.snapshot.truncated||t.loading!==e.snapshot.loading||t.error!==e.snapshot.error){e.snapshot=t;for(let t of[...e.listeners])J(t,`log:${e.path}`)}}class Z{constructor(e,t){this.channel=e,this.connection=t,this.records=new Map,this.connectionEpoch=0,this.disposed=!1,this.unsubscribeEvents=e.subscribe(e=>this.handleEvent(e)),this.unsubscribeConnection=t.subscribe(()=>this.handleConnectionChange())}open(e){if(this.disposed)throw Error("Plugin log host has been disposed");let t=e.trim();if(!t)throw Error("日志路径不能为空");let i=this.records.get(t);i||(i={path:t,references:0,observed:!1,blockedByError:!1,refreshRequested:!1,syncRequested:!1,syncPromise:null,snapshot:{...K},listeners:new Set},this.records.set(t,i)),i.references+=1,this.requestSync(i);let s=!0;return{getSnapshot:()=>i.snapshot,subscribe:e=>{if(!s)throw Error("Plugin log handle has been disposed");return i.listeners.add(e),()=>{i.listeners.delete(e)}},retry:()=>{s&&!this.disposed&&(i.blockedByError=!1,i.refreshRequested=!0,Q(i,{...i.snapshot,loading:!0,error:null}),this.requestSync(i))},dispose:()=>{s&&(s=!1,i.references-=1,this.requestSync(i))}}}dispose(){if(!this.disposed){for(let e of(this.disposed=!0,this.unsubscribeEvents(),this.unsubscribeConnection(),this.records.values()))e.observed&&"ready"===this.connection.getSnapshot().status&&this.channel.unwatch(e.path).catch(()=>void 0),e.listeners.clear();this.records.clear()}}handleConnectionChange(){if(this.disposed)return;this.connectionEpoch+=1;let e="ready"===this.connection.getSnapshot().status;for(let t of this.records.values())t.observed=!1,t.blockedByError=!1,t.refreshRequested=e,t.references>0&&Q(t,{...t.snapshot,loading:!0,error:e?null:t.snapshot.error}),this.requestSync(t)}handleEvent(e){if(this.disposed)return;let t=this.records.get(e.path);if(t&&0!==t.references){if("text_append"===e.event.type)return void Q(t,{...t.snapshot,text:t.snapshot.text+e.event.text,loading:!1,error:null});if("snapshot"===e.event.type)return void Q(t,{...e.event.snapshot,loading:!1,error:null});t.observed=!1,t.blockedByError=!0,Q(t,{...t.snapshot,loading:!1,error:"日志暂不可用"})}}requestSync(e){this.disposed||(e.syncRequested=!0,e.syncPromise||(e.syncPromise=(async()=>{for(;e.syncRequested&&!this.disposed;)e.syncRequested=!1,await this.reconcileRecord(e)})().finally(()=>{e.syncPromise=null,e.syncRequested&&!this.disposed&&this.requestSync(e)})))}async reconcileRecord(e){if(this.records.get(e.path)!==e)return;let t="ready"===this.connection.getSnapshot().status;if(!(e.references>0&&t&&!e.blockedByError)){if(e.observed&&t){let t=this.connectionEpoch;try{await this.channel.unwatch(e.path)}catch{}t===this.connectionEpoch&&(e.observed=!1)}else e.observed=!1;0!==e.references||e.observed||this.records.delete(e.path);return}if(e.observed&&!e.refreshRequested)return;e.refreshRequested=!1,Q(e,{...e.snapshot,loading:!0,error:null});let i=this.connectionEpoch;try{let t=await this.channel.watch(e.path);if(this.disposed||i!==this.connectionEpoch||this.records.get(e.path)!==e)return;e.observed=!0,e.blockedByError=!1,Q(e,{...t,loading:!1,error:null})}catch(t){if(i!==this.connectionEpoch||"ready"!==this.connection.getSnapshot().status){e.syncRequested=!0;return}e.observed=!1,e.blockedByError=!0,Q(e,{...e.snapshot,loading:!1,error:t instanceof Error&&t.message?t.message:"读取日志失败"})}finally{(0===e.references||e.syncRequested)&&(e.syncRequested=!0)}}}function X(e){if(null!==e&&"object"==typeof e){for(let t of Object.values(e))X(t);Object.freeze(e)}return e}let ee=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,et=/^[a-z0-9]+(?:-[a-z0-9]+)*\/[a-z0-9]+(?:-[a-z0-9]+)*$/,ei=new Set(["plugin","server","rocket","settings","panel","message","terminal","file","folder","bot","wrench","database","globe"]),es=new Set(["application","composer-panel","settings-page","message-view","session-sidebar-tab"]);function eo(e,t){return`${e}\u0000${t}`}function er(e,t,i){return`${e}\u0000${eo(t,i)}`}function en(e){return import(e)}function ea(){return"u"<typeof document?{mode:"light"}:((0,h.Is)(),Object.freeze({mode:document.documentElement.classList.contains("dark")?"dark":"light"}))}function el(e,t){return e.workId===t.workId&&e.sessionId===t.sessionId&&e.branchId===t.branchId}function ec(e){return{source:{workId:e.workId,sessionId:e.sessionId,branchId:e.branchId},cwd:e.cwd,status:e.status}}function ed(e,t){let i=e.trim();if(!i||i.length>100)throw Error(`${t} must contain 1-100 characters`);return i}function eh(e){if("string"!=typeof e)throw Error("Contribution name 必须是字符串");let t=e.trim();if(!t||t.length>64||!ee.test(t))throw Error("Contribution name 必须是 1-64 字符的小写 kebab-case");return t}function eu(e){if(void 0!==e){if(!e||"object"!=typeof e||Array.isArray(e))throw Error("Contribution icon 无效");if("builtin"===e.type){if(2!==Object.keys(e).length||"string"!=typeof e.name||!ei.has(e.name))throw Error("Contribution builtin icon 无效");return{type:"builtin",name:e.name}}if("svg"===e.type){let t="string"==typeof e.content?e.content.trim():"";if(2!==Object.keys(e).length||!t||t.length>16384)throw Error("Contribution SVG icon 无效");return{type:"svg",content:t}}throw Error("Contribution icon type 无效")}}class ep{constructor(e,t=en,i=()=>void 0){this.transport=e,this.entryImporter=t,this.notifyPlugin=i,this.entryDescriptors=[],this.entryDescriptorsByPlugin=new Map,this.entryStates=new Map,this.ownersByPlugin=new Map,this.registrations=new Map,this.contributionLoadStates=new Map,this.browserDescriptors=[],this.registrySnapshot={revision:0,descriptors:this.browserDescriptors},this.messageViewResolutions=new Map,this.logHosts=new Map,this.registryListeners=new Set,this.workSessionListeners=new Set,this.connectionListeners=new Set,this.themeListeners=new Set,this.globalPluginStates={},this.workSessions=[],this.workSessionCreate=null,this.workSessionGoTo=null,this.projectPreview=null,this.terminalOpen=null,this.workSessionFilePreview=null,this.workSessionFileReveal=null,this.imageReader=null,this.connectionSnapshot={status:"disconnected",error:null},this.themeSnapshot={mode:"light"},this.refreshPromise=null,this.refreshPending=!1,this.entriesMaintaining=!1,this.entriesInitialized=!1,this.entryListError=null,this.applicationResolveController=null,this.applicationResolveEpoch=0,this.applicationVisibility=new Map,this.disposed=!1,this.unsubscribePush=e.subscribePush(e=>this.dispatchPush(e));const s=()=>{let e=ea();e.mode!==this.themeSnapshot.mode&&(this.themeSnapshot=e,this.notify(this.themeListeners))};this.themeSnapshot=ea(),this.unsubscribeTheme=(0,h.Cy)(s);const o=window.matchMedia("(prefers-color-scheme: dark)");o.addEventListener("change",s),this.removeSystemThemeListener=()=>o.removeEventListener("change",s)}subscribeRegistry(e){return this.registryListeners.add(e),()=>this.registryListeners.delete(e)}getBrowserDescriptors(){return this.browserDescriptors}getRegisteredBrowserDescriptors(){return[...this.ownersByPlugin.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({pluginName:e,contributions:[...t.registrations.values()].sort((e,t)=>{let i=e.kind.localeCompare(t.kind);return 0===i?e.contributionName.localeCompare(t.contributionName):i}).map(e=>structuredClone(e.descriptor))}))}getRegistrySnapshot(){return this.registrySnapshot}areEntriesInitialized(){return this.entriesInitialized}isRefreshingEntries(){return this.entriesMaintaining||null!==this.refreshPromise}setEntriesMaintaining(e){this.disposed||this.entriesMaintaining===e||(this.entriesMaintaining=e,this.publishRegistryChange())}getEntryListError(){return this.entryListError}getEntryState(e){return this.entryStates.get(e)??{status:"unloaded"}}getFailedEntries(){return[...this.entryStates.entries()].flatMap(([e,t])=>"failed"===t.status?[{pluginName:e,error:t.error}]:[])}getContributionLoadState(e,t,i){return this.contributionLoadStates.get(er(e,t,i))??{status:"unloaded"}}getMessageViewResolution(e){return this.messageViewResolutions.get(e)??null}bindWorkSessionCreate(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionCreate)throw Error("Workbench WorkSession 创建能力已经绑定");this.workSessionCreate=e;let t=!0;return()=>{t&&(t=!1,this.workSessionCreate===e&&(this.workSessionCreate=null))}}bindWorkSessionGoTo(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionGoTo)throw Error("Workbench WorkSession 前往能力已经绑定");this.workSessionGoTo=e;let t=!0;return()=>{t&&(t=!1,this.workSessionGoTo===e&&(this.workSessionGoTo=null))}}bindTerminalOpen(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if(this.terminalOpen)throw Error("终端创建能力已经绑定");return this.terminalOpen=e,()=>{this.terminalOpen===e&&(this.terminalOpen=null)}}bindProjectPreview(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if(this.projectPreview)throw Error("项目预览能力已经绑定");return this.projectPreview=e,()=>{this.projectPreview===e&&(this.projectPreview=null)}}previewProject(e){if(this.disposed)throw Error("Plugin Host Runtime 已释放");if("string"!=typeof e||!e.trim())throw Error("项目预览需要有效目录");if(!this.projectPreview)throw Error("项目预览尚未准备好");this.projectPreview(e.trim())}bindWorkSessionFilePreview(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionFilePreview)throw Error("Workbench 文件预览能力已经绑定");this.workSessionFilePreview=e;let t=!0;return()=>{t&&(t=!1,this.workSessionFilePreview===e&&(this.workSessionFilePreview=null))}}bindImageReader(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.imageReader)throw Error("Workbench 图片读取能力已经绑定");return this.imageReader=e,()=>{this.imageReader===e&&(this.imageReader=null)}}bindWorkSessionFileReveal(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(this.workSessionFileReveal)throw Error("Workbench 文件定位能力已经绑定");this.workSessionFileReveal=e;let t=!0;return()=>{t&&(t=!1,this.workSessionFileReveal===e&&(this.workSessionFileReveal=null))}}replaceGlobalPluginStates(e){let t=X(structuredClone(e)),i=[...new Set([...Object.keys(this.globalPluginStates),...Object.keys(t)])].filter(e=>JSON.stringify(this.globalPluginStates[e]??null)!==JSON.stringify(t[e]??null));if(0!==i.length){for(let e of(this.globalPluginStates=t,i)){let t=this.ownersByPlugin.get(e);t&&this.notify(t.globalStateListeners)}this.entriesInitialized&&i.some(e=>[...this.ownersByPlugin.get(e)?.registrations.values()??[]].some(e=>"application"===e.kind&&e.resolve))&&this.scheduleApplicationResolution()}}async dispatchNotificationEvent(e,t){let i=this.entryStates.get(t.pluginName);if(i?.status!=="ready")throw Error(`插件 Browser Entry 尚未就绪:${t.pluginName}`);let s=i.runtime.owner,o=s.notificationEventListeners.get(t.name);if(!o)throw Error(`插件未注册通知事件:${t.pluginName}/${t.name}`);if(await o({notificationId:e,data:structuredClone(t.data)}),!s.active)throw Error("Browser Entry 已失效")}replaceWorkSessions(e){var t;let i=X(e.map(ec));t=this.workSessions,!(t.length===i.length&&t.every((e,t)=>void 0!==i[t]&&el(e.source,i[t].source)&&e.cwd===i[t].cwd&&e.status===i[t].status))&&(this.workSessions=i,this.notify(this.workSessionListeners),this.entriesInitialized&&this.scheduleApplicationResolution())}markConnecting(){this.replaceConnection({status:"connecting",error:null})}markReady(){this.replaceConnection({status:"ready",error:null})}markDisconnected(e=null){this.setEntriesMaintaining(!1),this.replaceConnection({status:"disconnected",error:e})}async refreshEntries(){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");return this.refreshPromise?this.refreshPending=!0:(this.entriesInitialized||this.replaceEntriesInitialized(!1),this.refreshPromise=(async()=>{try{do{this.refreshPending=!1;let e=await this.transport.listBrowserEntries();if(this.disposed||this.entriesMaintaining||(await this.replaceEntries(e),this.disposed))return;this.replaceEntriesInitialized(!0),this.replaceEntryListError(null)}while(this.refreshPending&&!this.disposed)}catch(e){throw this.replaceEntriesInitialized(!0),this.replaceEntryListError(e instanceof Error?e.message:String(e)),this.rebuildRegistry(),e}})().finally(()=>{this.refreshPromise=null,this.disposed||this.publishRegistryChange()}),this.publishRegistryChange()),this.refreshPromise}retryEntry(e){return this.entryStates.get(e)?.status==="failed"&&(this.entryStates.delete(e),this.publishRegistryChange()),this.loadEntry(e).then(async e=>(await this.resolveApplications(),e))}retryContribution(e,t,i){let s=er(e,t,i);this.contributionLoadStates.get(s)?.status==="failed"&&(this.contributionLoadStates.delete(s),this.publishRegistryChange());let o=this.registrations.get(s);return o?this.loadContribution(o):Promise.reject(new W.qj({pluginName:e,contributionName:i,phase:"registration",message:"插件 Contribution 不存在"}))}async mountContribution(e){let t=er(e.pluginName,e.kind,e.contributionName),i=this.registrations.get(t);if(!i)throw new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"registration",message:"插件 Contribution 不存在"});let s=new AbortController,o=new Promise(e=>{s.signal.addEventListener("abort",()=>e(),{once:!0})}),r=e.target;if("session-sidebar-tab"===r.kind&&r.setHeaderActions){let t=r.setHeaderActions,o=[];s.signal.addEventListener("abort",()=>{o=[],t([])},{once:!0}),r={...r,setHeaderActions:r=>{if(s.signal.aborted||!i.owner.active)return;if(!Array.isArray(r))throw Error("侧栏操作必须为数组");let n=r.map(t=>{let r=ed(t.label,"Sidebar action label"),a=eu(t.icon),l=!0===t.disabled,c=!0===t.busy,d=t.onSelect;if("function"!=typeof d)throw Error("侧栏操作缺少 onSelect 回调");let h=!1;return{label:r,icon:a,disabled:l,busy:c,onSelect:()=>{s.signal.aborted||!i.owner.active||o!==n||l||c||h||(h=!0,J(async()=>{try{await d()}catch(e){throw!s.signal.aborted&&i.owner.active&&i.owner.host.notify({level:"error",title:r,description:e instanceof Error?e.message:String(e)}),e}finally{h=!1}},`sidebar-action:${r}`,e.pluginName))}}});o=n,t(n)}}}let n=Promise.resolve().then(async()=>{if(s.signal.aborted)throw Error("插件视图已关闭");let t=await this.loadContribution(i);if(s.signal.aborted||!i.owner.active)throw Error("插件视图已失效");let o=t.mount,n=await o({container:e.container,target:r,host:i.owner.host,signal:s.signal});if(void 0!==n&&"function"!=typeof n)throw Error("Contribution mount must return void or a disposer");return n??null}),a=null,l=()=>a||(i.owner.mounts.delete(l),e.signal?.removeEventListener("abort",c),s.abort(),a=Y(e.pluginName,`mount:${e.contributionName}`,async()=>{let e=await n.catch(()=>null);await e?.()})),c=()=>{l()};i.owner.mounts.add(l),e.signal?.addEventListener("abort",c,{once:!0}),e.signal?.aborted&&c();try{if(await Promise.race([n,o]),s.signal.aborted||!i.owner.active)throw Error("插件视图已失效");return l}catch(t){if(await l(),t instanceof W.qj)throw t;throw new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"mount",message:t instanceof Error?t.message:String(t),cause:t})}}async dispose(){if(this.disposed)return;this.disposed=!0,this.applicationResolveController?.abort(),this.applicationResolveController=null,this.unsubscribePush(),this.unsubscribeTheme(),this.removeSystemThemeListener();let e=[...this.ownersByPlugin.values()].reverse();for(let t of(this.ownersByPlugin.clear(),await Promise.all(e.map(e=>this.disposeEntryOwner(e))),this.entriesMaintaining=!1,this.entryStates.clear(),this.entryDescriptorsByPlugin.clear(),this.entryDescriptors=[],this.registrations.clear(),this.contributionLoadStates.clear(),this.browserDescriptors=[],this.messageViewResolutions.clear(),this.applicationVisibility.clear(),this.logHosts.values()))t.dispose();this.logHosts.clear(),this.globalPluginStates={},this.workSessionCreate=null,this.workSessionGoTo=null,this.workSessionFilePreview=null,this.workSessionFileReveal=null,this.imageReader=null,this.projectPreview=null,this.terminalOpen=null,this.registryListeners.clear(),this.workSessionListeners.clear(),this.connectionListeners.clear(),this.themeListeners.clear()}async replaceEntries(e){var t;let i=[...e].sort((e,t)=>e.pluginName.localeCompare(t.pluginName)),s=new Map;for(let e of i){if(s.has(e.pluginName))throw Error(`重复 Plugin Browser Entry:${e.pluginName}`);s.set(e.pluginName,e)}for(let[e,t]of this.entryDescriptorsByPlugin){let i=s.get(e);i?.url!==t.url&&this.disposeEntry(e)}if(this.disposed)return;for(let[e,t]of(this.entryDescriptorsByPlugin.clear(),s))this.entryDescriptorsByPlugin.set(e,t);let o=(t=this.entryDescriptors,JSON.stringify(t)!==JSON.stringify(i));this.entryDescriptors=structuredClone(i),await Promise.allSettled(i.map(e=>this.loadEntry(e.pluginName))),await this.resolveApplications(),o&&this.publishRegistryChange()}loadEntry(e){if(this.disposed)return Promise.reject(Error("Plugin Host Runtime has been disposed"));let t=this.entryDescriptorsByPlugin.get(e);if(!t)return Promise.reject(Error(`Plugin Browser Entry 不存在:${e}`));let i=this.entryStates.get(e);if(i?.status==="ready")return Promise.resolve(i.runtime);if(i?.status==="loading")return i.promise;if(i?.status==="failed")return Promise.reject(i.error);let s=this.initializeEntry(t).then(i=>(this.disposed||this.entryDescriptorsByPlugin.get(e)?.url!==t.url?i.dispose():(this.entryStates.set(e,{status:"ready",runtime:i}),this.ownersByPlugin.set(e,i.owner),this.commitRegistrations(i.owner),this.rebuildRegistry()),this.publishRegistryChange(),i),i=>{let s=i instanceof Error?i:new W.qj({pluginName:e,phase:"entry-import",message:String(i)});throw this.disposed||this.entryDescriptorsByPlugin.get(e)?.url!==t.url||(this.entryStates.set(e,{status:"failed",error:s}),this.rebuildRegistry(),this.publishRegistryChange()),s});return this.entryStates.set(e,{status:"loading",promise:s}),this.publishRegistryChange(),s}async initializeEntry(e){let t;try{t=await this.entryImporter(e.url)}catch(t){throw new W.qj({pluginName:e.pluginName,phase:"entry-import",message:t instanceof Error?t.message:"Browser Entry import 失败",cause:t})}if(this.disposed||this.entryDescriptorsByPlugin.get(e.pluginName)?.url!==e.url)throw Error("Browser Entry 已失效");if("function"!=typeof t.default)throw new W.qj({pluginName:e.pluginName,phase:"entry-factory",message:"Browser Entry 必须 default-export defineBrowserEntry(...)"});let i={descriptor:e,registrations:new Map,pushListeners:new Set,notificationEventListeners:new Map,globalStateListeners:new Set,subscriptionDisposers:new Set,mounts:new Set,disposer:null,registrationOpen:!0,active:!0},s=Object.assign(i,{host:this.createBrowserHost(i)});try{let i=t.default(this.createBrowserFacade(e.pluginName,s));if(s.registrationOpen=!1,"object"==typeof i&&null!==i&&"function"==typeof Reflect.get(i,"then"))throw J(async()=>{let t=await i;"function"==typeof t&&await Y(e.pluginName,"entry-factory",async()=>{await t()})},"entry-factory",e.pluginName),Error("Browser Entry factory must register synchronously");if(void 0!==i&&"function"!=typeof i)throw Error("Browser Entry factory must return void or a disposer");s.disposer=i??null}catch(t){throw s.registrationOpen=!1,await this.disposeEntryOwner(s),new W.qj({pluginName:e.pluginName,phase:"entry-factory",message:t instanceof Error?t.message:String(t),cause:t})}return{pluginName:e.pluginName,owner:s,dispose:()=>this.disposeEntryOwner(s)}}createBrowserFacade(e,t){return{name:e,host:t.host,notifications:{onEvent:(i,s)=>{if(!t.active)throw Error("Browser Entry owner is no longer active");let o=eh(i);if(t.notificationEventListeners.has(o))throw Error(`Browser Notification Event 重复:${e}/${o}`);return t.notificationEventListeners.set(o,s),()=>{t.notificationEventListeners.get(o)===s&&t.notificationEventListeners.delete(o)}}},notify:i=>{t.active&&this.notifyPlugin(e,structuredClone(i))},registerContribution:(i,s,o)=>{if(!t.active||!t.registrationOpen)throw Error("Browser Entry registration phase has ended");if(!es.has(i))throw Error(`Browser Contribution kind 无效:${String(i)}`);let r=this.createRegistration(e,i,s,o,t),n=eo(i,r.contributionName);if(t.registrations.has(n))throw Error(`Browser Contribution 重复:${e}/${i}/${r.contributionName}`);t.registrations.set(n,r)},onPush:e=>{if(!t.active)throw Error("Browser Entry owner is no longer active");return t.pushListeners.add(e),()=>{t.pushListeners.delete(e)}}}}createRegistration(e,t,i,s,o){let r=eh(i);if(!s||"object"!=typeof s||"function"!=typeof s.load)throw Error(`Browser Contribution 必须提供 load():${t}/${r}`);if("application"===t){let i=ed(s.label,"Application label"),n=eu(s.icon),a=s.chrome??"host";if("host"!==a&&"none"!==a)throw Error("Application chrome 必须是 host 或 none");if(void 0!==s.resolve&&"function"!=typeof s.resolve)throw Error("Application resolve 必须是函数");return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:i,title:ed(s.title??i,"Application title"),...n?{icon:n}:{},chrome:a},load:s.load,resolve:s.resolve,owner:o}}if("composer-panel"===t){let i=eu(s.icon);return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:ed(s.label,"Composer Panel label"),...i?{icon:i}:{}},load:s.load,owner:o}}if("settings-page"===t){let i=eu(s.icon);return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,label:ed(s.label,"Settings Page label"),...i?{icon:i}:{}},load:s.load,owner:o}}if("message-view"===t)return{pluginName:e,kind:t,contributionName:r,descriptor:{kind:t,contributionName:r,viewKey:function(e){if("string"!=typeof e)throw Error("Message View viewKey 必须是字符串");let t=e.trim();if(t.length<3||t.length>129||!et.test(t))throw Error("Message View viewKey 必须是 plugin-name/view-name");return t}(s.viewKey),priority:function(e){if(!Number.isSafeInteger(e))throw Error("Message View priority must be a safe integer");return e}(s.priority)},load:s.load,owner:o};let n=eu(s.icon);return{pluginName:e,kind:"session-sidebar-tab",contributionName:r,descriptor:{kind:"session-sidebar-tab",contributionName:r,label:ed(s.label,"Session Sidebar Tab label"),...n?{icon:n}:{}},load:s.load,owner:o}}commitRegistrations(e){for(let t of e.registrations.values()){let e=er(t.pluginName,t.kind,t.contributionName);if(this.registrations.has(e))throw Error(`Browser Contribution Registry 重复:${e}`);this.registrations.set(e,t)}}loadContribution(e){let t=er(e.pluginName,e.kind,e.contributionName),i=this.contributionLoadStates.get(t);if(i?.status==="ready")return Promise.resolve(i.implementation);if(i?.status==="loading")return i.promise;if(i?.status==="failed")return Promise.reject(i.error);let s=Promise.resolve().then(e.load).then(i=>{if(!i||"function"!=typeof i.mount)throw Error("Lazy Contribution Module 必须导出 mount()");if(!e.owner.active||this.registrations.get(t)!==e)throw Error("Browser Contribution 已失效");return this.contributionLoadStates.set(t,{status:"ready",implementation:i}),this.publishRegistryChange(),i},e=>{throw e}).catch(i=>{let s=i instanceof Error?i:new W.qj({pluginName:e.pluginName,contributionName:e.contributionName,phase:"contribution-load",message:String(i)});throw e.owner.active&&this.registrations.get(t)===e&&(this.contributionLoadStates.set(t,{status:"failed",error:s}),this.publishRegistryChange()),s});return this.contributionLoadStates.set(t,{status:"loading",promise:s}),this.publishRegistryChange(),s}async resolveApplications(){if(this.disposed)return;let e=new AbortController;this.applicationResolveController?.abort(),this.applicationResolveController=e;let t=++this.applicationResolveEpoch,i=[...this.registrations.values()].filter(e=>"application"===e.kind),s=new Map;if(await Promise.all(i.map(async t=>{let i=er(t.pluginName,t.kind,t.contributionName);if(!t.resolve)return void s.set(i,!0);try{let o=await t.resolve({workSessions:this.workSessions,host:t.owner.host,signal:e.signal});e.signal.aborted||s.set(i,!1!==o)}catch(o){if(e.signal.aborted)return;s.set(i,!1),console.warn("[Pi Desk][PluginHost] Application resolve 失败",{pluginName:t.pluginName,contributionName:t.contributionName,errorName:o instanceof Error?o.name:"UnknownError",message:o instanceof Error?o.message:String(o)})}})),!this.disposed&&!e.signal.aborted&&this.applicationResolveController===e&&this.applicationResolveEpoch===t){for(let[e,t]of(this.applicationVisibility.clear(),s))this.applicationVisibility.set(e,t);this.rebuildRegistry()}}scheduleApplicationResolution(){queueMicrotask(()=>{this.disposed||this.resolveApplications().catch(e=>{console.error("[Pi Desk][PluginHost] 刷新 Application 可见性失败",{errorName:e instanceof Error?e.name:"UnknownError",message:e instanceof Error?e.message:String(e)})})})}rebuildRegistry(){let e=[...this.ownersByPlugin.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({pluginName:e,contributions:[...t.registrations.values()].filter(e=>"application"!==e.kind||(this.applicationVisibility.get(er(e.pluginName,e.kind,e.contributionName))??!1)).sort((e,t)=>{let i=e.kind.localeCompare(t.kind);return 0===i?e.contributionName.localeCompare(t.contributionName):i}).map(e=>structuredClone(e.descriptor))}));JSON.stringify(this.browserDescriptors)!==JSON.stringify(e)&&(this.browserDescriptors=e,this.rebuildMessageViewResolutions(),this.publishRegistryChange())}rebuildMessageViewResolutions(){this.messageViewResolutions.clear();let e=new Map;for(let t of this.browserDescriptors)for(let i of t.contributions){if("message-view"!==i.kind)continue;let s=e.get(i.viewKey)??[];s.push({pluginName:t.pluginName,descriptor:i}),e.set(i.viewKey,s)}for(let[t,i]of e){let e=Math.max(...i.map(e=>e.descriptor.priority)),s=i.filter(t=>t.descriptor.priority===e);this.messageViewResolutions.set(t,1===s.length?{status:"winner",...s[0]}:{status:"conflict",viewKey:t,candidates:s})}}disposeEntry(e){this.entryDescriptorsByPlugin.delete(e),this.entryStates.delete(e);let t=this.ownersByPlugin.get(e);this.ownersByPlugin.delete(e),t&&this.disposeEntryOwner(t),this.rebuildRegistry()}async disposeEntryOwner(e){if(!e.active)return;for(let t of(e.active=!1,e.registrationOpen=!1,e.pushListeners.clear(),e.notificationEventListeners.clear(),e.globalStateListeners.clear(),e.subscriptionDisposers))J(t,"entry-subscription-dispose",e.descriptor.pluginName);e.subscriptionDisposers.clear();let t=this.logHosts.get(e.descriptor.pluginName);for(let i of(t===e.host.logs&&(this.logHosts.delete(e.descriptor.pluginName),J(()=>t.dispose(),"logs-dispose",e.descriptor.pluginName)),e.registrations.values())){let e=er(i.pluginName,i.kind,i.contributionName);this.registrations.get(e)===i&&(this.registrations.delete(e),this.contributionLoadStates.delete(e),this.applicationVisibility.delete(e))}let i=[...e.mounts].reverse();e.mounts.clear();let s=e.disposer;e.disposer=null,e.registrations.clear(),await Promise.all(i.map(e=>e())),s&&await Y(e.descriptor.pluginName,"entry-dispose",s)}previewWorkSessionFile(e,t,i){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("string"!=typeof t||!t.trim())throw Error("文件预览需要有效路径");let s=function(e){if(void 0!==e&&(null===e||"object"!=typeof e||Array.isArray(e)))throw Error("文件预览选项无效");let t=e?.mode;if(void 0===t||"session"===t||"expanded"===t||"standalone"===t)return t??"session";throw Error("文件预览模式无效")}(i),o=this.workSessions.find(t=>el(t.source,e));if(!o)throw Error("工作会话来源已变化");let r=this.workSessionFilePreview;if(!r)throw Error("Workbench 尚未准备好预览文件");r({source:structuredClone(o.source),cwd:o.cwd,path:t.trim(),mode:s,...i?.imagePaths===void 0?{}:{imagePaths:i.imagePaths}})}async revealWorkSessionFile(e,t){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("string"!=typeof t||!t.trim())throw Error("文件定位需要有效路径");let i=this.workSessions.find(t=>el(t.source,e));if(!i)throw Error("工作会话来源已变化");let s=this.workSessionFileReveal;if(!s)throw Error("Workbench 尚未准备好定位文件");await s({source:structuredClone(i.source),cwd:i.cwd,path:t.trim()})}async readImage(e,t,i){i.throwIfAborted();let s=V._g.parse(t),o=this.workSessions.find(t=>el(t.source,e));if(!o)throw Error("工作会话来源已变化");let r=this.imageReader;if(!r)throw Error("Workbench 尚未准备好读取图片");let n=await r({source:structuredClone(o.source),cwd:o.cwd,path:s},i);if(i.throwIfAborted(),!this.workSessions.some(t=>el(t.source,e)))throw Error("工作会话来源已变化");return n}async createWorkSession(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if(!e||"string"!=typeof e.cwd||!e.cwd.trim())throw Error("创建工作会话需要有效 cwd");let t=this.workSessionCreate;if(!t)throw Error("Workbench 尚未准备好创建工作会话");return ec(await t(e.cwd.trim()))}async goToWorkSession(e){if(this.disposed)throw Error("Plugin Host Runtime has been disposed");if("workId"in e){if("string"!=typeof e.workId||!e.workId.trim())throw Error("前往工作会话需要有效 workId")}else{if("string"!=typeof e.sessionId||!e.sessionId.trim())throw Error("前往工作会话需要有效 sessionId");if(void 0!==e.cwd&&("string"!=typeof e.cwd||!e.cwd.trim()))throw Error("cwd 必须是非空字符串")}let t=this.workSessionGoTo;if(!t)throw Error("Workbench 尚未准备好前往工作会话");return ec(await t(e))}createBrowserHost(e){let t=e.descriptor.pluginName,i=()=>{if(!e.active||this.disposed)throw Error("Browser Entry 已失效")},s=async e=>{i();let t=await e();return i(),t},o=this.transport.createPiDeskChannel(t),r=this.transport.pi,n=(s,o,r)=>{i();let n=()=>{e.active&&J(o,r,t)},a=()=>{s.delete(n),e.subscriptionDisposers.delete(a)};return s.add(n),e.subscriptionDisposers.add(a),a},a={getSnapshot:()=>(i(),this.connectionSnapshot),subscribe:e=>n(this.connectionListeners,e,"connection")},l=this.logHosts.get(t);return l||(l=new Z(this.transport.createLogChannel(t),{getSnapshot:()=>this.connectionSnapshot,subscribe:a.subscribe}),this.logHosts.set(t,l)),{settings:{getSnapshot:()=>(i(),(0,C.SJ)()),subscribe:s=>{i();let o=(0,C.ae)(()=>{e.active&&J(s,"settings",t)});return e.subscriptionDisposers.add(o),()=>{e.subscriptionDisposers.delete(o),o()}}},notify:e=>{i(),this.notifyPlugin(t,structuredClone(e))},locale:{getSnapshot:()=>(i(),(0,C.SJ)().region)},globalState:{getSnapshot:()=>(i(),this.globalPluginStates[t]??null),subscribe:t=>n(e.globalStateListeners,t,"global-state")},piDesk:{invokeGlobal:(e,t)=>s(()=>o.invokeGlobal(e,t)),invokeSession:(e,t,i)=>s(()=>o.invokeSession(e,t,i))},pi:{prompt:(e,t)=>s(()=>r.prompt(e,t)),commands:{list:e=>s(()=>r.commands.list(e)),execute:(e,t,i)=>s(()=>r.commands.execute(e,t,i))},tools:{list:e=>s(()=>r.tools.list(e))},bash:{execute:(e,t)=>s(()=>r.bash.execute(e,t)),abort:e=>s(()=>r.bash.abort(e))},interrupt:e=>s(()=>r.interrupt(e))},workSessions:{getSnapshot:()=>(i(),this.workSessions),subscribe:e=>n(this.workSessionListeners,e,"work-sessions"),create:e=>s(()=>this.createWorkSession(e)),goTo:e=>s(()=>this.goToWorkSession(e))},workSessionFiles:{preview:(e,t,s)=>{i(),this.previewWorkSessionFile(e,t,s)},reveal:(e,t)=>s(()=>this.revealWorkSessionFile(e,t)),readImage:(t,i,o)=>s(async()=>{let s=new AbortController,r=()=>s.abort();e.subscriptionDisposers.add(r);try{return await this.readImage(t,i,o?AbortSignal.any([o,s.signal]):s.signal)}finally{e.subscriptionDisposers.delete(r)}})},projects:{preview:e=>{i(),this.previewProject(e)}},terminals:{open:t=>s(async()=>{if(!t||"string"!=typeof t.cwd||!t.cwd.trim())throw Error("新建终端需要有效 cwd");let i=this.terminalOpen;if(!i)throw Error("终端创建能力尚未准备好");let s=new AbortController,o=()=>s.abort();e.subscriptionDisposers.add(o);try{await i(t.cwd,s.signal)}finally{e.subscriptionDisposers.delete(o)}})},logs:l,connection:a,theme:{getSnapshot:()=>(i(),this.themeSnapshot),subscribe:e=>n(this.themeListeners,e,"theme")}}}dispatchPush(e){let t=this.entryStates.get(e.pluginName);if(t?.status!=="ready")return;let i=t.runtime.owner;for(let t of[...i.pushListeners]){if(!i.active)break;J(()=>t(e),`push:${e.event}`,e.pluginName)}}replaceEntriesInitialized(e){this.entriesInitialized!==e&&(this.entriesInitialized=e,this.publishRegistryChange())}replaceEntryListError(e){this.entryListError!==e&&(this.entryListError=e,this.publishRegistryChange())}replaceConnection(e){(e.status!==this.connectionSnapshot.status||e.error!==this.connectionSnapshot.error)&&(this.connectionSnapshot=Object.freeze({...e}),this.notify(this.connectionListeners))}publishRegistryChange(){this.registrySnapshot={revision:this.registrySnapshot.revision+1,descriptors:this.browserDescriptors},this.notify(this.registryListeners)}notify(e){for(let t of[...e])J(t,"notify")}}var eg=i(31761),em=i(24925),ef=i(48155),ev=i(63013),ey=i(55079),eb=i(49667),ew=i(90680),eC=i(49362),eS=i(24863),ek=i(49762),eP=i(60278),ex=i(5464),eD=i(72282),ej=i(86963),eR=i(55945),eI=i(35842),eM=i(73068),eE=i(99084),eN=i(49426),eT=i(93119),eA=i(93320),eF=i(56592);class eL{constructor(e,t){this.cwd=e,this.reader=t,this.state={snapshot:{status:"idle",repositories:[],error:null},layout:"directory",changesOnly:!1,expandedRepositories:new Set},this.listeners=new Set,this.revision=0,this.request=null,this.disposed=!1,this.subscribe=e=>(this.listeners.add(e),()=>this.listeners.delete(e)),this.getRevision=()=>this.revision}getWorkspace(e){return e===this.cwd?this.state:null}ensureSnapshot(e){return e!==this.cwd||"ready"===this.state.snapshot.status||this.request?Promise.resolve():this.load(!1)}refreshSnapshot(e){return e===this.cwd?this.load(!0):Promise.resolve()}setLayout(e,t){this.state.layout=t,this.publish()}setChangesOnly(e,t){this.state.changesOnly=t,this.publish()}toggleRepository(e,t){let i=new Set(this.state.expandedRepositories);i.has(t)?i.delete(t):i.add(t),this.state.expandedRepositories=i,this.publish()}dispose(){this.disposed=!0,this.request?.abort(),this.request=null,this.listeners.clear()}async load(e){if(this.disposed)return;this.request?.abort();let t=new AbortController;this.request=t,this.state.snapshot={...this.state.snapshot,status:"loading",error:null},this.publish();try{let i=await this.reader.snapshot(t.signal,e);if(this.request!==t)return;this.state.snapshot={status:"ready",repositories:i.repositories,error:null}}catch(e){if(this.request!==t)return;this.state.snapshot={...this.state.snapshot,status:"error",error:e instanceof Error?e.message:"读取 Git 状态失败"}}this.request===t&&(this.request=null,this.publish())}publish(){if(!this.disposed)for(let e of(this.revision+=1,this.listeners))e()}}var ez=i(20476),eO=i(73230),eB=i(82075);function eU(e,t){return(0,eO.B)({msg:o[e],i18n:{key:`projectHistory:${e}`,...t?{params:t}:{}}})}function eq(){return{status:"idle",data:null,error:null}}class eG{constructor(e,t){this.reader=e,this.files=t,this.state={repositoryRoot:null,mode:"history",tip:"HEAD",base:"",target:"HEAD",strategy:"merge-base",query:"",author:"",authorSuggestions:[],selectedCommit:null,selectedChangePath:null,branches:eq(),log:eq(),changes:eq()},this.scroll={log:0,changes:0},this.listeners=new Set,this.requests=new Map,this.revision=0,this.disposed=!1,this.logPage=1,this.changesPage=1,this.range=null,this.selection=null,this.restoredCommit=null,this.restoredChangePath=null,this.restoredChangesScroll=null,this.queryTimer=null,this.collapsedDirectories=new Set,this.changeTree=(0,eB.OA)([]),this.changeRows=[],this.subscribe=e=>(this.listeners.add(e),()=>this.listeners.delete(e)),this.getRevision=()=>this.revision}getChangeRows(){return this.changeRows}restoreBrowsing(e){Object.assign(this.state,{repositoryRoot:e.repositoryRoot,mode:e.mode,tip:e.tip,base:e.base,target:e.target,strategy:e.strategy,query:e.query,author:e.author}),this.scroll.log=e.logScroll,this.restoredChangesScroll=e.changesScroll,this.restoredCommit=e.selectedCommit,this.restoredChangePath=e.selectedChangePath,null!==e.repositoryRoot&&(this.loadBranches(),this.reload())}selectChange(e){this.state.changes.data?.items.some(t=>t.path===e)&&(this.state.selectedChangePath=e,this.publish())}toggleChangeDirectory(e){let t=this.changeRows.find(t=>t.directory?.path===e);if(t?.directory){if(t.expanded)this.collapsedDirectories.add(e);else for(let e of t.directory.paths)this.collapsedDirectories.delete(e);this.rebuildChangeRows(),this.publish()}}setScroll(e,t){this.scroll[e]=t}setRepository(e){e!==this.state.repositoryRoot&&(this.cancel("branches"),this.state.repositoryRoot=e,this.state.tip=this.state.target="HEAD",this.state.base="",this.state.author="",this.state.authorSuggestions=[],this.state.branches=eq(),this.resetSelection(),this.loadBranches(),this.reload())}setMode(e){this.state.mode!==e&&(this.state.mode=e,this.resetSelection(),this.reload())}setRevision(e,t){this.state[e]!==t&&(this.state[e]=t,this.resetSelection(),this.reload())}setStrategy(e){this.state.strategy!==e&&(this.state.strategy=e,this.resetSelection(),this.reload())}setQuery(e){this.setLogFilter("query",e)}setAuthor(e){this.setLogFilter("author",e)}setLogFilter(e,t){this.state[e]=t,this.resetSelection(),this.queryTimer=setTimeout(()=>{this.queryTimer=null,this.reload()},220)}refresh(){this.resetSelection(),this.loadBranches(),this.reload()}async reload(){if(!this.disposed&&null!==this.state.repositoryRoot){if("compare"===this.state.mode)return this.state.base?void await this.loadChanges({base:this.state.base,target:this.state.target,strategy:this.state.strategy},1,!0):void this.publish();await this.loadLog(1)}}selectCommit(e,t){let i="string"==typeof e?e:e.oid;this.state.selectedCommit=i,this.scroll.changes=0,this.clearHistoricalDiff(),this.loadChanges({commit:i,...t?{parent:t}:{}},1)}showAggregate(){this.range&&(this.state.selectedCommit=null,this.clearHistoricalDiff(),this.loadChanges(this.range,1))}loadMoreLog(){"ready"===this.state.log.status&&this.state.log.data?.hasMore&&!(this.state.log.data.items.length>=2e3)&&this.loadLog(this.logPage+1)}loadMoreChanges(){this.selection&&"ready"===this.state.changes.status&&this.state.changes.data?.hasMore&&this.loadChanges(this.selection,this.changesPage+1)}openChange(e){if(null===this.state.repositoryRoot)return;let t=this.state.changes.data,i=t?.items.find(t=>t.path===e);if(!t||!i)return;this.state.selectedChangePath=e,this.publish();let{original:s,target:o}=t.comparison,r=s?s.slice(0,8):eU("emptyRevision"),n=eU(this.state.selectedCommit||"merge-base"!==this.state.strategy?"historyDiffDirect":"historyDiffAncestor",{left:r,target:o.slice(0,8)});this.files.openDiff(this.state.repositoryRoot,e,{baseCommit:s,targetCommit:o,...i.oldPath?{oldPath:i.oldPath}:{}},n)}dispose(){for(let e of(this.disposed=!0,this.queryTimer&&clearTimeout(this.queryTimer),this.requests.values()))e.abort();this.requests.clear(),this.resetChangeTree(),this.listeners.clear()}async loadBranches(){let e=this.state.repositoryRoot;if(null===e||this.disposed)return;let t=this.begin("branches");this.state.branches={status:"loading",data:this.state.branches.data,error:null},this.publish();try{let i=await this.reader.branches(e,t.signal);if(!this.current("branches",t))return;this.state.branches={status:"ready",data:i,error:null}}catch(e){if(!this.current("branches",t))return;this.state.branches={status:"error",data:null,error:this.error(e)}}this.requests.delete("branches"),this.publish()}async loadLog(e){let t=this.state.repositoryRoot;if(this.disposed||null===t)return;let i=e>1?this.state.log.data:null,s=i?.tip??("compare"===this.state.mode?this.range?.target:this.state.tip),o=i?.exclude??("compare"===this.state.mode?this.range?.base:void 0);if(!s)return;let r=this.begin("log");this.state.log={status:"loading",data:i,error:null},this.publish();try{let n=await this.reader.log(t,{tip:s,...o?{exclude:o}:{},query:this.state.query,...this.state.author.trim()?{author:this.state.author.trim()}:{},page:{index:e,size:50}},r.signal);if(!this.current("log",r))return;for(let{author:t}of(this.logPage=e,n.items))t&&this.state.authorSuggestions.length<200&&!this.state.authorSuggestions.includes(t)&&this.state.authorSuggestions.push(t);if(this.state.log={status:"ready",data:{...n,items:[...i?.items??[],...n.items].slice(0,2e3)},error:null},1===e&&n.items[0]){let e=n.items.find(e=>e.oid===this.restoredCommit);this.restoredCommit=null,e?(this.state.selectedCommit=e.oid,this.loadChanges({commit:e.oid},1)):"history"===this.state.mode&&this.selectCommit(n.items[0])}}catch(e){if(!this.current("log",r))return;this.state.log={status:"error",data:i,error:this.error(e)}}this.requests.delete("log"),this.publish()}async loadChanges(e,t,i=!1){let s=this.state.repositoryRoot;if(this.disposed||null===s)return;let o=this.begin("changes"),r=t>1?this.state.changes.data:null;1===t&&this.resetChangeTree(),this.selection=e,this.state.changes={status:"loading",data:r,error:null},this.publish();try{let n=await this.reader.changes(s,{selection:e,page:{index:t,size:200}},o.signal);if(!this.current("changes",o))return;this.changesPage=t;let a=[...r?.items??[],...n.items];this.state.changes={status:"ready",data:{...n,items:a},error:null},this.changeTree=(0,eB.OA)(a.map(e=>e.path)),null!==this.restoredChangesScroll&&(this.scroll.changes=this.restoredChangesScroll,this.restoredChangesScroll=null),this.rebuildChangeRows(),this.restoredChangePath&&a.some(e=>e.path===this.restoredChangePath)&&(this.state.selectedChangePath=this.restoredChangePath,this.restoredChangePath=null),this.selection="commit"in e?{commit:n.comparison.target,...n.commit?.selectedParent?{parent:n.commit.selectedParent}:{}}:{base:n.comparison.base,target:n.comparison.target,strategy:e.strategy},i&&"base"in this.selection&&(this.range=this.selection,this.loadLog(1))}catch(e){if(!this.current("changes",o))return;this.state.changes={status:"error",data:r,error:this.error(e)}}this.requests.delete("changes"),this.publish()}resetSelection(){this.restoredCommit=null,this.restoredChangePath=null,this.restoredChangesScroll=null,this.queryTimer&&clearTimeout(this.queryTimer),this.queryTimer=null,this.scroll.log=this.scroll.changes=0,this.cancel("log"),this.cancel("changes"),this.range=null,this.selection=null,this.state.selectedCommit=null,this.state.log=eq(),this.state.changes=eq(),this.resetChangeTree(),this.clearHistoricalDiff(),this.publish()}resetChangeTree(){this.collapsedDirectories.clear(),this.changeTree=(0,eB.OA)([]),this.changeRows=[],this.state.selectedChangePath=null,this.scroll.changes=0}rebuildChangeRows(){let e=Math.floor(this.scroll.changes/36),t=this.changeRows[e],i=this.scroll.changes%36;this.changeRows=(0,eB.qV)(this.changeTree,this.collapsedDirectories);let s=t?this.changeRows.findIndex(e=>e.key===t.key):-1;this.scroll.changes=s>=0?36*s+i:Math.min(this.scroll.changes,Math.max(0,(this.changeRows.length-1)*36))}clearHistoricalDiff(){this.files.state.activeDiff?.comparison&&this.files.closeDiff()}begin(e){this.cancel(e);let t=new AbortController;return this.requests.set(e,t),t}cancel(e){this.requests.get(e)?.abort(),this.requests.delete(e)}current(e,t){return!this.disposed&&this.requests.get(e)===t}error(e){return e instanceof Error?e.message:eU("historyReadFailed")}publish(){if(!this.disposed)for(let e of(this.revision+=1,this.listeners))e()}}var eH=i(14044),e_=i(57731),e$=i(35995),eW=i(15265),eV=i(74675),eJ=i(73429),eY=i(60471);function eK({items:e,label:t,scrollTop:i,onScroll:o,render:r,role:n="listbox",onKeyDown:a}){let l=(0,p.useRef)(null),[c,d]=(0,p.useState)({top:i,height:300});(0,p.useLayoutEffect)(()=>{let e=l.current;if(!e)return;e.scrollTop=i;let t=()=>d({top:e.scrollTop,height:e.clientHeight});t();let s=new ResizeObserver(t);return s.observe(e),()=>s.disconnect()},[]),(0,p.useLayoutEffect)(()=>{l.current&&(l.current.scrollTop=i)},[e,i]);let h=Math.max(0,Math.floor(c.top/36)-8),u=Math.min(e.length,Math.ceil((c.top+c.height)/36)+8);return(0,s.jsx)("div",{ref:l,role:n,tabIndex:"tree"===n?0:void 0,onKeyDown:a,"aria-label":t,className:"min-h-0 flex-1 overflow-auto overscroll-contain",onScroll:e=>{let t=e.currentTarget.scrollTop;d(e=>({...e,top:t})),o(t)},children:(0,s.jsx)("div",{style:{height:36*e.length,position:"relative"},children:(0,s.jsx)("div",{style:{position:"absolute",top:36*h,left:0,right:0},children:e.slice(h,u).map((e,t)=>r(e,h+t))})})})}var eQ=i(36670),eZ=i(50479),eX=i(66584),e0=i(60682);let e1={added:"A",modified:"M",deleted:"D",renamed:"R","type-changed":"T"};function e2({cwd:e,repositoryRoot:t,rows:i,changes:o,selectedPath:r,scrollTop:n,onScroll:a,onSelect:l,onToggle:c,onOpen:d,onReveal:h}){let{t:u}=(0,v.Bd)("projectHistory"),p=new Map(o.map(e=>[e.path,e]));return(0,s.jsx)(eK,{role:"tree",label:u("changeFiles"),items:i,scrollTop:n,onScroll:a,onKeyDown:e=>{if(e.defaultPrevented||!e.currentTarget.contains(e.target))return;let t=e.target instanceof Element?e.target.closest("[data-tree-key]"):null;if(e.target instanceof Element&&e.target.closest("button"))return;let s=t?i.findIndex(e=>e.key===t.dataset.treeKey):-1,o=i[s],r=s;if("ArrowDown"===e.key)r=Math.min(i.length-1,s+1);else if("ArrowUp"===e.key)r=Math.max(0,s-1);else if("Home"===e.key)r=0;else if("End"===e.key)r=i.length-1;else if("ArrowRight"===e.key&&o?.directory)o.expanded?r=Math.min(i.length-1,s+1):c(o.directory.path);else if("ArrowLeft"===e.key&&o){if(o.expanded&&o.directory)c(o.directory.path);else for(let e=s-1;e>=0;e-=1)if(i[e].depth<o.depth){r=e;break}}else{if("Enter"!==e.key&&" "!==e.key||!o)return;o.directory?c(o.directory.path):"Enter"===e.key?d(o.path):l(o.path)}e.preventDefault();let n=i[r];if(!n)return;let a=e.currentTarget;36*r<a.scrollTop?a.scrollTop=36*r:(r+1)*36>a.scrollTop+a.clientHeight&&(a.scrollTop=(r+1)*36-a.clientHeight),requestAnimationFrame(()=>{[...a.querySelectorAll("[data-tree-key]")].find(e=>e.dataset.treeKey===n.key)?.focus()})},render:i=>{let o=p.get(i.path),n=(0,eB._J)(t,i.path),a=i.directory;return(0,s.jsx)(e0.J,{cwd:e,path:n,type:i.type,historical:!0,expanded:i.expanded,onToggle:a?()=>c(a.path):void 0,onOpen:"file"===i.type?()=>d(i.path):void 0,openLabel:u("viewDiff"),oldPath:"file"===i.type&&o?.oldPath?(0,eB._J)(t,o.oldPath):void 0,onReveal:h,trigger:(0,s.jsxs)("div",{role:"treeitem",tabIndex:0,"aria-level":i.depth+1,"aria-expanded":i.expanded,"aria-selected":"file"===i.type&&r===i.path,"data-tree-key":i.key,className:(0,eN.cn)("flex h-9 min-w-0 cursor-pointer items-center gap-2 pr-2 text-sm outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring","file"===i.type&&r===i.path&&"bg-accent"),style:{paddingLeft:8+16*i.depth},title:o?.oldPath&&"file"===i.type?`${(0,eB._J)(t,o.oldPath)} → ${n}`:n,onClick:e=>{a?e.detail<2&&c(a.path):l(i.path)},onDoubleClick:()=>{"file"===i.type&&d(i.path)},children:[a?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(eQ.A,{className:(0,eN.cn)("size-4 shrink-0 text-muted-foreground",i.expanded&&"rotate-90")}),i.expanded?(0,s.jsx)(eZ.A,{className:"size-4 shrink-0 text-muted-foreground"}):(0,s.jsx)(eX.A,{className:"size-4 shrink-0 text-muted-foreground"})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"w-4 shrink-0"}),(0,s.jsx)("span",{className:(0,eN.cn)("w-4 shrink-0 font-mono text-xs",o?.status==="added"?"text-emerald-600 dark:text-emerald-400":o?.status==="deleted"?"text-red-600 dark:text-red-400":"text-blue-600 dark:text-blue-400"),"aria-label":u("gitStatus",{status:o?e1[o.status]:""}),children:o?e1[o.status]:""})]}),(0,s.jsxs)("span",{className:"min-w-0 flex-1 truncate",children:[i.label,"directory"===i.type&&p.has(i.path)?"/":""]}),"file"===i.type?(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":u("viewDiffPath",{path:i.path}),onDoubleClick:e=>e.stopPropagation(),onClick:e=>{e.stopPropagation(),d(i.path)},children:(0,s.jsx)(eP.A,{className:"size-4"})}):null]})},i.key)}})}function e4(e){let{state:t,repositories:i,projectName:o,narrow:r,scroll:n}=e,{t:a}=(0,v.Bd)("projectHistory"),{locale:l,timeZone:c}=(0,f.i)(),d=(0,p.useMemo)(()=>new Intl.DateTimeFormat("en"===l?"en-US":"zh-CN",{timeZone:c,month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[l,c]),h=(0,p.useMemo)(()=>new Intl.DateTimeFormat("en"===l?"en-US":"zh-CN",{timeZone:c,timeZoneName:"shortOffset",year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[l,c]),u=(0,p.useId)(),{mobilePane:g,onMobilePane:m}=e,y=t.changes.data,b=`${t.repositoryRoot}:${y?.comparison.original}:${y?.comparison.target}`,w=t.selectedChangePath,C=[{value:"HEAD",label:a("currentHead")},...(t.branches.data?.local??[]).map(e=>({value:`refs/heads/${e}`,label:e,description:a("localBranch")})),...(t.branches.data?.remote??[]).map(e=>({value:`refs/remotes/${e}`,label:e,description:a("remoteBranch")}))],S=t.branches.data?.upstream,k=y?.commit,P=i=>i?(0,s.jsxs)("div",{role:"alert",className:"flex flex-wrap items-center gap-2 p-3 text-sm text-destructive",children:[(0,s.jsx)("span",{className:"min-w-0 flex-1 break-words",children:i}),(0,s.jsx)(ej.$,{size:"sm",variant:"outline",onClick:e.onRefresh,children:a("retry")}),"compare"===t.mode&&"merge-base"===t.strategy?(0,s.jsx)(ej.$,{size:"sm",variant:"outline",onClick:()=>e.onStrategy("direct"),children:a("compareDirect")}):null]}):null,x=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[P(t.log.error),"loading"===t.log.status?(0,s.jsxs)("div",{className:"flex items-center gap-2 px-3 py-2 text-xs text-muted-foreground",children:[(0,s.jsx)(eH.A,{className:"size-4 animate-spin"}),a("loadingCommits")]}):null,(0,s.jsx)(eK,{items:t.log.data?.items??[],label:a("commitList"),scrollTop:n.log,onScroll:t=>e.onScroll("log",t),render:i=>(0,s.jsxs)("button",{type:"button",role:"option","aria-selected":t.selectedCommit===i.oid,className:(0,eN.cn)("flex h-9 w-full items-center gap-3 border-b border-border/40 px-3 text-left text-sm outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",t.selectedCommit===i.oid&&"bg-accent"),onClick:()=>{var t;return t=i.oid,void(e.onCommit(t),r&&m("files"))},title:`${i.subject}
|
|
2
2
|
${i.oid}
|
|
3
|
-
${i.author} \xb7 ${h.format(i.timestampMs)}`,children:[(0,s.jsxs)("span",{className:"min-w-0 flex-1 truncate",children:[i.subject||a("noCommitMessage"),i.refs.length?(0,s.jsx)("span",{className:"ml-2 text-xs text-muted-foreground",children:i.refs.join(" \xb7 ")}):null]}),(0,s.jsx)("span",{className:"shrink-0 font-mono text-xs text-muted-foreground",children:i.oid.slice(0,7)}),r?null:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"w-20 truncate text-xs text-muted-foreground",children:i.author}),(0,s.jsx)("time",{className:"w-28 shrink-0 text-right text-xs text-muted-foreground",children:d.format(i.timestampMs)})]})]},i.oid)},`${t.repositoryRoot}:${t.mode}:${t.tip}:${t.base}:${t.target}:${t.query}:${t.author}`),"ready"!==t.log.status||t.log.data?.items.length?null:(0,s.jsx)("p",{className:"px-3 py-4 text-sm text-muted-foreground",children:t.query||t.author?a("noMatchingCommits"):a("noCommits")}),t.log.data?.truncated?(0,s.jsx)("p",{className:"px-3 py-2 text-xs text-muted-foreground",children:a("scanLimit")}):null,(t.log.data?.items.length??0)>=2e3?(0,s.jsx)("p",{className:"px-3 py-2 text-xs text-muted-foreground",children:a("loadedLimit")}):t.log.data?.hasMore?(0,s.jsx)(eR.$,{variant:"ghost",size:"sm",disabled:"loading"===t.log.status,onClick:e.onMoreLog,children:a("loadMoreCommits")}):null]}),D=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsxs)("div",{className:"flex min-h-9 shrink-0 flex-wrap items-center gap-2 border-b px-3 py-1",children:[r?(0,s.jsx)(eR.$,{variant:"ghost",size:"icon-sm","aria-label":a("backCommits"),onClick:()=>m("log"),children:(0,s.jsx)(e_.A,{className:"size-4"})}):null,(0,s.jsx)("span",{className:"text-sm font-medium",children:t.selectedCommit?a("commitChanges"):a("cumulativeChanges")}),y?(0,s.jsx)("span",{className:"text-xs text-muted-foreground",children:a("loadedFiles",{count:y.items.length})}):null,"compare"===t.mode&&t.selectedCommit?(0,s.jsx)(eR.$,{variant:"ghost",size:"sm",onClick:e.onAggregate,children:a("backCumulative")}):null]}),P(t.changes.error),"loading"===t.changes.status?(0,s.jsxs)("div",{className:"flex items-center gap-2 p-3 text-xs text-muted-foreground",children:[(0,s.jsx)(eH.A,{className:"size-4 animate-spin"}),a("loadingChanges")]}):null,(0,s.jsxs)(eD.HK,{orientation:"vertical",defaultLayout:{"project-changes":e.panelSizes.changes,"project-detail":100-e.panelSizes.changes},onLayoutChanged:(t,i)=>{i.isUserInteraction&&void 0!==t["project-changes"]&&e.onPanelSize("changes",t["project-changes"])},children:[(0,s.jsx)(eD.wV,{id:"project-changes",defaultSize:`${e.panelSizes.changes}%`,minSize:"80px",children:(0,s.jsxs)("div",{className:"flex size-full min-h-0 flex-col",children:[(0,s.jsx)(e2,{cwd:e.cwd,repositoryRoot:t.repositoryRoot??"",rows:e.changeRows,changes:y?.items??[],selectedPath:w,scrollTop:n.changes,onScroll:t=>e.onScroll("changes",t),onSelect:e.onSelectChange,onToggle:e.onToggleDirectory,onOpen:e.onOpenFile,onReveal:e.onReveal},b),"ready"!==t.changes.status||y?.items.length?null:(0,s.jsx)("p",{className:"px-3 py-4 text-sm text-muted-foreground",children:a("noDiff")}),y?.hasMore?(0,s.jsx)(eR.$,{size:"sm",variant:"ghost",disabled:"loading"===t.changes.status,onClick:e.onMoreChanges,children:a("loadMoreFiles")}):null,y?.truncated?(0,s.jsx)("p",{className:"p-3 text-xs text-muted-foreground",children:a("changesLimit")}):null]})}),(0,s.jsx)(eD.WM,{}),(0,s.jsx)(eD.wV,{id:"project-detail",defaultSize:`${100-e.panelSizes.changes}%`,minSize:"60px",children:(0,s.jsxs)(eV.V,{className:"h-full",viewportClassName:"p-3 text-sm",role:"region","aria-label":a("commitDetails"),children:[k?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("pre",{className:"mb-3 whitespace-pre-wrap break-words font-sans leading-relaxed",children:k.message}),(0,s.jsxs)("div",{className:"mb-2 flex items-center gap-2",children:[(0,s.jsx)("span",{className:"min-w-0 flex-1 break-all font-mono text-xs",children:k.oid}),(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":a("copySha"),onClick:()=>e.onCopy(k.oid),children:(0,s.jsx)(e$.A,{className:"size-4"})})]}),(0,s.jsxs)("p",{className:"mb-3 text-xs text-muted-foreground",children:[k.author," \xb7 ",h.format(k.timestampMs)]}),k.parents.length>1?(0,s.jsx)(eY.b,{className:"mb-3",ariaLabel:a("compareParent"),value:k.selectedParent??"",options:k.parents.map((e,t)=>({value:e,label:a("parentCommit",{count:t+1,oid:e.slice(0,10)})})),onChange:t=>e.onCommit(k.oid,t)}):null]}):y?(0,s.jsxs)("div",{className:"space-y-2 text-xs text-muted-foreground",children:[(0,s.jsx)("p",{children:"merge-base"===t.strategy?a("mergeBaseToTarget"):a("baseToTarget")}),(0,s.jsx)("p",{className:"break-all font-mono",children:y.comparison.original??a("emptyRevision")}),(0,s.jsx)("p",{className:"break-all font-mono",children:y.comparison.target})]}):(0,s.jsx)("p",{className:"text-muted-foreground",children:a("selectCommit")}),w?(0,s.jsx)("p",{className:"mt-3 break-all font-mono text-xs text-muted-foreground",children:w}):null]})})]})]});return(0,s.jsxs)("section",{className:"flex size-full min-h-0 min-w-0 flex-col","aria-label":a("historyAndCompare"),children:[(0,s.jsxs)("div",{className:"flex shrink-0 flex-wrap items-center gap-2 border-b px-3 py-2",children:[(0,s.jsxs)("div",{className:"flex gap-1",role:"group","aria-label":a("viewMode"),children:[(0,s.jsx)(eR.$,{size:"sm",variant:"history"===t.mode?"secondary":"ghost","aria-pressed":"history"===t.mode,onClick:()=>{e.onMode("history"),m("log")},children:a("historyMode")}),(0,s.jsx)(eR.$,{size:"sm",variant:"compare"===t.mode?"secondary":"ghost","aria-pressed":"compare"===t.mode,onClick:()=>{e.onMode("compare"),m("log")},children:a("compareMode")})]}),(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("selectRepository"),value:t.repositoryRoot??"",options:i.map(e=>({value:e.root,label:e.root||o,description:"unavailable"===e.state?(0,eW.fD)(e.message,l):void 0})),onChange:e.onRepository}),"history"===t.mode?(0,s.jsx)(eY.b,{className:"w-48",ariaLabel:a("viewBranch"),value:t.tip,options:C,onChange:t=>e.onRevision("tip",t)}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("baseBranch"),placeholder:a("chooseBase"),value:t.base,options:C,onChange:t=>e.onRevision("base",t)}),(0,s.jsx)("span",{className:"text-xs text-muted-foreground",children:"→"}),(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("targetBranch"),value:t.target,options:C,onChange:t=>e.onRevision("target",t)}),(0,s.jsx)(eY.b,{className:"w-48",ariaLabel:a("comparison"),value:t.strategy,options:[{value:"merge-base",label:a("introducedChanges")},{value:"direct",label:a("directComparison")}],onChange:t=>e.onStrategy("direct"===t?"direct":"merge-base")}),r?(0,s.jsx)(eR.$,{size:"sm",variant:"outline",onClick:()=>m("files"),children:a("cumulativeChanges")}):null]}),(0,s.jsx)(eJ.p,{className:"w-40 shrink-0","aria-label":a("filterAuthor"),placeholder:a("author"),list:u,value:t.author,onChange:t=>e.onAuthor(t.target.value)}),(0,s.jsx)("datalist",{id:u,children:t.authorSuggestions.map(e=>(0,s.jsx)("option",{value:e},e))}),(0,s.jsx)(eJ.p,{className:"min-w-32 flex-1 basis-40","aria-label":a("searchCommits"),placeholder:a("searchCommits"),value:t.query,onChange:t=>e.onQuery(t.target.value)}),(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":a("refreshGit"),onClick:e.onRefresh,children:(0,s.jsx)(ew.A,{className:"size-4"})})]}),t.branches.error?P(t.branches.error):null,S?(0,s.jsxs)("p",{className:"shrink-0 truncate border-b px-3 py-1 text-xs text-muted-foreground",title:S.ref,children:[S.ref.replace("refs/remotes/","")," \xb7 ",a("localRecord")," \xb7"," ",null===S.ahead||null===S.behind?a("refUnavailable"):a("aheadBehind",{ahead:S.ahead,behind:S.behind})]}):null,"compare"!==t.mode||t.base?r?"log"===g?x:D:(0,s.jsxs)(eD.HK,{orientation:"horizontal",defaultLayout:{"project-log":e.panelSizes.log,"project-files":100-e.panelSizes.log},onLayoutChanged:(t,i)=>{i.isUserInteraction&&void 0!==t["project-log"]&&e.onPanelSize("log",t["project-log"])},children:[(0,s.jsx)(eD.wV,{id:"project-log",defaultSize:`${e.panelSizes.log}%`,minSize:"30%",children:x}),(0,s.jsx)(eD.WM,{}),(0,s.jsx)(eD.wV,{id:"project-files",defaultSize:`${100-e.panelSizes.log}%`,minSize:"25%",children:D})]}):(0,s.jsx)("p",{className:"p-4 text-sm text-muted-foreground",children:a("chooseBaseBranch")})]})}var e3=i(86062);let e6="pi-super:project-preview:global",e9="pi-super:project-preview:projects",e5=x.ai().min(5).max(95),e7=x.Ik({maximized:x.zM(),directoryOpen:x.zM(),gitOpen:x.zM(),gitMaximized:x.zM(),treeLayout:x.k5(["directory","repository"]),directorySize:e5,gitSize:e5,logSize:e5,changeSize:e5}),e8={maximized:!1,directoryOpen:!0,gitOpen:!1,gitMaximized:!1,treeLayout:"directory",directorySize:22,gitSize:45,logSize:62,changeSize:70},te=x.Ik({repositoryRoot:x.Yj().nullable(),mode:x.k5(["history","compare"]),tip:x.Yj(),base:x.Yj(),target:x.Yj(),strategy:x.k5(["merge-base","direct"]),query:x.Yj().max(200),author:x.Yj().max(200),selectedCommit:e3.aD.nullable(),selectedChangePath:V._g.nullable(),logScroll:x.ai().nonnegative(),changesScroll:x.ai().nonnegative()}),tt=x.Ie(e=>"object"==typeof e&&null!==e&&Array.isArray(e.cursorState)&&"object"==typeof e.viewState),ti=x.Ik({page:x.k5(["files","code","git"]),historyPane:x.k5(["log","files"]),tabs:x.YO(V._g).max(20),activePath:V._g.nullable(),editorStates:x.g1(V._g,tt),fileViewModes:x.g1(V._g,x.k5(["source","preview"])),expandedPaths:x.YO(x.Yj()).max(500),treeScrollTop:x.ai().nonnegative(),searchQuery:x.Yj().max(200),changesOnly:x.zM(),expandedRepositories:x.YO(x.Yj()).max(100),history:te,activeDiff:x.Ik({repositoryRoot:x.Yj(),path:V._g,comparison:e3.xv.optional()}).nullable()}),ts=x.Ik({cwd:x.Yj(),lastOpenedAt:x.ai(),state:ti});function to(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return/^[a-z]:\//i.test(t)||t.startsWith("//")?t.toLowerCase():t}function tr(){try{let e=JSON.parse(window.localStorage.getItem(e9)??"[]");if(!Array.isArray(e))return[];let t=Date.now();return e.flatMap(e=>{let i=ts.safeParse(e);return i.success&&t-i.data.lastOpenedAt<2592e6?[i.data]:[]})}catch{return[]}}function tn(e){try{window.localStorage.setItem(e9,JSON.stringify(e.sort((e,t)=>t.lastOpenedAt-e.lastOpenedAt).slice(0,50)))}catch(e){console.warn("[Pi Desk][ProjectPreview] 保存项目浏览状态失败",e)}}function ta(){try{let e=JSON.parse(window.localStorage.getItem(e6)??"null");return{...e8,...e7.partial().parse(e)}}catch{return{...e8}}}function tl({clientId:e,cwd:t,onClose:i}){let{t:o}=(0,v.Bd)("projectHistory"),r=(0,y.G)(),[n]=(0,p.useState)(ta),[a,l]=(0,p.useState)(n),c=(0,p.useCallback)(e=>{l(t=>({...t,...e}));var t={...ta(),...e};try{window.localStorage.setItem(e6,JSON.stringify(t))}catch(e){console.warn("[Pi Desk][ProjectPreview] 保存全局布局失败",e)}},[]),[d]=(0,p.useState)(()=>{let e,i,s;return e=to(t),(s=(i=tr()).find(t=>t.cwd===e))&&(s.lastOpenedAt=Date.now()),tn(i),s?.state??null}),[h]=(0,p.useState)(()=>{var i;let s,o,a,l,c;return i=e=>r.show({level:"info",title:e}),s=(0,eA.Y4)(e,{cwd:t}),o=new eF.h(t,s,{imagePreviewMode:ez.Wq,onNotice:i,reveal:(i,s="file")=>(0,eT.P)(e,{cwd:t},i,s),maxTabs:20}),a=new eL(t,s),l=new eG(s,o),c=!1,{files:o,git:a,history:l,restore(){if(!c&&(c=!0,a.setLayout(t,n.treeLayout),d)){for(let e of(a.setChangesOnly(t,d.changesOnly),d.expandedRepositories))a.toggleRepository(t,e);o.restoreBrowsing(d),l.restoreBrowsing(d.history)}},dispose(){l.dispose(),a.dispose(),o.dispose()}}}),{files:u,git:g,history:m}=h;(0,p.useSyncExternalStore)(u.subscribe,u.getRevision,u.getRevision);let f=(0,p.useSyncExternalStore)(g.subscribe,g.getRevision,g.getRevision);(0,p.useSyncExternalStore)(m.subscribe,m.getRevision,m.getRevision);let{directoryOpen:b,gitOpen:w,gitMaximized:C,maximized:S}=a,[k,P]=(0,p.useState)(d?.page??"files"),[x,D]=(0,p.useState)({width:1200,height:800}),[R,j]=(0,p.useState)(null),[I,M]=(0,p.useState)(d?.historyPane??"log"),E=(0,p.useRef)(null),N=(0,p.useRef)(()=>void 0),T=x.width<900,A=T||x.height<680,F=t.replaceAll("\\","/").split("/").filter(Boolean).at(-1)??t,L=g.getWorkspace(t),z=L.snapshot.repositories,O=u.state,B=O.activeDiff?[O.activeDiff.repositoryRoot,O.activeDiff.path].filter(Boolean).join("/"):null;(0,p.useEffect)(()=>{N.current=()=>{let e=g.getWorkspace(t),i=m.state;!function(e,t){let i=ti.safeParse(t);if(!i.success)return;let s=to(e),o=tr(),r=o.find(e=>e.cwd===s);r?r.state=i.data:o.push({cwd:s,lastOpenedAt:Date.now(),state:i.data}),tn(o)}(t,{page:k,historyPane:I,tabs:[...u.state.tabs],activePath:u.state.activePath,...u.getBrowsingDocumentSettings(),expandedPaths:[...u.state.expandedPaths].slice(0,500),treeScrollTop:u.state.treeScrollTop,searchQuery:u.state.search.query.slice(0,200),changesOnly:e.changesOnly,expandedRepositories:[...e.expandedRepositories].slice(0,100),history:{repositoryRoot:i.repositoryRoot,mode:i.mode,tip:i.tip,base:i.base,target:i.target,strategy:i.strategy,query:i.query.slice(0,200),author:i.author.slice(0,200),selectedCommit:i.selectedCommit,selectedChangePath:i.selectedChangePath,logScroll:m.scroll.log,changesScroll:m.scroll.changes},activeDiff:u.state.activeDiff?{repositoryRoot:u.state.activeDiff.repositoryRoot,path:u.state.activeDiff.path,...u.state.activeDiff.comparison?{comparison:u.state.activeDiff.comparison}:{}}:null})}},[t,u,g,m,I,k]),(0,p.useEffect)(()=>{E.current={},h.restore(),u.ensureRoot(),g.ensureSnapshot(t);let e=Date.now(),i=()=>{Date.now()-e<5e3||(e=Date.now(),g.refreshSnapshot(t))};window.addEventListener("focus",i);let s=()=>N.current();return window.addEventListener("pagehide",s),()=>{E.current=null,window.removeEventListener("focus",i),window.removeEventListener("pagehide",s),queueMicrotask(()=>{null===E.current&&(N.current(),h.dispose())})}},[t,u,g,h]),(0,p.useEffect)(()=>{if(!R)return;let e=new ResizeObserver(()=>D({width:R.clientWidth,height:R.clientHeight}));return e.observe(R),()=>e.disconnect()},[R]),(0,p.useEffect)(()=>{if(!w||!z.length||z.some(e=>e.root===m.state.repositoryRoot))return;let e=O.activeDiff?[O.activeDiff.repositoryRoot,O.activeDiff.path].filter(Boolean).join("/"):O.activePath,t=e?[...z].sort((e,t)=>t.root.length-e.root.length).find(t=>!t.root||e.startsWith(`${t.root}/`)):null;m.setRepository(t?.root??z.find(e=>""===e.root)?.root??z[0].root)},[w,f,m,z,O.activeDiff,O.activePath]),(0,p.useEffect)(()=>g.subscribe(()=>{let e=g.getWorkspace(t)?.layout;e&&e!==a.treeLayout&&c({treeLayout:e})}),[t,g,a.treeLayout,c]);let U=e=>{c({gitOpen:!0}),P("git"),void 0!==e&&m.setRepository(e)},q=(0,s.jsx)(ej.F,{cwd:t,projectName:F,runtime:u,gitRuntime:g,onOpenGitBranches:U,onFileOpened:()=>P("code")}),G=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsx)(eI.X,{cwd:t,gitRuntime:g,paths:O.tabs,activePath:O.activePath,diffPath:B,mobile:T,onActivate:e=>u.openFile(e),onClose:(e,t)=>u.closeTabs(e,t)}),(0,s.jsx)(eM.R,{runtime:u,gitRuntime:g,compact:x.width<1100||T,onEscape:i})]}),H=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsxs)("div",{className:"flex h-9 shrink-0 items-center gap-2 border-b bg-muted px-3",children:[(0,s.jsx)(eg.A,{className:"size-4"}),(0,s.jsx)("span",{className:"flex-1 text-sm font-medium",children:"Git"}),A?null:(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o(C?"restoreGit":"maximizeGit"),onClick:()=>c({gitMaximized:!C}),children:C?(0,s.jsx)(em.A,{className:"size-4"}):(0,s.jsx)(ef.A,{className:"size-4"})}),(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o("collapseGit"),onClick:()=>{c({gitOpen:!1,gitMaximized:!1}),P("code")},children:(0,s.jsx)(ev.A,{className:"size-4"})})]}),z.length?(0,s.jsx)(e4,{state:m.state,cwd:t,changeRows:m.getChangeRows(),onSelectChange:e=>m.selectChange(e),onToggleDirectory:e=>m.toggleChangeDirectory(e),onReveal:(e,t)=>u.revealFile(e,t),repositories:z,projectName:F,narrow:T,mobilePane:I,onMobilePane:M,scroll:m.scroll,onScroll:(e,t)=>m.setScroll(e,t),panelSizes:{log:a.logSize,changes:a.changeSize},onPanelSize:(e,t)=>c("log"===e?{logSize:t}:{changeSize:t}),onRepository:e=>{m.setRepository(e),M("log")},onMode:e=>m.setMode(e),onRevision:(e,t)=>m.setRevision(e,t),onStrategy:e=>m.setStrategy(e),onQuery:e=>m.setQuery(e),onAuthor:e=>m.setAuthor(e),onCommit:(e,t)=>m.selectCommit(e,t),onAggregate:()=>m.showAggregate(),onMoreLog:()=>m.loadMoreLog(),onMoreChanges:()=>m.loadMoreChanges(),onOpenFile:e=>{m.openChange(e),P("code"),c({gitMaximized:!1})},onRefresh:()=>m.refresh(),onCopy:e=>{(0,eE.x)(e).then(e=>{e||r.error(o("copyFailed"))})}}):(0,s.jsx)("p",{className:"p-4 text-sm text-muted-foreground",children:"loading"===L.snapshot.status||"idle"===L.snapshot.status?o("findingGit"):L.snapshot.error??o("noGit")})]}),_=(0,s.jsxs)(eD.HK,{orientation:"horizontal",defaultLayout:b?{"project-tree":a.directorySize,"project-code":100-a.directorySize}:void 0,onLayoutChanged:(e,t)=>{t.isUserInteraction&&void 0!==e["project-tree"]&&c({directorySize:e["project-tree"]})},children:[b?(0,s.jsx)(eD.wV,{id:"project-tree",defaultSize:`${a.directorySize}%`,minSize:"180px",maxSize:"40%",children:q}):null,b?(0,s.jsx)(eD.WM,{}):null,(0,s.jsx)(eD.wV,{id:"project-code",minSize:"40%",children:G})]},b?"tree-visible":"tree-hidden");return(0,s.jsx)(ex.YV,{open:!0,onOpenChange:e=>{e||i()},children:(0,s.jsxs)(ex.hA,{ref:j,showCloseButton:!1,"data-testid":"project-preview-dialog",className:(0,eN.cn)("h-[min(94dvh,1080px)] w-[min(96dvw,1600px)] max-w-none gap-0 p-0",S&&"h-dvh max-h-none w-dvw rounded-none","max-sm:h-dvh max-sm:max-h-none max-sm:w-dvw max-sm:rounded-none"),children:[(0,s.jsxs)("header",{className:"flex min-h-14 shrink-0 flex-wrap items-center gap-2 border-b bg-muted px-3 py-2 pt-[max(8px,env(safe-area-inset-top))]",children:[A?null:(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o(b?"collapseDirectory":"expandDirectory"),onClick:()=>c({directoryOpen:!b}),children:b?(0,s.jsx)(ey.A,{className:"size-4"}):(0,s.jsx)(eb.A,{className:"size-4"})}),(0,s.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,s.jsx)(ex.YM,{className:"truncate",title:t,children:F}),(0,s.jsx)("p",{className:"truncate text-xs text-muted-foreground",title:t,children:t})]}),(0,s.jsx)(ex.uX,{className:"sr-only",children:o("previewDescription")}),(0,s.jsxs)(eR.$,{size:"sm",variant:w?"secondary":"ghost","aria-pressed":w,onClick:()=>U(),children:[(0,s.jsx)(eg.A,{className:"size-4"}),(0,s.jsx)("span",{className:"max-sm:hidden",children:o("gitRecords")})]}),(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o("refreshPreview"),onClick:()=>{u.refreshTree(),g.refreshSnapshot(t),O.activeDiff?u.reloadDiff():O.activePath&&u.reloadFile(O.activePath),w&&m.refresh()},children:(0,s.jsx)(ew.A,{className:"size-4"})}),T?null:(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o(S?"restoreWindow":"maximizeWindow"),onClick:()=>c({maximized:!S}),children:S?(0,s.jsx)(em.A,{className:"size-4"}):(0,s.jsx)(ef.A,{className:"size-4"})}),(0,s.jsx)(eR.$,{size:"icon-sm",variant:"ghost","aria-label":o("closePreview"),onClick:i,children:(0,s.jsx)(eC.A,{className:"size-4"})})]}),L.snapshot.error?(0,s.jsx)("p",{role:"alert",className:"shrink-0 border-b px-3 py-2 text-sm text-destructive",children:L.snapshot.error}):null,A?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("div",{className:"flex shrink-0 gap-1 border-b px-2 py-1",role:"group","aria-label":o("previewArea"),children:[(0,s.jsxs)(eR.$,{size:"sm",variant:"files"===k?"secondary":"ghost",onClick:()=>P("files"),children:[(0,s.jsx)(eS.A,{className:"size-4"}),o("files")]}),(0,s.jsxs)(eR.$,{size:"sm",variant:"code"===k?"secondary":"ghost",onClick:()=>P("code"),children:[(0,s.jsx)(ek.A,{className:"size-4"}),o("code")]}),(0,s.jsxs)(eR.$,{size:"sm",variant:"git"===k?"secondary":"ghost",onClick:()=>U(),children:[(0,s.jsx)(eP.A,{className:"size-4"}),"Git"]})]}),(0,s.jsx)("div",{className:"min-h-0 flex-1",children:"files"===k?q:"git"===k?H:G})]}):C&&w?H:(0,s.jsxs)(eD.HK,{orientation:"vertical",defaultLayout:w?{"project-main":100-a.gitSize,"project-git":a.gitSize}:void 0,onLayoutChanged:(e,t)=>{t.isUserInteraction&&void 0!==e["project-git"]&&c({gitSize:e["project-git"]})},children:[(0,s.jsx)(eD.wV,{id:"project-main",defaultSize:w?`${100-a.gitSize}%`:"100%",minSize:"35%",children:_}),w?(0,s.jsx)(eD.WM,{}):null,w?(0,s.jsx)(eD.wV,{id:"project-git",defaultSize:`${a.gitSize}%`,minSize:"300px",children:H}):null]},w?"git-visible":"git-hidden")]})})}var tc=i(67837),td=i(74166),th=i(67069);function tu({children:e}){let t=(0,y.G)(),[i]=(0,p.useState)(()=>{var e,i,s;let o,r,n,a=(0,tc.y)(),l=(0,th.YW)(a);return{clientId:a,...(e=(e,i)=>{t.show(i)},o="off"===new URL(window.location.href).searchParams.get("plugins"),r="normal",i=()=>!o&&"normal"===r,n=new ep({pi:{prompt:(e,t)=>l.request(S.P6.send,{source:e,mode:t.mode,text:t.text,images:(t.images??[]).map(e=>({...e}))}),commands:{list:async e=>(await l.request(q.QV.commandsList,{source:e})).commands.filter(e=>"extension"===e.source).map(({name:e,description:t})=>({name:e,description:t})),execute:async(e,t,i)=>{await l.request(q.QV.commandExecute,{source:e,command:t,...void 0===i?{}:{args:i}})}},tools:{list:async e=>(await l.request(q.QV.toolsList,{source:e})).tools},bash:{execute:(e,t)=>l.request(q.QV.bashExecute,{source:e,command:t.command,excludeFromContext:t.excludeFromContext}),abort:async e=>{await l.request(q.QV.bashAbort,{source:e})}},interrupt:async e=>{await l.request(S.P6.interrupt,{source:e})}},listBrowserEntries:async()=>{if(!i())return[];let{entries:e}=await l.request(N.list,{});return i()?e:[]},subscribePush:e=>l.subscribe($,e),createPiDeskChannel:e=>({invokeGlobal:(t,i)=>l.request(k.OY.invoke,{pluginName:e,method:t,scope:"global",input:i}),invokeSession:(t,i,s)=>l.request(k.OY.invoke,{pluginName:e,method:i,scope:"session",source:t,input:s})}),createLogChannel:e=>({watch:async t=>(await l.request(U.watch,{pluginName:e,path:t})).snapshot,unwatch:async t=>{await l.request(U.unwatch,{pluginName:e,path:t})},subscribe:t=>l.subscribe(U.event,i=>{i.pluginName===e&&t({path:i.path,event:i.event})})})},void 0,e),{appSocket:(s=e=>{r=e},{async connect(e){n.markConnecting();try{return await l.connect(e)}catch(e){throw n.markDisconnected(e instanceof Error?e.message:"WebSocket 连接失败"),e}},async request(e,t){let i=await l.request(e,t);if(e.path!==P.kM.list.path)return i;let o=P.e4.parse(i);return s(o.appRuntime.mode),(0,C.UV)(o.appRuntime.settings),n.replaceGlobalPluginStates(o.appRuntime.plugins),n.replaceWorkSessions(o.workSessions),n.markReady(),n.refreshEntries().catch(e=>{console.error("[Pi Desk][PluginHost] 初始化 Browser Entry 失败",{errorName:e instanceof Error?e.name:"UnknownError",message:e instanceof Error?e.message:String(e)})}),i},subscribe:(e,t)=>l.subscribe(e,t),async waitForClose(){let e=await l.waitForClose();return n.markDisconnected(e.reason||null),e},close(){l.close()}}),pluginHost:n})}}),[o,r]=(0,p.useState)(null);(0,p.useEffect)(()=>i.pluginHost.bindProjectPreview(e=>{r(e),requestAnimationFrame(()=>document.querySelector('[data-testid="project-preview-dialog"]')?.focus())}),[i]);let n=(0,p.useRef)(null);return(0,p.useEffect)(()=>{let e={};return n.current={token:e,runtime:i},()=>{n.current?.token===e&&(n.current=null),queueMicrotask(()=>{n.current?.runtime!==i&&(i.appSocket.close(),i.pluginHost.dispose())})}},[i]),(0,s.jsx)(th.o5.Provider,{value:i,children:(0,s.jsxs)(td.Dq.Provider,{value:i.pluginHost,children:[e,o?(0,s.jsx)(tl,{clientId:i.clientId,cwd:o,onClose:()=>r(null)},o):null]})})}let tp={en:{...d.n.en,errors:{invalidJson:"Invalid request JSON",invalidClient:"Invalid client identifier",invalidInput:"Invalid request details",sourceExpired:"The chat source has changed",sessionMissing:"Work session not found",projectChanged:"The work session project has changed",projectMissing:"Project directory not found",fileMissing:"File or directory not found",notDirectory:"The target is not a directory",notFile:"The target is not a file",outsideProject:"The target is outside the current project",textTooLarge:"This text file exceeds 5 MB and cannot be previewed online",imageTooLarge:"This image is too large for online preview",previewUnsupported:"This file type cannot be previewed online",fileReadFailed:"Could not read the project file",revealFailed:"Could not open the file location",repositoryMissing:"Git repository not found",gitOutsideProject:"The Git target is outside the current project",gitReadFailed:"Could not read the Git repository",skillsInputInvalid:"Invalid Skills request details",skillsContentTooLarge:"The submitted text exceeds the file size limit",skillsProjectChanged:"This project is no longer in the workspace. Select a project again",skillMissing:"Skill or file not found",skillsPermissionDenied:"Permission denied when accessing the Skill file",skillsFileFailed:"Could not process the Skills file. Please try again",chatSubscribeInvalid:"Invalid chat subscription details",chatSubscribeExpired:"The chat subscription source has changed",chatSubscribeFailed:"Could not initialize chat subscriptions",chatSendInvalid:"Invalid message details",chatSendTooLarge:"Message exceeds 31 MB",chatInterruptInvalid:"Invalid interrupt request",chatCompactInvalid:"Invalid compaction request",chatReloadInvalid:"Invalid Pi configuration reload request",chatRestoreInvalid:"Invalid queued message restore request",chatRestoreTooLarge:"Restored content exceeds the transport limit",chatModelInvalid:"Invalid model settings request",chatModeInvalid:"Invalid capability mode request",chatSourceBusy:"The work session is changing or switching branches",socketUnknownPath:"Unknown WebSocket operation",sessionsNotReady:"Work sessions are not initialized yet",sessionsInitializing:"Work sessions are initializing",sessionsInitializeInvalid:"Invalid work session initialization request",sessionsInitializeFailed:"Could not initialize work sessions",completionAckInvalid:"Invalid completion acknowledgement",completionAckFailed:"Could not confirm the work session completion state",capabilityFailed:"Could not update capability modes",capabilityRuleInvalid:"Check the capability mode rules",chatContextJsonInvalid:"Invalid JSON for system context request",chatContextInvalid:"Invalid system context request",chatContextBusy:"Session is running. System context is temporarily unavailable",chatContextFailed:"Could not read system context",chatMessageInvalid:"Invalid message detail request",chatMessageMissing:"Chat message not found",chatMessageFailed:"Could not load message details",chatImageInvalid:"Invalid chat image request",chatImageMissing:"Chat image not found",chatImageFailed:"Could not load chat image",modelSettingsInvalid:"Invalid model configuration",modelCatalogInvalid:"Invalid model catalog request",modelCatalogUnavailable:"Model reference catalog is temporarily unavailable",modelSaveFailed:"Could not save model configuration",modelSettingsGetInvalid:"Invalid model settings request",modelSettingsGetFailed:"Could not read model settings",projectDefaultInputInvalid:"Invalid project directory",projectDefaultGetFailed:"Could not read project model default",projectDefaultSaveInvalid:"Invalid project model default",projectDefaultSaveFailed:"Could not save project model default",modelsListFailed:"Could not list models",directoryBrowseInvalid:"Invalid directory browser request",directoryMissing:"Directory not found or is not a folder",directoryReadDenied:"Could not read directory",directoryBrowseFailed:"Could not browse server directories",workSessionCreateInvalid:"Invalid cwd or session ID",workSessionDirectoryMissing:"Project directory does not exist or is not a folder",historySessionMissing:"No Pi session found in this directory",historySessionOccupied:"Pi session is already used by another work session",workSessionCreateFailed:"Could not create work session",workSessionReplaceInvalid:"Invalid work session replacement request",workSessionReplaceOccupied:"Pi session is bound to another work session",workSessionReplaceFailed:"Could not replace the Pi session",workSessionRenameInvalid:"Invalid work session title request",workSessionRenameChanged:"Work session changed. Reopen the title editor",workSessionRenameFailed:"Could not rename the work session",workSessionDeleteInvalid:"Invalid work ID",workSessionDeleteFailed:"Could not delete work session",workSessionSortInvalid:"Invalid work session order or pinned count",workSessionOrderChanged:"Work session list changed. Refresh and try again",workSessionSortFailed:"Could not reorder work sessions",sessionTreeInvalid:"Invalid session tree request",sessionTreeChanged:"Work session changed. Reopen the session tree",sessionTreeFailed:"Could not read session tree",sessionTreeEntryInvalid:"Invalid session tree entry request",sessionTreeEntryMissing:"Session tree entry not found or no longer available",sessionTreeEntryFailed:"Could not read session tree entry",branchInputInvalid:"Invalid branch operation request",branchEntryMissing:"Branch entry not found or no longer available",branchForkUserOnly:"Only user messages can start a new session",branchCloneEmpty:"There are no messages to clone yet",branchFailed:"Could not perform branch operation",taskDetailInvalid:"Invalid task detail request",taskSourceChanged:"Work session source changed",taskMissing:"Task not found",taskDetailUnsupported:"Task does not provide conversation details",taskMessageMissing:"Task message not found",taskMessageNoDetail:"Task message has no details",taskConversationUnavailable:"Task conversation is temporarily unavailable",taskMessageFailed:"Could not read task message details",taskImageMissing:"Task image not found",taskImageFailed:"Could not read task image",refreshInvalid:"Invalid forceRefresh setting",piDirectoriesFailed:"Could not list Pi project directories",ignoredDirectoriesFailed:"Could not list ignored folders",directoryIgnoreInvalid:"Invalid ignored folder request",directoryIgnoreFailed:"Could not update ignored folders",historyQueryInvalid:"Invalid session history search",historyQueryFailed:"Could not list Pi session history",userMessagesInvalid:"Invalid user message request",piSessionMissing:"Pi session not found",userMessagesFailed:"Could not load past user messages",projectJsonInvalid:"Invalid project request JSON",projectInputInvalid:"Invalid project request",projectCwdAbsolute:"Project directory must be an absolute path",projectOperationFailed:"Project operation failed",capabilityGetInvalid:"Invalid capability mode query",capabilityGetFailed:"Could not read capability modes",capabilityReplaceInvalid:"Invalid capability mode configuration",capabilityReplaceFailed:"Could not save capability modes",pluginResourceMissing:"Plugin browser resource not found",pluginResourceReadFailed:"Could not read plugin browser resource",hostResourceMissing:"Host plugin resource not found",hostRuntimeUnavailable:"Host plugin runtime is not built",hostResourceReadFailed:"Could not read Host plugin resource",gitAddJsonInvalid:"Invalid JSON for new Git branch",gitAddInputInvalid:"Invalid new Git branch request",gitAddFailed:"Could not create Git branch",gitSwitchJsonInvalid:"Invalid Git branch switch JSON",gitSwitchInputInvalid:"Invalid Git branch switch request",gitSwitchFailed:"Could not switch Git branch",gitReadOperationFailed:"Could not read Git data",pluginNpmRootUnavailable:"Pi Package npm root is unavailable: {{detail}}",pluginNpmRootMissingDeclarations:"Pi Package configuration does not match the npm root (missing declarations: {{declarations}})",pluginNpmRootMissingFolders:"Pi Package configuration does not match the npm root (missing folders: {{folders}})",pluginNpmRootMissingBoth:"Pi Package configuration does not match the npm root (missing declarations: {{declarations}}; missing folders: {{folders}})",pluginReloadBlocked:"Work session {{workId}} blocked plugin reload: {{reason}}",pluginRuntimeBusy:"Plugin runtime still has active calls",pluginRestartPending:"Another plugin operation must finish restarting first",pluginRestartUnavailable:"This launch mode cannot restart Pi Desk automatically",pluginNotFound:"Plugin not found: {{source}}",pluginSourceInvalid:"Invalid plugin source"},auth:{title:"Sign in to Pi Desk",subtitle:"Continue your work.",protection:"Sign-in protection",enabled:"Enabled",disabled:"Not enabled",publicAccess:"Anyone who can reach this service can open the workspace.",changePassword:"Change password",setPassword:"Set a password",newPassword:"New password",passwordHint:"12–64 characters; use at least three of: uppercase letters, lowercase letters, numbers and symbols. No leading/trailing spaces, line breaks or invisible control characters.",generatePassword:"Generate password",generatePasswordHint:"Generate a random 16-character password",generatePasswordFailed:"Unable to generate a password. Please try again.",saveEffect:"Keep your password safe. Saving requires all devices to sign in again.",enable:"Enable sign-in protection",saveAndSignIn:"Save and sign in again",saving:"Saving…",logout:"Sign out",signingOut:"Signing out…",logoutFailed:"Unable to sign out. Please try again later.",logoutInvalid:"Invalid sign-out request.",logoutCrossOriginDenied:"Cross-site sign-out requests are not allowed.",disable:"Disable protection",disableTitle:"Disable sign-in protection?",disableDescription:"Anyone who can reach this service will be able to open the workspace. Continue?",recovery:"Forgot your password?",recoveryDescription:"Delete this file on the device running the service, then refresh the page to restore access.",settingsFailed:"Unable to load or save sign-in protection settings.",settingsInvalid:"The password does not meet the requirements shown below the field.",configUnavailable:"Unable to read sign-in protection settings. Repair the configuration or delete auth.json and set it up again.",crossOriginDenied:"Cross-site changes to sign-in protection are not allowed.",password:"Password",submit:"Sign in",submitting:"Signing in…",loginFailed:"Unable to sign in",invalidResponse:"Invalid response from the sign-in service",invalidCredentials:"Sign-in failed. Check your sign-in details and try again.",invalidInput:"Sign-in failed. Check your sign-in details and try again.",unavailable:"Sign-in is temporarily unavailable. Please try again later.",tooManyAttempts:"Too many sign-in attempts. Please try again later.",loginAlertTitle:"Unusual sign-in activity",loginAlertDescription:"More than 5 consecutive sign-in failures. Check whether these attempts were yours.",invalidClient:"Invalid client identifier"},capabilityModes:{saved:"Capability modes saved",saving:"Saving…",saveModes:"Save modes",settings:"Capability mode settings",editMode:"Edit mode",selectMode:"Select a capability mode to edit",unnamedMode:"Unnamed mode",allDefault:"All enabled \xb7 Default",addMode:"Add mode",copyMode:"Copy current mode",copyTitle:"Copy mode",deleteMode:"Delete current mode",deleteTitle:"Delete mode",refreshCatalog:"Refresh capability options",retryRead:"Retry loading",loadingCatalog:"Loading capability options…",allEnabled:"All enabled",allDescription:"Use all loaded capabilities.",unsaved:"Unsaved changes",allIsDefault:"All enabled is the default mode",policyAll:"Enable all",policyAllow:"Only these",policyDeny:"Exclude these",policyNone:"Disable all",ruleEditor:"Edit {{name}} rules",ruleMode:"{{name}} availability",exclusions:"Exclusions",ruleSearch:"Search or enter capability rules",ruleSearchPlaceholder:"Search names or enter * patterns",clearSearch:"Clear rule search",selectedOnly:"Selected only",selectedShort:"Selected",allowRules:"Allow rules",excludeRules:"Exclude rules",selectedCount_one:"{{count}} selected",selectedCount_other:"{{count}} selected",selectVisible:"Select visible",clearSelected:"Clear selected",addRule:"Add rule",allowValue:"Allow {{name}}",excludeValue:"Exclude {{name}}",pattern:"Pattern",noMatches:"No matches; you can add the rule above.",noSelection:"No rules selected yet.",enterPattern:"Enter a name or wildcard rule to add it.",moreRules:"Show more \xb7 {{count}} remaining",deleteConfirm:"Delete capability mode?",saveConfirm:"Save mode changes?",deleteDescription:"Delete “{{name}}” and save? Sessions using it will switch to All enabled.",unsavedDescription:"Changes to capability modes have not been saved.",cancel:"Cancel",delete:"Delete mode",discard:"Discard changes",saveContinue:"Save and continue",modeName:"Mode name",category:"Capability categories",groupTools:"Tools",modeSwitching:"Switching…",modePicker:"Capability mode: {{name}}",catalogFailed:"Could not load capability options",saveFailed:"Could not save capability modes",copySuffix:"{{name}} copy",newMode:"New mode"},pluginManagement:{actionAdd:"Install plugin",actionUpdate:"Update plugin",actionDelete:"Uninstall plugin",actionReload:"Restart Pi Desk",restartNormal:"Restart with plugins",restartNormalDescription:"Restart Pi Desk and load external plugins again. All connections will be restored after restart.",applyChanges:"Load changes",applyDescription:"Update plugin services and views now. Existing Pi sessions keep their extensions until manually reloaded.",reloadOne:"Reload",reloadSource:"Reload {{name}}",basicModeNotice:"Basic mode skips plugin loading and inspection. Repair files using chat, then choose Restart with plugins.",localExtension:"Local source",localSourceHelp:"Manage this entry in its source directory",discovered:"Enabled",disabledByPi:"Disabled",active:"Enabled",notLoaded:"Not loaded",phase_queued:"Queued",phase_checking:"Checking",phase_applying:"Applying",phase_waiting:"Waiting to activate",phase_failed:"Failed",updateCheckFailed:"Could not check plugin updates",actionFailed:"{{action}} failed",retrying:"Retrying {{name}}",retryFailed:"Could not retry plugin UI",refreshingEntries:"Refreshing plugin UI",refreshEntriesFailed:"Could not refresh plugin UI",detailFailed:"Could not load plugin details",title:"Plugins",description:"Manage plugin packages and local extensions.",noPluginDescription:"No description available",checkUpdates:"Check updates",checkingUpdates:"Checking…",restartApply:"Restart to finish",installPlugin:"Install plugin",source:"Plugin source",sourcePlaceholder:"npm package, Git URL or local directory",install:"Install",installVersion:"Install this version",installIncompatible:"This plugin version is incompatible with the current Pi Desk version and cannot be installed.",pendingRestart:"Plugin changes will take effect after restart",retry:"Retry",confirmAction:"{{action}}?",restartDescription:"Restart Pi Desk to apply pending changes. Connections will be restored after restart.",cancel:"Cancel",installed:"Installed plugins",loading:"Loading plugins…",updateAvailable:"Update available",abnormal:"Error",capabilityCategories:"Plugin capability categories",update:"Update",details:"Details",viewDetails:"View plugin details: {{name}}",remove:"Uninstall",empty:"No plugins found",viewLoading:"Loading plugin UI…",viewFailed:"Could not load plugin UI",closeApplication:"Close plugin application",closeNamedApplication:"Close {{name}}",eventAgentStart:"Before agent starts",eventAgentStartDescription:"Can append to or replace the system prompt and inject session messages.",eventContext:"Before model call",eventContextDescription:"Can replace the messages sent to the model for this call.",eventInput:"User input",eventInputDescription:"Can rewrite, intercept or handle user input.",eventProvider:"Before provider request",eventProviderDescription:"Can replace the final provider payload.",eventToolCall:"Before tool call",eventToolCallDescription:"Can modify tool arguments or block execution.",eventToolResult:"After tool result",eventToolResultDescription:"Can modify tool results entering later model context.",eventMessageEnd:"After message completes",eventMessageEndDescription:"Can replace the final message and affect later context.",eventBeforeCompact:"Before context compaction",eventBeforeCompactDescription:"Can cancel compaction or replace the summary.",contributionApplication:"Application",contributionComposer:"Composer panel",contributionSettings:"Settings page",contributionMessage:"Message view",contributionSidebar:"Session sidebar",tagTools:"{{count}} tools",tagFixed:"{{count}} fixed prompts",tagDynamic:"{{count}} dynamic hooks",tagOverride:"{{count}} builtin overrides",tagManual:"{{count}} manual prompts",tagInteraction:"{{count}} interactions",unknown:"Unknown",stateActive:"Active",stateInactive:"Inactive",stateShadowed:"Overridden",copied:"Copied",copy:"Copy",copyNamed:"Copy {{name}}",dynamicTitle:"Dynamic context hooks",dynamicDescription:"These hooks can affect prompts and messages, but registration does not mean each call changed them.",arguments:"Arguments",none:"None",required:"Required",optional:"Optional",noArguments:"This tool takes no arguments.",rawSchema:"Raw schema",toolCapabilities:"Tool capabilities",toolDescription:"Each tool shows its purpose, parameters and declared system prompts.",overridesBuiltin:"Overrides a Pi builtin tool",noDescription:"No description provided",systemPrompts:"System prompts",inactivePrompt:"This tool is inactive; its prompts do not enter the system prompt.",truncated:"Content exceeds 64 KB; showing the first 64 KB.",resourcesTitle:"Skills and prompts",resourcesDescription:"Callable Skills contribute metadata to the system prompt; full content is loaded on demand. Prompt templates expand when invoked by the user.",skillModelVisible:"Description in system prompt",manualOnly:"Manual invocation only",skillMetadata:"Skill metadata in system prompt",viewSkillContent:"View Skill content",viewPromptContent:"View prompt content",otherCapabilities:"Other capabilities",messageDeclarations:"Message declarations:",backToList:"Back to plugins",incompleteCapabilities:"Capability list incomplete: {{error}}",metricToolDefinitions:"Tool definitions",metricFixed:"Fixed prompts",metricDynamic:"Dynamic hooks",metricManual:"Manual prompt resources",loadingFullDetails:"Loading full capability details",installedTab:"Installed",searchPlugins:"Find plugins",directInstall:"Manual install",advancedOptions:"Advanced options",capabilityDetails:"Features and runtime details",newVersion:"New v{{version}}",removeNamed:"Uninstall {{name}}",updateAll:"Update all ({{count}})",batchManage:"Select plugins",finishSelection:"Done",selectAll:"Select all",filterStatus:"Plugin status",statusFilter_all:"All statuses",statusFilter_updates:"Updates available",statusFilter_disabled:"Disabled",statusFilter_failed:"Errors",batchWaiting:"Not submitted. Finish pending operations, then try again.",batchInstall:"Install plugins",batchSourcePlaceholder:"One npm package per line; a single source can also be a Git URL or local directory",batchNpmOnly:"Enter one npm package per line for batch installation.",batchLimit:"Choose up to 32 plugins per batch.",batchFailed:"Could not submit plugin changes",sourceBusy:"This plugin has an operation in progress. Try again when it finishes.",selectFiltered:"Select all results",selectPlugin:"Select {{name}}",selectedCount:"{{count}} selected",clearSelection:"Clear selection",checkSelected:"Check selected",updateSelected:"Update selected",removeSelected:"Uninstall selected",setChannel:"Set channel",installChannel:"Version preference",defaultChannel:"Default",automaticVersion:"Default version",allChannels:"All channels",filterChannel:"Filter by channel",channelLatest:"Stable",channelDev:"Development",followingChannel:"Channel: {{tag}}",targetVersion:"Target: {{version}}",itemCheckFailed:"Update check failed: {{error}}",filterInstalled:"Search installed plugins",noMatches:"No matching plugins",enabled:"Enabled",disabled:"Disabled",enable:"Enable",disable:"Disable",togglePlugin:"Enable or disable {{name}}",submitting:"Submitting…",installing:"Installing…",alreadyInstalled:"Installed",retryView:"Retry plugin view",more:"More",downloadSource:"Download source",installDownloadSource:"Download source for this install",useDefaultSource:"Use saved default",download_local:"No override (local configuration)",download_auto:"Automatic",download_domestic:"China mirror",download_official:"Official npm",download_custom:"Custom",registryUrl:"Registry URL",sourceDetails:"View source URL",recommending:"Choosing a source…",saving:"Saving…",save:"Save",settingsFailed:"Could not save or read download settings",invalidRegistry:"Enter a valid HTTP or HTTPS registry URL without credentials, query or fragment.",searchPlaceholder:"Search plugin name or description",searchSource:"Search registry",publicNpm:"Public npm",customSearchSource:"Custom registry",searchRegistryUrl:"Search registry URL",pluginKind:"Plugin type",kind_all:"All types",kind_desk:"Pi Desk",kind_pi:"Pi",kind_unknown:"Unverified type",official:"Official",publisher:"Publisher",unknownPublisher:"Publisher not provided",searchFailed:"Could not search plugins",searching:"Searching…",noSearchResults:"No matching plugins. Try another search.",loadMore:"Load more",loadingPackage:"Loading package details…",readPackage:"Read package details",version:"Version",packageName:"Package",readme:"README",noReadme:"No README provided",readmeLanguage:"Language",defaultLanguage:"Automatic / original",compatible:"Compatible",incompatible:"Not compatible with this version",compatibilityUnknown:"Compatibility not verified",homepage:"Website",repository:"Source code",removeDescription:"Remove this plugin. Saved configuration and data will be kept.",thirdPartyDescription:"This plugin can execute code on your computer. Only install it if you trust its publisher and source.",confirmChange:"Apply this change to the selected plugin.",fromSource:"Version from source",pluginDetails:"Plugin details",pluginRemoved:"This plugin is no longer installed.",close:"Close"},projectHistory:{currentHead:"Current HEAD",localBranch:"Local branch",remoteBranch:"Remote branch \xb7 local record",retry:"Retry",compareDirect:"Compare directly",loadingCommits:"Loading commits…",commitList:"Git commits",noCommitMessage:"(no commit message)",noMatchingCommits:"No matching commits",noCommits:"No commits",scanLimit:"History scan limit reached. Choose a more specific branch or commit.",loadedLimit:"2,000 commits loaded. Narrow your search.",loadMoreCommits:"Load more commits",backCommits:"Back to commits",commitChanges:"Commit changes",cumulativeChanges:"Cumulative changes",loadedFiles:"{{count}} files loaded",backCumulative:"Back to cumulative changes",loadingChanges:"Loading changes…",noDiff:"No file differences",loadMoreFiles:"Load more files",changesLimit:"Change file display limit reached.",commitDetails:"Commit details",copySha:"Copy commit SHA",compareParent:"Compare parent commit",parentCommit:"Parent {{count}} \xb7 {{oid}}",mergeBaseToTarget:"Common ancestor → target commit",baseToTarget:"Base commit → target commit",emptyRevision:"Empty revision",selectCommit:"Select a commit to view its details",historyAndCompare:"Git history and comparison",viewMode:"Git view mode",historyMode:"Commit history",compareMode:"Compare branches",selectRepository:"Select repository",viewBranch:"View branch",baseBranch:"Base branch",chooseBase:"Choose base branch",targetBranch:"Target branch",comparison:"Comparison method",introducedChanges:"Changes introduced by this branch",directComparison:"Compare two versions directly",filterAuthor:"Filter by author",author:"Commit author",searchCommits:"Search commit message or SHA",refreshGit:"Refresh Git history",localRecord:"Local record",refUnavailable:"Reference unavailable",aheadBehind:"{{ahead}} ahead \xb7 {{behind}} behind",chooseBaseBranch:"Choose a base branch",restoreGit:"Restore Git panel",maximizeGit:"Maximize Git panel",collapseGit:"Collapse Git panel",copyFailed:"Could not copy",findingGit:"Detecting Git repositories…",noGit:"No Git repository found",collapseDirectory:"Collapse folder tree",expandDirectory:"Expand folder tree",previewDescription:"Read-only preview of project files and Git history",gitRecords:"Git history",refreshPreview:"Refresh project preview",restoreWindow:"Restore preview window",maximizeWindow:"Maximize preview window",closePreview:"Close project preview",previewArea:"Project preview area",files:"Files",code:"Code",changeFiles:"Files changed in commit",viewDiff:"View diff",gitStatus:"Git status {{status}}",viewDiffPath:"View diff: {{path}}",historyDiffAncestor:"Common ancestor {{left}} ↔ {{target}}",historyDiffDirect:"{{left}} ↔ {{target}}",historyReadFailed:"Could not read Git history"},settings:{title:"Settings",general:"General settings",workCapabilities:"Tools & models",application:"Application",category:"Settings section",appearance:"Appearance",region:"Language & time zone",habits:"Preferences",loginProtection:"Sign in",models:"Models",mcpSettings:"MCP",capabilityModes:"Capability modes",skills:"Skills",plugins:"Plugins",pluginSettings:"Plugin settings",about:"About",language:"Language",timeZone:"Time zone",currentLanguage:"Current language: {{locale}}",currentTimeZone:"Current time zone: {{timeZone}}",timeExample:"Local time",searchTimeZones:"Search time zones",reloadLanguage:"Reload to use this language",version:"Current version",versionUpdated:"Version updated",webDescription:"Pi in your browser",discardModelTitle:"Unsaved model settings",discardModelDescription:"Discard changes to model settings?",discardModelConfirm:"Discard changes",theme:"Theme",themeLight:"Light",themeDark:"Dark",displaySize:"Display size",sizeCompact:"Compact",sizeStandard:"Standard",sizeLarge:"Large",displayPreview:"Display preview",displayPreviewContent:'## Project progress\n\nToday we organized the work plan. Next, we will finish the remaining tasks.\n\n```ts\nconst status = "ready"\n```',browserOnly:"These settings only apply to this browser.",newSessionBehavior:"After creating a session",behaviorNone:"Keep current session",behaviorNoneDescription:"Stay in the current session after creating another.",behaviorActivate:"Switch to new session",behaviorActivateDescription:"Open the new session immediately.",behaviorPin:"Pin automatically",behaviorPinDescription:"Pin the new session and keep the current one active.",desktopOnlyBehavior:"Applies on desktop only; mobile always opens the new session.",imagePreviewMode:"Image preview",imageCompressed:"Optimized preview",imageCompressedDescription:"Reduce data use for large images without modifying project files.",imageOriginal:"Original image",imageOriginalDescription:"Keep original quality; large images use more data.",imagePreviewApply:"Changes apply to newly loaded or manually reloaded images.",modelProviders:"Model management",modelPresets:"Common combinations",serviceAddress:"Service address",serviceKey:"Access key",serviceId:"Service ID",serviceIdInvalid:"Enter a unique, non-empty service ID.",serviceConnection:"Service connection",serviceSettingsNamed:"{{name}} connection settings",currentServiceSettings:"Current service connection settings",modelAddToService:"Add a model to {{name}}",inheritService:"Inherit service settings",inheritServiceValue:"Inherit service: {{value}}",applyServiceDraft:"Apply to draft",serviceDraftScope:"Used by {{count}} models. Apply here, then save the model configuration.",discardServiceTitle:"Unsaved connection changes",discardServiceDescription:"Discard this connection draft?",selectModelToEdit:"Select a model to edit",backModelList:"Back to model list",modelIdRequired:"Enter a model ID.",modelNameRequired:"Enter a display name.",capacityInvalid:"Enter a positive number with up to three decimal places.",priceInvalid:"Enter a non-negative number.",inputAndThinking:"Input and reasoning",addModelPreset:"Add to common combinations",saveBeforePreset:"Save this model before adding it to common combinations.",modelDraftPending:"Configuration changes are not saved",modelDraftClean:"No unsaved changes",fixModelInputs:"Correct the invalid model fields before saving",revertModels:"Discard configuration changes",modelMoreActions:"Model configuration actions",nativeConfig:"Pi configuration",nativeConfigEditor:"Pi model configuration",nativeConfigScope:"Edit the complete models.json configuration, including modelOverrides, inputLimits, promptCache, samplingParams and tiered pricing.",nativeProtectDraft:"Save or discard your form changes before opening Pi configuration.",saveNativeConfig:"Save Pi configuration",discardNativeTitle:"Unsaved Pi configuration",discardNativeDescription:"Discard changes to the Pi configuration?",projectDefault:"Project defaults",loadingModels:"Loading model settings…",modelsUnavailable:"Model settings unavailable",modelsLoadFailed:"Could not load model settings",catalogCached:"Refresh failed. Using the previous model catalog.",catalogPartial:"Model catalog partly updated. Failed sources are using cached data.",catalogUnchanged:"Model catalog is already up to date.",catalogUpdated:"Model catalog updated.",catalogRefreshFailed:"Could not refresh the model catalog",modelsNoChanges:"There are no model configuration changes to save.",removeInvalidPresetsTitle:"Remove invalid common combinations?",removeInvalidPresets_one:"{{count}} common combination refers to a removed model. Saving will remove this combination.",removeInvalidPresets_other:"{{count}} common combinations refer to removed models. Saving will remove them.",removeAndSave:"Remove and save",modelSaved:"Model configuration saved.",modelSaveFailed:"Could not save the model configuration",catalogUpdatedAt:"Reference catalog updated at {{time}}",catalogUnavailable:"Reference catalog unavailable",refreshingCatalog:"Refreshing…",refreshCatalog:"Refresh model catalog",savingModels:"Saving…",saveModels:"Save model configuration",thinkingOff:"Off",thinkingMinimal:"Minimal",thinkingLow:"Low",thinkingMedium:"Medium",thinkingHigh:"High",thinkingXhigh:"Very high",thinkingMax:"Maximum",priceMissing:"Price unavailable",priceInput:"Input {{price}}",priceOutput:"Output {{price}}",priceCacheRead:"Cached {{price}}",priceCacheWrite:"Cache write {{price}}",perMillionTokens:" / million tokens",catalogSearchFailed:"Could not search the model catalog",catalogSelected:"Selected {{provider}} / {{model}}.",modelId:"Model ID",modelIdSearch:"Search and select by model ID",chooseModel:"Choose or change model",matchingCatalog:"Finding models…",noCatalogMatches:"No matching models",officialRecommended:"Official recommendation",sameConfiguration:"{{count}} identical sources",contextAndOutput:"{{context}} context \xb7 {{output}} output",contextAndOutputTitle:"Context {{context}} tokens, maximum output {{output}} tokens",moreConfigurations:"Show {{count}} more configurations",modelName:"Display name",contextLength:"Context window",maximumOutput:"Maximum output per request",capabilities:"Capabilities",textInput:"Text input",imageInput:"Image input",supportsThinking:"Supports reasoning",thinkingMapping:"Thinking levels and provider mapping",providerMapping:"{{level}} provider mapping",noMapping:"No mapping",price:"Pricing",inputPrice:"Input price / million tokens",outputPrice:"Output price / million tokens",cacheReadPrice:"Cache read price",cacheWritePrice:"Cache write price",clearPrice:"Clear pricing",advancedCompatibility:"Advanced settings",apiOverride:"Model API override",baseUrlOverride:"Model Base URL override",inheritProvider:"Leave blank to inherit the provider",developerRole:"Supports Developer Role",replayReasoning:"Replay reasoning_content",modelHeaders:"Model headers",headerPlaceholder:"Header-Name: value, one per line",useDefault:"Use default",yes:"Yes",no:"No",providerNew:"Add service connection",accountCustomApi:"Custom API",accountLogin:"Sign in",accountRelogin:"Sign in again",accountLogout:"Sign out",accountLogoutTitle:"Sign out of this service?",accountLogoutDescription:"Sign out of “{{name}}”? Its account models will be unavailable until you sign in again. Your model selections and drafts will be kept; this will not switch the current session.",accountLogoutFailed:"Could not sign out",accountCustomSettings:"Custom API settings",accountCustomModel:"Custom model",accountChooseProvider:"Choose a service",accountLoadingProviders:"Loading services…",accountNoProviders:"No sign-in services available",accountChooseOption:"Choose an option",accountContinue:"Continue",accountWaiting:"Waiting for authorization…",accountLoggedIn:"Signed in",accountLoggedOut:"Not signed in",accountLoginFailed:"Could not sign in",accountRefreshFailed:"Signed in, but could not refresh the model list",accountDisconnected:"Connection lost. This sign-in was cancelled. Reconnect, then start again.",accountConnectionNotReady:"Connection is not ready. Try again after it reconnects.",accountDeviceCode:"Authorization code",accountCopyCode:"Copy code",accountOpenLink:"Open authorization page",accountCopyLink:"Copy link",accountInvalidLink:"This authorization link is not a valid web address.",accountCopied:"Copied",accountCopyFailed:"Could not copy",accountModelSearch:"Search model name or ID",accountModelAdded:"Added",accountNoModels:"No matching models",accountAddLater:"Add later",accountAddSelected:"Add {{count}} selected",accountModelUnavailable:"This model is no longer available in the service catalog. You can remove it from your configuration.",accountModelUnavailableShort:"Unavailable",accountSubscription:"Subscription",accountReferencePrice:"Reference pricing",accountAdjustParameters:"Adjust parameters",accountRestoreDefaults:"Restore defaults",accountRemove:"Remove model",accountRemoveTitle:"Remove model?",accountRemoveDescription:"Remove “{{name}}” from your model list? This takes effect after saving and does not sign you out.",providerUnnamed:"Service ID required",providerList:"Model services",providerSummary:"{{providers}} providers \xb7 {{models}} models",providerConfig:"Provider configuration",providerEmpty:"No services configured",providerModels:"{{count}} custom models",providerDelete:"Remove service",providerDeleteTitle:"Remove service?",providerDeleteDescription:"Remove “{{name}}” and its {{count}} models? The change takes effect after you save.",modelDeleteTitle:"Remove model?",modelDeleteDescription:"Remove “{{name}}”? The change takes effect after you save.",providerIdExample:"e.g. my-provider",providerApiType:"Default API",providerAdvanced:"Advanced connection settings",providerAuthHeader:"Add Authorization header automatically",providerHeaders:"Service headers",modelsHeading:"Models",modelAdd:"Add model",modelEmpty:"No models yet",modelUnnamed:"Unnamed model",modelIdPending:"Model ID required",modelDelete:"Remove model",modelDeleteNamed:"Remove model {{name}}",presetDescription:"Choose a model and reasoning level quickly in chat. Drag or use the buttons to reorder.",presetDrag:"Drag to reorder",presetMoveUp:"Move combination up",presetMoveDown:"Move combination down",presetModel:"Combination model",presetModelNew:"Model for new combination",modelSearch:"Search model name, service ID or model ID",thinkingLevel:"Thinking level",presetThinking:"Combination thinking level",presetThinkingNew:"Thinking level for new combination",presetColor:"Color",presetColorLabel:"Combination color",presetColorNone:"No color",presetColorCustom:"Custom color",presetColorBlue:"Blue",presetColorCyan:"Cyan",presetColorGreen:"Green",presetColorAmber:"Amber",presetColorOrange:"Orange",presetColorRed:"Red",presetColorPink:"Pink",presetColorPurple:"Purple",presetDelete:"Remove combination",presetAdd:"Add",presetEmpty:"No common combinations yet",projectSessionCount_one:"{{count}} session",projectSessionCount_other:"{{count}} sessions",projectDirectoriesFailed:"Could not load project directories",projectDefaultFailed:"Could not load project model defaults",projectDefaultSaved:"Project model default saved.",projectDefaultGlobalSaved:"Project is following the current global Pi model.",projectDefaultSaveFailed:"Could not save the project model default",projectLoading:"Loading project settings…",projectDescription:"Project settings take precedence over Pi’s current global selection. Changing a model in chat will not change this setting.",projectEmpty:"No project directories with Pi sessions found",project:"Project",projectSearch:"Search project paths",projectList:"Project list",backProjectList:"Back to project list",selectProjectToConfigure:"Select a project to configure its default model",projectDefaultSource:"Project model default source",projectFollowGlobal:"Follow current global Pi selection",projectFollowGlobalDescription:"Do not set a separate default model for this project.",projectFixed:"Set a project default",projectFixedDescription:"Select a model and reasoning level for this project.",projectDefaultModel:"Default model",projectDefaultThinking:"Project default thinking level",fromPreset:"Choose from common combinations",saveProjectDefault:"Save project default"},skills:r.P.en,taskCenter:n.U.en,workbench:a.R.en,workbenchPicker:{sessionFallback:"Session {{id}}",newSession:"New session",scopeTitle:"Title",scopeUser:"User messages",scopeAssistant:"AI replies",scopeUserMatches:"User messages {{count}}",scopeAssistantMatches:"AI replies {{count}}",loadUserFailed:"Could not load user messages",ignoredRestoreTitle:"Restore ignored folder",browseOtherTitle:"Choose a project folder",replaceTitle:"Replace work session",createTitle:"Create work session",ignoredRestoreDescription:"This project will appear again in regular folder lists.",browseDescription:"Browse the filesystem of the server running Pi Desk to choose a project directory.",replaceDescription:"Replace: {{project}} \xb7 {{session}}",replaceMissingDescription:"Replacement target is no longer available. Close this dialog and select a work session again.",createDescription:"Choose an existing Pi project or browse server folders to create a work session.",searchHistory:"Search past sessions",searchBrowser:"Search folders in this location",searchIgnored:"Search ignored folders",searchProjects:"Search project names or full paths",currentProject:"Current project: {{path}}",ignoredCount_one:"{{count}} ignored folder",ignoredCount_other:"{{count}} ignored folders",rootChoose:"Choose a drive or root directory",root:"Drives or root directories",replaceChooseFirst:"Choose a project to see its available past sessions.",regularExcludesIgnored:"Ignored projects are excluded from regular folder lists.",loadingHistory:"Loading past sessions…",loadingIgnored:"Loading ignored folders…",loadingBrowser:"Browsing server folders…",loadingProjects:"Loading Pi projects…",backFolders:"Back to folder list",pastePath:"Paste a full folder path and press Enter",fullPath:"Full folder path",openTyped:"Open entered folder",enterAbsolute:"Enter an absolute folder path",open:"Open",absoluteExample:"Enter an absolute folder path, e.g. C:\\projects\\example.",pasteHint:"Paste and open a full path; Windows “Copy as path” is supported.",searchScopes:"Search in",replaceTargetMissing:"Replacement target is no longer available.",noHistoryMatches:"No matching past sessions",noReplaceHistory:"This project has no available past sessions",sessionFound_one:"{{count}} session found",sessionFound_other:"{{count}} sessions found",sessionMessages:"{{users}}/{{total}} messages \xb7 {{time}}",replacing:"Replacing",current:"Current",alreadyUsed:"In use",targetUnavailable:"Target unavailable",replace:"Replace",currentBound:"This past session is bound to the current work session",historyUsed:"This past session is in use by another work session",replaceTargetUnavailable:"Replacement target is unavailable",replaceWith:"Replace with {{name}}",hideUserMessages:"Hide user messages",viewMatching_one:"View {{count}} match",viewMatching_other:"View all {{count}} matches",viewUserMessages_one:"View {{count}} user message",viewUserMessages_other:"View {{count}} user messages",viewMatch:"View {{label}}",matchingUserCount:"{{count}} matching user messages",userCount:"{{count}} user messages",viewAll:"View all",noUserMessages:"No user messages to display",noText:"(no text)",loadMore:"Load more",browserEmpty:"No subfolders here. You can select this folder.",rootsEmpty:"No drives or root directories to browse",subfoldersNoMatches:"No matching subfolders",ignoredEmpty:"No ignored Pi projects",projectsEmpty:"No Pi projects available",projectNoMatches:"No matching Pi projects",restoreFolder:"Restore folder {{name}}",restoreTip:"Restore to regular folder lists",restore:"Restore",directorySessions_one:"{{count}} session \xb7 {{time}}",directorySessions_other:"{{count}} sessions \xb7 {{time}}",directoryCount_one:"{{count}} session",directoryCount_other:"{{count}} sessions",creating:"Creating",ignoreFolder:"Ignore folder {{name}}",ignoreTip:"Hide from regular folder lists",ignoredFolders:"Ignored folders",chooseOther:"Choose another folder",selectCurrent:"Select this folder",parentDirectory:"Back to parent folder",backRoots:"Back to drives or roots",refreshList:"Refresh this list",filterDefault:"Default",filterNoTools:"Hide tools",filterUserOnly:"User messages",filterLabeled:"Labeled",filterAll:"All",kindUser:"User",kindTool:"Tool",kindMessage:"Message",kindCompaction:"Summary",kindBranchSummary:"Branch summary",kindCustom:"Record",kindModel:"Model",kindThinking:"Thinking",kindSession:"Session",kindLabel:"Label",treeIntent:"Switch the current session branch",forkIntent:"Start a session from a user message",cloneIntent:"Clone the current session",runningTitle:"The current session is running",runningStop:"To continue “{{action}}”, the current response will stop. Saved messages remain available.",runningWait:"To continue “{{action}}”, wait for the running background task to finish.",confirming:"Working…",confirmContinue:"Confirm and continue",back:"Back",confirmHint:"Enter to confirm \xb7 Esc to go back",branchPicker:"Session branch picker",branchTitle:"Session branches",closeBranchPicker:"Close session branch picker",branchSearch:"Search session branches",branchSearchPlaceholder:"Search messages, tools or labels",branchFilter:"Filter session tree, current: {{filter}}",loadingEntry:"Loading full content…",entryEmpty:"No text available for this entry",entryTruncated:"Long content has been truncated.",selectEntry:"Select an entry to view its full content",branchWorking:"Stopping or waiting for the running task…",branchLoading:"Loading session tree…",branchEmpty:"No entries to select yet",branchNoMatches:"No matching session entries",branchTree:"Session tree",collapseBranch:"Collapse branch",expandBranch:"Expand branch",noPreview:"Nothing to preview",switchToMessage:"Switch to {{kind}} message",switch:"Switch",forkFromUser:"Start a session from this user message",branchShortcuts:"↑↓ Select \xb7 Tab Filter \xb7 ←→ Branch \xb7 Enter Switch \xb7 Esc Close"},conversation:l.W.en,projectFiles:c.C.en},"zh-CN":{...d.n["zh-CN"],errors:{invalidJson:"请求 JSON 格式无效",invalidClient:"客户端标识无效",invalidInput:"请求参数无效",sourceExpired:"聊天 Source 已过期",sessionMissing:"工作会话不存在",projectChanged:"工作会话项目已变化",projectMissing:"项目目录不存在",fileMissing:"文件或目录不存在",notDirectory:"目标不是目录",notFile:"目标不是文件",outsideProject:"目标不在当前项目目录内",textTooLarge:"文本文件超过 5MB,暂不支持在线预览",imageTooLarge:"图片过大,暂不支持在线预览",previewUnsupported:"当前文件类型不支持在线预览",fileReadFailed:"读取项目文件失败",revealFailed:"打开所在文件夹失败",repositoryMissing:"Git 仓库不存在",gitOutsideProject:"Git 目标不在当前项目目录内",gitReadFailed:"读取 Git 仓库失败",skillsInputInvalid:"Skills 请求参数无效",skillsContentTooLarge:"提交文本超过大小限制",skillsProjectChanged:"此项目已不在当前工作区,请重新选择项目",skillMissing:"Skill 或文件已不存在",skillsPermissionDenied:"没有权限读写此 Skill 文件",skillsFileFailed:"Skills 文件操作失败,请重试",chatSubscribeInvalid:"聊天订阅参数无效",chatSubscribeExpired:"聊天订阅绑定已过期",chatSubscribeFailed:"聊天订阅初始化失败",chatSendInvalid:"聊天发送参数无效",chatSendTooLarge:"聊天发送内容超过 31MB",chatInterruptInvalid:"聊天打断参数无效",chatCompactInvalid:"上下文压缩参数无效",chatReloadInvalid:"Pi 配置重载参数无效",chatRestoreInvalid:"恢复队列参数无效",chatRestoreTooLarge:"恢复内容超过传输上限",chatModelInvalid:"模型设置参数无效",chatModeInvalid:"能力模式参数无效",chatSourceBusy:"工作会话正在替换或切换分支",socketUnknownPath:"未知 WebSocket 路径",sessionsNotReady:"工作会话尚未初始化",sessionsInitializing:"工作会话正在初始化",sessionsInitializeInvalid:"工作会话初始化参数无效",sessionsInitializeFailed:"工作会话初始化失败",completionAckInvalid:"工作会话完成确认参数无效",completionAckFailed:"确认工作会话完成状态失败",capabilityFailed:"能力模式请求失败",capabilityRuleInvalid:"请检查模式规则",chatContextJsonInvalid:"系统上下文请求 JSON 格式无效",chatContextInvalid:"系统上下文请求参数无效",chatContextBusy:"当前会话正在运行,暂时无法查看系统上下文",chatContextFailed:"读取系统上下文失败",chatMessageInvalid:"消息详情参数无效",chatMessageMissing:"聊天消息不存在",chatMessageFailed:"查询聊天消息详情失败",chatImageInvalid:"聊天图片参数无效",chatImageMissing:"聊天图片不存在",chatImageFailed:"查询聊天图片失败",modelSettingsInvalid:"模型配置格式无效",modelCatalogInvalid:"模型目录参数无效",modelCatalogUnavailable:"模型参考目录暂不可用",modelSaveFailed:"保存模型配置失败",modelSettingsGetInvalid:"模型配置参数无效",modelSettingsGetFailed:"读取模型配置失败",projectDefaultInputInvalid:"项目目录参数无效",projectDefaultGetFailed:"读取项目默认模型失败",projectDefaultSaveInvalid:"项目默认模型格式无效",projectDefaultSaveFailed:"保存项目默认模型失败",modelsListFailed:"查询模型目录失败",directoryBrowseInvalid:"目录浏览参数无效",directoryMissing:"目录不存在或不是目录",directoryReadDenied:"无法读取目录",directoryBrowseFailed:"浏览服务端目录失败",workSessionCreateInvalid:"cwd 或 sessionId 无效",workSessionDirectoryMissing:"项目目录不存在或不是目录",historySessionMissing:"指定目录中不存在 Pi 会话",historySessionOccupied:"Pi 会话已经关联到其他工作会话",workSessionCreateFailed:"创建工作会话失败",workSessionReplaceInvalid:"替换会话参数无效",workSessionReplaceOccupied:"Pi 会话已绑定到其他工作会话",workSessionReplaceFailed:"替换 Pi 会话失败",workSessionRenameInvalid:"会话标题参数无效",workSessionRenameChanged:"工作会话已切换,请重新打开标题编辑",workSessionRenameFailed:"修改会话标题失败",workSessionDeleteInvalid:"workId 格式无效",workSessionDeleteFailed:"删除工作会话失败",workSessionSortInvalid:"workIds 或 pinnedCount 格式无效",workSessionOrderChanged:"工作会话列表已变化,请刷新后重试",workSessionSortFailed:"更新工作会话排列失败",sessionTreeInvalid:"会话树查询参数无效",sessionTreeChanged:"工作会话已切换,请重新打开会话树",sessionTreeFailed:"读取会话树失败",sessionTreeEntryInvalid:"会话树节点参数无效",sessionTreeEntryMissing:"会话树节点不存在或已失效",sessionTreeEntryFailed:"读取会话树节点详情失败",branchInputInvalid:"分支操作参数无效",branchEntryMissing:"分支节点不存在或已失效",branchForkUserOnly:"只有用户消息可以 Fork",branchCloneEmpty:"当前会话还没有可克隆的消息",branchFailed:"执行分支操作失败",taskDetailInvalid:"任务详情参数无效",taskSourceChanged:"工作会话来源已变化",taskMissing:"任务不存在",taskDetailUnsupported:"任务不支持会话详情",taskMessageMissing:"任务消息不存在",taskMessageNoDetail:"任务消息没有详情",taskConversationUnavailable:"任务会话暂不可用",taskMessageFailed:"查询任务消息详情失败",taskImageMissing:"任务图片不存在",taskImageFailed:"查询任务图片失败",refreshInvalid:"forceRefresh 格式无效",piDirectoriesFailed:"查询 Pi 目录失败",ignoredDirectoriesFailed:"查询忽略目录失败",directoryIgnoreInvalid:"忽略目录参数无效",directoryIgnoreFailed:"更新忽略目录失败",historyQueryInvalid:"历史会话查询参数无效",historyQueryFailed:"查询 Pi 历史会话失败",userMessagesInvalid:"用户消息参数无效",piSessionMissing:"Pi 会话不存在",userMessagesFailed:"查询历史用户消息失败",projectJsonInvalid:"项目请求 JSON 格式无效",projectInputInvalid:"项目请求参数无效",projectCwdAbsolute:"项目目录必须是绝对路径",projectOperationFailed:"项目操作失败",capabilityGetInvalid:"能力模式查询参数无效",capabilityGetFailed:"读取能力模式失败",capabilityReplaceInvalid:"能力模式格式无效",capabilityReplaceFailed:"保存能力模式失败",pluginResourceMissing:"插件资源不存在",pluginResourceReadFailed:"读取插件资源失败",hostResourceMissing:"Host 公共插件资源不存在",hostRuntimeUnavailable:"Host 公共插件 Runtime 尚未构建",hostResourceReadFailed:"读取 Host 公共插件资源失败",gitAddJsonInvalid:"新建 Git 分支请求 JSON 格式无效",gitAddInputInvalid:"新建 Git 分支请求参数无效",gitAddFailed:"新建 Git 分支失败",gitSwitchJsonInvalid:"Git 分支切换请求 JSON 格式无效",gitSwitchInputInvalid:"Git 分支切换请求参数无效",gitSwitchFailed:"切换 Git 分支失败",gitReadOperationFailed:"读取 Git 失败",pluginNpmRootUnavailable:"Pi Package npm 根不可用:{{detail}}",pluginNpmRootMissingDeclarations:"Pi Package 配置与 npm 根不一致(缺少声明:{{declarations}})",pluginNpmRootMissingFolders:"Pi Package 配置与 npm 根不一致(缺少目录:{{folders}})",pluginNpmRootMissingBoth:"Pi Package 配置与 npm 根不一致(缺少声明:{{declarations}};缺少目录:{{folders}})",pluginReloadBlocked:"工作会话 {{workId}} 阻止插件重载:{{reason}}",pluginRuntimeBusy:"插件运行时仍有调用正在执行",pluginRestartPending:"已有插件操作需要重启完成",pluginRestartUnavailable:"当前启动方式不支持自动重启 Pi Desk",pluginNotFound:"插件不存在:{{source}}",pluginSourceInvalid:"插件来源无效"},auth:{title:"登录 Pi Desk",subtitle:"继续你的工作会话",protection:"登录保护",enabled:"已启用",disabled:"未启用",publicAccess:"任何能够访问此服务的人都可以进入工作台。",changePassword:"修改密码",setPassword:"设置密码",newPassword:"新密码",passwordHint:"12–64 个字符,至少包含大写字母、小写字母、数字、符号中的三类;不能有首尾空白、换行或不可见控制字符。",generatePassword:"生成密码",generatePasswordHint:"随机生成 16 位密码",generatePasswordFailed:"生成密码失败,请重试。",saveEffect:"请妥善保存密码。保存后,所有设备都需要重新登录。",enable:"启用登录保护",saveAndSignIn:"保存并重新登录",saving:"正在保存…",logout:"退出登录",signingOut:"正在退出…",logoutFailed:"退出登录失败,请稍后重试。",logoutInvalid:"退出登录参数无效。",logoutCrossOriginDenied:"不允许跨站退出登录。",disable:"关闭保护",disableTitle:"关闭登录保护?",disableDescription:"关闭后,任何能够访问此服务的人都可以直接进入工作台。是否继续?",recovery:"忘记密码?",recoveryDescription:"在运行服务的设备上删除下面的文件,然后刷新页面,即可恢复访问。",settingsFailed:"登录保护设置处理失败。",settingsInvalid:"密码不符合要求,请按输入框下方的规则调整。",configUnavailable:"登录保护配置无法读取,请修复配置或删除 auth.json 后重新设置。",crossOriginDenied:"不允许跨站修改登录保护。",password:"密码",submit:"登录",submitting:"正在登录",loginFailed:"登录失败",invalidResponse:"登录服务响应无效",invalidCredentials:"登录失败,请检查登录信息后重试。",invalidInput:"登录失败,请检查登录信息后重试。",unavailable:"登录暂不可用,请稍后重试。",tooManyAttempts:"登录尝试过多,请稍后重试。",loginAlertTitle:"登录异常提醒",loginAlertDescription:"登录已连续失败超过 5 次,请确认是否为本人操作。",invalidClient:"客户端标识无效"},capabilityModes:{saved:"能力模式已保存",saving:"保存中…",saveModes:"保存模式",settings:"能力模式设置",editMode:"编辑模式",selectMode:"选择要编辑的能力模式",unnamedMode:"未命名模式",allDefault:"全开 \xb7 默认",addMode:"新增模式",copyMode:"复制当前模式",copyTitle:"复制模式",deleteMode:"删除当前模式",deleteTitle:"删除模式",refreshCatalog:"刷新能力选项",retryRead:"重试读取",loadingCatalog:"正在读取能力选项…",allEnabled:"全开",allDescription:"使用全部已加载能力。",unsaved:"有未保存的修改",allIsDefault:"全开为默认模式",policyAll:"全部开启",policyAllow:"只开这些",policyDeny:"关闭这些",policyNone:"全部关闭",ruleEditor:"{{name}}规则编辑",ruleMode:"{{name}}开放方式",exclusions:"排除项",ruleSearch:"搜索或输入能力规则",ruleSearchPlaceholder:"搜索名称或输入 * 规则",clearSearch:"清空规则搜索",selectedOnly:"仅看已选",selectedShort:"已选",allowRules:"允许规则",excludeRules:"排除规则",selectedCount_one:"已选 {{count}} 条",selectedCount_other:"已选 {{count}} 条",selectVisible:"全选可见项",clearSelected:"清空已选",addRule:"添加规则",allowValue:"允许 {{name}}",excludeValue:"排除 {{name}}",pattern:"匹配规则",noMatches:"没有匹配项,可直接添加上面的规则。",noSelection:"尚未选择规则。",enterPattern:"输入名称或通配规则即可添加。",moreRules:"显示更多 \xb7 剩余 {{count}} 项",deleteConfirm:"删除能力模式?",saveConfirm:"保存模式修改?",deleteDescription:"删除“{{name}}”并保存后,使用此模式的会话将切回全开。",unsavedDescription:"能力模式的修改尚未保存。",cancel:"取消",delete:"删除模式",discard:"放弃修改",saveContinue:"保存并继续",modeName:"模式名称",category:"能力分类",groupTools:"工具",modeSwitching:"切换中…",modePicker:"能力模式:{{name}}",catalogFailed:"读取能力选项失败",saveFailed:"保存能力模式失败",copySuffix:"{{name}} 副本",newMode:"新模式"},pluginManagement:{actionAdd:"安装插件",actionUpdate:"更新插件",actionDelete:"卸载插件",actionReload:"重启 Pi Desk",restartNormal:"重启并启用插件",restartNormalDescription:"重启 Pi Desk 并重新加载外部插件,完成后恢复所有连接。",applyChanges:"加载变更",applyDescription:"更新插件服务和界面;已有会话扩展保持不变,手动重载 PI 后更新。",reloadOne:"重新加载",reloadSource:"重新加载 {{name}}",basicModeNotice:"基础模式已关闭插件加载与盘点。可以继续聊天修复文件,再选择“重启并启用插件”。",localExtension:"本地源码",localSourceHelp:"在源目录管理此入口",discovered:"已启用",disabledByPi:"已停用",active:"已启用",notLoaded:"未加载",phase_queued:"排队中",phase_checking:"检查中",phase_applying:"应用中",phase_waiting:"等待生效",phase_failed:"操作失败",updateCheckFailed:"检查插件更新失败",actionFailed:"{{action}}失败",retrying:"重试 {{name}}",retryFailed:"重试插件界面失败",refreshingEntries:"刷新插件界面",refreshEntriesFailed:"刷新插件界面失败",detailFailed:"读取插件详情失败",title:"插件",description:"管理插件包与本地扩展。",noPluginDescription:"暂无说明",checkUpdates:"检查更新",checkingUpdates:"检查中…",restartApply:"重启并完成",installPlugin:"安装插件",source:"插件来源",sourcePlaceholder:"npm Package、Git 地址或本地目录",install:"安装",installVersion:"安装此版本",installIncompatible:"此插件版本不兼容当前 Pi Desk,无法安装。",pendingRestart:"插件变化待重启生效",retry:"重试",confirmAction:"确认{{action}}?",restartDescription:"重启 Pi Desk 以应用待处理变更,完成后自动恢复连接。",cancel:"取消",installed:"已安装插件",loading:"正在读取插件",updateAvailable:"可更新",abnormal:"异常",capabilityCategories:"插件能力类别",update:"更新",details:"详情",viewDetails:"查看插件详情:{{name}}",remove:"卸载",empty:"暂无插件",viewLoading:"正在加载插件界面…",viewFailed:"插件界面加载失败",closeApplication:"关闭插件应用",closeNamedApplication:"关闭 {{name}}",eventAgentStart:"任务开始前",eventAgentStartDescription:"具备追加或替换系统提示词、注入会话消息的能力。",eventContext:"模型调用前",eventContextDescription:"具备替换本次发送给模型的会话消息的能力。",eventInput:"用户输入阶段",eventInputDescription:"具备改写、拦截或接管用户输入的能力。",eventProvider:"Provider 请求前",eventProviderDescription:"具备替换最终 Provider Payload 的能力。",eventToolCall:"工具调用前",eventToolCallDescription:"具备修改工具参数或阻止工具调用的能力。",eventToolResult:"工具结果后",eventToolResultDescription:"具备修改进入后续模型上下文的工具结果的能力。",eventMessageEnd:"消息完成后",eventMessageEndDescription:"具备替换最终消息并影响后续上下文的能力。",eventBeforeCompact:"上下文压缩前",eventBeforeCompactDescription:"具备取消压缩或替换压缩摘要的能力。",contributionApplication:"应用入口",contributionComposer:"输入面板",contributionSettings:"设置页",contributionMessage:"消息视图",contributionSidebar:"会话侧栏",tagTools:"工具 {{count}}",tagFixed:"固定提示 {{count}}",tagDynamic:"动态影响 {{count}}",tagOverride:"替换内置 {{count}}",tagManual:"手动提示 {{count}}",tagInteraction:"交互 {{count}}",unknown:"未知",stateActive:"启用",stateInactive:"未启用",stateShadowed:"被覆盖",copied:"已复制",copy:"复制",copyNamed:"复制{{name}}",dynamicTitle:"动态上下文能力",dynamicDescription:"以下内容表示插件注册了对应运行时钩子,不代表每次调用都实际修改了提示词或消息。",arguments:"调用参数",none:"无",required:"必填",optional:"可选",noArguments:"该 Tool 不需要参数。",rawSchema:"原始 Schema",toolCapabilities:"工具能力",toolDescription:"每个 Tool 同时展示能力说明、调用参数及其声明的系统提示词。",overridesBuiltin:"替换 Pi 内置工具",noDescription:"未提供能力说明",systemPrompts:"系统提示词",inactivePrompt:"当前 Tool 未启用,不会进入系统提示词",truncated:"正文超过 64KB,当前显示前 64KB。",resourcesTitle:"Skill 与提示模板",resourcesDescription:"可由模型调用的 Skill 只会常驻名称、描述和位置,完整正文按需读取;Prompt 模板仅在用户手动调用后展开。",skillModelVisible:"描述进入系统提示词",manualOnly:"仅手动调用",skillMetadata:"系统提示词中的 Skill 元数据",viewSkillContent:"查看 Skill 正文",viewPromptContent:"查看 Prompt 正文",otherCapabilities:"其他能力",messageDeclarations:"消息声明:",backToList:"返回插件列表",incompleteCapabilities:"能力清单读取不完整:{{error}}",metricToolDefinitions:"工具定义",metricFixed:"当前固定提示",metricDynamic:"动态影响钩子",metricManual:"手动提示资源",loadingFullDetails:"正在读取完整能力详情",installedTab:"已安装",searchPlugins:"搜索插件",directInstall:"手动安装",advancedOptions:"高级选项",capabilityDetails:"功能与运行信息",newVersion:"新版本 v{{version}}",removeNamed:"卸载 {{name}}",updateAll:"全部更新({{count}})",batchManage:"批量管理",finishSelection:"完成",selectAll:"全选",filterStatus:"插件状态",statusFilter_all:"全部状态",statusFilter_updates:"有更新",statusFilter_disabled:"已停用",statusFilter_failed:"异常",batchWaiting:"尚未提交,请完成等待中的操作后重试。",batchInstall:"批量安装",batchSourcePlaceholder:"每行一个 npm 包名;单项也可填写 Git 地址或本地目录",batchNpmOnly:"批量安装时请每行填写一个 npm 包名。",batchLimit:"每次批量操作最多选择 32 个插件。",batchFailed:"提交插件变更失败",sourceBusy:"此插件正在处理其他操作,完成后可重试。",selectFiltered:"全选当前结果",selectPlugin:"选择 {{name}}",selectedCount:"已选 {{count}} 项",clearSelection:"清空选择",checkSelected:"批量检查",updateSelected:"更新所选",removeSelected:"卸载所选",setChannel:"设置渠道",installChannel:"版本偏好",defaultChannel:"默认",automaticVersion:"默认版本",allChannels:"全部渠道",filterChannel:"按渠道筛选",channelLatest:"稳定版",channelDev:"开发版",followingChannel:"跟随 {{tag}}",targetVersion:"目标版本 {{version}}",itemCheckFailed:"查询更新失败:{{error}}",filterInstalled:"搜索已安装插件",noMatches:"没有匹配的插件",enabled:"已启用",disabled:"已停用",enable:"启用",disable:"停用",togglePlugin:"启用或停用 {{name}}",submitting:"正在提交…",installing:"安装中…",alreadyInstalled:"已安装",retryView:"重试插件界面",more:"更多",downloadSource:"下载源",installDownloadSource:"本次安装下载源",useDefaultSource:"使用已保存的默认设置",download_local:"不使用源(本机配置)",download_auto:"自动",download_domestic:"国内加速",download_official:"官方",download_custom:"自定义",registryUrl:"仓库地址",sourceDetails:"查看来源地址",recommending:"正在推荐来源…",saving:"正在保存…",save:"保存",settingsFailed:"保存或读取下载设置失败",invalidRegistry:"请输入有效的 HTTP 或 HTTPS 仓库地址,不包含账号、查询参数或片段。",searchPlaceholder:"搜索插件名称或简介",searchSource:"搜索仓库",publicNpm:"npm 公开仓库",customSearchSource:"自定义仓库",searchRegistryUrl:"搜索仓库地址",pluginKind:"插件类型",kind_all:"全部类型",kind_desk:"Pi Desk",kind_pi:"Pi",kind_unknown:"类型待确认",official:"官方",publisher:"发布者",unknownPublisher:"未提供发布者",searchFailed:"搜索插件失败",searching:"正在搜索…",noSearchResults:"没有匹配的插件,可以换个关键词。",loadMore:"加载更多",loadingPackage:"正在读取包详情…",readPackage:"读取包详情",version:"版本",packageName:"插件包",readme:"使用说明",noReadme:"未提供使用说明",readmeLanguage:"语言",defaultLanguage:"自动 / 原文",compatible:"兼容当前版本",incompatible:"不兼容当前版本",compatibilityUnknown:"兼容性待确认",homepage:"官网",repository:"源码",removeDescription:"卸载此插件,保留已保存的配置和数据。",thirdPartyDescription:"此插件能够在你的电脑上执行代码。请确认信任其发布者和来源后再安装。",confirmChange:"应用此插件变更。",fromSource:"以来源提供的版本为准",pluginDetails:"插件详情",pluginRemoved:"此插件已不在安装列表中。",close:"关闭"},projectHistory:o,settings:{title:"设置",general:"通用设置",workCapabilities:"工作能力",application:"应用",category:"设置分类",appearance:"外观",region:"语言与地区",habits:"习惯",loginProtection:"登录",models:"模型",mcpSettings:"MCP",capabilityModes:"能力模式",skills:"Skills",plugins:"插件",pluginSettings:"插件设置",about:"关于",language:"语言",timeZone:"时区",currentLanguage:"当前语言:{{locale}}",currentTimeZone:"当前时区:{{timeZone}}",timeExample:"当前时间",searchTimeZones:"搜索时区",reloadLanguage:"重新加载以使用该语言",version:"当前版本",versionUpdated:"版本更新时间",webDescription:"Pi 的 Web 端",discardModelTitle:"模型配置尚未保存",discardModelDescription:"要丢弃尚未保存的模型配置吗?",discardModelConfirm:"丢弃修改",theme:"界面主题",themeLight:"浅色",themeDark:"深色",displaySize:"显示大小",sizeCompact:"紧凑",sizeStandard:"标准",sizeLarge:"大号",displayPreview:"界面预览",displayPreviewContent:'## 项目进展\n\n今天整理了工作计划,接下来继续完成待办事项。\n\n```ts\nconst status = "ready"\n```',browserOnly:"设置仅在当前浏览器生效。",newSessionBehavior:"新建会话后的行为",behaviorNone:"无操作",behaviorNoneDescription:"创建后保留当前会话。",behaviorActivate:"切换到新会话",behaviorActivateDescription:"创建后立即进入新会话。",behaviorPin:"自动固定",behaviorPinDescription:"固定新会话,保留当前活跃会话。",desktopOnlyBehavior:"仅桌面端生效;移动端始终进入新会话。",imagePreviewMode:"图片预览方式",imageCompressed:"压缩预览",imageCompressedDescription:"优化大图以减少流量,不修改项目原文件。",imageOriginal:"原图预览",imageOriginalDescription:"保留原始画质,加载大图会消耗更多流量。",imagePreviewApply:"更改后对新加载或主动重新加载的图片生效。",modelProviders:"模型管理",modelPresets:"常用组合",serviceAddress:"服务地址",serviceKey:"访问密钥",serviceId:"服务 ID",serviceIdInvalid:"请填写非空且不重复的服务 ID。",serviceConnection:"服务连接",serviceSettingsNamed:"{{name}}连接设置",currentServiceSettings:"当前服务连接设置",modelAddToService:"在{{name}}添加模型",inheritService:"继承服务设置",inheritServiceValue:"继承服务:{{value}}",applyServiceDraft:"应用到草稿",serviceDraftScope:"供 {{count}} 个模型使用,应用后在主页面保存模型配置。",discardServiceTitle:"连接修改尚未应用",discardServiceDescription:"要丢弃这次连接修改吗?",selectModelToEdit:"选择一个模型进行编辑",backModelList:"返回模型列表",modelIdRequired:"请填写模型 ID。",modelNameRequired:"请填写显示名称。",capacityInvalid:"请输入大于 0 的数值,最多保留三位小数。",priceInvalid:"请输入不小于 0 的数值。",inputAndThinking:"输入与思考",addModelPreset:"加入常用组合",saveBeforePreset:"保存模型后可加入常用组合。",modelDraftPending:"配置有未保存修改",modelDraftClean:"没有未保存的修改",fixModelInputs:"请先修正模型字段,再保存配置",revertModels:"撤销配置修改",modelMoreActions:"模型配置操作",nativeConfig:"Pi 配置",nativeConfigEditor:"Pi 模型配置",nativeConfigScope:"编辑完整 models.json,包括 modelOverrides、inputLimits、promptCache、samplingParams 与阶梯费率。",nativeProtectDraft:"请先保存或撤销表单修改,再打开 Pi 配置。",saveNativeConfig:"保存 Pi 配置",discardNativeTitle:"Pi 配置尚未保存",discardNativeDescription:"要丢弃这次 Pi 配置修改吗?",projectDefault:"项目默认",loadingModels:"加载模型设置…",modelsUnavailable:"模型设置暂不可用",modelsLoadFailed:"模型设置加载失败",catalogCached:"刷新失败,继续使用上次模型目录缓存。",catalogPartial:"模型目录已部分更新,失败来源继续使用缓存。",catalogUnchanged:"模型目录已经是最新。",catalogUpdated:"模型目录已更新。",catalogRefreshFailed:"模型目录刷新失败",modelsNoChanges:"没有需要保存的模型配置。",removeInvalidPresetsTitle:"删除失效的常用组合?",removeInvalidPresets_one:"有 {{count}} 个常用组合引用了已删除模型,保存配置将同时删除这些组合。",removeInvalidPresets_other:"有 {{count}} 个常用组合引用了已删除模型,保存配置将同时删除这些组合。",removeAndSave:"删除并保存",modelSaved:"模型配置已保存。",modelSaveFailed:"模型配置保存失败",catalogUpdatedAt:"参考目录更新于 {{time}}",catalogUnavailable:"参考目录尚未可用",refreshingCatalog:"刷新中…",refreshCatalog:"刷新模型目录",savingModels:"保存中…",saveModels:"保存模型配置",thinkingOff:"关闭",thinkingMinimal:"极少",thinkingLow:"低",thinkingMedium:"中",thinkingHigh:"高",thinkingXhigh:"超高",thinkingMax:"最大",priceMissing:"价格未提供",priceInput:"输入 {{price}}",priceOutput:"输出 {{price}}",priceCacheRead:"缓存 {{price}}",priceCacheWrite:"缓存写 {{price}}",perMillionTokens:" / 百万 Token",catalogSearchFailed:"查询模型目录失败",catalogSelected:"已选择 {{provider}} 的 {{model}}。",modelId:"模型 ID",modelIdSearch:"输入模型 ID 搜索并选择",chooseModel:"选择或切换模型",matchingCatalog:"正在匹配模型目录…",noCatalogMatches:"没有匹配的目录模型",officialRecommended:"官方推荐",sameConfiguration:"同配置 \xd7{{count}}",contextAndOutput:"{{context}} 上下文 \xb7 {{output}} 输出",contextAndOutputTitle:"上下文 {{context}} Token,最大输出 {{output}} Token",moreConfigurations:"查看其余 {{count}} 种配置",modelName:"显示名称",contextLength:"上下文容量",maximumOutput:"每次最多输出",capabilities:"能力",textInput:"文本输入",imageInput:"图片输入",supportsThinking:"支持思考",thinkingMapping:"思考等级与服务映射",providerMapping:"{{level}} 服务映射",noMapping:"无需映射",price:"价格",inputPrice:"输入价格 / 百万 Token",outputPrice:"输出价格 / 百万 Token",cacheReadPrice:"缓存读取价格",cacheWritePrice:"缓存写入价格",clearPrice:"清除价格配置",advancedCompatibility:"高级配置",apiOverride:"单独调用方式",baseUrlOverride:"单独服务地址",inheritProvider:"留空继承 Provider",developerRole:"支持 Developer Role",replayReasoning:"回放 reasoning_content",modelHeaders:"模型请求头",headerPlaceholder:"Header-Name: value,每行一个",useDefault:"使用默认",yes:"是",no:"否",providerNew:"添加服务连接",accountCustomApi:"自定义 API",accountLogin:"登录",accountRelogin:"重新登录",accountLogout:"退出登录",accountLogoutTitle:"退出这个服务的登录?",accountLogoutDescription:"退出“{{name}}”后,该账号模型在重新登录前将不可用。保留已收录模型与配置草稿,不切换当前会话。",accountLogoutFailed:"退出登录失败",accountCustomSettings:"自定义 API 设置",accountCustomModel:"自定义模型",accountChooseProvider:"选择服务商",accountLoadingProviders:"加载服务商…",accountNoProviders:"暂无可登录的服务商",accountChooseOption:"请选择",accountContinue:"继续",accountWaiting:"等待授权…",accountLoggedIn:"已登录",accountLoggedOut:"未登录",accountLoginFailed:"登录失败",accountRefreshFailed:"登录成功,但模型列表刷新失败",accountDisconnected:"连接已断开,本次登录已取消。连接恢复后请重新登录。",accountConnectionNotReady:"连接尚未就绪,请在连接恢复后重试。",accountDeviceCode:"授权码",accountCopyCode:"复制授权码",accountOpenLink:"打开授权页面",accountCopyLink:"复制链接",accountInvalidLink:"授权链接不是有效的网页地址。",accountCopied:"已复制",accountCopyFailed:"复制失败",accountModelSearch:"搜索模型名称或 ID",accountModelAdded:"已添加",accountNoModels:"没有匹配的模型",accountAddLater:"稍后添加",accountAddSelected:"添加选中的 {{count}} 个",accountModelUnavailable:"服务目录中已没有这个模型,可以从配置中移除。",accountModelUnavailableShort:"不可用",accountSubscription:"订阅",accountReferencePrice:"参考价格",accountAdjustParameters:"调整参数",accountRestoreDefaults:"恢复默认",accountRemove:"移除模型",accountRemoveTitle:"移除模型?",accountRemoveDescription:"将“{{name}}”从模型列表移除,保存配置后生效,不会退出账号登录。",providerUnnamed:"等待填写服务 ID",providerList:"模型服务",providerSummary:"{{providers}} 个 \xb7 {{models}} 个模型",providerConfig:"Provider 配置",providerEmpty:"还没有配置服务",providerModels:"{{count}} 个自定义模型",providerDelete:"删除服务",providerDeleteTitle:"删除服务?",providerDeleteDescription:"将移除“{{name}}”及其 {{count}} 个模型,保存配置后生效。",modelDeleteTitle:"删除模型?",modelDeleteDescription:"将移除“{{name}}”,保存配置后生效。",providerIdExample:"例如 my",providerApiType:"默认调用方式",providerAdvanced:"高级连接设置",providerAuthHeader:"自动添加 Authorization Header",providerHeaders:"服务请求头",modelsHeading:"模型",modelAdd:"添加模型",modelEmpty:"还没有模型",modelUnnamed:"未命名模型",modelIdPending:"等待填写模型 ID",modelDelete:"删除模型",modelDeleteNamed:"删除模型 {{name}}",presetDescription:"聊天中快速选择的模型与思考等级组合,拖拽或按钮可调整顺序。",presetDrag:"拖拽排序",presetMoveUp:"上移常用组合",presetMoveDown:"下移常用组合",presetModel:"常用模型",presetModelNew:"新增常用模型",modelSearch:"搜索模型名称、服务 ID 或模型 ID",thinkingLevel:"思考等级",presetThinking:"常用思考等级",presetThinkingNew:"新增组合的思考等级",presetColor:"颜色",presetColorLabel:"常用组合颜色",presetColorNone:"无颜色",presetColorCustom:"自定义颜色",presetColorBlue:"蓝色",presetColorCyan:"青色",presetColorGreen:"绿色",presetColorAmber:"琥珀色",presetColorOrange:"橙色",presetColorRed:"红色",presetColorPink:"粉色",presetColorPurple:"紫色",presetDelete:"删除常用组合",presetAdd:"添加",presetEmpty:"还没有常用组合",projectSessionCount_one:"{{count}} 个会话",projectSessionCount_other:"{{count}} 个会话",projectDirectoriesFailed:"项目目录加载失败",projectDefaultFailed:"项目默认模型加载失败",projectDefaultSaved:"项目固定默认模型已保存。",projectDefaultGlobalSaved:"项目已恢复跟随 Pi 全局当前值。",projectDefaultSaveFailed:"项目默认模型保存失败",projectLoading:"加载项目配置…",projectDescription:"项目配置优先于 Pi 全局当前值,普通模型切换不会修改这里。",projectEmpty:"没有找到已有 Pi 会话的项目目录",project:"项目",projectSearch:"搜索项目路径",projectList:"项目列表",backProjectList:"返回项目列表",selectProjectToConfigure:"选择项目配置默认模型",projectDefaultSource:"项目默认模型来源",projectFollowGlobal:"跟随 Pi 全局当前值",projectFollowGlobalDescription:"不单独设置这个项目的默认模型。",projectFixed:"固定项目默认",projectFixedDescription:"为这个项目指定模型和思考等级。",projectDefaultModel:"默认模型",projectDefaultThinking:"项目默认思考等级",fromPreset:"从常用组合选择",saveProjectDefault:"保存项目默认"},skills:r.P["zh-CN"],taskCenter:n.U["zh-CN"],workbench:a.R["zh-CN"],workbenchPicker:{sessionFallback:"会话 {{id}}",newSession:"新会话",scopeTitle:"标题",scopeUser:"用户消息",scopeAssistant:"AI 回复",scopeUserMatches:"用户消息 {{count}}",scopeAssistantMatches:"AI 回复 {{count}}",loadUserFailed:"加载用户消息失败",ignoredRestoreTitle:"恢复忽略目录",browseOtherTitle:"选择项目目录",replaceTitle:"替换工作会话",createTitle:"新建工作会话",ignoredRestoreDescription:"恢复后,该项目会重新出现在所有普通目录列表中。",browseDescription:"浏览运行 Pi Desk 的服务端文件系统,选择项目工作目录。",replaceDescription:"将替换到:{{project}} \xb7 {{session}}",replaceMissingDescription:"替换目标已失效,请关闭后重新选择工作会话。",createDescription:"选择已有 Pi 项目,或浏览服务端目录创建新的工作会话。",searchHistory:"搜索历史会话",searchBrowser:"搜索当前层级的目录",searchIgnored:"搜索已忽略目录",searchProjects:"搜索项目名称或完整路径",currentProject:"当前项目:{{path}}",ignoredCount_one:"{{count}} 个已忽略目录",ignoredCount_other:"{{count}} 个已忽略目录",rootChoose:"选择磁盘或根目录",root:"磁盘或根目录",replaceChooseFirst:"选择项目后查看可替换的历史会话。",regularExcludesIgnored:"普通目录列表已自动排除忽略项目。",loadingHistory:"正在加载历史会话…",loadingIgnored:"正在加载忽略目录…",loadingBrowser:"正在浏览服务端目录…",loadingProjects:"正在加载 Pi 项目…",backFolders:"返回目录列表",pastePath:"粘贴完整目录路径后按 Enter",fullPath:"完整目录路径",openTyped:"打开输入的目录",enterAbsolute:"请输入绝对目录路径",open:"打开",absoluteExample:"请输入绝对目录路径,例如 C:\\projects\\example。",pasteHint:"可直接粘贴完整路径并打开;兼容 Windows“复制为路径”。",searchScopes:"搜索范围",replaceTargetMissing:"替换目标已失效,无法继续替换。",noHistoryMatches:"没有匹配的历史会话",noReplaceHistory:"当前项目没有可替换的历史会话",sessionFound_one:"找到 {{count}} 个会话",sessionFound_other:"找到 {{count}} 个会话",sessionMessages:"{{users}}/{{total}} 条消息 \xb7 {{time}}",replacing:"替换中",current:"当前",alreadyUsed:"已使用",targetUnavailable:"目标失效",replace:"替换",currentBound:"当前工作会话已绑定此历史会话",historyUsed:"该历史会话已被其他工作会话占用",replaceTargetUnavailable:"替换目标已失效",replaceWith:"替换为 {{name}}",hideUserMessages:"收起用户消息",viewMatching_one:"查看全部 {{count}} 条匹配",viewMatching_other:"查看全部 {{count}} 条匹配",viewUserMessages_one:"查看 {{count}} 条用户消息",viewUserMessages_other:"查看 {{count}} 条用户消息",viewMatch:"查看{{label}}",matchingUserCount:"匹配的用户消息 {{count}} 条",userCount:"用户消息 {{count}} 条",viewAll:"查看全部",noUserMessages:"没有可展示的用户消息",noText:"(无文字内容)",loadMore:"加载更多",browserEmpty:"当前目录没有可浏览的子目录,可直接选择当前目录",rootsEmpty:"没有可浏览的磁盘或根目录",subfoldersNoMatches:"没有匹配的子目录",ignoredEmpty:"没有已忽略的 Pi 项目",projectsEmpty:"没有可选择的 Pi 项目",projectNoMatches:"没有匹配的 Pi 项目",restoreFolder:"恢复目录 {{name}}",restoreTip:"恢复到普通目录列表",restore:"恢复",directorySessions_one:"{{count}} 个会话 \xb7 {{time}}",directorySessions_other:"{{count}} 个会话 \xb7 {{time}}",directoryCount_one:"{{count}} 个会话",directoryCount_other:"{{count}} 个会话",creating:"创建中",ignoreFolder:"忽略目录 {{name}}",ignoreTip:"从所有普通目录列表中隐藏",ignoredFolders:"已忽略目录",chooseOther:"选择其他目录",selectCurrent:"选择当前目录",parentDirectory:"返回上一级目录",backRoots:"返回磁盘或根目录",refreshList:"刷新当前列表",filterDefault:"默认",filterNoTools:"无工具",filterUserOnly:"仅用户",filterLabeled:"有标签",filterAll:"全部",kindUser:"用户",kindTool:"工具",kindMessage:"消息",kindCompaction:"压缩",kindBranchSummary:"摘要",kindCustom:"记录",kindModel:"模型",kindThinking:"思考",kindSession:"会话",kindLabel:"标签",treeIntent:"切换当前会话分支",forkIntent:"从用户消息新开会话",cloneIntent:"克隆当前会话",runningTitle:"当前工作会话正在运行",runningStop:"继续“{{action}}”会先停止当前响应。已保存的消息会保留。",runningWait:"继续“{{action}}”会等待当前后台任务结束。",confirming:"正在处理…",confirmContinue:"确认并继续",back:"返回",confirmHint:"Enter 确认 \xb7 Esc 返回",branchPicker:"会话分支选择器",branchTitle:"会话分支",closeBranchPicker:"关闭会话分支选择器",branchSearch:"搜索会话分支",branchSearchPlaceholder:"搜索消息、工具或标签",branchFilter:"过滤会话树,当前:{{filter}}",loadingEntry:"正在读取完整内容…",entryEmpty:"该节点没有可展示的文字内容",entryTruncated:"内容较长,已截断显示。",selectEntry:"从树中选择一条记录查看完整内容",branchWorking:"正在停止或等待当前运行并执行操作…",branchLoading:"正在读取会话树…",branchEmpty:"当前会话还没有可选择的节点",branchNoMatches:"没有匹配的会话节点",branchTree:"会话树",collapseBranch:"收起分支",expandBranch:"展开分支",noPreview:"无可预览文字",switchToMessage:"切换到{{kind}}消息",switch:"切换",forkFromUser:"从这条用户消息新开会话",branchShortcuts:"↑↓ 选择 \xb7 Tab 筛选 \xb7 ←→ 分支 \xb7 Enter 切换 \xb7 Esc 关闭"},conversation:l.W["zh-CN"],projectFiles:c.C["zh-CN"]}};function tg({children:e,initialSettings:t}){return(0,s.jsx)(h.rg,{children:(0,s.jsx)(u.Zi,{children:(0,s.jsx)(m,{children:(0,s.jsx)(f.A,{resources:tp,initialSettings:t,children:(0,s.jsxs)(y.c,{children:[(0,s.jsx)(b,{}),(0,s.jsx)(tu,{children:(0,s.jsx)(w.Bc,{children:e})})]})})})})})}},84178:()=>{}},e=>{e.O(0,[81966,43579,78923,96995,46270,39654,3814,74220,75130,31087,4904,64444,77358],()=>e(e.s=48923)),_N_E=e.O()}]);
|
|
3
|
+
${i.author} \xb7 ${h.format(i.timestampMs)}`,children:[(0,s.jsxs)("span",{className:"min-w-0 flex-1 truncate",children:[i.subject||a("noCommitMessage"),i.refs.length?(0,s.jsx)("span",{className:"ml-2 text-xs text-muted-foreground",children:i.refs.join(" \xb7 ")}):null]}),(0,s.jsx)("span",{className:"shrink-0 font-mono text-xs text-muted-foreground",children:i.oid.slice(0,7)}),r?null:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"w-20 truncate text-xs text-muted-foreground",children:i.author}),(0,s.jsx)("time",{className:"w-28 shrink-0 text-right text-xs text-muted-foreground",children:d.format(i.timestampMs)})]})]},i.oid)},`${t.repositoryRoot}:${t.mode}:${t.tip}:${t.base}:${t.target}:${t.query}:${t.author}`),"ready"!==t.log.status||t.log.data?.items.length?null:(0,s.jsx)("p",{className:"px-3 py-4 text-sm text-muted-foreground",children:t.query||t.author?a("noMatchingCommits"):a("noCommits")}),t.log.data?.truncated?(0,s.jsx)("p",{className:"px-3 py-2 text-xs text-muted-foreground",children:a("scanLimit")}):null,(t.log.data?.items.length??0)>=2e3?(0,s.jsx)("p",{className:"px-3 py-2 text-xs text-muted-foreground",children:a("loadedLimit")}):t.log.data?.hasMore?(0,s.jsx)(ej.$,{variant:"ghost",size:"sm",disabled:"loading"===t.log.status,onClick:e.onMoreLog,children:a("loadMoreCommits")}):null]}),D=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsxs)("div",{className:"flex min-h-9 shrink-0 flex-wrap items-center gap-2 border-b px-3 py-1",children:[r?(0,s.jsx)(ej.$,{variant:"ghost",size:"icon-sm","aria-label":a("backCommits"),onClick:()=>m("log"),children:(0,s.jsx)(e_.A,{className:"size-4"})}):null,(0,s.jsx)("span",{className:"text-sm font-medium",children:t.selectedCommit?a("commitChanges"):a("cumulativeChanges")}),y?(0,s.jsx)("span",{className:"text-xs text-muted-foreground",children:a("loadedFiles",{count:y.items.length})}):null,"compare"===t.mode&&t.selectedCommit?(0,s.jsx)(ej.$,{variant:"ghost",size:"sm",onClick:e.onAggregate,children:a("backCumulative")}):null]}),P(t.changes.error),"loading"===t.changes.status?(0,s.jsxs)("div",{className:"flex items-center gap-2 p-3 text-xs text-muted-foreground",children:[(0,s.jsx)(eH.A,{className:"size-4 animate-spin"}),a("loadingChanges")]}):null,(0,s.jsxs)(eD.HK,{orientation:"vertical",defaultLayout:{"project-changes":e.panelSizes.changes,"project-detail":100-e.panelSizes.changes},onLayoutChanged:(t,i)=>{i.isUserInteraction&&void 0!==t["project-changes"]&&e.onPanelSize("changes",t["project-changes"])},children:[(0,s.jsx)(eD.wV,{id:"project-changes",defaultSize:`${e.panelSizes.changes}%`,minSize:"80px",children:(0,s.jsxs)("div",{className:"flex size-full min-h-0 flex-col",children:[(0,s.jsx)(e2,{cwd:e.cwd,repositoryRoot:t.repositoryRoot??"",rows:e.changeRows,changes:y?.items??[],selectedPath:w,scrollTop:n.changes,onScroll:t=>e.onScroll("changes",t),onSelect:e.onSelectChange,onToggle:e.onToggleDirectory,onOpen:e.onOpenFile,onReveal:e.onReveal},b),"ready"!==t.changes.status||y?.items.length?null:(0,s.jsx)("p",{className:"px-3 py-4 text-sm text-muted-foreground",children:a("noDiff")}),y?.hasMore?(0,s.jsx)(ej.$,{size:"sm",variant:"ghost",disabled:"loading"===t.changes.status,onClick:e.onMoreChanges,children:a("loadMoreFiles")}):null,y?.truncated?(0,s.jsx)("p",{className:"p-3 text-xs text-muted-foreground",children:a("changesLimit")}):null]})}),(0,s.jsx)(eD.WM,{}),(0,s.jsx)(eD.wV,{id:"project-detail",defaultSize:`${100-e.panelSizes.changes}%`,minSize:"60px",children:(0,s.jsxs)(eV.V,{className:"h-full",viewportClassName:"p-3 text-sm",role:"region","aria-label":a("commitDetails"),children:[k?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("pre",{className:"mb-3 whitespace-pre-wrap break-words font-sans leading-relaxed",children:k.message}),(0,s.jsxs)("div",{className:"mb-2 flex items-center gap-2",children:[(0,s.jsx)("span",{className:"min-w-0 flex-1 break-all font-mono text-xs",children:k.oid}),(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":a("copySha"),onClick:()=>e.onCopy(k.oid),children:(0,s.jsx)(e$.A,{className:"size-4"})})]}),(0,s.jsxs)("p",{className:"mb-3 text-xs text-muted-foreground",children:[k.author," \xb7 ",h.format(k.timestampMs)]}),k.parents.length>1?(0,s.jsx)(eY.b,{className:"mb-3",ariaLabel:a("compareParent"),value:k.selectedParent??"",options:k.parents.map((e,t)=>({value:e,label:a("parentCommit",{count:t+1,oid:e.slice(0,10)})})),onChange:t=>e.onCommit(k.oid,t)}):null]}):y?(0,s.jsxs)("div",{className:"space-y-2 text-xs text-muted-foreground",children:[(0,s.jsx)("p",{children:"merge-base"===t.strategy?a("mergeBaseToTarget"):a("baseToTarget")}),(0,s.jsx)("p",{className:"break-all font-mono",children:y.comparison.original??a("emptyRevision")}),(0,s.jsx)("p",{className:"break-all font-mono",children:y.comparison.target})]}):(0,s.jsx)("p",{className:"text-muted-foreground",children:a("selectCommit")}),w?(0,s.jsx)("p",{className:"mt-3 break-all font-mono text-xs text-muted-foreground",children:w}):null]})})]})]});return(0,s.jsxs)("section",{className:"flex size-full min-h-0 min-w-0 flex-col","aria-label":a("historyAndCompare"),children:[(0,s.jsxs)("div",{className:"flex shrink-0 flex-wrap items-center gap-2 border-b px-3 py-2",children:[(0,s.jsxs)("div",{className:"flex gap-1",role:"group","aria-label":a("viewMode"),children:[(0,s.jsx)(ej.$,{size:"sm",variant:"history"===t.mode?"secondary":"ghost","aria-pressed":"history"===t.mode,onClick:()=>{e.onMode("history"),m("log")},children:a("historyMode")}),(0,s.jsx)(ej.$,{size:"sm",variant:"compare"===t.mode?"secondary":"ghost","aria-pressed":"compare"===t.mode,onClick:()=>{e.onMode("compare"),m("log")},children:a("compareMode")})]}),(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("selectRepository"),value:t.repositoryRoot??"",options:i.map(e=>({value:e.root,label:e.root||o,description:"unavailable"===e.state?(0,eW.fD)(e.message,l):void 0})),onChange:e.onRepository}),"history"===t.mode?(0,s.jsx)(eY.b,{className:"w-48",ariaLabel:a("viewBranch"),value:t.tip,options:C,onChange:t=>e.onRevision("tip",t)}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("baseBranch"),placeholder:a("chooseBase"),value:t.base,options:C,onChange:t=>e.onRevision("base",t)}),(0,s.jsx)("span",{className:"text-xs text-muted-foreground",children:"→"}),(0,s.jsx)(eY.b,{className:"w-44",ariaLabel:a("targetBranch"),value:t.target,options:C,onChange:t=>e.onRevision("target",t)}),(0,s.jsx)(eY.b,{className:"w-48",ariaLabel:a("comparison"),value:t.strategy,options:[{value:"merge-base",label:a("introducedChanges")},{value:"direct",label:a("directComparison")}],onChange:t=>e.onStrategy("direct"===t?"direct":"merge-base")}),r?(0,s.jsx)(ej.$,{size:"sm",variant:"outline",onClick:()=>m("files"),children:a("cumulativeChanges")}):null]}),(0,s.jsx)(eJ.p,{className:"w-40 shrink-0","aria-label":a("filterAuthor"),placeholder:a("author"),list:u,value:t.author,onChange:t=>e.onAuthor(t.target.value)}),(0,s.jsx)("datalist",{id:u,children:t.authorSuggestions.map(e=>(0,s.jsx)("option",{value:e},e))}),(0,s.jsx)(eJ.p,{className:"min-w-32 flex-1 basis-40","aria-label":a("searchCommits"),placeholder:a("searchCommits"),value:t.query,onChange:t=>e.onQuery(t.target.value)}),(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":a("refreshGit"),onClick:e.onRefresh,children:(0,s.jsx)(ew.A,{className:"size-4"})})]}),t.branches.error?P(t.branches.error):null,S?(0,s.jsxs)("p",{className:"shrink-0 truncate border-b px-3 py-1 text-xs text-muted-foreground",title:S.ref,children:[S.ref.replace("refs/remotes/","")," \xb7 ",a("localRecord")," \xb7"," ",null===S.ahead||null===S.behind?a("refUnavailable"):a("aheadBehind",{ahead:S.ahead,behind:S.behind})]}):null,"compare"!==t.mode||t.base?r?"log"===g?x:D:(0,s.jsxs)(eD.HK,{orientation:"horizontal",defaultLayout:{"project-log":e.panelSizes.log,"project-files":100-e.panelSizes.log},onLayoutChanged:(t,i)=>{i.isUserInteraction&&void 0!==t["project-log"]&&e.onPanelSize("log",t["project-log"])},children:[(0,s.jsx)(eD.wV,{id:"project-log",defaultSize:`${e.panelSizes.log}%`,minSize:"30%",children:x}),(0,s.jsx)(eD.WM,{}),(0,s.jsx)(eD.wV,{id:"project-files",defaultSize:`${100-e.panelSizes.log}%`,minSize:"25%",children:D})]}):(0,s.jsx)("p",{className:"p-4 text-sm text-muted-foreground",children:a("chooseBaseBranch")})]})}var e3=i(86062);let e6="pi-super:project-preview:global",e9="pi-super:project-preview:projects",e5=x.ai().min(5).max(95),e7=x.Ik({maximized:x.zM(),directoryOpen:x.zM(),gitOpen:x.zM(),gitMaximized:x.zM(),treeLayout:x.k5(["directory","repository"]),directorySize:e5,gitSize:e5,logSize:e5,changeSize:e5}),e8={maximized:!1,directoryOpen:!0,gitOpen:!1,gitMaximized:!1,treeLayout:"directory",directorySize:22,gitSize:45,logSize:62,changeSize:70},te=x.Ik({repositoryRoot:x.Yj().nullable(),mode:x.k5(["history","compare"]),tip:x.Yj(),base:x.Yj(),target:x.Yj(),strategy:x.k5(["merge-base","direct"]),query:x.Yj().max(200),author:x.Yj().max(200),selectedCommit:e3.aD.nullable(),selectedChangePath:V._g.nullable(),logScroll:x.ai().nonnegative(),changesScroll:x.ai().nonnegative()}),tt=x.Ie(e=>"object"==typeof e&&null!==e&&Array.isArray(e.cursorState)&&"object"==typeof e.viewState),ti=x.Ik({page:x.k5(["files","code","git"]),historyPane:x.k5(["log","files"]),tabs:x.YO(V._g).max(20),activePath:V._g.nullable(),editorStates:x.g1(V._g,tt),fileViewModes:x.g1(V._g,x.k5(["source","preview"])),expandedPaths:x.YO(x.Yj()).max(500),treeScrollTop:x.ai().nonnegative(),searchQuery:x.Yj().max(200),changesOnly:x.zM(),expandedRepositories:x.YO(x.Yj()).max(100),history:te,activeDiff:x.Ik({repositoryRoot:x.Yj(),path:V._g,comparison:e3.xv.optional()}).nullable()}),ts=x.Ik({cwd:x.Yj(),lastOpenedAt:x.ai(),state:ti});function to(e){let t=e.replaceAll("\\","/").replace(/\/+$/,"");return/^[a-z]:\//i.test(t)||t.startsWith("//")?t.toLowerCase():t}function tr(){try{let e=JSON.parse(window.localStorage.getItem(e9)??"[]");if(!Array.isArray(e))return[];let t=Date.now();return e.flatMap(e=>{let i=ts.safeParse(e);return i.success&&t-i.data.lastOpenedAt<2592e6?[i.data]:[]})}catch{return[]}}function tn(e){try{window.localStorage.setItem(e9,JSON.stringify(e.sort((e,t)=>t.lastOpenedAt-e.lastOpenedAt).slice(0,50)))}catch(e){console.warn("[Pi Desk][ProjectPreview] 保存项目浏览状态失败",e)}}function ta(){try{let e=JSON.parse(window.localStorage.getItem(e6)??"null");return{...e8,...e7.partial().parse(e)}}catch{return{...e8}}}function tl({clientId:e,cwd:t,onClose:i}){let{t:o}=(0,v.Bd)("projectHistory"),r=(0,y.G)(),[n]=(0,p.useState)(ta),[a,l]=(0,p.useState)(n),c=(0,p.useCallback)(e=>{l(t=>({...t,...e}));var t={...ta(),...e};try{window.localStorage.setItem(e6,JSON.stringify(t))}catch(e){console.warn("[Pi Desk][ProjectPreview] 保存全局布局失败",e)}},[]),[d]=(0,p.useState)(()=>{let e,i,s;return e=to(t),(s=(i=tr()).find(t=>t.cwd===e))&&(s.lastOpenedAt=Date.now()),tn(i),s?.state??null}),[h]=(0,p.useState)(()=>{var i;let s,o,a,l,c;return i=e=>r.show({level:"info",title:e}),s=(0,eA.Y4)(e,{cwd:t}),o=new eF.h(t,s,{imagePreviewMode:ez.Wq,onNotice:i,reveal:(i,s="file")=>(0,eT.P)(e,{cwd:t},i,s),maxTabs:20}),a=new eL(t,s),l=new eG(s,o),c=!1,{files:o,git:a,history:l,restore(){if(!c&&(c=!0,a.setLayout(t,n.treeLayout),d)){for(let e of(a.setChangesOnly(t,d.changesOnly),d.expandedRepositories))a.toggleRepository(t,e);o.restoreBrowsing(d),l.restoreBrowsing(d.history)}},dispose(){l.dispose(),a.dispose(),o.dispose()}}}),{files:u,git:g,history:m}=h;(0,p.useSyncExternalStore)(u.subscribe,u.getRevision,u.getRevision);let f=(0,p.useSyncExternalStore)(g.subscribe,g.getRevision,g.getRevision);(0,p.useSyncExternalStore)(m.subscribe,m.getRevision,m.getRevision);let{directoryOpen:b,gitOpen:w,gitMaximized:C,maximized:S}=a,[k,P]=(0,p.useState)(d?.page??"files"),[x,D]=(0,p.useState)({width:1200,height:800}),[j,R]=(0,p.useState)(null),[I,M]=(0,p.useState)(d?.historyPane??"log"),E=(0,p.useRef)(null),N=(0,p.useRef)(()=>void 0),T=x.width<900,A=T||x.height<680,F=t.replaceAll("\\","/").split("/").filter(Boolean).at(-1)??t,L=g.getWorkspace(t),z=L.snapshot.repositories,O=u.state,B=O.activeDiff?[O.activeDiff.repositoryRoot,O.activeDiff.path].filter(Boolean).join("/"):null;(0,p.useEffect)(()=>{N.current=()=>{let e=g.getWorkspace(t),i=m.state;!function(e,t){let i=ti.safeParse(t);if(!i.success)return;let s=to(e),o=tr(),r=o.find(e=>e.cwd===s);r?r.state=i.data:o.push({cwd:s,lastOpenedAt:Date.now(),state:i.data}),tn(o)}(t,{page:k,historyPane:I,tabs:[...u.state.tabs],activePath:u.state.activePath,...u.getBrowsingDocumentSettings(),expandedPaths:[...u.state.expandedPaths].slice(0,500),treeScrollTop:u.state.treeScrollTop,searchQuery:u.state.search.query.slice(0,200),changesOnly:e.changesOnly,expandedRepositories:[...e.expandedRepositories].slice(0,100),history:{repositoryRoot:i.repositoryRoot,mode:i.mode,tip:i.tip,base:i.base,target:i.target,strategy:i.strategy,query:i.query.slice(0,200),author:i.author.slice(0,200),selectedCommit:i.selectedCommit,selectedChangePath:i.selectedChangePath,logScroll:m.scroll.log,changesScroll:m.scroll.changes},activeDiff:u.state.activeDiff?{repositoryRoot:u.state.activeDiff.repositoryRoot,path:u.state.activeDiff.path,...u.state.activeDiff.comparison?{comparison:u.state.activeDiff.comparison}:{}}:null})}},[t,u,g,m,I,k]),(0,p.useEffect)(()=>{E.current={},h.restore(),u.ensureRoot(),g.ensureSnapshot(t);let e=Date.now(),i=()=>{Date.now()-e<5e3||(e=Date.now(),g.refreshSnapshot(t))};window.addEventListener("focus",i);let s=()=>N.current();return window.addEventListener("pagehide",s),()=>{E.current=null,window.removeEventListener("focus",i),window.removeEventListener("pagehide",s),queueMicrotask(()=>{null===E.current&&(N.current(),h.dispose())})}},[t,u,g,h]),(0,p.useEffect)(()=>{if(!j)return;let e=new ResizeObserver(()=>D({width:j.clientWidth,height:j.clientHeight}));return e.observe(j),()=>e.disconnect()},[j]),(0,p.useEffect)(()=>{if(!w||!z.length||z.some(e=>e.root===m.state.repositoryRoot))return;let e=O.activeDiff?[O.activeDiff.repositoryRoot,O.activeDiff.path].filter(Boolean).join("/"):O.activePath,t=e?[...z].sort((e,t)=>t.root.length-e.root.length).find(t=>!t.root||e.startsWith(`${t.root}/`)):null;m.setRepository(t?.root??z.find(e=>""===e.root)?.root??z[0].root)},[w,f,m,z,O.activeDiff,O.activePath]),(0,p.useEffect)(()=>g.subscribe(()=>{let e=g.getWorkspace(t)?.layout;e&&e!==a.treeLayout&&c({treeLayout:e})}),[t,g,a.treeLayout,c]);let U=e=>{c({gitOpen:!0}),P("git"),void 0!==e&&m.setRepository(e)},q=(0,s.jsx)(eR.F,{cwd:t,projectName:F,runtime:u,gitRuntime:g,onOpenGitBranches:U,onFileOpened:()=>P("code")}),G=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsx)(eI.X,{cwd:t,gitRuntime:g,paths:O.tabs,activePath:O.activePath,diffPath:B,mobile:T,onActivate:e=>u.openFile(e),onClose:(e,t)=>u.closeTabs(e,t)}),(0,s.jsx)(eM.R,{runtime:u,gitRuntime:g,compact:x.width<1100||T,onEscape:i})]}),H=(0,s.jsxs)("div",{className:"flex size-full min-h-0 min-w-0 flex-col",children:[(0,s.jsxs)("div",{className:"flex h-9 shrink-0 items-center gap-2 border-b bg-muted px-3",children:[(0,s.jsx)(eg.A,{className:"size-4"}),(0,s.jsx)("span",{className:"flex-1 text-sm font-medium",children:"Git"}),A?null:(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o(C?"restoreGit":"maximizeGit"),onClick:()=>c({gitMaximized:!C}),children:C?(0,s.jsx)(em.A,{className:"size-4"}):(0,s.jsx)(ef.A,{className:"size-4"})}),(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o("collapseGit"),onClick:()=>{c({gitOpen:!1,gitMaximized:!1}),P("code")},children:(0,s.jsx)(ev.A,{className:"size-4"})})]}),z.length?(0,s.jsx)(e4,{state:m.state,cwd:t,changeRows:m.getChangeRows(),onSelectChange:e=>m.selectChange(e),onToggleDirectory:e=>m.toggleChangeDirectory(e),onReveal:(e,t)=>u.revealFile(e,t),repositories:z,projectName:F,narrow:T,mobilePane:I,onMobilePane:M,scroll:m.scroll,onScroll:(e,t)=>m.setScroll(e,t),panelSizes:{log:a.logSize,changes:a.changeSize},onPanelSize:(e,t)=>c("log"===e?{logSize:t}:{changeSize:t}),onRepository:e=>{m.setRepository(e),M("log")},onMode:e=>m.setMode(e),onRevision:(e,t)=>m.setRevision(e,t),onStrategy:e=>m.setStrategy(e),onQuery:e=>m.setQuery(e),onAuthor:e=>m.setAuthor(e),onCommit:(e,t)=>m.selectCommit(e,t),onAggregate:()=>m.showAggregate(),onMoreLog:()=>m.loadMoreLog(),onMoreChanges:()=>m.loadMoreChanges(),onOpenFile:e=>{m.openChange(e),P("code"),c({gitMaximized:!1})},onRefresh:()=>m.refresh(),onCopy:e=>{(0,eE.x)(e).then(e=>{e||r.error(o("copyFailed"))})}}):(0,s.jsx)("p",{className:"p-4 text-sm text-muted-foreground",children:"loading"===L.snapshot.status||"idle"===L.snapshot.status?o("findingGit"):L.snapshot.error??o("noGit")})]}),_=(0,s.jsxs)(eD.HK,{orientation:"horizontal",defaultLayout:b?{"project-tree":a.directorySize,"project-code":100-a.directorySize}:void 0,onLayoutChanged:(e,t)=>{t.isUserInteraction&&void 0!==e["project-tree"]&&c({directorySize:e["project-tree"]})},children:[b?(0,s.jsx)(eD.wV,{id:"project-tree",defaultSize:`${a.directorySize}%`,minSize:"180px",maxSize:"40%",children:q}):null,b?(0,s.jsx)(eD.WM,{}):null,(0,s.jsx)(eD.wV,{id:"project-code",minSize:"40%",children:G})]},b?"tree-visible":"tree-hidden");return(0,s.jsx)(ex.YV,{open:!0,onOpenChange:e=>{e||i()},children:(0,s.jsxs)(ex.hA,{ref:R,showCloseButton:!1,"data-testid":"project-preview-dialog",className:(0,eN.cn)("h-[min(94dvh,1080px)] w-[min(96dvw,1600px)] max-w-none gap-0 p-0",S&&"h-dvh max-h-none w-dvw rounded-none","max-sm:h-dvh max-sm:max-h-none max-sm:w-dvw max-sm:rounded-none"),children:[(0,s.jsxs)("header",{className:"flex min-h-14 shrink-0 flex-wrap items-center gap-2 border-b bg-muted px-3 py-2 pt-[max(8px,env(safe-area-inset-top))]",children:[A?null:(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o(b?"collapseDirectory":"expandDirectory"),onClick:()=>c({directoryOpen:!b}),children:b?(0,s.jsx)(ey.A,{className:"size-4"}):(0,s.jsx)(eb.A,{className:"size-4"})}),(0,s.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,s.jsx)(ex.YM,{className:"truncate",title:t,children:F}),(0,s.jsx)("p",{className:"truncate text-xs text-muted-foreground",title:t,children:t})]}),(0,s.jsx)(ex.uX,{className:"sr-only",children:o("previewDescription")}),(0,s.jsxs)(ej.$,{size:"sm",variant:w?"secondary":"ghost","aria-pressed":w,onClick:()=>U(),children:[(0,s.jsx)(eg.A,{className:"size-4"}),(0,s.jsx)("span",{className:"max-sm:hidden",children:o("gitRecords")})]}),(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o("refreshPreview"),onClick:()=>{u.refreshTree(),g.refreshSnapshot(t),O.activeDiff?u.reloadDiff():O.activePath&&u.reloadFile(O.activePath),w&&m.refresh()},children:(0,s.jsx)(ew.A,{className:"size-4"})}),T?null:(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o(S?"restoreWindow":"maximizeWindow"),onClick:()=>c({maximized:!S}),children:S?(0,s.jsx)(em.A,{className:"size-4"}):(0,s.jsx)(ef.A,{className:"size-4"})}),(0,s.jsx)(ej.$,{size:"icon-sm",variant:"ghost","aria-label":o("closePreview"),onClick:i,children:(0,s.jsx)(eC.A,{className:"size-4"})})]}),L.snapshot.error?(0,s.jsx)("p",{role:"alert",className:"shrink-0 border-b px-3 py-2 text-sm text-destructive",children:L.snapshot.error}):null,A?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("div",{className:"flex shrink-0 gap-1 border-b px-2 py-1",role:"group","aria-label":o("previewArea"),children:[(0,s.jsxs)(ej.$,{size:"sm",variant:"files"===k?"secondary":"ghost",onClick:()=>P("files"),children:[(0,s.jsx)(eS.A,{className:"size-4"}),o("files")]}),(0,s.jsxs)(ej.$,{size:"sm",variant:"code"===k?"secondary":"ghost",onClick:()=>P("code"),children:[(0,s.jsx)(ek.A,{className:"size-4"}),o("code")]}),(0,s.jsxs)(ej.$,{size:"sm",variant:"git"===k?"secondary":"ghost",onClick:()=>U(),children:[(0,s.jsx)(eP.A,{className:"size-4"}),"Git"]})]}),(0,s.jsx)("div",{className:"min-h-0 flex-1",children:"files"===k?q:"git"===k?H:G})]}):C&&w?H:(0,s.jsxs)(eD.HK,{orientation:"vertical",defaultLayout:w?{"project-main":100-a.gitSize,"project-git":a.gitSize}:void 0,onLayoutChanged:(e,t)=>{t.isUserInteraction&&void 0!==e["project-git"]&&c({gitSize:e["project-git"]})},children:[(0,s.jsx)(eD.wV,{id:"project-main",defaultSize:w?`${100-a.gitSize}%`:"100%",minSize:"35%",children:_}),w?(0,s.jsx)(eD.WM,{}):null,w?(0,s.jsx)(eD.wV,{id:"project-git",defaultSize:`${a.gitSize}%`,minSize:"300px",children:H}):null]},w?"git-visible":"git-hidden")]})})}var tc=i(67837),td=i(74166),th=i(67069);function tu({children:e}){let t=(0,y.G)(),[i]=(0,p.useState)(()=>{var e,i,s;let o,r,n,a=(0,tc.y)(),l=(0,th.YW)(a);return{clientId:a,...(e=(e,i)=>{t.show(i)},o="off"===new URL(window.location.href).searchParams.get("plugins"),r="normal",i=()=>!o&&"normal"===r,n=new ep({pi:{prompt:(e,t)=>l.request(S.P6.send,{source:e,mode:t.mode,text:t.text,images:(t.images??[]).map(e=>({...e}))}),commands:{list:async e=>(await l.request(q.QV.commandsList,{source:e})).commands.filter(e=>"extension"===e.source).map(({name:e,description:t})=>({name:e,description:t})),execute:async(e,t,i)=>{await l.request(q.QV.commandExecute,{source:e,command:t,...void 0===i?{}:{args:i}})}},tools:{list:async e=>(await l.request(q.QV.toolsList,{source:e})).tools},bash:{execute:(e,t)=>l.request(q.QV.bashExecute,{source:e,command:t.command,excludeFromContext:t.excludeFromContext}),abort:async e=>{await l.request(q.QV.bashAbort,{source:e})}},interrupt:async e=>{await l.request(S.P6.interrupt,{source:e})}},listBrowserEntries:async()=>{if(!i())return[];let{entries:e}=await l.request(N.list,{});return i()?e:[]},subscribePush:e=>l.subscribe($,e),createPiDeskChannel:e=>({invokeGlobal:(t,i)=>l.request(k.OY.invoke,{pluginName:e,method:t,scope:"global",input:i}),invokeSession:(t,i,s)=>l.request(k.OY.invoke,{pluginName:e,method:i,scope:"session",source:t,input:s})}),createLogChannel:e=>({watch:async t=>(await l.request(U.watch,{pluginName:e,path:t})).snapshot,unwatch:async t=>{await l.request(U.unwatch,{pluginName:e,path:t})},subscribe:t=>l.subscribe(U.event,i=>{i.pluginName===e&&t({path:i.path,event:i.event})})})},void 0,e),{appSocket:(s=e=>{r=e},{async connect(e){n.markConnecting();try{return await l.connect(e)}catch(e){throw n.markDisconnected(e instanceof Error?e.message:"WebSocket 连接失败"),e}},async request(e,t){let i=await l.request(e,t);if(e.path!==P.kM.list.path)return i;let o=P.e4.parse(i);return s(o.appRuntime.mode),(0,C.UV)(o.appRuntime.settings),n.replaceGlobalPluginStates(o.appRuntime.plugins),n.replaceWorkSessions(o.workSessions),n.markReady(),n.refreshEntries().catch(e=>{console.error("[Pi Desk][PluginHost] 初始化 Browser Entry 失败",{errorName:e instanceof Error?e.name:"UnknownError",message:e instanceof Error?e.message:String(e)})}),i},subscribe:(e,t)=>l.subscribe(e,t),async waitForClose(){let e=await l.waitForClose();return n.markDisconnected(e.reason||null),e},close(){l.close()}}),pluginHost:n})}}),[o,r]=(0,p.useState)(null);(0,p.useEffect)(()=>i.pluginHost.bindProjectPreview(e=>{r(e),requestAnimationFrame(()=>document.querySelector('[data-testid="project-preview-dialog"]')?.focus())}),[i]);let n=(0,p.useRef)(null);return(0,p.useEffect)(()=>{let e={};return n.current={token:e,runtime:i},()=>{n.current?.token===e&&(n.current=null),queueMicrotask(()=>{n.current?.runtime!==i&&(i.appSocket.close(),i.pluginHost.dispose())})}},[i]),(0,s.jsx)(th.o5.Provider,{value:i,children:(0,s.jsxs)(td.Dq.Provider,{value:i.pluginHost,children:[e,o?(0,s.jsx)(tl,{clientId:i.clientId,cwd:o,onClose:()=>r(null)},o):null]})})}let tp={en:{...d.n.en,errors:{invalidJson:"Invalid request JSON",invalidClient:"Invalid client identifier",invalidInput:"Invalid request details",sourceExpired:"The chat source has changed",sessionMissing:"Work session not found",projectChanged:"The work session project has changed",projectMissing:"Project directory not found",fileMissing:"File or directory not found",notDirectory:"The target is not a directory",notFile:"The target is not a file",outsideProject:"The target is outside the current project",textTooLarge:"This text file exceeds 5 MB and cannot be previewed online",imageTooLarge:"This image is too large for online preview",previewUnsupported:"This file type cannot be previewed online",fileReadFailed:"Could not read the project file",revealFailed:"Could not open the file location",repositoryMissing:"Git repository not found",gitOutsideProject:"The Git target is outside the current project",gitReadFailed:"Could not read the Git repository",skillsInputInvalid:"Invalid Skills request details",skillsContentTooLarge:"The submitted text exceeds the file size limit",skillsProjectChanged:"This project is no longer in the workspace. Select a project again",skillMissing:"Skill or file not found",skillsPermissionDenied:"Permission denied when accessing the Skill file",skillsFileFailed:"Could not process the Skills file. Please try again",chatSubscribeInvalid:"Invalid chat subscription details",chatSubscribeExpired:"The chat subscription source has changed",chatSubscribeFailed:"Could not initialize chat subscriptions",chatSendInvalid:"Invalid message details",chatSendTooLarge:"Message exceeds 31 MB",chatInterruptInvalid:"Invalid interrupt request",chatCompactInvalid:"Invalid compaction request",chatReloadInvalid:"Invalid Pi configuration reload request",chatRestoreInvalid:"Invalid queued message restore request",chatRestoreTooLarge:"Restored content exceeds the transport limit",chatModelInvalid:"Invalid model settings request",chatModeInvalid:"Invalid capability mode request",chatSourceBusy:"The work session is changing or switching branches",socketUnknownPath:"Unknown WebSocket operation",sessionsNotReady:"Work sessions are not initialized yet",sessionsInitializing:"Work sessions are initializing",sessionsInitializeInvalid:"Invalid work session initialization request",sessionsInitializeFailed:"Could not initialize work sessions",completionAckInvalid:"Invalid completion acknowledgement",completionAckFailed:"Could not confirm the work session completion state",capabilityFailed:"Could not update capability modes",capabilityRuleInvalid:"Check the capability mode rules",chatContextJsonInvalid:"Invalid JSON for system context request",chatContextInvalid:"Invalid system context request",chatContextBusy:"Session is running. System context is temporarily unavailable",chatContextFailed:"Could not read system context",chatMessageInvalid:"Invalid message detail request",chatMessageMissing:"Chat message not found",chatMessageFailed:"Could not load message details",chatImageInvalid:"Invalid chat image request",chatImageMissing:"Chat image not found",chatImageFailed:"Could not load chat image",modelSettingsInvalid:"Invalid model configuration",modelCatalogInvalid:"Invalid model catalog request",modelCatalogUnavailable:"Model reference catalog is temporarily unavailable",modelSaveFailed:"Could not save model configuration",modelSettingsGetInvalid:"Invalid model settings request",modelSettingsGetFailed:"Could not read model settings",projectDefaultInputInvalid:"Invalid project directory",projectDefaultGetFailed:"Could not read project model default",projectDefaultSaveInvalid:"Invalid project model default",projectDefaultSaveFailed:"Could not save project model default",modelsListFailed:"Could not list models",directoryBrowseInvalid:"Invalid directory browser request",directoryMissing:"Directory not found or is not a folder",directoryReadDenied:"Could not read directory",directoryBrowseFailed:"Could not browse server directories",workSessionCreateInvalid:"Invalid cwd or session ID",workSessionDirectoryMissing:"Project directory does not exist or is not a folder",historySessionMissing:"No Pi session found in this directory",historySessionOccupied:"Pi session is already used by another work session",workSessionCreateFailed:"Could not create work session",workSessionReplaceInvalid:"Invalid work session replacement request",workSessionReplaceOccupied:"Pi session is bound to another work session",workSessionReplaceFailed:"Could not replace the Pi session",workSessionRenameInvalid:"Invalid work session title request",workSessionRenameChanged:"Work session changed. Reopen the title editor",workSessionRenameFailed:"Could not rename the work session",workSessionDeleteInvalid:"Invalid work ID",workSessionDeleteFailed:"Could not delete work session",workSessionSortInvalid:"Invalid work session order or pinned count",workSessionOrderChanged:"Work session list changed. Refresh and try again",workSessionSortFailed:"Could not reorder work sessions",sessionTreeInvalid:"Invalid session tree request",sessionTreeChanged:"Work session changed. Reopen the session tree",sessionTreeFailed:"Could not read session tree",sessionTreeEntryInvalid:"Invalid session tree entry request",sessionTreeEntryMissing:"Session tree entry not found or no longer available",sessionTreeEntryFailed:"Could not read session tree entry",branchInputInvalid:"Invalid branch operation request",branchEntryMissing:"Branch entry not found or no longer available",branchForkUserOnly:"Only user messages can start a new session",branchCloneEmpty:"There are no messages to clone yet",branchFailed:"Could not perform branch operation",taskDetailInvalid:"Invalid task detail request",taskSourceChanged:"Work session source changed",taskMissing:"Task not found",taskDetailUnsupported:"Task does not provide conversation details",taskMessageMissing:"Task message not found",taskMessageNoDetail:"Task message has no details",taskConversationUnavailable:"Task conversation is temporarily unavailable",taskMessageFailed:"Could not read task message details",taskImageMissing:"Task image not found",taskImageFailed:"Could not read task image",refreshInvalid:"Invalid forceRefresh setting",piDirectoriesFailed:"Could not list Pi project directories",ignoredDirectoriesFailed:"Could not list ignored folders",directoryIgnoreInvalid:"Invalid ignored folder request",directoryIgnoreFailed:"Could not update ignored folders",historyQueryInvalid:"Invalid session history search",historyQueryFailed:"Could not list Pi session history",userMessagesInvalid:"Invalid user message request",piSessionMissing:"Pi session not found",userMessagesFailed:"Could not load past user messages",projectJsonInvalid:"Invalid project request JSON",projectInputInvalid:"Invalid project request",projectCwdAbsolute:"Project directory must be an absolute path",projectOperationFailed:"Project operation failed",capabilityGetInvalid:"Invalid capability mode query",capabilityGetFailed:"Could not read capability modes",capabilityReplaceInvalid:"Invalid capability mode configuration",capabilityReplaceFailed:"Could not save capability modes",pluginResourceMissing:"Plugin browser resource not found",pluginResourceReadFailed:"Could not read plugin browser resource",hostResourceMissing:"Host plugin resource not found",hostRuntimeUnavailable:"Host plugin runtime is not built",hostResourceReadFailed:"Could not read Host plugin resource",gitAddJsonInvalid:"Invalid JSON for new Git branch",gitAddInputInvalid:"Invalid new Git branch request",gitAddFailed:"Could not create Git branch",gitSwitchJsonInvalid:"Invalid Git branch switch JSON",gitSwitchInputInvalid:"Invalid Git branch switch request",gitSwitchFailed:"Could not switch Git branch",gitReadOperationFailed:"Could not read Git data",pluginNpmRootUnavailable:"Pi Package npm root is unavailable: {{detail}}",pluginNpmRootMissingDeclarations:"Pi Package configuration does not match the npm root (missing declarations: {{declarations}})",pluginNpmRootMissingFolders:"Pi Package configuration does not match the npm root (missing folders: {{folders}})",pluginNpmRootMissingBoth:"Pi Package configuration does not match the npm root (missing declarations: {{declarations}}; missing folders: {{folders}})",pluginReloadBlocked:"Work session {{workId}} blocked plugin reload: {{reason}}",pluginRuntimeBusy:"Plugin runtime still has active calls",pluginRestartPending:"Another plugin operation must finish restarting first",pluginRestartUnavailable:"This launch mode cannot restart Pi Desk automatically",pluginNotFound:"Plugin not found: {{source}}",pluginSourceInvalid:"Invalid plugin source"},auth:{title:"Sign in to Pi Desk",subtitle:"Continue your work.",protection:"Sign-in protection",enabled:"Enabled",disabled:"Not enabled",publicAccess:"Anyone who can reach this service can open the workspace.",changePassword:"Change password",setPassword:"Set a password",newPassword:"New password",passwordHint:"12–64 characters; use at least three of: uppercase letters, lowercase letters, numbers and symbols. No leading/trailing spaces, line breaks or invisible control characters.",generatePassword:"Generate password",generatePasswordHint:"Generate a random 16-character password",generatePasswordFailed:"Unable to generate a password. Please try again.",saveEffect:"Keep your password safe. Saving requires all devices to sign in again.",enable:"Enable sign-in protection",saveAndSignIn:"Save and sign in again",saving:"Saving…",logout:"Sign out",signingOut:"Signing out…",logoutFailed:"Unable to sign out. Please try again later.",logoutInvalid:"Invalid sign-out request.",logoutCrossOriginDenied:"Cross-site sign-out requests are not allowed.",disable:"Disable protection",disableTitle:"Disable sign-in protection?",disableDescription:"Anyone who can reach this service will be able to open the workspace. Continue?",recovery:"Forgot your password?",recoveryDescription:"Delete this file on the device running the service, then refresh the page to restore access.",settingsFailed:"Unable to load or save sign-in protection settings.",settingsInvalid:"The password does not meet the requirements shown below the field.",configUnavailable:"Unable to read sign-in protection settings. Repair the configuration or delete auth.json and set it up again.",crossOriginDenied:"Cross-site changes to sign-in protection are not allowed.",password:"Password",submit:"Sign in",submitting:"Signing in…",loginFailed:"Unable to sign in",invalidResponse:"Invalid response from the sign-in service",invalidCredentials:"Sign-in failed. Check your sign-in details and try again.",invalidInput:"Sign-in failed. Check your sign-in details and try again.",unavailable:"Sign-in is temporarily unavailable. Please try again later.",tooManyAttempts:"Too many sign-in attempts. Please try again later.",loginAlertTitle:"Unusual sign-in activity",loginAlertDescription:"More than 5 consecutive sign-in failures. Check whether these attempts were yours.",invalidClient:"Invalid client identifier"},capabilityModes:{saved:"Capability modes saved",saving:"Saving…",saveModes:"Save modes",settings:"Capability mode settings",editMode:"Edit mode",selectMode:"Select a capability mode to edit",unnamedMode:"Unnamed mode",allDefault:"All enabled \xb7 Default",addMode:"Add mode",copyMode:"Copy current mode",copyTitle:"Copy mode",deleteMode:"Delete current mode",deleteTitle:"Delete mode",refreshCatalog:"Refresh capability options",retryRead:"Retry loading",loadingCatalog:"Loading capability options…",allEnabled:"All enabled",allDescription:"Use all loaded capabilities.",unsaved:"Unsaved changes",allIsDefault:"All enabled is the default mode",policyAll:"Enable all",policyAllow:"Only these",policyDeny:"Exclude these",policyNone:"Disable all",ruleEditor:"Edit {{name}} rules",ruleMode:"{{name}} availability",exclusions:"Exclusions",ruleSearch:"Search or enter capability rules",ruleSearchPlaceholder:"Search names or enter * patterns",clearSearch:"Clear rule search",selectedOnly:"Selected only",selectedShort:"Selected",allowRules:"Allow rules",excludeRules:"Exclude rules",selectedCount_one:"{{count}} selected",selectedCount_other:"{{count}} selected",selectVisible:"Select visible",clearSelected:"Clear selected",addRule:"Add rule",allowValue:"Allow {{name}}",excludeValue:"Exclude {{name}}",pattern:"Pattern",noMatches:"No matches; you can add the rule above.",noSelection:"No rules selected yet.",enterPattern:"Enter a name or wildcard rule to add it.",moreRules:"Show more \xb7 {{count}} remaining",deleteConfirm:"Delete capability mode?",saveConfirm:"Save mode changes?",deleteDescription:"Delete “{{name}}” and save? Sessions using it will switch to All enabled.",unsavedDescription:"Changes to capability modes have not been saved.",cancel:"Cancel",delete:"Delete mode",discard:"Discard changes",saveContinue:"Save and continue",modeName:"Mode name",category:"Capability categories",groupTools:"Tools",modeSwitching:"Switching…",modePicker:"Capability mode: {{name}}",catalogFailed:"Could not load capability options",saveFailed:"Could not save capability modes",copySuffix:"{{name}} copy",newMode:"New mode"},pluginManagement:{actionAdd:"Install plugin",actionUpdate:"Update plugin",actionDelete:"Uninstall plugin",actionReload:"Restart Pi Desk",restartNormal:"Restart with plugins",restartNormalDescription:"Restart Pi Desk and load external plugins again. All connections will be restored after restart.",applyChanges:"Load changes",applyDescription:"Update plugin services and views now. Existing Pi sessions keep their extensions until manually reloaded.",reloadOne:"Reload",reloadSource:"Reload {{name}}",basicModeNotice:"Basic mode skips plugin loading and inspection. Repair files using chat, then choose Restart with plugins.",localExtension:"Local source",localSourceHelp:"Manage this entry in its source directory",discovered:"Enabled",disabledByPi:"Disabled",active:"Enabled",notLoaded:"Not loaded",phase_queued:"Queued",phase_checking:"Checking",phase_applying:"Applying",phase_waiting:"Waiting to activate",phase_failed:"Failed",updateCheckFailed:"Could not check plugin updates",actionFailed:"{{action}} failed",retrying:"Retrying {{name}}",retryFailed:"Could not retry plugin UI",refreshingEntries:"Refreshing plugin UI",refreshEntriesFailed:"Could not refresh plugin UI",detailFailed:"Could not load plugin details",title:"Plugins",description:"Manage plugin packages and local extensions.",noPluginDescription:"No description available",checkUpdates:"Check updates",checkingUpdates:"Checking…",restartApply:"Restart to finish",installPlugin:"Install plugin",source:"Plugin source",sourcePlaceholder:"npm package, Git URL or local directory",install:"Install",installVersion:"Install this version",installIncompatible:"This plugin version is incompatible with the current Pi Desk version and cannot be installed.",pendingRestart:"Plugin changes will take effect after restart",retry:"Retry",confirmAction:"{{action}}?",restartDescription:"Restart Pi Desk to apply pending changes. Connections will be restored after restart.",cancel:"Cancel",installed:"Installed plugins",loading:"Loading plugins…",updateAvailable:"Update available",abnormal:"Error",capabilityCategories:"Plugin capability categories",update:"Update",details:"Details",viewDetails:"View plugin details: {{name}}",remove:"Uninstall",empty:"No plugins found",viewLoading:"Loading plugin UI…",viewFailed:"Could not load plugin UI",closeApplication:"Close plugin application",closeNamedApplication:"Close {{name}}",eventAgentStart:"Before agent starts",eventAgentStartDescription:"Can append to or replace the system prompt and inject session messages.",eventContext:"Before model call",eventContextDescription:"Can replace the messages sent to the model for this call.",eventInput:"User input",eventInputDescription:"Can rewrite, intercept or handle user input.",eventProvider:"Before provider request",eventProviderDescription:"Can replace the final provider payload.",eventToolCall:"Before tool call",eventToolCallDescription:"Can modify tool arguments or block execution.",eventToolResult:"After tool result",eventToolResultDescription:"Can modify tool results entering later model context.",eventMessageEnd:"After message completes",eventMessageEndDescription:"Can replace the final message and affect later context.",eventBeforeCompact:"Before context compaction",eventBeforeCompactDescription:"Can cancel compaction or replace the summary.",contributionApplication:"Application",contributionComposer:"Composer panel",contributionSettings:"Settings page",contributionMessage:"Message view",contributionSidebar:"Session sidebar",tagTools:"{{count}} tools",tagFixed:"{{count}} fixed prompts",tagDynamic:"{{count}} dynamic hooks",tagOverride:"{{count}} builtin overrides",tagManual:"{{count}} manual prompts",tagInteraction:"{{count}} interactions",unknown:"Unknown",stateActive:"Active",stateInactive:"Inactive",stateShadowed:"Overridden",copied:"Copied",copy:"Copy",copyNamed:"Copy {{name}}",dynamicTitle:"Dynamic context hooks",dynamicDescription:"These hooks can affect prompts and messages, but registration does not mean each call changed them.",arguments:"Arguments",none:"None",required:"Required",optional:"Optional",noArguments:"This tool takes no arguments.",rawSchema:"Raw schema",toolCapabilities:"Tool capabilities",toolDescription:"Each tool shows its purpose, parameters and declared system prompts.",overridesBuiltin:"Overrides a Pi builtin tool",noDescription:"No description provided",systemPrompts:"System prompts",inactivePrompt:"This tool is inactive; its prompts do not enter the system prompt.",truncated:"Content exceeds 64 KB; showing the first 64 KB.",resourcesTitle:"Skills and prompts",resourcesDescription:"Callable Skills contribute metadata to the system prompt; full content is loaded on demand. Prompt templates expand when invoked by the user.",skillModelVisible:"Description in system prompt",manualOnly:"Manual invocation only",skillMetadata:"Skill metadata in system prompt",viewSkillContent:"View Skill content",viewPromptContent:"View prompt content",otherCapabilities:"Other capabilities",messageDeclarations:"Message declarations:",backToList:"Back to plugins",incompleteCapabilities:"Capability list incomplete: {{error}}",metricToolDefinitions:"Tool definitions",metricFixed:"Fixed prompts",metricDynamic:"Dynamic hooks",metricManual:"Manual prompt resources",loadingFullDetails:"Loading full capability details",installedTab:"Installed",searchPlugins:"Find plugins",directInstall:"Manual install",advancedOptions:"Advanced options",capabilityDetails:"Features and runtime details",newVersion:"New v{{version}}",removeNamed:"Uninstall {{name}}",updateAll:"Update all ({{count}})",batchManage:"Select plugins",finishSelection:"Done",selectAll:"Select all",filterStatus:"Plugin status",statusFilter_all:"All statuses",statusFilter_updates:"Updates available",statusFilter_disabled:"Disabled",statusFilter_failed:"Errors",batchWaiting:"Not submitted. Finish pending operations, then try again.",batchInstall:"Install plugins",batchSourcePlaceholder:"One npm package per line; a single source can also be a Git URL or local directory",batchNpmOnly:"Enter one npm package per line for batch installation.",batchLimit:"Choose up to 32 plugins per batch.",batchFailed:"Could not submit plugin changes",sourceBusy:"This plugin has an operation in progress. Try again when it finishes.",selectFiltered:"Select all results",selectPlugin:"Select {{name}}",selectedCount:"{{count}} selected",clearSelection:"Clear selection",checkSelected:"Check selected",updateSelected:"Update selected",removeSelected:"Uninstall selected",setChannel:"Set channel",installChannel:"Version preference",defaultChannel:"Default",automaticVersion:"Default version",allChannels:"All channels",filterChannel:"Filter by channel",channelLatest:"Stable",channelDev:"Development",followingChannel:"Channel: {{tag}}",targetVersion:"Target: {{version}}",itemCheckFailed:"Update check failed: {{error}}",filterInstalled:"Search installed plugins",noMatches:"No matching plugins",enabled:"Enabled",disabled:"Disabled",enable:"Enable",disable:"Disable",togglePlugin:"Enable or disable {{name}}",submitting:"Submitting…",installing:"Installing…",alreadyInstalled:"Installed",retryView:"Retry plugin view",more:"More",downloadSource:"Download source",installDownloadSource:"Download source for this install",useDefaultSource:"Use saved default",download_local:"No override (local configuration)",download_auto:"Automatic",download_domestic:"China mirror",download_official:"Official npm",download_custom:"Custom",registryUrl:"Registry URL",sourceDetails:"View source URL",recommending:"Choosing a source…",saving:"Saving…",save:"Save",settingsFailed:"Could not save or read download settings",invalidRegistry:"Enter a valid HTTP or HTTPS registry URL without credentials, query or fragment.",searchPlaceholder:"Search plugin name or description",searchSource:"Search registry",publicNpm:"Public npm",customSearchSource:"Custom registry",searchRegistryUrl:"Search registry URL",pluginKind:"Plugin type",kind_all:"All types",kind_desk:"Pi Desk",kind_pi:"Pi",kind_unknown:"Unverified type",official:"Official",publisher:"Publisher",unknownPublisher:"Publisher not provided",searchFailed:"Could not search plugins",searching:"Searching…",noSearchResults:"No matching plugins. Try another search.",loadMore:"Load more",loadingPackage:"Loading package details…",readPackage:"Read package details",version:"Version",packageName:"Package",readme:"README",noReadme:"No README provided",readmeLanguage:"Language",defaultLanguage:"Automatic / original",compatible:"Compatible",incompatible:"Not compatible with this version",compatibilityUnknown:"Compatibility not verified",homepage:"Website",repository:"Source code",removeDescription:"Remove this plugin. Saved configuration and data will be kept.",thirdPartyDescription:"This plugin can execute code on your computer. Only install it if you trust its publisher and source.",confirmChange:"Apply this change to the selected plugin.",fromSource:"Version from source",pluginDetails:"Plugin details",pluginRemoved:"This plugin is no longer installed.",close:"Close"},projectHistory:{currentHead:"Current HEAD",localBranch:"Local branch",remoteBranch:"Remote branch \xb7 local record",retry:"Retry",compareDirect:"Compare directly",loadingCommits:"Loading commits…",commitList:"Git commits",noCommitMessage:"(no commit message)",noMatchingCommits:"No matching commits",noCommits:"No commits",scanLimit:"History scan limit reached. Choose a more specific branch or commit.",loadedLimit:"2,000 commits loaded. Narrow your search.",loadMoreCommits:"Load more commits",backCommits:"Back to commits",commitChanges:"Commit changes",cumulativeChanges:"Cumulative changes",loadedFiles:"{{count}} files loaded",backCumulative:"Back to cumulative changes",loadingChanges:"Loading changes…",noDiff:"No file differences",loadMoreFiles:"Load more files",changesLimit:"Change file display limit reached.",commitDetails:"Commit details",copySha:"Copy commit SHA",compareParent:"Compare parent commit",parentCommit:"Parent {{count}} \xb7 {{oid}}",mergeBaseToTarget:"Common ancestor → target commit",baseToTarget:"Base commit → target commit",emptyRevision:"Empty revision",selectCommit:"Select a commit to view its details",historyAndCompare:"Git history and comparison",viewMode:"Git view mode",historyMode:"Commit history",compareMode:"Compare branches",selectRepository:"Select repository",viewBranch:"View branch",baseBranch:"Base branch",chooseBase:"Choose base branch",targetBranch:"Target branch",comparison:"Comparison method",introducedChanges:"Changes introduced by this branch",directComparison:"Compare two versions directly",filterAuthor:"Filter by author",author:"Commit author",searchCommits:"Search commit message or SHA",refreshGit:"Refresh Git history",localRecord:"Local record",refUnavailable:"Reference unavailable",aheadBehind:"{{ahead}} ahead \xb7 {{behind}} behind",chooseBaseBranch:"Choose a base branch",restoreGit:"Restore Git panel",maximizeGit:"Maximize Git panel",collapseGit:"Collapse Git panel",copyFailed:"Could not copy",findingGit:"Detecting Git repositories…",noGit:"No Git repository found",collapseDirectory:"Collapse folder tree",expandDirectory:"Expand folder tree",previewDescription:"Read-only preview of project files and Git history",gitRecords:"Git history",refreshPreview:"Refresh project preview",restoreWindow:"Restore preview window",maximizeWindow:"Maximize preview window",closePreview:"Close project preview",previewArea:"Project preview area",files:"Files",code:"Code",changeFiles:"Files changed in commit",viewDiff:"View diff",gitStatus:"Git status {{status}}",viewDiffPath:"View diff: {{path}}",historyDiffAncestor:"Common ancestor {{left}} ↔ {{target}}",historyDiffDirect:"{{left}} ↔ {{target}}",historyReadFailed:"Could not read Git history"},settings:{title:"Settings",general:"General settings",workCapabilities:"Tools & models",application:"Application",category:"Settings section",appearance:"Appearance",region:"Language & time zone",habits:"Preferences",loginProtection:"Sign in",models:"Models",mcpSettings:"MCP",capabilityModes:"Capability modes",skills:"Skills",plugins:"Plugins",pluginSettings:"Plugin settings",about:"About",language:"Language",timeZone:"Time zone",currentLanguage:"Current language: {{locale}}",currentTimeZone:"Current time zone: {{timeZone}}",timeExample:"Local time",searchTimeZones:"Search time zones",reloadLanguage:"Reload to use this language",version:"Current version",versionUpdated:"Version updated",webDescription:"Pi in your browser",discardModelTitle:"Unsaved model settings",discardModelDescription:"Discard changes to model settings?",discardModelConfirm:"Discard changes",theme:"Theme",themeLight:"Light",themeDark:"Dark",displaySize:"Display size",sizeCompact:"Compact",sizeStandard:"Standard",sizeLarge:"Large",displayPreview:"Display preview",displayPreviewContent:'## Project progress\n\nToday we organized the work plan. Next, we will finish the remaining tasks.\n\n```ts\nconst status = "ready"\n```',browserOnly:"These settings only apply to this browser.",newSessionBehavior:"After creating a session",behaviorNone:"Keep current session",behaviorNoneDescription:"Stay in the current session after creating another.",behaviorActivate:"Switch to new session",behaviorActivateDescription:"Open the new session immediately.",behaviorPin:"Pin automatically",behaviorPinDescription:"Pin the new session and keep the current one active.",desktopOnlyBehavior:"Applies on desktop only; mobile always opens the new session.",imagePreviewMode:"Image preview",imageCompressed:"Optimized preview",imageCompressedDescription:"Reduce data use for large images without modifying project files.",imageOriginal:"Original image",imageOriginalDescription:"Keep original quality; large images use more data.",imagePreviewApply:"Changes apply to newly loaded or manually reloaded images.",modelProviders:"Model management",modelPresets:"Common combinations",serviceAddress:"Service address",serviceKey:"Access key",serviceId:"Service ID",serviceIdInvalid:"Enter a unique, non-empty service ID.",serviceConnection:"Service connection",serviceSettingsNamed:"{{name}} connection settings",currentServiceSettings:"Current service connection settings",modelAddToService:"Add a model to {{name}}",inheritService:"Inherit service settings",inheritServiceValue:"Inherit service: {{value}}",applyServiceDraft:"Apply to draft",serviceDraftScope:"Used by {{count}} models. Apply here, then save the model configuration.",discardServiceTitle:"Unsaved connection changes",discardServiceDescription:"Discard this connection draft?",selectModelToEdit:"Select a model to edit",backModelList:"Back to model list",modelIdRequired:"Enter a model ID.",modelNameRequired:"Enter a display name.",capacityInvalid:"Enter a positive number with up to three decimal places.",priceInvalid:"Enter a non-negative number.",inputAndThinking:"Input and reasoning",addModelPreset:"Add to common combinations",saveBeforePreset:"Save this model before adding it to common combinations.",modelDraftPending:"Configuration changes are not saved",modelDraftClean:"No unsaved changes",fixModelInputs:"Correct the invalid model fields before saving",revertModels:"Discard configuration changes",modelMoreActions:"Model configuration actions",nativeConfig:"Pi configuration",nativeConfigEditor:"Pi model configuration",nativeConfigScope:"Edit the complete models.json configuration, including modelOverrides, inputLimits, promptCache, samplingParams and tiered pricing.",nativeProtectDraft:"Save or discard your form changes before opening Pi configuration.",saveNativeConfig:"Save Pi configuration",discardNativeTitle:"Unsaved Pi configuration",discardNativeDescription:"Discard changes to the Pi configuration?",projectDefault:"Project defaults",loadingModels:"Loading model settings…",modelsUnavailable:"Model settings unavailable",modelsLoadFailed:"Could not load model settings",catalogCached:"Refresh failed. Using the previous model catalog.",catalogPartial:"Model catalog partly updated. Failed sources are using cached data.",catalogUnchanged:"Model catalog is already up to date.",catalogUpdated:"Model catalog updated.",catalogRefreshFailed:"Could not refresh the model catalog",modelsNoChanges:"There are no model configuration changes to save.",removeInvalidPresetsTitle:"Remove invalid common combinations?",removeInvalidPresets_one:"{{count}} common combination refers to a removed model. Saving will remove this combination.",removeInvalidPresets_other:"{{count}} common combinations refer to removed models. Saving will remove them.",removeAndSave:"Remove and save",replaceProjectDefaultsTitle:"Update project default models",replaceProjectDefaultsDescription:"The following projects will use the new model settings. Confirm to save all changes together.",confirmAndSaveModels:"Confirm and save",modelSaved:"Model configuration saved.",modelSaveFailed:"Could not save the model configuration",catalogUpdatedAt:"Reference catalog updated at {{time}}",catalogUnavailable:"Reference catalog unavailable",refreshingCatalog:"Refreshing…",refreshCatalog:"Refresh model catalog",savingModels:"Saving…",saveModels:"Save model configuration",thinkingOff:"Off",thinkingMinimal:"Minimal",thinkingLow:"Low",thinkingMedium:"Medium",thinkingHigh:"High",thinkingXhigh:"Very high",thinkingMax:"Maximum",priceMissing:"Price unavailable",priceInput:"Input {{price}}",priceOutput:"Output {{price}}",priceCacheRead:"Cached {{price}}",priceCacheWrite:"Cache write {{price}}",perMillionTokens:" / million tokens",catalogSearchFailed:"Could not search the model catalog",catalogSelected:"Selected {{provider}} / {{model}}.",modelId:"Model ID",modelIdSearch:"Search and select by model ID",chooseModel:"Choose or change model",matchingCatalog:"Finding models…",noCatalogMatches:"No matching models",officialRecommended:"Official recommendation",sameConfiguration:"{{count}} identical sources",contextAndOutput:"{{context}} context \xb7 {{output}} output",contextAndOutputTitle:"Context {{context}} tokens, maximum output {{output}} tokens",moreConfigurations:"Show {{count}} more configurations",modelName:"Display name",contextLength:"Context window",maximumOutput:"Maximum output per request",capabilities:"Capabilities",textInput:"Text input",imageInput:"Image input",supportsThinking:"Supports reasoning",thinkingMapping:"Thinking levels and provider mapping",providerMapping:"{{level}} provider mapping",noMapping:"No mapping",price:"Pricing",inputPrice:"Input price / million tokens",outputPrice:"Output price / million tokens",cacheReadPrice:"Cache read price",cacheWritePrice:"Cache write price",clearPrice:"Clear pricing",advancedCompatibility:"Advanced settings",apiOverride:"Model API override",baseUrlOverride:"Model Base URL override",inheritProvider:"Leave blank to inherit the provider",developerRole:"Supports Developer Role",replayReasoning:"Replay reasoning_content",modelHeaders:"Model headers",headerPlaceholder:"Header-Name: value, one per line",useDefault:"Use default",yes:"Yes",no:"No",providerNew:"Add service connection",accountCustomApi:"Custom API",accountLogin:"Sign in",accountRelogin:"Sign in again",accountLogout:"Sign out",accountLogoutTitle:"Sign out of this service?",accountLogoutDescription:"Sign out of “{{name}}”? Its account models will be unavailable until you sign in again. Your model selections and drafts will be kept; this will not switch the current session.",accountLogoutFailed:"Could not sign out",accountCustomSettings:"Custom API settings",accountCustomModel:"Custom model",accountChooseProvider:"Choose a service",accountLoadingProviders:"Loading services…",accountNoProviders:"No sign-in services available",accountChooseOption:"Choose an option",accountContinue:"Continue",accountWaiting:"Waiting for authorization…",accountLoggedIn:"Signed in",accountLoggedOut:"Not signed in",accountLoginFailed:"Could not sign in",accountRefreshFailed:"Signed in, but could not refresh the model list",accountDisconnected:"Connection lost. This sign-in was cancelled. Reconnect, then start again.",accountConnectionNotReady:"Connection is not ready. Try again after it reconnects.",accountDeviceCode:"Authorization code",accountCopyCode:"Copy code",accountOpenLink:"Open authorization page",accountCopyLink:"Copy link",accountInvalidLink:"This authorization link is not a valid web address.",accountCopied:"Copied",accountCopyFailed:"Could not copy",accountModelSearch:"Search model name or ID",accountModelAdded:"Added",accountNoModels:"No matching models",accountAddLater:"Add later",accountAddSelected:"Add {{count}} selected",accountModelUnavailable:"This model is no longer available in the service catalog. You can remove it from your configuration.",accountModelUnavailableShort:"Unavailable",accountSubscription:"Subscription",accountReferencePrice:"Reference pricing",accountAdjustParameters:"Adjust parameters",accountRestoreDefaults:"Restore defaults",accountRemove:"Remove model",accountRemoveTitle:"Remove model?",accountRemoveDescription:"Remove “{{name}}” from your model list? This takes effect after saving and does not sign you out.",providerUnnamed:"Service ID required",providerList:"Model services",providerSummary:"{{providers}} providers \xb7 {{models}} models",providerConfig:"Provider configuration",providerEmpty:"No services configured",providerModels:"{{count}} custom models",providerDelete:"Remove service",providerDeleteTitle:"Remove service?",providerDeleteDescription:"Remove “{{name}}” and its {{count}} models? The change takes effect after you save.",modelDeleteTitle:"Remove model?",modelDeleteDescription:"Remove “{{name}}”? The change takes effect after you save.",providerIdExample:"e.g. my-provider",providerApiType:"Default API",providerAdvanced:"Advanced connection settings",providerAuthHeader:"Add Authorization header automatically",providerHeaders:"Service headers",modelsHeading:"Models",modelAdd:"Add model",modelEmpty:"No models yet",modelUnnamed:"Unnamed model",modelIdPending:"Model ID required",modelDelete:"Remove model",modelDeleteNamed:"Remove model {{name}}",presetDescription:"Choose a model and reasoning level quickly in chat. Drag or use the buttons to reorder.",presetDrag:"Drag to reorder",presetMoveUp:"Move combination up",presetMoveDown:"Move combination down",presetModel:"Combination model",presetModelNew:"Model for new combination",modelSearch:"Search model name, service ID or model ID",thinkingLevel:"Thinking level",presetThinking:"Combination thinking level",presetThinkingNew:"Thinking level for new combination",presetColor:"Color",presetColorLabel:"Combination color",presetColorNone:"No color",presetColorCustom:"Custom color",presetColorBlue:"Blue",presetColorCyan:"Cyan",presetColorGreen:"Green",presetColorAmber:"Amber",presetColorOrange:"Orange",presetColorRed:"Red",presetColorPink:"Pink",presetColorPurple:"Purple",presetDelete:"Remove combination",presetAdd:"Add",presetEmpty:"No common combinations yet",projectSessionCount_one:"{{count}} session",projectSessionCount_other:"{{count}} sessions",projectDirectoriesFailed:"Could not load project directories",projectDefaultFailed:"Could not load project model defaults",projectDefaultSaved:"Project model default saved.",projectDefaultGlobalSaved:"Project is following the current global Pi model.",projectDefaultSaveFailed:"Could not save the project model default",projectLoading:"Loading project settings…",projectDescription:"Project settings take precedence over Pi’s current global selection. Changing a model in chat will not change this setting.",projectEmpty:"No project directories with Pi sessions found",project:"Project",projectSearch:"Search project paths",projectList:"Project list",backProjectList:"Back to project list",selectProjectToConfigure:"Select a project to configure its default model",projectDefaultSource:"Project model default source",projectFollowGlobal:"Follow current global Pi selection",projectFollowGlobalDescription:"Do not set a separate default model for this project.",projectFixed:"Set a project default",projectFixedDescription:"Select a model and reasoning level for this project.",projectDefaultModel:"Default model",projectDefaultThinking:"Project default thinking level",fromPreset:"Choose from common combinations",saveProjectDefault:"Save project default"},skills:r.P.en,taskCenter:n.U.en,workbench:a.R.en,workbenchPicker:{sessionFallback:"Session {{id}}",newSession:"New session",scopeTitle:"Title",scopeUser:"User messages",scopeAssistant:"AI replies",scopeUserMatches:"User messages {{count}}",scopeAssistantMatches:"AI replies {{count}}",loadUserFailed:"Could not load user messages",ignoredRestoreTitle:"Restore ignored folder",browseOtherTitle:"Choose a project folder",replaceTitle:"Replace work session",createTitle:"Create work session",ignoredRestoreDescription:"This project will appear again in regular folder lists.",browseDescription:"Browse the filesystem of the server running Pi Desk to choose a project directory.",replaceDescription:"Replace: {{project}} \xb7 {{session}}",replaceMissingDescription:"Replacement target is no longer available. Close this dialog and select a work session again.",createDescription:"Choose an existing Pi project or browse server folders to create a work session.",searchHistory:"Search past sessions",searchBrowser:"Search folders in this location",searchIgnored:"Search ignored folders",searchProjects:"Search project names or full paths",currentProject:"Current project: {{path}}",ignoredCount_one:"{{count}} ignored folder",ignoredCount_other:"{{count}} ignored folders",rootChoose:"Choose a drive or root directory",root:"Drives or root directories",replaceChooseFirst:"Choose a project to see its available past sessions.",regularExcludesIgnored:"Ignored projects are excluded from regular folder lists.",loadingHistory:"Loading past sessions…",loadingIgnored:"Loading ignored folders…",loadingBrowser:"Browsing server folders…",loadingProjects:"Loading Pi projects…",backFolders:"Back to folder list",pastePath:"Paste a full folder path and press Enter",fullPath:"Full folder path",openTyped:"Open entered folder",enterAbsolute:"Enter an absolute folder path",open:"Open",absoluteExample:"Enter an absolute folder path, e.g. C:\\projects\\example.",pasteHint:"Paste and open a full path; Windows “Copy as path” is supported.",searchScopes:"Search in",replaceTargetMissing:"Replacement target is no longer available.",noHistoryMatches:"No matching past sessions",noReplaceHistory:"This project has no available past sessions",sessionFound_one:"{{count}} session found",sessionFound_other:"{{count}} sessions found",sessionMessages:"{{users}}/{{total}} messages \xb7 {{time}}",replacing:"Replacing",current:"Current",alreadyUsed:"In use",targetUnavailable:"Target unavailable",replace:"Replace",currentBound:"This past session is bound to the current work session",historyUsed:"This past session is in use by another work session",replaceTargetUnavailable:"Replacement target is unavailable",replaceWith:"Replace with {{name}}",hideUserMessages:"Hide user messages",viewMatching_one:"View {{count}} match",viewMatching_other:"View all {{count}} matches",viewUserMessages_one:"View {{count}} user message",viewUserMessages_other:"View {{count}} user messages",viewMatch:"View {{label}}",matchingUserCount:"{{count}} matching user messages",userCount:"{{count}} user messages",viewAll:"View all",noUserMessages:"No user messages to display",noText:"(no text)",loadMore:"Load more",browserEmpty:"No subfolders here. You can select this folder.",rootsEmpty:"No drives or root directories to browse",subfoldersNoMatches:"No matching subfolders",ignoredEmpty:"No ignored Pi projects",projectsEmpty:"No Pi projects available",projectNoMatches:"No matching Pi projects",restoreFolder:"Restore folder {{name}}",restoreTip:"Restore to regular folder lists",restore:"Restore",directorySessions_one:"{{count}} session \xb7 {{time}}",directorySessions_other:"{{count}} sessions \xb7 {{time}}",directoryCount_one:"{{count}} session",directoryCount_other:"{{count}} sessions",creating:"Creating",ignoreFolder:"Ignore folder {{name}}",ignoreTip:"Hide from regular folder lists",ignoredFolders:"Ignored folders",chooseOther:"Choose another folder",selectCurrent:"Select this folder",parentDirectory:"Back to parent folder",backRoots:"Back to drives or roots",refreshList:"Refresh this list",filterDefault:"Default",filterNoTools:"Hide tools",filterUserOnly:"User messages",filterLabeled:"Labeled",filterAll:"All",kindUser:"User",kindTool:"Tool",kindMessage:"Message",kindCompaction:"Summary",kindBranchSummary:"Branch summary",kindCustom:"Record",kindModel:"Model",kindThinking:"Thinking",kindSession:"Session",kindLabel:"Label",treeIntent:"Switch the current session branch",forkIntent:"Start a session from a user message",cloneIntent:"Clone the current session",runningTitle:"The current session is running",runningStop:"To continue “{{action}}”, the current response will stop. Saved messages remain available.",runningWait:"To continue “{{action}}”, wait for the running background task to finish.",confirming:"Working…",confirmContinue:"Confirm and continue",back:"Back",confirmHint:"Enter to confirm \xb7 Esc to go back",branchPicker:"Session branch picker",branchTitle:"Session branches",closeBranchPicker:"Close session branch picker",branchSearch:"Search session branches",branchSearchPlaceholder:"Search messages, tools or labels",branchFilter:"Filter session tree, current: {{filter}}",loadingEntry:"Loading full content…",entryEmpty:"No text available for this entry",entryTruncated:"Long content has been truncated.",selectEntry:"Select an entry to view its full content",branchWorking:"Stopping or waiting for the running task…",branchLoading:"Loading session tree…",branchEmpty:"No entries to select yet",branchNoMatches:"No matching session entries",branchTree:"Session tree",collapseBranch:"Collapse branch",expandBranch:"Expand branch",noPreview:"Nothing to preview",switchToMessage:"Switch to {{kind}} message",switch:"Switch",forkFromUser:"Start a session from this user message",branchShortcuts:"↑↓ Select \xb7 Tab Filter \xb7 ←→ Branch \xb7 Enter Switch \xb7 Esc Close"},conversation:l.W.en,projectFiles:c.C.en},"zh-CN":{...d.n["zh-CN"],errors:{invalidJson:"请求 JSON 格式无效",invalidClient:"客户端标识无效",invalidInput:"请求参数无效",sourceExpired:"聊天 Source 已过期",sessionMissing:"工作会话不存在",projectChanged:"工作会话项目已变化",projectMissing:"项目目录不存在",fileMissing:"文件或目录不存在",notDirectory:"目标不是目录",notFile:"目标不是文件",outsideProject:"目标不在当前项目目录内",textTooLarge:"文本文件超过 5MB,暂不支持在线预览",imageTooLarge:"图片过大,暂不支持在线预览",previewUnsupported:"当前文件类型不支持在线预览",fileReadFailed:"读取项目文件失败",revealFailed:"打开所在文件夹失败",repositoryMissing:"Git 仓库不存在",gitOutsideProject:"Git 目标不在当前项目目录内",gitReadFailed:"读取 Git 仓库失败",skillsInputInvalid:"Skills 请求参数无效",skillsContentTooLarge:"提交文本超过大小限制",skillsProjectChanged:"此项目已不在当前工作区,请重新选择项目",skillMissing:"Skill 或文件已不存在",skillsPermissionDenied:"没有权限读写此 Skill 文件",skillsFileFailed:"Skills 文件操作失败,请重试",chatSubscribeInvalid:"聊天订阅参数无效",chatSubscribeExpired:"聊天订阅绑定已过期",chatSubscribeFailed:"聊天订阅初始化失败",chatSendInvalid:"聊天发送参数无效",chatSendTooLarge:"聊天发送内容超过 31MB",chatInterruptInvalid:"聊天打断参数无效",chatCompactInvalid:"上下文压缩参数无效",chatReloadInvalid:"Pi 配置重载参数无效",chatRestoreInvalid:"恢复队列参数无效",chatRestoreTooLarge:"恢复内容超过传输上限",chatModelInvalid:"模型设置参数无效",chatModeInvalid:"能力模式参数无效",chatSourceBusy:"工作会话正在替换或切换分支",socketUnknownPath:"未知 WebSocket 路径",sessionsNotReady:"工作会话尚未初始化",sessionsInitializing:"工作会话正在初始化",sessionsInitializeInvalid:"工作会话初始化参数无效",sessionsInitializeFailed:"工作会话初始化失败",completionAckInvalid:"工作会话完成确认参数无效",completionAckFailed:"确认工作会话完成状态失败",capabilityFailed:"能力模式请求失败",capabilityRuleInvalid:"请检查模式规则",chatContextJsonInvalid:"系统上下文请求 JSON 格式无效",chatContextInvalid:"系统上下文请求参数无效",chatContextBusy:"当前会话正在运行,暂时无法查看系统上下文",chatContextFailed:"读取系统上下文失败",chatMessageInvalid:"消息详情参数无效",chatMessageMissing:"聊天消息不存在",chatMessageFailed:"查询聊天消息详情失败",chatImageInvalid:"聊天图片参数无效",chatImageMissing:"聊天图片不存在",chatImageFailed:"查询聊天图片失败",modelSettingsInvalid:"模型配置格式无效",modelCatalogInvalid:"模型目录参数无效",modelCatalogUnavailable:"模型参考目录暂不可用",modelSaveFailed:"保存模型配置失败",modelSettingsGetInvalid:"模型配置参数无效",modelSettingsGetFailed:"读取模型配置失败",projectDefaultInputInvalid:"项目目录参数无效",projectDefaultGetFailed:"读取项目默认模型失败",projectDefaultSaveInvalid:"项目默认模型格式无效",projectDefaultSaveFailed:"保存项目默认模型失败",modelsListFailed:"查询模型目录失败",directoryBrowseInvalid:"目录浏览参数无效",directoryMissing:"目录不存在或不是目录",directoryReadDenied:"无法读取目录",directoryBrowseFailed:"浏览服务端目录失败",workSessionCreateInvalid:"cwd 或 sessionId 无效",workSessionDirectoryMissing:"项目目录不存在或不是目录",historySessionMissing:"指定目录中不存在 Pi 会话",historySessionOccupied:"Pi 会话已经关联到其他工作会话",workSessionCreateFailed:"创建工作会话失败",workSessionReplaceInvalid:"替换会话参数无效",workSessionReplaceOccupied:"Pi 会话已绑定到其他工作会话",workSessionReplaceFailed:"替换 Pi 会话失败",workSessionRenameInvalid:"会话标题参数无效",workSessionRenameChanged:"工作会话已切换,请重新打开标题编辑",workSessionRenameFailed:"修改会话标题失败",workSessionDeleteInvalid:"workId 格式无效",workSessionDeleteFailed:"删除工作会话失败",workSessionSortInvalid:"workIds 或 pinnedCount 格式无效",workSessionOrderChanged:"工作会话列表已变化,请刷新后重试",workSessionSortFailed:"更新工作会话排列失败",sessionTreeInvalid:"会话树查询参数无效",sessionTreeChanged:"工作会话已切换,请重新打开会话树",sessionTreeFailed:"读取会话树失败",sessionTreeEntryInvalid:"会话树节点参数无效",sessionTreeEntryMissing:"会话树节点不存在或已失效",sessionTreeEntryFailed:"读取会话树节点详情失败",branchInputInvalid:"分支操作参数无效",branchEntryMissing:"分支节点不存在或已失效",branchForkUserOnly:"只有用户消息可以 Fork",branchCloneEmpty:"当前会话还没有可克隆的消息",branchFailed:"执行分支操作失败",taskDetailInvalid:"任务详情参数无效",taskSourceChanged:"工作会话来源已变化",taskMissing:"任务不存在",taskDetailUnsupported:"任务不支持会话详情",taskMessageMissing:"任务消息不存在",taskMessageNoDetail:"任务消息没有详情",taskConversationUnavailable:"任务会话暂不可用",taskMessageFailed:"查询任务消息详情失败",taskImageMissing:"任务图片不存在",taskImageFailed:"查询任务图片失败",refreshInvalid:"forceRefresh 格式无效",piDirectoriesFailed:"查询 Pi 目录失败",ignoredDirectoriesFailed:"查询忽略目录失败",directoryIgnoreInvalid:"忽略目录参数无效",directoryIgnoreFailed:"更新忽略目录失败",historyQueryInvalid:"历史会话查询参数无效",historyQueryFailed:"查询 Pi 历史会话失败",userMessagesInvalid:"用户消息参数无效",piSessionMissing:"Pi 会话不存在",userMessagesFailed:"查询历史用户消息失败",projectJsonInvalid:"项目请求 JSON 格式无效",projectInputInvalid:"项目请求参数无效",projectCwdAbsolute:"项目目录必须是绝对路径",projectOperationFailed:"项目操作失败",capabilityGetInvalid:"能力模式查询参数无效",capabilityGetFailed:"读取能力模式失败",capabilityReplaceInvalid:"能力模式格式无效",capabilityReplaceFailed:"保存能力模式失败",pluginResourceMissing:"插件资源不存在",pluginResourceReadFailed:"读取插件资源失败",hostResourceMissing:"Host 公共插件资源不存在",hostRuntimeUnavailable:"Host 公共插件 Runtime 尚未构建",hostResourceReadFailed:"读取 Host 公共插件资源失败",gitAddJsonInvalid:"新建 Git 分支请求 JSON 格式无效",gitAddInputInvalid:"新建 Git 分支请求参数无效",gitAddFailed:"新建 Git 分支失败",gitSwitchJsonInvalid:"Git 分支切换请求 JSON 格式无效",gitSwitchInputInvalid:"Git 分支切换请求参数无效",gitSwitchFailed:"切换 Git 分支失败",gitReadOperationFailed:"读取 Git 失败",pluginNpmRootUnavailable:"Pi Package npm 根不可用:{{detail}}",pluginNpmRootMissingDeclarations:"Pi Package 配置与 npm 根不一致(缺少声明:{{declarations}})",pluginNpmRootMissingFolders:"Pi Package 配置与 npm 根不一致(缺少目录:{{folders}})",pluginNpmRootMissingBoth:"Pi Package 配置与 npm 根不一致(缺少声明:{{declarations}};缺少目录:{{folders}})",pluginReloadBlocked:"工作会话 {{workId}} 阻止插件重载:{{reason}}",pluginRuntimeBusy:"插件运行时仍有调用正在执行",pluginRestartPending:"已有插件操作需要重启完成",pluginRestartUnavailable:"当前启动方式不支持自动重启 Pi Desk",pluginNotFound:"插件不存在:{{source}}",pluginSourceInvalid:"插件来源无效"},auth:{title:"登录 Pi Desk",subtitle:"继续你的工作会话",protection:"登录保护",enabled:"已启用",disabled:"未启用",publicAccess:"任何能够访问此服务的人都可以进入工作台。",changePassword:"修改密码",setPassword:"设置密码",newPassword:"新密码",passwordHint:"12–64 个字符,至少包含大写字母、小写字母、数字、符号中的三类;不能有首尾空白、换行或不可见控制字符。",generatePassword:"生成密码",generatePasswordHint:"随机生成 16 位密码",generatePasswordFailed:"生成密码失败,请重试。",saveEffect:"请妥善保存密码。保存后,所有设备都需要重新登录。",enable:"启用登录保护",saveAndSignIn:"保存并重新登录",saving:"正在保存…",logout:"退出登录",signingOut:"正在退出…",logoutFailed:"退出登录失败,请稍后重试。",logoutInvalid:"退出登录参数无效。",logoutCrossOriginDenied:"不允许跨站退出登录。",disable:"关闭保护",disableTitle:"关闭登录保护?",disableDescription:"关闭后,任何能够访问此服务的人都可以直接进入工作台。是否继续?",recovery:"忘记密码?",recoveryDescription:"在运行服务的设备上删除下面的文件,然后刷新页面,即可恢复访问。",settingsFailed:"登录保护设置处理失败。",settingsInvalid:"密码不符合要求,请按输入框下方的规则调整。",configUnavailable:"登录保护配置无法读取,请修复配置或删除 auth.json 后重新设置。",crossOriginDenied:"不允许跨站修改登录保护。",password:"密码",submit:"登录",submitting:"正在登录",loginFailed:"登录失败",invalidResponse:"登录服务响应无效",invalidCredentials:"登录失败,请检查登录信息后重试。",invalidInput:"登录失败,请检查登录信息后重试。",unavailable:"登录暂不可用,请稍后重试。",tooManyAttempts:"登录尝试过多,请稍后重试。",loginAlertTitle:"登录异常提醒",loginAlertDescription:"登录已连续失败超过 5 次,请确认是否为本人操作。",invalidClient:"客户端标识无效"},capabilityModes:{saved:"能力模式已保存",saving:"保存中…",saveModes:"保存模式",settings:"能力模式设置",editMode:"编辑模式",selectMode:"选择要编辑的能力模式",unnamedMode:"未命名模式",allDefault:"全开 \xb7 默认",addMode:"新增模式",copyMode:"复制当前模式",copyTitle:"复制模式",deleteMode:"删除当前模式",deleteTitle:"删除模式",refreshCatalog:"刷新能力选项",retryRead:"重试读取",loadingCatalog:"正在读取能力选项…",allEnabled:"全开",allDescription:"使用全部已加载能力。",unsaved:"有未保存的修改",allIsDefault:"全开为默认模式",policyAll:"全部开启",policyAllow:"只开这些",policyDeny:"关闭这些",policyNone:"全部关闭",ruleEditor:"{{name}}规则编辑",ruleMode:"{{name}}开放方式",exclusions:"排除项",ruleSearch:"搜索或输入能力规则",ruleSearchPlaceholder:"搜索名称或输入 * 规则",clearSearch:"清空规则搜索",selectedOnly:"仅看已选",selectedShort:"已选",allowRules:"允许规则",excludeRules:"排除规则",selectedCount_one:"已选 {{count}} 条",selectedCount_other:"已选 {{count}} 条",selectVisible:"全选可见项",clearSelected:"清空已选",addRule:"添加规则",allowValue:"允许 {{name}}",excludeValue:"排除 {{name}}",pattern:"匹配规则",noMatches:"没有匹配项,可直接添加上面的规则。",noSelection:"尚未选择规则。",enterPattern:"输入名称或通配规则即可添加。",moreRules:"显示更多 \xb7 剩余 {{count}} 项",deleteConfirm:"删除能力模式?",saveConfirm:"保存模式修改?",deleteDescription:"删除“{{name}}”并保存后,使用此模式的会话将切回全开。",unsavedDescription:"能力模式的修改尚未保存。",cancel:"取消",delete:"删除模式",discard:"放弃修改",saveContinue:"保存并继续",modeName:"模式名称",category:"能力分类",groupTools:"工具",modeSwitching:"切换中…",modePicker:"能力模式:{{name}}",catalogFailed:"读取能力选项失败",saveFailed:"保存能力模式失败",copySuffix:"{{name}} 副本",newMode:"新模式"},pluginManagement:{actionAdd:"安装插件",actionUpdate:"更新插件",actionDelete:"卸载插件",actionReload:"重启 Pi Desk",restartNormal:"重启并启用插件",restartNormalDescription:"重启 Pi Desk 并重新加载外部插件,完成后恢复所有连接。",applyChanges:"加载变更",applyDescription:"更新插件服务和界面;已有会话扩展保持不变,手动重载 PI 后更新。",reloadOne:"重新加载",reloadSource:"重新加载 {{name}}",basicModeNotice:"基础模式已关闭插件加载与盘点。可以继续聊天修复文件,再选择“重启并启用插件”。",localExtension:"本地源码",localSourceHelp:"在源目录管理此入口",discovered:"已启用",disabledByPi:"已停用",active:"已启用",notLoaded:"未加载",phase_queued:"排队中",phase_checking:"检查中",phase_applying:"应用中",phase_waiting:"等待生效",phase_failed:"操作失败",updateCheckFailed:"检查插件更新失败",actionFailed:"{{action}}失败",retrying:"重试 {{name}}",retryFailed:"重试插件界面失败",refreshingEntries:"刷新插件界面",refreshEntriesFailed:"刷新插件界面失败",detailFailed:"读取插件详情失败",title:"插件",description:"管理插件包与本地扩展。",noPluginDescription:"暂无说明",checkUpdates:"检查更新",checkingUpdates:"检查中…",restartApply:"重启并完成",installPlugin:"安装插件",source:"插件来源",sourcePlaceholder:"npm Package、Git 地址或本地目录",install:"安装",installVersion:"安装此版本",installIncompatible:"此插件版本不兼容当前 Pi Desk,无法安装。",pendingRestart:"插件变化待重启生效",retry:"重试",confirmAction:"确认{{action}}?",restartDescription:"重启 Pi Desk 以应用待处理变更,完成后自动恢复连接。",cancel:"取消",installed:"已安装插件",loading:"正在读取插件",updateAvailable:"可更新",abnormal:"异常",capabilityCategories:"插件能力类别",update:"更新",details:"详情",viewDetails:"查看插件详情:{{name}}",remove:"卸载",empty:"暂无插件",viewLoading:"正在加载插件界面…",viewFailed:"插件界面加载失败",closeApplication:"关闭插件应用",closeNamedApplication:"关闭 {{name}}",eventAgentStart:"任务开始前",eventAgentStartDescription:"具备追加或替换系统提示词、注入会话消息的能力。",eventContext:"模型调用前",eventContextDescription:"具备替换本次发送给模型的会话消息的能力。",eventInput:"用户输入阶段",eventInputDescription:"具备改写、拦截或接管用户输入的能力。",eventProvider:"Provider 请求前",eventProviderDescription:"具备替换最终 Provider Payload 的能力。",eventToolCall:"工具调用前",eventToolCallDescription:"具备修改工具参数或阻止工具调用的能力。",eventToolResult:"工具结果后",eventToolResultDescription:"具备修改进入后续模型上下文的工具结果的能力。",eventMessageEnd:"消息完成后",eventMessageEndDescription:"具备替换最终消息并影响后续上下文的能力。",eventBeforeCompact:"上下文压缩前",eventBeforeCompactDescription:"具备取消压缩或替换压缩摘要的能力。",contributionApplication:"应用入口",contributionComposer:"输入面板",contributionSettings:"设置页",contributionMessage:"消息视图",contributionSidebar:"会话侧栏",tagTools:"工具 {{count}}",tagFixed:"固定提示 {{count}}",tagDynamic:"动态影响 {{count}}",tagOverride:"替换内置 {{count}}",tagManual:"手动提示 {{count}}",tagInteraction:"交互 {{count}}",unknown:"未知",stateActive:"启用",stateInactive:"未启用",stateShadowed:"被覆盖",copied:"已复制",copy:"复制",copyNamed:"复制{{name}}",dynamicTitle:"动态上下文能力",dynamicDescription:"以下内容表示插件注册了对应运行时钩子,不代表每次调用都实际修改了提示词或消息。",arguments:"调用参数",none:"无",required:"必填",optional:"可选",noArguments:"该 Tool 不需要参数。",rawSchema:"原始 Schema",toolCapabilities:"工具能力",toolDescription:"每个 Tool 同时展示能力说明、调用参数及其声明的系统提示词。",overridesBuiltin:"替换 Pi 内置工具",noDescription:"未提供能力说明",systemPrompts:"系统提示词",inactivePrompt:"当前 Tool 未启用,不会进入系统提示词",truncated:"正文超过 64KB,当前显示前 64KB。",resourcesTitle:"Skill 与提示模板",resourcesDescription:"可由模型调用的 Skill 只会常驻名称、描述和位置,完整正文按需读取;Prompt 模板仅在用户手动调用后展开。",skillModelVisible:"描述进入系统提示词",manualOnly:"仅手动调用",skillMetadata:"系统提示词中的 Skill 元数据",viewSkillContent:"查看 Skill 正文",viewPromptContent:"查看 Prompt 正文",otherCapabilities:"其他能力",messageDeclarations:"消息声明:",backToList:"返回插件列表",incompleteCapabilities:"能力清单读取不完整:{{error}}",metricToolDefinitions:"工具定义",metricFixed:"当前固定提示",metricDynamic:"动态影响钩子",metricManual:"手动提示资源",loadingFullDetails:"正在读取完整能力详情",installedTab:"已安装",searchPlugins:"搜索插件",directInstall:"手动安装",advancedOptions:"高级选项",capabilityDetails:"功能与运行信息",newVersion:"新版本 v{{version}}",removeNamed:"卸载 {{name}}",updateAll:"全部更新({{count}})",batchManage:"批量管理",finishSelection:"完成",selectAll:"全选",filterStatus:"插件状态",statusFilter_all:"全部状态",statusFilter_updates:"有更新",statusFilter_disabled:"已停用",statusFilter_failed:"异常",batchWaiting:"尚未提交,请完成等待中的操作后重试。",batchInstall:"批量安装",batchSourcePlaceholder:"每行一个 npm 包名;单项也可填写 Git 地址或本地目录",batchNpmOnly:"批量安装时请每行填写一个 npm 包名。",batchLimit:"每次批量操作最多选择 32 个插件。",batchFailed:"提交插件变更失败",sourceBusy:"此插件正在处理其他操作,完成后可重试。",selectFiltered:"全选当前结果",selectPlugin:"选择 {{name}}",selectedCount:"已选 {{count}} 项",clearSelection:"清空选择",checkSelected:"批量检查",updateSelected:"更新所选",removeSelected:"卸载所选",setChannel:"设置渠道",installChannel:"版本偏好",defaultChannel:"默认",automaticVersion:"默认版本",allChannels:"全部渠道",filterChannel:"按渠道筛选",channelLatest:"稳定版",channelDev:"开发版",followingChannel:"跟随 {{tag}}",targetVersion:"目标版本 {{version}}",itemCheckFailed:"查询更新失败:{{error}}",filterInstalled:"搜索已安装插件",noMatches:"没有匹配的插件",enabled:"已启用",disabled:"已停用",enable:"启用",disable:"停用",togglePlugin:"启用或停用 {{name}}",submitting:"正在提交…",installing:"安装中…",alreadyInstalled:"已安装",retryView:"重试插件界面",more:"更多",downloadSource:"下载源",installDownloadSource:"本次安装下载源",useDefaultSource:"使用已保存的默认设置",download_local:"不使用源(本机配置)",download_auto:"自动",download_domestic:"国内加速",download_official:"官方",download_custom:"自定义",registryUrl:"仓库地址",sourceDetails:"查看来源地址",recommending:"正在推荐来源…",saving:"正在保存…",save:"保存",settingsFailed:"保存或读取下载设置失败",invalidRegistry:"请输入有效的 HTTP 或 HTTPS 仓库地址,不包含账号、查询参数或片段。",searchPlaceholder:"搜索插件名称或简介",searchSource:"搜索仓库",publicNpm:"npm 公开仓库",customSearchSource:"自定义仓库",searchRegistryUrl:"搜索仓库地址",pluginKind:"插件类型",kind_all:"全部类型",kind_desk:"Pi Desk",kind_pi:"Pi",kind_unknown:"类型待确认",official:"官方",publisher:"发布者",unknownPublisher:"未提供发布者",searchFailed:"搜索插件失败",searching:"正在搜索…",noSearchResults:"没有匹配的插件,可以换个关键词。",loadMore:"加载更多",loadingPackage:"正在读取包详情…",readPackage:"读取包详情",version:"版本",packageName:"插件包",readme:"使用说明",noReadme:"未提供使用说明",readmeLanguage:"语言",defaultLanguage:"自动 / 原文",compatible:"兼容当前版本",incompatible:"不兼容当前版本",compatibilityUnknown:"兼容性待确认",homepage:"官网",repository:"源码",removeDescription:"卸载此插件,保留已保存的配置和数据。",thirdPartyDescription:"此插件能够在你的电脑上执行代码。请确认信任其发布者和来源后再安装。",confirmChange:"应用此插件变更。",fromSource:"以来源提供的版本为准",pluginDetails:"插件详情",pluginRemoved:"此插件已不在安装列表中。",close:"关闭"},projectHistory:o,settings:{title:"设置",general:"通用设置",workCapabilities:"工作能力",application:"应用",category:"设置分类",appearance:"外观",region:"语言与地区",habits:"习惯",loginProtection:"登录",models:"模型",mcpSettings:"MCP",capabilityModes:"能力模式",skills:"Skills",plugins:"插件",pluginSettings:"插件设置",about:"关于",language:"语言",timeZone:"时区",currentLanguage:"当前语言:{{locale}}",currentTimeZone:"当前时区:{{timeZone}}",timeExample:"当前时间",searchTimeZones:"搜索时区",reloadLanguage:"重新加载以使用该语言",version:"当前版本",versionUpdated:"版本更新时间",webDescription:"Pi 的 Web 端",discardModelTitle:"模型配置尚未保存",discardModelDescription:"要丢弃尚未保存的模型配置吗?",discardModelConfirm:"丢弃修改",theme:"界面主题",themeLight:"浅色",themeDark:"深色",displaySize:"显示大小",sizeCompact:"紧凑",sizeStandard:"标准",sizeLarge:"大号",displayPreview:"界面预览",displayPreviewContent:'## 项目进展\n\n今天整理了工作计划,接下来继续完成待办事项。\n\n```ts\nconst status = "ready"\n```',browserOnly:"设置仅在当前浏览器生效。",newSessionBehavior:"新建会话后的行为",behaviorNone:"无操作",behaviorNoneDescription:"创建后保留当前会话。",behaviorActivate:"切换到新会话",behaviorActivateDescription:"创建后立即进入新会话。",behaviorPin:"自动固定",behaviorPinDescription:"固定新会话,保留当前活跃会话。",desktopOnlyBehavior:"仅桌面端生效;移动端始终进入新会话。",imagePreviewMode:"图片预览方式",imageCompressed:"压缩预览",imageCompressedDescription:"优化大图以减少流量,不修改项目原文件。",imageOriginal:"原图预览",imageOriginalDescription:"保留原始画质,加载大图会消耗更多流量。",imagePreviewApply:"更改后对新加载或主动重新加载的图片生效。",modelProviders:"模型管理",modelPresets:"常用组合",serviceAddress:"服务地址",serviceKey:"访问密钥",serviceId:"服务 ID",serviceIdInvalid:"请填写非空且不重复的服务 ID。",serviceConnection:"服务连接",serviceSettingsNamed:"{{name}}连接设置",currentServiceSettings:"当前服务连接设置",modelAddToService:"在{{name}}添加模型",inheritService:"继承服务设置",inheritServiceValue:"继承服务:{{value}}",applyServiceDraft:"应用到草稿",serviceDraftScope:"供 {{count}} 个模型使用,应用后在主页面保存模型配置。",discardServiceTitle:"连接修改尚未应用",discardServiceDescription:"要丢弃这次连接修改吗?",selectModelToEdit:"选择一个模型进行编辑",backModelList:"返回模型列表",modelIdRequired:"请填写模型 ID。",modelNameRequired:"请填写显示名称。",capacityInvalid:"请输入大于 0 的数值,最多保留三位小数。",priceInvalid:"请输入不小于 0 的数值。",inputAndThinking:"输入与思考",addModelPreset:"加入常用组合",saveBeforePreset:"保存模型后可加入常用组合。",modelDraftPending:"配置有未保存修改",modelDraftClean:"没有未保存的修改",fixModelInputs:"请先修正模型字段,再保存配置",revertModels:"撤销配置修改",modelMoreActions:"模型配置操作",nativeConfig:"Pi 配置",nativeConfigEditor:"Pi 模型配置",nativeConfigScope:"编辑完整 models.json,包括 modelOverrides、inputLimits、promptCache、samplingParams 与阶梯费率。",nativeProtectDraft:"请先保存或撤销表单修改,再打开 Pi 配置。",saveNativeConfig:"保存 Pi 配置",discardNativeTitle:"Pi 配置尚未保存",discardNativeDescription:"要丢弃这次 Pi 配置修改吗?",projectDefault:"项目默认",loadingModels:"加载模型设置…",modelsUnavailable:"模型设置暂不可用",modelsLoadFailed:"模型设置加载失败",catalogCached:"刷新失败,继续使用上次模型目录缓存。",catalogPartial:"模型目录已部分更新,失败来源继续使用缓存。",catalogUnchanged:"模型目录已经是最新。",catalogUpdated:"模型目录已更新。",catalogRefreshFailed:"模型目录刷新失败",modelsNoChanges:"没有需要保存的模型配置。",removeInvalidPresetsTitle:"删除失效的常用组合?",removeInvalidPresets_one:"有 {{count}} 个常用组合引用了已删除模型,保存配置将同时删除这些组合。",removeInvalidPresets_other:"有 {{count}} 个常用组合引用了已删除模型,保存配置将同时删除这些组合。",removeAndSave:"删除并保存",replaceProjectDefaultsTitle:"同步项目默认模型",replaceProjectDefaultsDescription:"以下项目的默认模型将替换为本次设置的新模型,确认后一起保存。",confirmAndSaveModels:"确认并保存",modelSaved:"模型配置已保存。",modelSaveFailed:"模型配置保存失败",catalogUpdatedAt:"参考目录更新于 {{time}}",catalogUnavailable:"参考目录尚未可用",refreshingCatalog:"刷新中…",refreshCatalog:"刷新模型目录",savingModels:"保存中…",saveModels:"保存模型配置",thinkingOff:"关闭",thinkingMinimal:"极少",thinkingLow:"低",thinkingMedium:"中",thinkingHigh:"高",thinkingXhigh:"超高",thinkingMax:"最大",priceMissing:"价格未提供",priceInput:"输入 {{price}}",priceOutput:"输出 {{price}}",priceCacheRead:"缓存 {{price}}",priceCacheWrite:"缓存写 {{price}}",perMillionTokens:" / 百万 Token",catalogSearchFailed:"查询模型目录失败",catalogSelected:"已选择 {{provider}} 的 {{model}}。",modelId:"模型 ID",modelIdSearch:"输入模型 ID 搜索并选择",chooseModel:"选择或切换模型",matchingCatalog:"正在匹配模型目录…",noCatalogMatches:"没有匹配的目录模型",officialRecommended:"官方推荐",sameConfiguration:"同配置 \xd7{{count}}",contextAndOutput:"{{context}} 上下文 \xb7 {{output}} 输出",contextAndOutputTitle:"上下文 {{context}} Token,最大输出 {{output}} Token",moreConfigurations:"查看其余 {{count}} 种配置",modelName:"显示名称",contextLength:"上下文容量",maximumOutput:"每次最多输出",capabilities:"能力",textInput:"文本输入",imageInput:"图片输入",supportsThinking:"支持思考",thinkingMapping:"思考等级与服务映射",providerMapping:"{{level}} 服务映射",noMapping:"无需映射",price:"价格",inputPrice:"输入价格 / 百万 Token",outputPrice:"输出价格 / 百万 Token",cacheReadPrice:"缓存读取价格",cacheWritePrice:"缓存写入价格",clearPrice:"清除价格配置",advancedCompatibility:"高级配置",apiOverride:"单独调用方式",baseUrlOverride:"单独服务地址",inheritProvider:"留空继承 Provider",developerRole:"支持 Developer Role",replayReasoning:"回放 reasoning_content",modelHeaders:"模型请求头",headerPlaceholder:"Header-Name: value,每行一个",useDefault:"使用默认",yes:"是",no:"否",providerNew:"添加服务连接",accountCustomApi:"自定义 API",accountLogin:"登录",accountRelogin:"重新登录",accountLogout:"退出登录",accountLogoutTitle:"退出这个服务的登录?",accountLogoutDescription:"退出“{{name}}”后,该账号模型在重新登录前将不可用。保留已收录模型与配置草稿,不切换当前会话。",accountLogoutFailed:"退出登录失败",accountCustomSettings:"自定义 API 设置",accountCustomModel:"自定义模型",accountChooseProvider:"选择服务商",accountLoadingProviders:"加载服务商…",accountNoProviders:"暂无可登录的服务商",accountChooseOption:"请选择",accountContinue:"继续",accountWaiting:"等待授权…",accountLoggedIn:"已登录",accountLoggedOut:"未登录",accountLoginFailed:"登录失败",accountRefreshFailed:"登录成功,但模型列表刷新失败",accountDisconnected:"连接已断开,本次登录已取消。连接恢复后请重新登录。",accountConnectionNotReady:"连接尚未就绪,请在连接恢复后重试。",accountDeviceCode:"授权码",accountCopyCode:"复制授权码",accountOpenLink:"打开授权页面",accountCopyLink:"复制链接",accountInvalidLink:"授权链接不是有效的网页地址。",accountCopied:"已复制",accountCopyFailed:"复制失败",accountModelSearch:"搜索模型名称或 ID",accountModelAdded:"已添加",accountNoModels:"没有匹配的模型",accountAddLater:"稍后添加",accountAddSelected:"添加选中的 {{count}} 个",accountModelUnavailable:"服务目录中已没有这个模型,可以从配置中移除。",accountModelUnavailableShort:"不可用",accountSubscription:"订阅",accountReferencePrice:"参考价格",accountAdjustParameters:"调整参数",accountRestoreDefaults:"恢复默认",accountRemove:"移除模型",accountRemoveTitle:"移除模型?",accountRemoveDescription:"将“{{name}}”从模型列表移除,保存配置后生效,不会退出账号登录。",providerUnnamed:"等待填写服务 ID",providerList:"模型服务",providerSummary:"{{providers}} 个 \xb7 {{models}} 个模型",providerConfig:"Provider 配置",providerEmpty:"还没有配置服务",providerModels:"{{count}} 个自定义模型",providerDelete:"删除服务",providerDeleteTitle:"删除服务?",providerDeleteDescription:"将移除“{{name}}”及其 {{count}} 个模型,保存配置后生效。",modelDeleteTitle:"删除模型?",modelDeleteDescription:"将移除“{{name}}”,保存配置后生效。",providerIdExample:"例如 my",providerApiType:"默认调用方式",providerAdvanced:"高级连接设置",providerAuthHeader:"自动添加 Authorization Header",providerHeaders:"服务请求头",modelsHeading:"模型",modelAdd:"添加模型",modelEmpty:"还没有模型",modelUnnamed:"未命名模型",modelIdPending:"等待填写模型 ID",modelDelete:"删除模型",modelDeleteNamed:"删除模型 {{name}}",presetDescription:"聊天中快速选择的模型与思考等级组合,拖拽或按钮可调整顺序。",presetDrag:"拖拽排序",presetMoveUp:"上移常用组合",presetMoveDown:"下移常用组合",presetModel:"常用模型",presetModelNew:"新增常用模型",modelSearch:"搜索模型名称、服务 ID 或模型 ID",thinkingLevel:"思考等级",presetThinking:"常用思考等级",presetThinkingNew:"新增组合的思考等级",presetColor:"颜色",presetColorLabel:"常用组合颜色",presetColorNone:"无颜色",presetColorCustom:"自定义颜色",presetColorBlue:"蓝色",presetColorCyan:"青色",presetColorGreen:"绿色",presetColorAmber:"琥珀色",presetColorOrange:"橙色",presetColorRed:"红色",presetColorPink:"粉色",presetColorPurple:"紫色",presetDelete:"删除常用组合",presetAdd:"添加",presetEmpty:"还没有常用组合",projectSessionCount_one:"{{count}} 个会话",projectSessionCount_other:"{{count}} 个会话",projectDirectoriesFailed:"项目目录加载失败",projectDefaultFailed:"项目默认模型加载失败",projectDefaultSaved:"项目固定默认模型已保存。",projectDefaultGlobalSaved:"项目已恢复跟随 Pi 全局当前值。",projectDefaultSaveFailed:"项目默认模型保存失败",projectLoading:"加载项目配置…",projectDescription:"项目配置优先于 Pi 全局当前值,普通模型切换不会修改这里。",projectEmpty:"没有找到已有 Pi 会话的项目目录",project:"项目",projectSearch:"搜索项目路径",projectList:"项目列表",backProjectList:"返回项目列表",selectProjectToConfigure:"选择项目配置默认模型",projectDefaultSource:"项目默认模型来源",projectFollowGlobal:"跟随 Pi 全局当前值",projectFollowGlobalDescription:"不单独设置这个项目的默认模型。",projectFixed:"固定项目默认",projectFixedDescription:"为这个项目指定模型和思考等级。",projectDefaultModel:"默认模型",projectDefaultThinking:"项目默认思考等级",fromPreset:"从常用组合选择",saveProjectDefault:"保存项目默认"},skills:r.P["zh-CN"],taskCenter:n.U["zh-CN"],workbench:a.R["zh-CN"],workbenchPicker:{sessionFallback:"会话 {{id}}",newSession:"新会话",scopeTitle:"标题",scopeUser:"用户消息",scopeAssistant:"AI 回复",scopeUserMatches:"用户消息 {{count}}",scopeAssistantMatches:"AI 回复 {{count}}",loadUserFailed:"加载用户消息失败",ignoredRestoreTitle:"恢复忽略目录",browseOtherTitle:"选择项目目录",replaceTitle:"替换工作会话",createTitle:"新建工作会话",ignoredRestoreDescription:"恢复后,该项目会重新出现在所有普通目录列表中。",browseDescription:"浏览运行 Pi Desk 的服务端文件系统,选择项目工作目录。",replaceDescription:"将替换到:{{project}} \xb7 {{session}}",replaceMissingDescription:"替换目标已失效,请关闭后重新选择工作会话。",createDescription:"选择已有 Pi 项目,或浏览服务端目录创建新的工作会话。",searchHistory:"搜索历史会话",searchBrowser:"搜索当前层级的目录",searchIgnored:"搜索已忽略目录",searchProjects:"搜索项目名称或完整路径",currentProject:"当前项目:{{path}}",ignoredCount_one:"{{count}} 个已忽略目录",ignoredCount_other:"{{count}} 个已忽略目录",rootChoose:"选择磁盘或根目录",root:"磁盘或根目录",replaceChooseFirst:"选择项目后查看可替换的历史会话。",regularExcludesIgnored:"普通目录列表已自动排除忽略项目。",loadingHistory:"正在加载历史会话…",loadingIgnored:"正在加载忽略目录…",loadingBrowser:"正在浏览服务端目录…",loadingProjects:"正在加载 Pi 项目…",backFolders:"返回目录列表",pastePath:"粘贴完整目录路径后按 Enter",fullPath:"完整目录路径",openTyped:"打开输入的目录",enterAbsolute:"请输入绝对目录路径",open:"打开",absoluteExample:"请输入绝对目录路径,例如 C:\\projects\\example。",pasteHint:"可直接粘贴完整路径并打开;兼容 Windows“复制为路径”。",searchScopes:"搜索范围",replaceTargetMissing:"替换目标已失效,无法继续替换。",noHistoryMatches:"没有匹配的历史会话",noReplaceHistory:"当前项目没有可替换的历史会话",sessionFound_one:"找到 {{count}} 个会话",sessionFound_other:"找到 {{count}} 个会话",sessionMessages:"{{users}}/{{total}} 条消息 \xb7 {{time}}",replacing:"替换中",current:"当前",alreadyUsed:"已使用",targetUnavailable:"目标失效",replace:"替换",currentBound:"当前工作会话已绑定此历史会话",historyUsed:"该历史会话已被其他工作会话占用",replaceTargetUnavailable:"替换目标已失效",replaceWith:"替换为 {{name}}",hideUserMessages:"收起用户消息",viewMatching_one:"查看全部 {{count}} 条匹配",viewMatching_other:"查看全部 {{count}} 条匹配",viewUserMessages_one:"查看 {{count}} 条用户消息",viewUserMessages_other:"查看 {{count}} 条用户消息",viewMatch:"查看{{label}}",matchingUserCount:"匹配的用户消息 {{count}} 条",userCount:"用户消息 {{count}} 条",viewAll:"查看全部",noUserMessages:"没有可展示的用户消息",noText:"(无文字内容)",loadMore:"加载更多",browserEmpty:"当前目录没有可浏览的子目录,可直接选择当前目录",rootsEmpty:"没有可浏览的磁盘或根目录",subfoldersNoMatches:"没有匹配的子目录",ignoredEmpty:"没有已忽略的 Pi 项目",projectsEmpty:"没有可选择的 Pi 项目",projectNoMatches:"没有匹配的 Pi 项目",restoreFolder:"恢复目录 {{name}}",restoreTip:"恢复到普通目录列表",restore:"恢复",directorySessions_one:"{{count}} 个会话 \xb7 {{time}}",directorySessions_other:"{{count}} 个会话 \xb7 {{time}}",directoryCount_one:"{{count}} 个会话",directoryCount_other:"{{count}} 个会话",creating:"创建中",ignoreFolder:"忽略目录 {{name}}",ignoreTip:"从所有普通目录列表中隐藏",ignoredFolders:"已忽略目录",chooseOther:"选择其他目录",selectCurrent:"选择当前目录",parentDirectory:"返回上一级目录",backRoots:"返回磁盘或根目录",refreshList:"刷新当前列表",filterDefault:"默认",filterNoTools:"无工具",filterUserOnly:"仅用户",filterLabeled:"有标签",filterAll:"全部",kindUser:"用户",kindTool:"工具",kindMessage:"消息",kindCompaction:"压缩",kindBranchSummary:"摘要",kindCustom:"记录",kindModel:"模型",kindThinking:"思考",kindSession:"会话",kindLabel:"标签",treeIntent:"切换当前会话分支",forkIntent:"从用户消息新开会话",cloneIntent:"克隆当前会话",runningTitle:"当前工作会话正在运行",runningStop:"继续“{{action}}”会先停止当前响应。已保存的消息会保留。",runningWait:"继续“{{action}}”会等待当前后台任务结束。",confirming:"正在处理…",confirmContinue:"确认并继续",back:"返回",confirmHint:"Enter 确认 \xb7 Esc 返回",branchPicker:"会话分支选择器",branchTitle:"会话分支",closeBranchPicker:"关闭会话分支选择器",branchSearch:"搜索会话分支",branchSearchPlaceholder:"搜索消息、工具或标签",branchFilter:"过滤会话树,当前:{{filter}}",loadingEntry:"正在读取完整内容…",entryEmpty:"该节点没有可展示的文字内容",entryTruncated:"内容较长,已截断显示。",selectEntry:"从树中选择一条记录查看完整内容",branchWorking:"正在停止或等待当前运行并执行操作…",branchLoading:"正在读取会话树…",branchEmpty:"当前会话还没有可选择的节点",branchNoMatches:"没有匹配的会话节点",branchTree:"会话树",collapseBranch:"收起分支",expandBranch:"展开分支",noPreview:"无可预览文字",switchToMessage:"切换到{{kind}}消息",switch:"切换",forkFromUser:"从这条用户消息新开会话",branchShortcuts:"↑↓ 选择 \xb7 Tab 筛选 \xb7 ←→ 分支 \xb7 Enter 切换 \xb7 Esc 关闭"},conversation:l.W["zh-CN"],projectFiles:c.C["zh-CN"]}};function tg({children:e,initialSettings:t}){return(0,s.jsx)(h.rg,{children:(0,s.jsx)(u.Zi,{children:(0,s.jsx)(m,{children:(0,s.jsx)(f.A,{resources:tp,initialSettings:t,children:(0,s.jsxs)(y.c,{children:[(0,s.jsx)(b,{}),(0,s.jsx)(tu,{children:(0,s.jsx)(w.Bc,{children:e})})]})})})})})}},84178:()=>{}},e=>{e.O(0,[81966,43579,78923,96995,46270,39654,3814,74220,75130,31087,4904,64444,77358],()=>e(e.s=48923)),_N_E=e.O()}]);
|