@jetcrab/pi-desk 1.1.12 → 1.1.16-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/docs/plugins.md +21 -1
  2. package/package.json +2 -2
  3. package/src/app/api/model-settings/preview/route.ts +1 -0
  4. package/src/app/api/work-sessions/rename/route.ts +1 -0
  5. package/src/client/l2_biz/auth/l2-login.tsx +1 -1
  6. package/src/client/l2_biz/plugin-host/l2-plugin-session-sidebar-tab.tsx +6 -2
  7. package/src/client/l2_biz/settings/hooks/l2-use-model-provider-settings.ts +54 -10
  8. package/src/client/l2_biz/settings/hooks/l2-use-model-settings.ts +37 -9
  9. package/src/client/l2_biz/settings/l2-auth-settings.tsx +1 -1
  10. package/src/client/l2_biz/settings/l2-model-settings-biz.ts +26 -12
  11. package/src/client/l2_biz/settings/views/l2-appearance-settings.tsx +1 -16
  12. package/src/client/l2_biz/settings/views/l2-model-provider-settings.tsx +3 -2
  13. package/src/client/l2_biz/settings/views/l2-model-replacement-preview.tsx +34 -0
  14. package/src/client/l2_biz/task-center/l2-task-center.tsx +4 -30
  15. package/src/client/l2_biz/workbench/file-workspace/l2-plugin-standalone-file-preview.tsx +45 -7
  16. package/src/client/l2_biz/workbench/hooks/l2-work-session-rename.ts +57 -0
  17. package/src/client/l2_biz/workbench/l2-work-session-columns.tsx +0 -11
  18. package/src/client/l2_biz/workbench/l2-work-session-sidebar.tsx +107 -6
  19. package/src/client/l2_biz/workbench/l2-workbench-biz.ts +5 -0
  20. package/src/client/l2_biz/workbench/l2-workbench-chat-composer.tsx +333 -350
  21. package/src/client/l2_biz/workbench/l2-workbench.tsx +46 -1
  22. package/src/client/l2_biz/workbench/views/l2-work-session-rename-dialog.tsx +88 -0
  23. package/src/client/l3_modules/project-files/l3-markdown-preview.module.css +81 -0
  24. package/src/client/l3_modules/project-files/l3-markdown-preview.tsx +52 -0
  25. package/src/client/l3_modules/project-files/l3-project-document-view.tsx +26 -8
  26. package/src/client/l3_modules/project-files/l3-project-file-runtime.ts +16 -1
  27. package/src/client/l3_modules/project-files/l3-project-text-preview.ts +5 -0
  28. package/src/client/l3_modules/work-session-visual/l3-work-session-visual-effects.module.css +0 -36
  29. package/src/client/l3_modules/work-session-visual/l3-work-session-visual-view.tsx +0 -5
  30. package/src/client/l4_foundation/plugin-host/l4-plugin-host-runtime.ts +71 -1
  31. package/src/client/l4_foundation/styles/l4-globals.css +0 -19
  32. package/src/client/l4_foundation/ui/code/l4-code-preview.tsx +2 -1
  33. package/src/client/l4_foundation/ui/l4-confirm-dialog.tsx +9 -1
  34. package/src/common/l2_biz/auth/l2-auth-contract.ts +2 -2
  35. package/src/common/l2_biz/auth/l2-auth-messages.ts +2 -2
  36. package/src/common/l2_biz/model-settings/l2-model-settings-contract.ts +23 -1
  37. package/src/common/l2_biz/settings/l2-settings-messages.ts +8 -6
  38. package/src/common/l2_biz/work-session/l2-work-session-contract.ts +9 -0
  39. package/src/common/l2_biz/workbench/l2-workbench-locale-messages.ts +6 -0
  40. package/src/common/l3_modules/project-files/l3-project-files-locale-messages.ts +4 -0
  41. package/src/common/l4_foundation/locale/l4-host-error-messages.ts +6 -0
  42. package/src/server/l1_entry/api/l1-model-settings-preview-route.ts +32 -0
  43. package/src/server/l1_entry/api/l1-work-session-rename-route.ts +52 -0
  44. package/src/server/l2_biz/model-settings/l2-model-settings.ts +9 -0
  45. package/src/server/l2_biz/plugin-management/l2-plugin-management.ts +159 -52
  46. package/src/server/l2_biz/work-session/l2-work-session-chat-runtime.ts +5 -0
  47. package/src/server/l2_biz/work-session/l2-work-session-manage.ts +13 -0
  48. package/src/server/l3_modules/work-session/l3-work-session.ts +4 -0
  49. package/src/server/l4_foundation/model-settings/l4-model-settings-store.ts +161 -38
  50. package/src/server/l4_foundation/model-settings/l4-model-settings-types.ts +11 -0
  51. package/src/server/l4_foundation/model-settings/l4-model-settings.ts +1 -0
  52. package/src/server/l4_foundation/pi/l4-pi-chat-worker.ts +12 -1
  53. package/src/server/l4_foundation/pi/l4-pi-package-maintenance-runner.mts +56 -65
  54. package/src/server/l4_foundation/pi/l4-pi-package-maintenance.ts +2 -0
  55. package/src/server/l4_foundation/pi/l4-pi-package-reinstall-runner.mts +49 -0
  56. package/src/server/l4_foundation/pi/l4-pi-package-root-consistency.ts +6 -2
  57. package/src/server/l4_foundation/pi/l4-pi-plugin-probe.ts +3 -1
  58. package/src/server/l4_foundation/pi/l4-pi-runner-process.ts +9 -0
  59. package/src/server/l4_foundation/pi/l4-pi-work-session-runtime.ts +5 -0
  60. package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
  61. package/temp/build/pi-desk/release/.next/app-path-routes-manifest.json +2 -0
  62. package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
  63. package/temp/build/pi-desk/release/.next/prerender-manifest.json +3 -3
  64. package/temp/build/pi-desk/release/.next/react-loadable-manifest.json +1 -2
  65. package/temp/build/pi-desk/release/.next/required-server-files.js +3 -3
  66. package/temp/build/pi-desk/release/.next/required-server-files.json +3 -3
  67. package/temp/build/pi-desk/release/.next/routes-manifest.json +12 -0
  68. package/temp/build/pi-desk/release/.next/server/app/_global-error/page.js +1 -1
  69. package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  70. package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
  71. package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +1 -1
  72. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  73. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  74. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  75. package/temp/build/pi-desk/release/.next/server/app/_not-found/page.js +1 -1
  76. package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  77. package/temp/build/pi-desk/release/.next/server/app/api/auth/login/route.js +2 -2
  78. package/temp/build/pi-desk/release/.next/server/app/api/auth/logout/route.js +1 -1
  79. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/get/route.js +1 -1
  80. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/replace/route.js +1 -1
  81. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/get/route.js +1 -1
  82. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/replace/route.js +1 -1
  83. package/temp/build/pi-desk/release/.next/server/app/api/chat/context/get/route.js +1 -1
  84. package/temp/build/pi-desk/release/.next/server/app/api/chat/images/get/route.js +1 -1
  85. package/temp/build/pi-desk/release/.next/server/app/api/chat/messages/get/route.js +1 -1
  86. package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
  87. package/temp/build/pi-desk/release/.next/server/app/api/mcp-check/get/route.js +1 -1
  88. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/del/route.js +1 -1
  89. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/get/route.js +1 -1
  90. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/replace/route.js +1 -1
  91. package/temp/build/pi-desk/release/.next/server/app/api/model-catalog/list/route.js +1 -1
  92. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/get/route.js +1 -1
  93. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route.js +1 -0
  94. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route_client-reference-manifest.js +1 -0
  95. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/replace/route.js +1 -1
  96. package/temp/build/pi-desk/release/.next/server/app/api/pi/directories/list/route.js +1 -1
  97. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-entries/list/route.js +1 -1
  98. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/list/route.js +1 -1
  99. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/replace/route.js +1 -1
  100. package/temp/build/pi-desk/release/.next/server/app/api/pi/models/list/route.js +1 -1
  101. package/temp/build/pi-desk/release/.next/server/app/api/pi/session-user-messages/list/route.js +1 -1
  102. package/temp/build/pi-desk/release/.next/server/app/api/pi/sessions/list/route.js +1 -1
  103. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/get/route.js +1 -1
  104. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/search/route.js +1 -1
  105. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-get/route.js +1 -1
  106. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-replace/route.js +1 -1
  107. package/temp/build/pi-desk/release/.next/server/app/api/plugins/add/route.js +1 -1
  108. package/temp/build/pi-desk/release/.next/server/app/api/plugins/apply/route.js +1 -1
  109. package/temp/build/pi-desk/release/.next/server/app/api/plugins/batch/route.js +1 -1
  110. package/temp/build/pi-desk/release/.next/server/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route.js +1 -1
  111. package/temp/build/pi-desk/release/.next/server/app/api/plugins/del/route.js +1 -1
  112. package/temp/build/pi-desk/release/.next/server/app/api/plugins/enabled-set/route.js +1 -1
  113. package/temp/build/pi-desk/release/.next/server/app/api/plugins/get/route.js +1 -1
  114. package/temp/build/pi-desk/release/.next/server/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route.js +1 -1
  115. package/temp/build/pi-desk/release/.next/server/app/api/plugins/list/route.js +1 -1
  116. package/temp/build/pi-desk/release/.next/server/app/api/plugins/reload/route.js +1 -1
  117. package/temp/build/pi-desk/release/.next/server/app/api/plugins/update/route.js +1 -1
  118. package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +1 -1
  119. package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +1 -1
  120. package/temp/build/pi-desk/release/.next/server/app/api/project-files/reveal/route.js +1 -1
  121. package/temp/build/pi-desk/release/.next/server/app/api/project-files/search/route.js +1 -1
  122. package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +1 -1
  123. package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +1 -1
  124. package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +1 -1
  125. package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +1 -1
  126. package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +1 -1
  127. package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +1 -1
  128. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/get/route.js +1 -1
  129. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/replace/route.js +1 -1
  130. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/get/route.js +1 -1
  131. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/list/route.js +1 -1
  132. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/replace/route.js +1 -1
  133. package/temp/build/pi-desk/release/.next/server/app/api/skills/list/route.js +1 -1
  134. package/temp/build/pi-desk/release/.next/server/app/api/task-center/images/get/route.js +1 -1
  135. package/temp/build/pi-desk/release/.next/server/app/api/task-center/messages/get/route.js +1 -1
  136. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/add/route.js +1 -1
  137. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/replace/route.js +1 -1
  138. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree/get/route.js +1 -1
  139. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree-entry/get/route.js +1 -1
  140. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/add/route.js +1 -1
  141. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/branch/route.js +1 -1
  142. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/del/route.js +1 -1
  143. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route.js +1 -0
  144. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route_client-reference-manifest.js +1 -0
  145. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/replace/route.js +1 -1
  146. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/sort/route.js +1 -1
  147. package/temp/build/pi-desk/release/.next/server/app/favicon.ico/route.js +1 -1
  148. package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
  149. package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
  150. package/temp/build/pi-desk/release/.next/server/app/page.js +72 -306
  151. package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
  152. package/temp/build/pi-desk/release/.next/server/app-paths-manifest.json +2 -0
  153. package/temp/build/pi-desk/release/.next/server/chunks/23054.js +1 -1
  154. package/temp/build/pi-desk/release/.next/server/chunks/25406.js +8 -8
  155. package/temp/build/pi-desk/release/.next/server/chunks/33658.js +296 -0
  156. package/temp/build/pi-desk/release/.next/server/chunks/35985.js +5 -5
  157. package/temp/build/pi-desk/release/.next/server/chunks/48180.js +1 -1
  158. package/temp/build/pi-desk/release/.next/server/chunks/49900.js +2 -2
  159. package/temp/build/pi-desk/release/.next/server/chunks/50520.js +5 -5
  160. package/temp/build/pi-desk/release/.next/server/chunks/6917.js +1 -1
  161. package/temp/build/pi-desk/release/.next/server/chunks/78262.js +3 -3
  162. package/temp/build/pi-desk/release/.next/server/chunks/82499.js +6 -6
  163. package/temp/build/pi-desk/release/.next/server/chunks/92386.js +3 -3
  164. package/temp/build/pi-desk/release/.next/server/chunks/94296.js +2 -2
  165. package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
  166. package/temp/build/pi-desk/release/.next/server/middleware-react-loadable-manifest.js +1 -1
  167. package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
  168. package/temp/build/pi-desk/release/.next/server/server-reference-manifest.json +1 -1
  169. package/temp/build/pi-desk/release/.next/static/chunks/31087-ba426d09d6f68bfd.js +1 -0
  170. package/temp/build/pi-desk/release/.next/static/chunks/39654-b5fedd762ea0312e.js +238 -0
  171. package/temp/build/pi-desk/release/.next/static/chunks/49516-cc4dcd84d64ab4fe.js +81 -0
  172. package/temp/build/pi-desk/release/.next/static/chunks/75130-d2ca74894aff8085.js +13 -0
  173. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-9969fe0baa238786.js +1 -0
  174. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-9969fe0baa238786.js +1 -0
  175. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-9969fe0baa238786.js +1 -0
  176. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-9969fe0baa238786.js +1 -0
  177. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-9969fe0baa238786.js +1 -0
  178. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-9969fe0baa238786.js +1 -0
  179. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-9969fe0baa238786.js +1 -0
  180. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-9969fe0baa238786.js +1 -0
  181. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-9969fe0baa238786.js +1 -0
  182. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-9969fe0baa238786.js +1 -0
  183. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-9969fe0baa238786.js +1 -0
  184. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-9969fe0baa238786.js +1 -0
  185. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-9969fe0baa238786.js +1 -0
  186. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-9969fe0baa238786.js +1 -0
  187. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-9969fe0baa238786.js +1 -0
  188. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-9969fe0baa238786.js +1 -0
  189. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-9969fe0baa238786.js +1 -0
  190. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-9969fe0baa238786.js +1 -0
  191. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-9969fe0baa238786.js +1 -0
  192. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-9969fe0baa238786.js +1 -0
  193. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-9969fe0baa238786.js +1 -0
  194. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-9969fe0baa238786.js +1 -0
  195. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-9969fe0baa238786.js +1 -0
  196. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-9969fe0baa238786.js +1 -0
  197. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-9969fe0baa238786.js +1 -0
  198. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-9969fe0baa238786.js +1 -0
  199. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-9969fe0baa238786.js +1 -0
  200. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-9969fe0baa238786.js +1 -0
  201. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-9969fe0baa238786.js +1 -0
  202. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-9969fe0baa238786.js +1 -0
  203. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-9969fe0baa238786.js +1 -0
  204. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-9969fe0baa238786.js +1 -0
  205. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-9969fe0baa238786.js +1 -0
  206. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-9969fe0baa238786.js +1 -0
  207. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-9969fe0baa238786.js +1 -0
  208. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-9969fe0baa238786.js +1 -0
  209. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-9969fe0baa238786.js +1 -0
  210. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-9969fe0baa238786.js +1 -0
  211. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-9969fe0baa238786.js +1 -0
  212. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-9969fe0baa238786.js +1 -0
  213. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-9969fe0baa238786.js +1 -0
  214. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-9969fe0baa238786.js +1 -0
  215. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-9969fe0baa238786.js +1 -0
  216. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-9969fe0baa238786.js +1 -0
  217. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-9969fe0baa238786.js +1 -0
  218. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-9969fe0baa238786.js +1 -0
  219. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-9969fe0baa238786.js +1 -0
  220. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-9969fe0baa238786.js +1 -0
  221. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-9969fe0baa238786.js +1 -0
  222. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-9969fe0baa238786.js +1 -0
  223. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-9969fe0baa238786.js +1 -0
  224. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-9969fe0baa238786.js +1 -0
  225. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-9969fe0baa238786.js +1 -0
  226. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-9969fe0baa238786.js +1 -0
  227. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-9969fe0baa238786.js +1 -0
  228. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-9969fe0baa238786.js +1 -0
  229. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-9969fe0baa238786.js +1 -0
  230. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-9969fe0baa238786.js +1 -0
  231. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-9969fe0baa238786.js +1 -0
  232. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-9969fe0baa238786.js +1 -0
  233. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-9969fe0baa238786.js +1 -0
  234. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-9969fe0baa238786.js +1 -0
  235. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-9969fe0baa238786.js +1 -0
  236. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-9969fe0baa238786.js +1 -0
  237. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-9969fe0baa238786.js +1 -0
  238. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-9969fe0baa238786.js +1 -0
  239. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-9969fe0baa238786.js +1 -0
  240. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-9969fe0baa238786.js +1 -0
  241. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-9969fe0baa238786.js +1 -0
  242. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-9969fe0baa238786.js +1 -0
  243. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-c0e1c5cef8620cf8.js +3 -0
  244. package/temp/build/pi-desk/release/.next/static/chunks/app/login/page-84892b06243891f0.js +1 -0
  245. package/temp/build/pi-desk/release/.next/static/chunks/app/page-df6045b319f52088.js +158 -0
  246. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-9969fe0baa238786.js +1 -0
  247. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-9969fe0baa238786.js +1 -0
  248. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9969fe0baa238786.js +1 -0
  249. package/temp/build/pi-desk/release/.next/static/chunks/webpack-40a782fc8a3535b9.js +1 -0
  250. package/temp/build/pi-desk/release/.next/static/css/6427d02b6edf406f.css +1 -0
  251. package/temp/build/pi-desk/release/.next/static/css/{adb1d4e48dd43c0a.css → 949d0d1a99d5de92.css} +1 -1
  252. package/temp/build/pi-desk/release/.next/static/uj2IMtGMwxhDXhTVi7sw5/_buildManifest.js +1 -0
  253. package/temp/build/pi-desk/release/.next/trace-build +1 -1
  254. package/src/client/l2_biz/workbench/hooks/l2-work-session-column-motion.ts +0 -87
  255. package/src/client/l3_modules/work-session-visual/l3-work-session-status-border.tsx +0 -66
  256. package/src/client/l4_foundation/ui/l4-power-saving.ts +0 -45
  257. package/src/client/l4_foundation/ui/l4-window-reveal.ts +0 -30
  258. package/temp/build/pi-desk/release/.next/server/chunks/56284.js +0 -62
  259. package/temp/build/pi-desk/release/.next/static/96geGVI-j_dC6I3k-XFCB/_buildManifest.js +0 -1
  260. package/temp/build/pi-desk/release/.next/static/chunks/31087-333cae396a52f232.js +0 -1
  261. package/temp/build/pi-desk/release/.next/static/chunks/45992-92d8b8b10fcfbb6b.js +0 -13
  262. package/temp/build/pi-desk/release/.next/static/chunks/47340-c1c09c77c1a88514.js +0 -318
  263. package/temp/build/pi-desk/release/.next/static/chunks/57208-d6d38167dabb91e4.js +0 -1
  264. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-dde4fd973791f7f7.js +0 -1
  265. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-dde4fd973791f7f7.js +0 -1
  266. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-dde4fd973791f7f7.js +0 -1
  267. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-dde4fd973791f7f7.js +0 -1
  268. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-dde4fd973791f7f7.js +0 -1
  269. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-dde4fd973791f7f7.js +0 -1
  270. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-dde4fd973791f7f7.js +0 -1
  271. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-dde4fd973791f7f7.js +0 -1
  272. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-dde4fd973791f7f7.js +0 -1
  273. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-dde4fd973791f7f7.js +0 -1
  274. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-dde4fd973791f7f7.js +0 -1
  275. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-dde4fd973791f7f7.js +0 -1
  276. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-dde4fd973791f7f7.js +0 -1
  277. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-dde4fd973791f7f7.js +0 -1
  278. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-dde4fd973791f7f7.js +0 -1
  279. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-dde4fd973791f7f7.js +0 -1
  280. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-dde4fd973791f7f7.js +0 -1
  281. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-dde4fd973791f7f7.js +0 -1
  282. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-dde4fd973791f7f7.js +0 -1
  283. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-dde4fd973791f7f7.js +0 -1
  284. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-dde4fd973791f7f7.js +0 -1
  285. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-dde4fd973791f7f7.js +0 -1
  286. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-dde4fd973791f7f7.js +0 -1
  287. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-dde4fd973791f7f7.js +0 -1
  288. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-dde4fd973791f7f7.js +0 -1
  289. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-dde4fd973791f7f7.js +0 -1
  290. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-dde4fd973791f7f7.js +0 -1
  291. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-dde4fd973791f7f7.js +0 -1
  292. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-dde4fd973791f7f7.js +0 -1
  293. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-dde4fd973791f7f7.js +0 -1
  294. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-dde4fd973791f7f7.js +0 -1
  295. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-dde4fd973791f7f7.js +0 -1
  296. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-dde4fd973791f7f7.js +0 -1
  297. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-dde4fd973791f7f7.js +0 -1
  298. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-dde4fd973791f7f7.js +0 -1
  299. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-dde4fd973791f7f7.js +0 -1
  300. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-dde4fd973791f7f7.js +0 -1
  301. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-dde4fd973791f7f7.js +0 -1
  302. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-dde4fd973791f7f7.js +0 -1
  303. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-dde4fd973791f7f7.js +0 -1
  304. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-dde4fd973791f7f7.js +0 -1
  305. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-dde4fd973791f7f7.js +0 -1
  306. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-dde4fd973791f7f7.js +0 -1
  307. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-dde4fd973791f7f7.js +0 -1
  308. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-dde4fd973791f7f7.js +0 -1
  309. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-dde4fd973791f7f7.js +0 -1
  310. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-dde4fd973791f7f7.js +0 -1
  311. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-dde4fd973791f7f7.js +0 -1
  312. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-dde4fd973791f7f7.js +0 -1
  313. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-dde4fd973791f7f7.js +0 -1
  314. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-dde4fd973791f7f7.js +0 -1
  315. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-dde4fd973791f7f7.js +0 -1
  316. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-dde4fd973791f7f7.js +0 -1
  317. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-dde4fd973791f7f7.js +0 -1
  318. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-dde4fd973791f7f7.js +0 -1
  319. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-dde4fd973791f7f7.js +0 -1
  320. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-dde4fd973791f7f7.js +0 -1
  321. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-dde4fd973791f7f7.js +0 -1
  322. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-dde4fd973791f7f7.js +0 -1
  323. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-dde4fd973791f7f7.js +0 -1
  324. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-dde4fd973791f7f7.js +0 -1
  325. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-dde4fd973791f7f7.js +0 -1
  326. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-dde4fd973791f7f7.js +0 -1
  327. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-dde4fd973791f7f7.js +0 -1
  328. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-dde4fd973791f7f7.js +0 -1
  329. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-dde4fd973791f7f7.js +0 -1
  330. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-dde4fd973791f7f7.js +0 -1
  331. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-dde4fd973791f7f7.js +0 -1
  332. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-839162b6cfae8347.js +0 -3
  333. package/temp/build/pi-desk/release/.next/static/chunks/app/login/page-4532a3bbee48e219.js +0 -1
  334. package/temp/build/pi-desk/release/.next/static/chunks/app/page-4b6367cde5c04597.js +0 -158
  335. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-dde4fd973791f7f7.js +0 -1
  336. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-dde4fd973791f7f7.js +0 -1
  337. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-dde4fd973791f7f7.js +0 -1
  338. package/temp/build/pi-desk/release/.next/static/chunks/webpack-735430d61da52e9d.js +0 -1
  339. package/temp/build/pi-desk/release/.next/static/css/4a5dda7ff3a82c4a.css +0 -1
  340. /package/temp/build/pi-desk/release/.next/static/{96geGVI-j_dC6I3k-XFCB → uj2IMtGMwxhDXhTVi7sw5}/_ssgManifest.js +0 -0
package/docs/plugins.md CHANGED
@@ -77,7 +77,7 @@ plugin.addPreviewDirectory(directory, { default: true })
77
77
 
78
78
  `directory` 为服务端绝对目录;省略第二个参数只登记,`default: true` 同时设为默认预览目录,后登记的默认生效。原 CWD 始终可选;目录规范化后去重,最多登记 32 个。重复快照不会覆盖用户的手动选择。登记只在当前会话运行态内,插件在 `session_start`、`session_tree` 从自身数据恢复后重新登记;不要在普通查询时重复请求默认选择。
79
79
 
80
- 调用不等待回执;非法路径或超限由宿主拒绝并记日志,实际目录内容按需读取。旧宿主或独立 Pi 不处理该登记;兼容旧 SDK 时使用 `plugin.addPreviewDirectory?.(...)`。`files.preview/reveal` 支持会话 CWD 下规范相对路径或服务端绝对文件路径(包括项目外文件);`preview` 的 `imagePaths` 使用相同路径规则。宿主仍校验当前 Source,目录浏览边界不变。依赖项目外文件的插件需要同步更新宿主,旧宿主只接受项目内相对路径。`readImage` 仍只接受会话 CWD 下规范相对路径。
80
+ 调用不等待回执;非法路径或超限由宿主拒绝并记日志,实际目录内容按需读取。旧宿主或独立 Pi 不处理该登记;兼容旧 SDK 时使用 `plugin.addPreviewDirectory?.(...)`。`files.preview/reveal` 支持会话 CWD 下规范相对路径或服务端绝对文件路径(包括项目外文件);`preview` 的 `imagePaths` 使用相同路径规则。宿主仍校验当前 Source,目录浏览边界不变。依赖项目外文件的插件需要同步更新宿主,旧宿主只接受项目内相对路径。`readImage` 仍只接受会话 CWD 下规范相对路径。`.md`、`.markdown` 在宿主文件查看器中默认以 Markdown 排版预览,可点击“源码”切换;会话文件视图与 `mode: 'standalone'` 独立查看器均支持,插件无需增加参数或自行渲染。
81
81
 
82
82
  ## Browser Entry 与懒界面
83
83
 
@@ -105,6 +105,26 @@ Application 使用 `chrome: 'host'` 让宿主负责 Dialog、标题、关闭、
105
105
 
106
106
  界面继承宿主明暗主题与字号,布局使用 `rem`、合理内边距和自身滚动;窄屏与触控可用,不以裁切或只靠 hover 隐藏必要操作。按钮、表单、加载/错误/重试优先复用 `/react/base`;需要 Markdown 时才加载 `/react/markdown`。
107
107
 
108
+ ### 侧栏顶部操作
109
+
110
+ `session-sidebar-tab` 的 Lazy `mount({ target, host })` 内可为当前 Tab 设置顶部右侧按钮:
111
+
112
+ ```ts
113
+ target.setHeaderActions?.([
114
+ {
115
+ label: '预览项目',
116
+ icon: { type: 'builtin', name: 'folder' },
117
+ onSelect: () => host.projects.preview(target.cwd)
118
+ }
119
+ ])
120
+ ```
121
+
122
+ 每次调用整体替换,`[]` 清空。按钮使用 `label` 作为可访问名称和提示,`icon` 复用 Contribution 图标;可选 `disabled` 禁用,`busy` 显示忙碌并禁用。状态变化时重新设置完整列表,不修改已提交对象。宿主保持列表顺序,超过三个操作时保留前两个,其余收进菜单。
123
+
124
+ `onSelect` 可返回 `Promise<void>`;同一按钮回调尚未完成时不重复执行,异常由宿主记录并在当前挂载仍有效时提示。插件负责业务加载状态和结果展示;请求已经产生的副作用不因 Tab 关闭而回滚。
125
+
126
+ 按钮只属于当前挂载,切换 Tab、关闭侧栏/移动抽屉、Source 或 CWD 变化、挂载失败及插件重载时自动清空;旧按钮、迟到更新和旧 disposer 均不能操作新挂载。旧宿主可能没有此方法,使用可选调用,不自行访问宿主 DOM。`PluginPanelHeader.actions` 仍只作用于插件内容区标题,不是此顶栏入口。
127
+
108
128
  ## 通信、通知与后台
109
129
 
110
130
  Browser Method 示例:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetcrab/pi-desk",
3
- "version": "1.1.12",
3
+ "version": "1.1.16-dev",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -69,7 +69,7 @@
69
69
  "viewerjs": "^1.11.8",
70
70
  "ws": "^8.21.3",
71
71
  "zod": "^4.4.3",
72
- "@jetcrab/pi-desk-sdk": "^1.1.3"
72
+ "@jetcrab/pi-desk-sdk": "^1.1.6-dev"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@earendil-works/pi-agent-core": "1.2.0",
@@ -0,0 +1 @@
1
+ export { POST } from '@server/l1_entry/api/l1-model-settings-preview-route'
@@ -0,0 +1 @@
1
+ export { POST } from '@server/l1_entry/api/l1-work-session-rename-route'
@@ -96,7 +96,7 @@ export function L2Login(): React.JSX.Element {
96
96
  name="password"
97
97
  value={password}
98
98
  autoComplete="current-password"
99
- maxLength={256}
99
+ maxLength={64}
100
100
  disabled={submitting}
101
101
  aria-describedby={error ? 'login-error' : undefined}
102
102
  onChange={(event) => setPassword(event.target.value)}
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type {
4
4
  BrowserFilePreviewOptions,
5
+ BrowserSessionSidebarHeaderAction,
5
6
  BrowserSessionSidebarTabTarget,
6
7
  PluginSource
7
8
  } from '@jetcrab/pi-desk-sdk/browser'
@@ -15,6 +16,7 @@ interface L2PluginSessionSidebarTabProps {
15
16
  cwd: string
16
17
  onPreviewFile: (path: string, options?: BrowserFilePreviewOptions) => void
17
18
  onRevealFile: (path: string) => Promise<void>
19
+ onHeaderActionsChange: (actions: readonly BrowserSessionSidebarHeaderAction[]) => void
18
20
  }
19
21
 
20
22
  export function L2PluginSessionSidebarTab({
@@ -23,13 +25,15 @@ export function L2PluginSessionSidebarTab({
23
25
  source,
24
26
  cwd,
25
27
  onPreviewFile,
26
- onRevealFile
28
+ onRevealFile,
29
+ onHeaderActionsChange
27
30
  }: L2PluginSessionSidebarTabProps): React.JSX.Element {
28
31
  const target: BrowserSessionSidebarTabTarget = {
29
32
  kind: 'session-sidebar-tab',
30
33
  source,
31
34
  cwd,
32
- files: { preview: onPreviewFile, reveal: onRevealFile }
35
+ files: { preview: onPreviewFile, reveal: onRevealFile },
36
+ setHeaderActions: onHeaderActionsChange
33
37
  }
34
38
  const targetKey = `${source.workId}\u0000${source.sessionId}\u0000${source.branchId}\u0000${cwd}`
35
39
 
@@ -1,7 +1,8 @@
1
1
  import { useEffect, useRef, useState } from 'react'
2
2
  import type {
3
3
  L2ModelConfig,
4
- L2ModelProviderConfig
4
+ L2ModelProviderConfig,
5
+ L2ModelReplacement
5
6
  } from '@common/l2_biz/model-settings/l2-model-settings-contract'
6
7
 
7
8
  export interface ModelInputState {
@@ -45,7 +46,7 @@ function emptyModel(): L2ModelConfig {
45
46
 
46
47
  export function useL2ModelProviderSettings(
47
48
  providers: L2ModelProviderConfig[],
48
- onChange: (providers: L2ModelProviderConfig[]) => void,
49
+ onChange: (providers: L2ModelProviderConfig[], replacements: L2ModelReplacement[]) => void,
49
50
  onInputState: (state: ModelInputState) => void,
50
51
  resetVersion: number
51
52
  ): {
@@ -79,6 +80,16 @@ export function useL2ModelProviderSettings(
79
80
  )
80
81
  )
81
82
  const nextKey = useRef(0)
83
+ const originalModels = useRef(
84
+ new Map(
85
+ providers.flatMap((provider, providerIndex) =>
86
+ provider.models.map((model, modelIndex) => [
87
+ `${providerIndex}:${modelIndex}`,
88
+ { provider: provider.provider, modelId: model.modelId }
89
+ ])
90
+ )
91
+ )
92
+ )
82
93
  const [inputStates, setInputStates] = useState<Record<string, ModelInputState>>({})
83
94
  const [serviceIndex, setServiceIndex] = useState<number | null>(null)
84
95
  const [newService, setNewService] = useState(false)
@@ -91,6 +102,14 @@ export function useL2ModelProviderSettings(
91
102
  useEffect(() => {
92
103
  queueMicrotask(() => {
93
104
  const current = latestProviders.current
105
+ originalModels.current = new Map(
106
+ current.flatMap((provider, providerIndex) =>
107
+ provider.models.map((model, modelIndex) => [
108
+ `${providerIndex}:${modelIndex}`,
109
+ { provider: provider.provider, modelId: model.modelId }
110
+ ])
111
+ )
112
+ )
94
113
  setInputStates({})
95
114
  setModelKeys(
96
115
  current.map((provider, providerIndex) =>
@@ -120,8 +139,22 @@ export function useL2ModelProviderSettings(
120
139
  )
121
140
  }
122
141
 
142
+ function changeProviders(next: L2ModelProviderConfig[], keys = modelKeys): void {
143
+ const replacements: L2ModelReplacement[] = []
144
+ next.forEach((provider, providerIndex) => {
145
+ provider.models.forEach((model, modelIndex) => {
146
+ const from = originalModels.current.get(keys[providerIndex][modelIndex])
147
+ const to = { provider: provider.provider.trim(), modelId: model.modelId.trim() }
148
+ if (from && (from.provider !== to.provider || from.modelId !== to.modelId)) {
149
+ replacements.push({ from, to })
150
+ }
151
+ })
152
+ })
153
+ onChange(next, replacements)
154
+ }
155
+
123
156
  function updateModel(providerIndex: number, modelIndex: number, model: L2ModelConfig): void {
124
- onChange(
157
+ changeProviders(
125
158
  providers.map((provider, index) =>
126
159
  index === providerIndex
127
160
  ? {
@@ -155,10 +188,12 @@ export function useL2ModelProviderSettings(
155
188
  closeService,
156
189
  applyService: (provider) => {
157
190
  if (newService) {
158
- onChange([...providers, provider])
191
+ changeProviders([...providers, provider], [...modelKeys, []])
159
192
  setModelKeys((keys) => [...keys, []])
160
193
  } else {
161
- onChange(providers.map((current, index) => (index === serviceIndex ? provider : current)))
194
+ changeProviders(
195
+ providers.map((current, index) => (index === serviceIndex ? provider : current))
196
+ )
162
197
  }
163
198
  closeService()
164
199
  },
@@ -166,7 +201,10 @@ export function useL2ModelProviderSettings(
166
201
  if (serviceIndex === null) return
167
202
  removeInputKeys(modelKeys[serviceIndex])
168
203
  const nextProviders = providers.filter((_, index) => index !== serviceIndex)
169
- onChange(nextProviders)
204
+ changeProviders(
205
+ nextProviders,
206
+ modelKeys.filter((_, index) => index !== serviceIndex)
207
+ )
170
208
  setModelKeys((keys) => keys.filter((_, index) => index !== serviceIndex))
171
209
  setSelection((current) => {
172
210
  if (!current || current.providerIndex === serviceIndex) {
@@ -182,14 +220,15 @@ export function useL2ModelProviderSettings(
182
220
  },
183
221
  addModel: (providerIndex) => {
184
222
  const provider = providers[providerIndex]
185
- onChange(
223
+ const key = `new-${++nextKey.current}`
224
+ changeProviders(
186
225
  providers.map((current, index) =>
187
226
  index === providerIndex
188
227
  ? { ...current, models: [...current.models, emptyModel()] }
189
228
  : current
190
- )
229
+ ),
230
+ modelKeys.map((current, index) => (index === providerIndex ? [...current, key] : current))
191
231
  )
192
- const key = `new-${++nextKey.current}`
193
232
  setModelKeys((keys) =>
194
233
  keys.map((current, index) => (index === providerIndex ? [...current, key] : current))
195
234
  )
@@ -213,7 +252,12 @@ export function useL2ModelProviderSettings(
213
252
  ? { ...provider, models: provider.models.filter((_, index) => index !== modelIndex) }
214
253
  : provider
215
254
  )
216
- onChange(nextProviders)
255
+ changeProviders(
256
+ nextProviders,
257
+ modelKeys.map((current, index) =>
258
+ index === providerIndex ? current.filter((_, index) => index !== modelIndex) : current
259
+ )
260
+ )
217
261
  setModelKeys((keys) =>
218
262
  keys.map((current, index) =>
219
263
  index === providerIndex ? current.filter((_, index) => index !== modelIndex) : current
@@ -1,16 +1,18 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
1
+ import { createElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
2
2
  import { useTranslation } from 'react-i18next'
3
3
  import type { BrowserBeforeLeaveHandler } from '@jetcrab/pi-desk-sdk/browser'
4
4
  import type {
5
5
  L2AccountModelSelection,
6
6
  L2ModelPreset,
7
7
  L2ModelProviderConfig,
8
+ L2ModelReplacement,
8
9
  L2ModelSettingsGetResponse,
9
10
  L2ModelSettingsReplaceRequest
10
11
  } from '@common/l2_biz/model-settings/l2-model-settings-contract'
11
12
  import { useL4AppSocket } from '@client/l4_foundation/realtime/app-socket/l4-app-socket'
12
13
  import { useL4AppToast } from '@client/l4_foundation/ui/l4-app-toast'
13
14
  import { useL4ConfirmDialog } from '@client/l4_foundation/ui/l4-confirm-dialog'
15
+ import { L2ModelReplacementPreview } from '../views/l2-model-replacement-preview'
14
16
  import { createL2ModelSettingsBiz, type L2ModelSettingsBiz } from '../l2-model-settings-biz'
15
17
  import {
16
18
  readL2ModelSettingsTab,
@@ -53,7 +55,7 @@ interface ModelSettingsState {
53
55
  setServiceDirty: (dirty: boolean) => void
54
56
  dialog: React.JSX.Element | null
55
57
  setProjectDefaultDirty: (dirty: boolean) => void
56
- changeProviders: (providers: L2ModelProviderConfig[]) => void
58
+ changeProviders: (providers: L2ModelProviderConfig[], replacements: L2ModelReplacement[]) => void
57
59
  changePresets: (presets: L2ModelPreset[]) => void
58
60
  selectTab: (tab: ModelSettingsTab) => void
59
61
  retry: () => void
@@ -95,6 +97,7 @@ export function useL2ModelSettings(
95
97
  const [nativeText, setNativeText] = useState('')
96
98
  const [nativeError, setNativeError] = useState<string | null>(null)
97
99
  const savingRef = useRef(false)
100
+ const modelReplacements = useRef<L2ModelReplacement[]>([])
98
101
  const nativeBaseline = settings ? JSON.stringify(settings.nativeConfig, null, 2) : ''
99
102
  const nativeDirty = nativeOpen && nativeText !== nativeBaseline
100
103
  const formDirty = providersDirty || presetsDirty || accountModelsDirty || inputState.dirty
@@ -127,6 +130,7 @@ export function useL2ModelSettings(
127
130
  }, [dirty])
128
131
 
129
132
  const applySettings = useCallback((result: L2ModelSettingsGetResponse): void => {
133
+ modelReplacements.current = []
130
134
  setSettings(result)
131
135
  setProviders(structuredClone(result.providers))
132
136
  setPresets(structuredClone(result.presets))
@@ -218,7 +222,35 @@ export function useL2ModelSettings(
218
222
  return !originalModels.has(key) || currentModels.has(key)
219
223
  })
220
224
  const removedPresetCount = presets.length - nextPresets.length
221
- if (
225
+ const input: L2ModelSettingsReplaceRequest = {
226
+ ...(providersDirty || inputState.dirty ? { providers } : {}),
227
+ ...(accountModelsDirty ? { accountModels } : {}),
228
+ ...(presetsDirty || removedPresetCount > 0 ? { presets: nextPresets } : {}),
229
+ ...(modelReplacements.current.length
230
+ ? { modelReplacements: modelReplacements.current }
231
+ : {})
232
+ }
233
+ const { projectDefaults } = modelReplacements.current.length
234
+ ? await biz.previewSettings(input)
235
+ : { projectDefaults: [] }
236
+ if (projectDefaults.length > 0) {
237
+ const description = [
238
+ t('replaceProjectDefaultsDescription'),
239
+ ...(removedPresetCount > 0
240
+ ? [t('removeInvalidPresets', { count: removedPresetCount })]
241
+ : [])
242
+ ].join(' ')
243
+ if (
244
+ !(await confirm({
245
+ title: t('replaceProjectDefaultsTitle'),
246
+ description,
247
+ content: createElement(L2ModelReplacementPreview, { projectDefaults }),
248
+ confirmLabel: t('confirmAndSaveModels'),
249
+ confirmVariant: 'default'
250
+ }))
251
+ )
252
+ return
253
+ } else if (
222
254
  removedPresetCount > 0 &&
223
255
  !(await confirm({
224
256
  title: t('removeInvalidPresetsTitle'),
@@ -229,11 +261,6 @@ export function useL2ModelSettings(
229
261
  return
230
262
  }
231
263
 
232
- const input: L2ModelSettingsReplaceRequest = {
233
- ...(providersDirty || inputState.dirty ? { providers } : {}),
234
- ...(accountModelsDirty ? { accountModels } : {}),
235
- ...(presetsDirty || removedPresetCount > 0 ? { presets: nextPresets } : {})
236
- }
237
264
  await biz.replaceSettings(input)
238
265
  applySettings(await biz.getSettings())
239
266
  setProvidersDirty(false)
@@ -375,7 +402,8 @@ export function useL2ModelSettings(
375
402
  setServiceDirty,
376
403
  dialog,
377
404
  setProjectDefaultDirty,
378
- changeProviders: (nextProviders) => {
405
+ changeProviders: (nextProviders, replacements) => {
406
+ modelReplacements.current = replacements
379
407
  setProviders(nextProviders)
380
408
  setProvidersDirty(JSON.stringify(nextProviders) !== JSON.stringify(settings?.providers))
381
409
  },
@@ -99,7 +99,7 @@ export function L2AuthSettings(): React.JSX.Element {
99
99
  className="[&::-ms-reveal]:hidden"
100
100
  autoComplete="new-password"
101
101
  minLength={12}
102
- maxLength={256}
102
+ maxLength={64}
103
103
  required
104
104
  disabled={busy}
105
105
  value={state.password}
@@ -4,6 +4,7 @@ import {
4
4
  L2ModelCatalogListRequestSchema,
5
5
  L2ModelCatalogListResponseSchema,
6
6
  L2ModelSettingsGetResponseSchema,
7
+ L2ModelSettingsPreviewResponseSchema,
7
8
  L2ModelSettingsReplaceRequestSchema,
8
9
  L2ModelSettingsReplaceResponseSchema,
9
10
  L2ProjectModelDefaultGetResponseSchema,
@@ -12,6 +13,7 @@ import {
12
13
  type L2ModelCatalogListRequest,
13
14
  type L2ModelCatalogListResponse,
14
15
  type L2ModelSettingsGetResponse,
16
+ type L2ModelSettingsPreviewResponse,
15
17
  type L2ModelSettingsReplaceRequest,
16
18
  type L2ProjectModelDefaultGetResponse,
17
19
  type L2ProjectModelDefaultReplaceRequest
@@ -25,6 +27,7 @@ import { saveL2ProjectModelDefaultCache } from './l2-model-settings-cache'
25
27
  export interface L2ModelSettingsBiz {
26
28
  parseNativeConfig: (text: string) => L2ModelNativeConfig
27
29
  getSettings: () => Promise<L2ModelSettingsGetResponse>
30
+ previewSettings: (input: L2ModelSettingsReplaceRequest) => Promise<L2ModelSettingsPreviewResponse>
28
31
  replaceSettings: (input: L2ModelSettingsReplaceRequest) => Promise<void>
29
32
  listCatalog: (input: L2ModelCatalogListRequest) => Promise<L2ModelCatalogListResponse>
30
33
  listDirectories: () => Promise<z.infer<typeof L2PiDirectoryListResponseSchema>>
@@ -32,6 +35,21 @@ export interface L2ModelSettingsBiz {
32
35
  replaceProjectDefault: (input: L2ProjectModelDefaultReplaceRequest) => Promise<void>
33
36
  }
34
37
 
38
+ function parseSettingsInput(input: L2ModelSettingsReplaceRequest): L2ModelSettingsReplaceRequest {
39
+ const parsed = L2ModelSettingsReplaceRequestSchema.safeParse(input)
40
+ if (!parsed.success) {
41
+ const field = parsed.error.issues[0]?.path.at(-1)
42
+ if (field === 'modelId') {
43
+ throw new Error('请填写模型 ID 后再保存配置。')
44
+ }
45
+ if (field === 'provider') {
46
+ throw new Error('请填写 Provider ID 后再保存配置。')
47
+ }
48
+ throw new Error('模型配置不完整或格式不正确,请检查必填字段和数值。')
49
+ }
50
+ return parsed.data
51
+ }
52
+
35
53
  export function createL2ModelSettingsBiz(clientId: string): L2ModelSettingsBiz {
36
54
  let settingsRequest: Promise<L2ModelSettingsGetResponse> | null = null
37
55
  return {
@@ -52,22 +70,18 @@ export function createL2ModelSettingsBiz(clientId: string): L2ModelSettingsBiz {
52
70
  }
53
71
  return settingsRequest
54
72
  },
73
+ previewSettings: (input) =>
74
+ request(
75
+ clientId,
76
+ '/api/model-settings/preview',
77
+ parseSettingsInput(input),
78
+ L2ModelSettingsPreviewResponseSchema
79
+ ),
55
80
  async replaceSettings(input): Promise<void> {
56
- const parsed = L2ModelSettingsReplaceRequestSchema.safeParse(input)
57
- if (!parsed.success) {
58
- const field = parsed.error.issues[0]?.path.at(-1)
59
- if (field === 'modelId') {
60
- throw new Error('请填写模型 ID 后再保存配置。')
61
- }
62
- if (field === 'provider') {
63
- throw new Error('请填写 Provider ID 后再保存配置。')
64
- }
65
- throw new Error('模型配置不完整或格式不正确,请检查必填字段和数值。')
66
- }
67
81
  await request(
68
82
  clientId,
69
83
  '/api/model-settings/replace',
70
- parsed.data,
84
+ parseSettingsInput(input),
71
85
  L2ModelSettingsReplaceResponseSchema
72
86
  )
73
87
  },
@@ -17,7 +17,6 @@ import {
17
17
  subscribeL4DisplaySize
18
18
  } from '@client/l4_foundation/ui/l4-display-size-provider'
19
19
  import { L3ConversationMarkdown } from '@client/l3_modules/conversation/l3-conversation-markdown'
20
- import { saveL4PowerSaving, useL4PowerSaving } from '@client/l4_foundation/ui/l4-power-saving'
21
20
 
22
21
  const THEME_OPTIONS = [
23
22
  { value: 'system', label: 'common:system', icon: MonitorIcon },
@@ -34,7 +33,6 @@ const DISPLAY_SIZE_OPTIONS = [
34
33
  export function L2AppearanceSettings(): React.JSX.Element {
35
34
  const { t } = useTranslation('settings')
36
35
  const theme = useSyncExternalStore(subscribeL4Theme, readL4Theme, () => L4_DEFAULT_THEME)
37
- const powerSaving = useL4PowerSaving()
38
36
  const size = useSyncExternalStore(
39
37
  subscribeL4DisplaySize,
40
38
  readL4DisplaySize,
@@ -58,7 +56,7 @@ export function L2AppearanceSettings(): React.JSX.Element {
58
56
  onChange={saveL4Theme}
59
57
  />
60
58
  </div>
61
- <div className="space-y-2 border-b pb-4">
59
+ <div className="space-y-2">
62
60
  <h3 className="text-sm font-medium">{t('displaySize')}</h3>
63
61
  <L4ChoiceGroup<L4DisplaySize>
64
62
  label={t('displaySize')}
@@ -71,19 +69,6 @@ export function L2AppearanceSettings(): React.JSX.Element {
71
69
  onChange={saveL4DisplaySize}
72
70
  />
73
71
  </div>
74
- <div className="space-y-2">
75
- <h3 className="text-sm font-medium">{t('powerSaving')}</h3>
76
- <L4ChoiceGroup<'off' | 'on'>
77
- label={t('powerSaving')}
78
- layout="segmented"
79
- value={powerSaving ? 'on' : 'off'}
80
- options={[
81
- { value: 'off', label: t('powerSavingOff'), testId: 'power-saving-off' },
82
- { value: 'on', label: t('powerSavingOn'), testId: 'power-saving-on' }
83
- ]}
84
- onChange={(value) => saveL4PowerSaving(value === 'on')}
85
- />
86
- </div>
87
72
  </div>
88
73
  <div className="min-w-0 space-y-2">
89
74
  <h3 className="text-sm font-medium">{t('displayPreview')}</h3>
@@ -16,7 +16,8 @@ import type {
16
16
  L2ModelSettingsGetResponse,
17
17
  L2ModelOption,
18
18
  L2ModelPreset,
19
- L2ModelProviderConfig
19
+ L2ModelProviderConfig,
20
+ L2ModelReplacement
20
21
  } from '@common/l2_biz/model-settings/l2-model-settings-contract'
21
22
  import { Button } from '@client/l4_foundation/ui/shadcn/button'
22
23
  import { Input } from '@client/l4_foundation/ui/shadcn/input'
@@ -61,7 +62,7 @@ interface Props {
61
62
  savedProviders: L2ModelProviderConfig[]
62
63
  presets: L2ModelPreset[]
63
64
  resetVersion: number
64
- onChange: (providers: L2ModelProviderConfig[]) => void
65
+ onChange: (providers: L2ModelProviderConfig[], replacements: L2ModelReplacement[]) => void
65
66
  onPresetsChange: (presets: L2ModelPreset[]) => void
66
67
  onInputState: (state: ModelInputState) => void
67
68
  onServiceDirtyChange: (dirty: boolean) => void
@@ -0,0 +1,34 @@
1
+ import { useTranslation } from 'react-i18next'
2
+ import type { L2ModelSettingsPreviewResponse } from '@common/l2_biz/model-settings/l2-model-settings-contract'
3
+
4
+ const THINKING_LABELS = {
5
+ off: 'thinkingOff',
6
+ minimal: 'thinkingMinimal',
7
+ low: 'thinkingLow',
8
+ medium: 'thinkingMedium',
9
+ high: 'thinkingHigh',
10
+ xhigh: 'thinkingXhigh',
11
+ max: 'thinkingMax'
12
+ } as const
13
+
14
+ export function L2ModelReplacementPreview({
15
+ projectDefaults
16
+ }: L2ModelSettingsPreviewResponse): React.JSX.Element {
17
+ const { t } = useTranslation('settings')
18
+ return (
19
+ <ul className="space-y-3 px-4 pb-4">
20
+ {projectDefaults.map(({ cwd, from, to }) => (
21
+ <li key={cwd} className="space-y-1">
22
+ <p className="break-all font-medium">{cwd}</p>
23
+ <p className="break-all text-muted-foreground">
24
+ {from.provider}/{from.modelId} · {t(THINKING_LABELS[from.thinkingLevel])}
25
+ <span className="mx-1.5">→</span>
26
+ <span className="text-foreground">
27
+ {to.provider}/{to.modelId} · {t(THINKING_LABELS[to.thinkingLevel])}
28
+ </span>
29
+ </p>
30
+ </li>
31
+ ))}
32
+ </ul>
33
+ )
34
+ }
@@ -14,7 +14,7 @@ import {
14
14
  XCircleIcon,
15
15
  XIcon
16
16
  } from 'lucide-react'
17
- import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
17
+ import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react'
18
18
  import { useTranslation } from 'react-i18next'
19
19
  import {
20
20
  type L2TaskDetailBody,
@@ -50,7 +50,6 @@ import {
50
50
  } from '@client/l3_modules/conversation/l3-conversation-messages'
51
51
  import { L3ConversationTailSpacerObserver } from '@client/l3_modules/conversation/l3-conversation-viewport'
52
52
  import { useL4AppToast } from '@client/l4_foundation/ui/l4-app-toast'
53
- import { useL4WindowReveal } from '@client/l4_foundation/ui/l4-window-reveal'
54
53
  import type { L2TaskCenterRuntime } from './l2-task-center-runtime'
55
54
 
56
55
  interface L2TaskCenterProps {
@@ -443,8 +442,6 @@ function TaskCenterPanel({
443
442
  }, [runtime])
444
443
  useSyncExternalStore(runtime.subscribe, getPanelSnapshot, getPanelSnapshot)
445
444
  const state = runtime.getState()
446
- const closeButtonRef = useRef<HTMLButtonElement>(null)
447
- const desktopCloseButtonRef = useRef<HTMLButtonElement>(null)
448
445
  const [mobileDetail, setMobileDetail] = useState(false)
449
446
  const selectedTask = tasks.find((task) => task.taskId === state.selectedTaskId) ?? null
450
447
 
@@ -455,17 +452,6 @@ function TaskCenterPanel({
455
452
 
456
453
  const showMobileDetail = mobileDetail && state.selectedTaskId !== null
457
454
  const panelOpen = state.open && sameSource(state.source, source)
458
- const listRef = useRef<HTMLDivElement>(null)
459
- const detailRef = useRef<HTMLDivElement>(null)
460
- useL4WindowReveal(listRef, panelOpen && !showMobileDetail ? 'task-list' : null)
461
- useL4WindowReveal(
462
- detailRef,
463
- panelOpen ? `${state.selectedTaskId ?? 'no-task'}:${showMobileDetail}` : null
464
- )
465
-
466
- if (!state.open || !sameSource(state.source, source) || typeof document === 'undefined') {
467
- return null
468
- }
469
455
 
470
456
  const select = (taskId: string): void => {
471
457
  runtime.selectTask(taskId)
@@ -474,23 +460,17 @@ function TaskCenterPanel({
474
460
 
475
461
  return (
476
462
  <L4AppDialogRoot
477
- open
463
+ open={panelOpen}
478
464
  onOpenChange={(open) => {
479
465
  if (!open) runtime.close()
480
466
  }}
481
467
  >
482
468
  <L4AppDialogContent
483
469
  aria-label={t('title')}
484
- initialFocus={() =>
485
- desktopCloseButtonRef.current?.getClientRects().length
486
- ? desktopCloseButtonRef.current
487
- : closeButtonRef.current
488
- }
489
470
  showCloseButton={false}
490
- className="h-[calc(100dvh-2rem)] max-w-[70rem] flex-row bg-background data-open:animate-none max-lg:h-dvh max-lg:max-h-dvh max-lg:w-dvw max-lg:max-w-none max-lg:rounded-none max-lg:border-0"
471
+ className="h-[calc(100dvh-2rem)] max-w-[70rem] flex-row bg-background max-lg:h-dvh max-lg:max-h-dvh max-lg:w-dvw max-lg:max-w-none max-lg:rounded-none max-lg:border-0"
491
472
  >
492
473
  <div
493
- ref={listRef}
494
474
  className={cn(
495
475
  'flex min-w-0 flex-1 flex-col border-r bg-sidebar lg:max-w-80',
496
476
  showMobileDetail && 'hidden lg:flex'
@@ -505,7 +485,6 @@ function TaskCenterPanel({
505
485
  </p>
506
486
  </div>
507
487
  <Button
508
- ref={showMobileDetail ? undefined : closeButtonRef}
509
488
  className="lg:hidden"
510
489
  type="button"
511
490
  variant="ghost"
@@ -576,10 +555,7 @@ function TaskCenterPanel({
576
555
  </div>
577
556
  </div>
578
557
 
579
- <div
580
- ref={detailRef}
581
- className={cn('min-w-0 flex-1', !showMobileDetail && 'hidden lg:block')}
582
- >
558
+ <div className={cn('min-w-0 flex-1', !showMobileDetail && 'hidden lg:block')}>
583
559
  <div className="flex h-full min-h-0 flex-col">
584
560
  <div className="flex min-h-12 items-center gap-2 border-b bg-muted/10 px-3 lg:hidden">
585
561
  <Button
@@ -595,7 +571,6 @@ function TaskCenterPanel({
595
571
  {selectedTask?.title ?? t('detail')}
596
572
  </span>
597
573
  <Button
598
- ref={showMobileDetail ? closeButtonRef : undefined}
599
574
  type="button"
600
575
  variant="ghost"
601
576
  size="icon"
@@ -616,7 +591,6 @@ function TaskCenterPanel({
616
591
  </div>
617
592
  </div>
618
593
  <Button
619
- ref={desktopCloseButtonRef}
620
594
  className="absolute right-4 top-3 z-10 hidden lg:inline-flex"
621
595
  type="button"
622
596
  variant="ghost"