@jetcrab/pi-desk 1.1.28-dev → 1.1.29-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 (337) hide show
  1. package/package.json +1 -1
  2. package/src/app/api/work-sessions/search/route.ts +1 -0
  3. package/src/app/project-preview/page.tsx +1 -3
  4. package/src/client/l2_biz/project-preview/hooks/l2-use-project-preview.ts +1 -14
  5. package/src/client/l2_biz/project-preview/l2-project-preview-dialog.tsx +0 -1
  6. package/src/client/l2_biz/project-preview/l2-project-preview-page.tsx +0 -1
  7. package/src/client/l2_biz/project-preview/l2-project-preview.tsx +1 -4
  8. package/src/client/l2_biz/project-preview/views/l2-project-branch-select.tsx +42 -3
  9. package/src/client/l2_biz/workbench/git-workspace/l2-git-workspace-runtime.ts +11 -10
  10. package/src/client/l2_biz/workbench/hooks/l2-work-session-search.ts +52 -0
  11. package/src/client/l2_biz/workbench/hooks/l2-workbench-branch-picker.ts +42 -7
  12. package/src/client/l2_biz/workbench/hooks/l2-workbench-session-history.ts +143 -131
  13. package/src/client/l2_biz/workbench/hooks/l2-workbench-session-search.ts +97 -0
  14. package/src/client/l2_biz/workbench/l2-work-session-columns.tsx +8 -0
  15. package/src/client/l2_biz/workbench/l2-work-session-sidebar.tsx +129 -10
  16. package/src/client/l2_biz/workbench/l2-workbench-biz.ts +20 -2
  17. package/src/client/l2_biz/workbench/l2-workbench-branch-filter-preferences.ts +34 -0
  18. package/src/client/l2_biz/workbench/l2-workbench-branch-picker.tsx +34 -71
  19. package/src/client/l2_biz/workbench/l2-workbench-chat-input-runtime.ts +38 -1
  20. package/src/client/l2_biz/workbench/l2-workbench-chat-view.tsx +11 -1
  21. package/src/client/l2_biz/workbench/l2-workbench-picker-dialog.tsx +55 -215
  22. package/src/client/l2_biz/workbench/l2-workbench.tsx +20 -38
  23. package/src/client/l2_biz/workbench/views/l2-workbench-session-search.tsx +123 -0
  24. package/src/client/l3_modules/conversation/l3-conversation-messages.tsx +43 -4
  25. package/src/client/l3_modules/project-files/l3-markdown-preview.module.css +1 -1
  26. package/src/client/l3_modules/project-files/l3-project-document-git.ts +13 -29
  27. package/src/client/l3_modules/project-files/l3-project-document-view.tsx +1 -4
  28. package/src/client/l3_modules/project-files/l3-project-file-browser.module.css +14 -18
  29. package/src/client/l3_modules/project-files/l3-project-file-browser.tsx +52 -95
  30. package/src/client/l3_modules/project-files/l3-project-file-runtime.ts +52 -21
  31. package/src/client/l3_modules/project-files/l3-project-file-tabs.tsx +41 -62
  32. package/src/client/l3_modules/project-files/l3-project-git-runtime.ts +5 -4
  33. package/src/client/l3_modules/project-files/l3-use-project-refresh.ts +36 -0
  34. package/src/client/l3_modules/project-files/views/l3-project-search-results.tsx +2 -2
  35. package/src/client/l3_modules/project-files/views/l3-project-tree-folder.tsx +86 -0
  36. package/src/client/l4_foundation/ui/file-icons/README.md +1 -1
  37. package/src/client/l4_foundation/ui/file-icons/l4-file-icon.tsx +49 -2
  38. package/src/common/l2_biz/pi-session/l2-pi-session-contract.ts +11 -24
  39. package/src/common/l2_biz/project-preview/l2-project-preview-navigation.ts +5 -12
  40. package/src/common/l2_biz/work-session/l2-work-session-search-contract.ts +26 -0
  41. package/src/common/l2_biz/work-session/l2-work-session-tree-contract.ts +9 -1
  42. package/src/common/l2_biz/workbench/l2-workbench-locale-messages.ts +12 -0
  43. package/src/common/l2_biz/workbench/l2-workbench-picker-messages.ts +6 -2
  44. package/src/common/l3_modules/conversation/l3-conversation-locale-messages.ts +2 -0
  45. package/src/common/l3_modules/pi/l3-pi-session-search-contract.ts +26 -0
  46. package/src/common/l4_foundation/locale/l4-host-error-messages.ts +2 -0
  47. package/src/server/l1_entry/api/l1-work-session-branch-route.ts +21 -15
  48. package/src/server/l1_entry/api/l1-work-session-search-route.ts +38 -0
  49. package/src/server/l2_biz/work-session/l2-work-session-chat-runtime.ts +4 -2
  50. package/src/server/l2_biz/work-session/l2-work-session-manage.ts +46 -10
  51. package/src/server/l3_modules/work-session/l3-work-session.ts +11 -6
  52. package/src/server/l4_foundation/pi/l4-pi-chat-worker.ts +35 -2
  53. package/src/server/l4_foundation/pi/l4-pi-session-history-catalog.ts +62 -113
  54. package/src/server/l4_foundation/pi/l4-pi-session-search.ts +166 -0
  55. package/src/server/l4_foundation/pi/l4-pi-work-session-runtime.ts +66 -5
  56. package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
  57. package/temp/build/pi-desk/release/.next/app-path-routes-manifest.json +1 -0
  58. package/temp/build/pi-desk/release/.next/build-manifest.json +2 -2
  59. package/temp/build/pi-desk/release/.next/required-server-files.js +2 -2
  60. package/temp/build/pi-desk/release/.next/required-server-files.json +2 -2
  61. package/temp/build/pi-desk/release/.next/routes-manifest.json +6 -0
  62. package/temp/build/pi-desk/release/.next/server/app/_global-error/page.js +1 -1
  63. package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  64. package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
  65. package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +1 -1
  66. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  67. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  68. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  69. package/temp/build/pi-desk/release/.next/server/app/_not-found/page.js +1 -1
  70. package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  71. package/temp/build/pi-desk/release/.next/server/app/api/auth/login/route.js +2 -2
  72. package/temp/build/pi-desk/release/.next/server/app/api/auth/logout/route.js +1 -1
  73. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/get/route.js +1 -1
  74. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/replace/route.js +1 -1
  75. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/get/route.js +1 -1
  76. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/replace/route.js +1 -1
  77. package/temp/build/pi-desk/release/.next/server/app/api/chat/context/get/route.js +1 -1
  78. package/temp/build/pi-desk/release/.next/server/app/api/chat/images/get/route.js +1 -1
  79. package/temp/build/pi-desk/release/.next/server/app/api/chat/messages/get/route.js +1 -1
  80. package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
  81. package/temp/build/pi-desk/release/.next/server/app/api/mcp-check/get/route.js +1 -1
  82. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/del/route.js +1 -1
  83. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/get/route.js +1 -1
  84. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/replace/route.js +1 -1
  85. package/temp/build/pi-desk/release/.next/server/app/api/model-catalog/list/route.js +1 -1
  86. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/get/route.js +1 -1
  87. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route.js +1 -1
  88. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/replace/route.js +1 -1
  89. package/temp/build/pi-desk/release/.next/server/app/api/pi/directories/list/route.js +1 -1
  90. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-entries/list/route.js +1 -1
  91. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/list/route.js +1 -1
  92. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/replace/route.js +1 -1
  93. package/temp/build/pi-desk/release/.next/server/app/api/pi/models/list/route.js +1 -1
  94. package/temp/build/pi-desk/release/.next/server/app/api/pi/session-user-messages/list/route.js +1 -1
  95. package/temp/build/pi-desk/release/.next/server/app/api/pi/sessions/list/route.js +1 -1
  96. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/get/route.js +1 -1
  97. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/search/route.js +1 -1
  98. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-get/route.js +1 -1
  99. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-replace/route.js +1 -1
  100. package/temp/build/pi-desk/release/.next/server/app/api/plugins/add/route.js +1 -1
  101. package/temp/build/pi-desk/release/.next/server/app/api/plugins/apply/route.js +1 -1
  102. package/temp/build/pi-desk/release/.next/server/app/api/plugins/batch/route.js +1 -1
  103. package/temp/build/pi-desk/release/.next/server/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route.js +1 -1
  104. package/temp/build/pi-desk/release/.next/server/app/api/plugins/del/route.js +1 -1
  105. package/temp/build/pi-desk/release/.next/server/app/api/plugins/enabled-set/route.js +1 -1
  106. package/temp/build/pi-desk/release/.next/server/app/api/plugins/get/route.js +1 -1
  107. package/temp/build/pi-desk/release/.next/server/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route.js +1 -1
  108. package/temp/build/pi-desk/release/.next/server/app/api/plugins/list/route.js +1 -1
  109. package/temp/build/pi-desk/release/.next/server/app/api/plugins/reload/route.js +1 -1
  110. package/temp/build/pi-desk/release/.next/server/app/api/plugins/update/route.js +1 -1
  111. package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +2 -2
  112. package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +1 -1
  113. package/temp/build/pi-desk/release/.next/server/app/api/project-files/reveal/route.js +1 -1
  114. package/temp/build/pi-desk/release/.next/server/app/api/project-files/search/route.js +1 -1
  115. package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +2 -2
  116. package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +2 -2
  117. package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +1 -1
  118. package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +2 -2
  119. package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +1 -1
  120. package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +2 -2
  121. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/get/route.js +1 -1
  122. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/replace/route.js +1 -1
  123. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/get/route.js +1 -1
  124. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/list/route.js +1 -1
  125. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/replace/route.js +1 -1
  126. package/temp/build/pi-desk/release/.next/server/app/api/skills/list/route.js +1 -1
  127. package/temp/build/pi-desk/release/.next/server/app/api/task-center/images/get/route.js +1 -1
  128. package/temp/build/pi-desk/release/.next/server/app/api/task-center/messages/get/route.js +1 -1
  129. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/add/route.js +1 -1
  130. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/replace/route.js +1 -1
  131. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree/get/route.js +1 -1
  132. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree-entry/get/route.js +1 -1
  133. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/add/route.js +1 -1
  134. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/branch/route.js +1 -1
  135. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/del/route.js +1 -1
  136. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route.js +1 -1
  137. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/replace/route.js +1 -1
  138. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/search/route.js +1 -0
  139. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/search/route_client-reference-manifest.js +1 -0
  140. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/sort/route.js +1 -1
  141. package/temp/build/pi-desk/release/.next/server/app/favicon.ico/route.js +1 -1
  142. package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
  143. package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
  144. package/temp/build/pi-desk/release/.next/server/app/page.js +138 -138
  145. package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
  146. package/temp/build/pi-desk/release/.next/server/app/project-preview/page.js +1 -1
  147. package/temp/build/pi-desk/release/.next/server/app/project-preview/page_client-reference-manifest.js +1 -1
  148. package/temp/build/pi-desk/release/.next/server/app-paths-manifest.json +1 -0
  149. package/temp/build/pi-desk/release/.next/server/chunks/23054.js +2 -2
  150. package/temp/build/pi-desk/release/.next/server/chunks/25406.js +8 -8
  151. package/temp/build/pi-desk/release/.next/server/chunks/27344.js +3 -3
  152. package/temp/build/pi-desk/release/.next/server/chunks/3108.js +3 -3
  153. package/temp/build/pi-desk/release/.next/server/chunks/35985.js +2 -2
  154. package/temp/build/pi-desk/release/.next/server/chunks/41856.js +1 -0
  155. package/temp/build/pi-desk/release/.next/server/chunks/62900.js +235 -0
  156. package/temp/build/pi-desk/release/.next/server/chunks/6917.js +1 -1
  157. package/temp/build/pi-desk/release/.next/server/chunks/81363.js +1 -1
  158. package/temp/build/pi-desk/release/.next/server/chunks/81912.js +3 -0
  159. package/temp/build/pi-desk/release/.next/server/chunks/92386.js +2 -2
  160. package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
  161. package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
  162. package/temp/build/pi-desk/release/.next/static/Yyfg-r17aYmEzlYYlIwDo/_buildManifest.js +1 -0
  163. package/temp/build/pi-desk/release/.next/static/chunks/10043-9d6c3735418ccaf9.js +238 -0
  164. package/temp/build/pi-desk/release/.next/static/chunks/11937-ac71fb0f7cef482a.js +1 -0
  165. package/temp/build/pi-desk/release/.next/static/chunks/30669-ffa76d39e0e25194.js +1 -0
  166. package/temp/build/pi-desk/release/.next/static/chunks/36643-f60e98278740073c.js +3 -0
  167. package/temp/build/pi-desk/release/.next/static/chunks/65232-a8571f78020eede2.js +15 -0
  168. package/temp/build/pi-desk/release/.next/static/chunks/{51474-8dc714cb76b2e60a.js → 65350-23bb961d87addf14.js} +3 -3
  169. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-295cb63da5f7262f.js +1 -0
  170. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-295cb63da5f7262f.js +1 -0
  171. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-295cb63da5f7262f.js +1 -0
  172. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-295cb63da5f7262f.js +1 -0
  173. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-295cb63da5f7262f.js +1 -0
  174. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-295cb63da5f7262f.js +1 -0
  175. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-295cb63da5f7262f.js +1 -0
  176. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-295cb63da5f7262f.js +1 -0
  177. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-295cb63da5f7262f.js +1 -0
  178. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-295cb63da5f7262f.js +1 -0
  179. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-295cb63da5f7262f.js +1 -0
  180. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-295cb63da5f7262f.js +1 -0
  181. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-295cb63da5f7262f.js +1 -0
  182. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-295cb63da5f7262f.js +1 -0
  183. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-295cb63da5f7262f.js +1 -0
  184. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-295cb63da5f7262f.js +1 -0
  185. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-295cb63da5f7262f.js +1 -0
  186. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-295cb63da5f7262f.js +1 -0
  187. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-295cb63da5f7262f.js +1 -0
  188. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-295cb63da5f7262f.js +1 -0
  189. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-295cb63da5f7262f.js +1 -0
  190. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-295cb63da5f7262f.js +1 -0
  191. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-295cb63da5f7262f.js +1 -0
  192. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-295cb63da5f7262f.js +1 -0
  193. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-295cb63da5f7262f.js +1 -0
  194. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-295cb63da5f7262f.js +1 -0
  195. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-295cb63da5f7262f.js +1 -0
  196. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-295cb63da5f7262f.js +1 -0
  197. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-295cb63da5f7262f.js +1 -0
  198. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-295cb63da5f7262f.js +1 -0
  199. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-295cb63da5f7262f.js +1 -0
  200. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-295cb63da5f7262f.js +1 -0
  201. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-295cb63da5f7262f.js +1 -0
  202. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-295cb63da5f7262f.js +1 -0
  203. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-295cb63da5f7262f.js +1 -0
  204. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-295cb63da5f7262f.js +1 -0
  205. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-295cb63da5f7262f.js +1 -0
  206. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-295cb63da5f7262f.js +1 -0
  207. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-295cb63da5f7262f.js +1 -0
  208. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-295cb63da5f7262f.js +1 -0
  209. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-295cb63da5f7262f.js +1 -0
  210. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-295cb63da5f7262f.js +1 -0
  211. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-295cb63da5f7262f.js +1 -0
  212. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-295cb63da5f7262f.js +1 -0
  213. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-295cb63da5f7262f.js +1 -0
  214. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-295cb63da5f7262f.js +1 -0
  215. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-295cb63da5f7262f.js +1 -0
  216. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-295cb63da5f7262f.js +1 -0
  217. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-295cb63da5f7262f.js +1 -0
  218. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-295cb63da5f7262f.js +1 -0
  219. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-295cb63da5f7262f.js +1 -0
  220. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-295cb63da5f7262f.js +1 -0
  221. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-295cb63da5f7262f.js +1 -0
  222. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-295cb63da5f7262f.js +1 -0
  223. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-295cb63da5f7262f.js +1 -0
  224. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-295cb63da5f7262f.js +1 -0
  225. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-295cb63da5f7262f.js +1 -0
  226. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-295cb63da5f7262f.js +1 -0
  227. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-295cb63da5f7262f.js +1 -0
  228. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-295cb63da5f7262f.js +1 -0
  229. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-295cb63da5f7262f.js +1 -0
  230. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-295cb63da5f7262f.js +1 -0
  231. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-295cb63da5f7262f.js +1 -0
  232. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-295cb63da5f7262f.js +1 -0
  233. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-295cb63da5f7262f.js +1 -0
  234. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-295cb63da5f7262f.js +1 -0
  235. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-295cb63da5f7262f.js +1 -0
  236. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-295cb63da5f7262f.js +1 -0
  237. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-295cb63da5f7262f.js +1 -0
  238. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/search/route-295cb63da5f7262f.js +1 -0
  239. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-295cb63da5f7262f.js +1 -0
  240. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-2c6a573d3004516e.js +1 -0
  241. package/temp/build/pi-desk/release/.next/static/chunks/app/login/{page-0d3d4827802108e5.js → page-0df9df996aa68060.js} +1 -1
  242. package/temp/build/pi-desk/release/.next/static/chunks/app/page-f78be007d97f0d95.js +158 -0
  243. package/temp/build/pi-desk/release/.next/static/chunks/app/project-preview/{page-038b6c14e03ed878.js → page-e1dbfcfc0f333e01.js} +1 -1
  244. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-295cb63da5f7262f.js +1 -0
  245. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-295cb63da5f7262f.js +1 -0
  246. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-295cb63da5f7262f.js +1 -0
  247. package/temp/build/pi-desk/release/.next/static/css/{1e780a4936aa6ba3.css → 2bb393927ba8f71d.css} +1 -1
  248. package/temp/build/pi-desk/release/.next/static/css/3a07dcc86ffdf88c.css +1 -0
  249. package/temp/build/pi-desk/release/.next/static/css/a677e7fbf6e2173e.css +1 -0
  250. package/temp/build/pi-desk/release/.next/trace-build +1 -1
  251. package/temp/build/pi-desk/release/.next/server/chunks/35348.js +0 -3
  252. package/temp/build/pi-desk/release/.next/server/chunks/56830.js +0 -235
  253. package/temp/build/pi-desk/release/.next/server/chunks/80780.js +0 -1
  254. package/temp/build/pi-desk/release/.next/static/bj2dB_Z10YB_CqK_VNhDx/_buildManifest.js +0 -1
  255. package/temp/build/pi-desk/release/.next/static/chunks/11937-1d0a9822f2c7995b.js +0 -1
  256. package/temp/build/pi-desk/release/.next/static/chunks/14197-3d3ddd426ac06c9c.js +0 -3
  257. package/temp/build/pi-desk/release/.next/static/chunks/37313-d5970e2d0c270d22.js +0 -238
  258. package/temp/build/pi-desk/release/.next/static/chunks/65232-ef4e5a4174f62faf.js +0 -15
  259. package/temp/build/pi-desk/release/.next/static/chunks/79267-7d21d7cdbd7cfca1.js +0 -1
  260. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-9969fe0baa238786.js +0 -1
  261. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-9969fe0baa238786.js +0 -1
  262. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-9969fe0baa238786.js +0 -1
  263. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-9969fe0baa238786.js +0 -1
  264. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-9969fe0baa238786.js +0 -1
  265. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-9969fe0baa238786.js +0 -1
  266. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-9969fe0baa238786.js +0 -1
  267. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-9969fe0baa238786.js +0 -1
  268. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-9969fe0baa238786.js +0 -1
  269. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-9969fe0baa238786.js +0 -1
  270. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-9969fe0baa238786.js +0 -1
  271. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-9969fe0baa238786.js +0 -1
  272. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-9969fe0baa238786.js +0 -1
  273. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-9969fe0baa238786.js +0 -1
  274. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-9969fe0baa238786.js +0 -1
  275. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-9969fe0baa238786.js +0 -1
  276. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-9969fe0baa238786.js +0 -1
  277. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-9969fe0baa238786.js +0 -1
  278. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-9969fe0baa238786.js +0 -1
  279. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-9969fe0baa238786.js +0 -1
  280. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-9969fe0baa238786.js +0 -1
  281. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-9969fe0baa238786.js +0 -1
  282. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-9969fe0baa238786.js +0 -1
  283. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-9969fe0baa238786.js +0 -1
  284. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-9969fe0baa238786.js +0 -1
  285. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-9969fe0baa238786.js +0 -1
  286. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-9969fe0baa238786.js +0 -1
  287. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-9969fe0baa238786.js +0 -1
  288. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-9969fe0baa238786.js +0 -1
  289. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-9969fe0baa238786.js +0 -1
  290. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-9969fe0baa238786.js +0 -1
  291. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-9969fe0baa238786.js +0 -1
  292. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-9969fe0baa238786.js +0 -1
  293. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-9969fe0baa238786.js +0 -1
  294. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-9969fe0baa238786.js +0 -1
  295. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-9969fe0baa238786.js +0 -1
  296. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-9969fe0baa238786.js +0 -1
  297. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-9969fe0baa238786.js +0 -1
  298. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-9969fe0baa238786.js +0 -1
  299. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-9969fe0baa238786.js +0 -1
  300. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-9969fe0baa238786.js +0 -1
  301. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-9969fe0baa238786.js +0 -1
  302. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-9969fe0baa238786.js +0 -1
  303. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-9969fe0baa238786.js +0 -1
  304. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-9969fe0baa238786.js +0 -1
  305. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-9969fe0baa238786.js +0 -1
  306. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-9969fe0baa238786.js +0 -1
  307. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-9969fe0baa238786.js +0 -1
  308. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-9969fe0baa238786.js +0 -1
  309. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-9969fe0baa238786.js +0 -1
  310. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-9969fe0baa238786.js +0 -1
  311. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-9969fe0baa238786.js +0 -1
  312. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-9969fe0baa238786.js +0 -1
  313. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-9969fe0baa238786.js +0 -1
  314. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-9969fe0baa238786.js +0 -1
  315. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-9969fe0baa238786.js +0 -1
  316. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-9969fe0baa238786.js +0 -1
  317. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-9969fe0baa238786.js +0 -1
  318. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-9969fe0baa238786.js +0 -1
  319. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-9969fe0baa238786.js +0 -1
  320. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-9969fe0baa238786.js +0 -1
  321. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-9969fe0baa238786.js +0 -1
  322. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-9969fe0baa238786.js +0 -1
  323. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-9969fe0baa238786.js +0 -1
  324. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-9969fe0baa238786.js +0 -1
  325. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-9969fe0baa238786.js +0 -1
  326. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-9969fe0baa238786.js +0 -1
  327. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-9969fe0baa238786.js +0 -1
  328. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-9969fe0baa238786.js +0 -1
  329. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-9969fe0baa238786.js +0 -1
  330. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-20718f1503910291.js +0 -1
  331. package/temp/build/pi-desk/release/.next/static/chunks/app/page-ce2ebf7d8ea7a330.js +0 -158
  332. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-9969fe0baa238786.js +0 -1
  333. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-9969fe0baa238786.js +0 -1
  334. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9969fe0baa238786.js +0 -1
  335. package/temp/build/pi-desk/release/.next/static/css/2c3b0c0ff1f49c68.css +0 -1
  336. package/temp/build/pi-desk/release/.next/static/css/c43b04c244a64fb4.css +0 -1
  337. /package/temp/build/pi-desk/release/.next/static/{bj2dB_Z10YB_CqK_VNhDx → Yyfg-r17aYmEzlYYlIwDo}/_ssgManifest.js +0 -0
@@ -15,6 +15,7 @@ import {
15
15
  FolderIcon,
16
16
  Layers3Icon,
17
17
  LoaderCircleIcon,
18
+ RotateCcwIcon,
18
19
  SearchIcon,
19
20
  TerminalIcon,
20
21
  WrenchIcon
@@ -566,11 +567,16 @@ function UserMessageText({ text }: { text: string }): React.JSX.Element {
566
567
 
567
568
  function UserMessage({
568
569
  message,
569
- onAcquireImage
570
+ onAcquireImage,
571
+ onResend,
572
+ resendDisabled
570
573
  }: {
571
574
  message: L3ConversationDisplayMessage
572
575
  onAcquireImage: L3ConversationAcquireImage
576
+ onResend?: (entryId: string) => void
577
+ resendDisabled?: boolean
573
578
  }): React.JSX.Element {
579
+ const { t } = useTranslation('conversation')
574
580
  if (message.summary.type !== 'user') throw new Error('UserMessage requires a user summary')
575
581
 
576
582
  return (
@@ -595,6 +601,18 @@ function UserMessage({
595
601
  </MessageContent>
596
602
  {message.timestampMs === null ? null : (
597
603
  <MessageToolbar className="mt-0 justify-end gap-1 text-xs text-muted-foreground">
604
+ {message.durable && onResend ? (
605
+ <MessageAction
606
+ tooltip={t('resendMessage')}
607
+ label={t('resendMessage')}
608
+ size="icon-sm"
609
+ className={cn(styles.messageCopyAction, 'text-muted-foreground')}
610
+ disabled={resendDisabled}
611
+ onClick={() => onResend(message.durable!.location.entryId)}
612
+ >
613
+ <RotateCcwIcon className="size-3.5" />
614
+ </MessageAction>
615
+ ) : null}
598
616
  <MessageCopyAction text={message.summary.text} />
599
617
  <MessageTime timestampMs={message.timestampMs} />
600
618
  </MessageToolbar>
@@ -1849,6 +1867,8 @@ interface L3ConversationTurnViewProps {
1849
1867
  turn: L3ConversationTurn
1850
1868
  cwd: string
1851
1869
  logicalTail?: boolean
1870
+ onResend?: (entryId: string) => void
1871
+ resendDisabled?: boolean
1852
1872
  onLoadDetail: L3ConversationLoadDetail
1853
1873
  onAcquireImage: L3ConversationAcquireImage
1854
1874
  onPreviewFile?: L3ConversationPreviewFile
@@ -1910,17 +1930,28 @@ function sameTurn(left: L3ConversationTurn, right: L3ConversationTurn): boolean
1910
1930
  function TurnUserMessageComponent({
1911
1931
  message,
1912
1932
  onLoadDetail,
1913
- onAcquireImage
1933
+ onAcquireImage,
1934
+ onResend,
1935
+ resendDisabled
1914
1936
  }: {
1915
1937
  message: L3ConversationDisplayMessage
1916
1938
  onLoadDetail: L3ConversationLoadDetail
1917
1939
  onAcquireImage: L3ConversationAcquireImage
1940
+ onResend?: (entryId: string) => void
1941
+ resendDisabled?: boolean
1918
1942
  }): React.JSX.Element {
1919
1943
  return (
1920
1944
  <L3ConversationMessageView
1921
1945
  message={message}
1922
1946
  loadDetail={onLoadDetail}
1923
- defaultView={<UserMessage message={message} onAcquireImage={onAcquireImage} />}
1947
+ defaultView={
1948
+ <UserMessage
1949
+ message={message}
1950
+ onAcquireImage={onAcquireImage}
1951
+ onResend={onResend}
1952
+ resendDisabled={resendDisabled}
1953
+ />
1954
+ }
1924
1955
  />
1925
1956
  )
1926
1957
  }
@@ -1930,6 +1961,8 @@ const TurnUserMessage = memo(
1930
1961
  (previous, next) =>
1931
1962
  previous.onLoadDetail === next.onLoadDetail &&
1932
1963
  previous.onAcquireImage === next.onAcquireImage &&
1964
+ previous.onResend === next.onResend &&
1965
+ previous.resendDisabled === next.resendDisabled &&
1933
1966
  sameDisplayMessage(previous.message, next.message)
1934
1967
  )
1935
1968
 
@@ -1963,7 +1996,9 @@ function L3ConversationTurnViewComponent({
1963
1996
  logicalTail = false,
1964
1997
  onLoadDetail,
1965
1998
  onAcquireImage,
1966
- onPreviewFile
1999
+ onPreviewFile,
2000
+ onResend,
2001
+ resendDisabled
1967
2002
  }: L3ConversationTurnViewProps): React.JSX.Element {
1968
2003
  if (turn.compaction) {
1969
2004
  return (
@@ -1995,6 +2030,8 @@ function L3ConversationTurnViewComponent({
1995
2030
  message={turn.user}
1996
2031
  onLoadDetail={onLoadDetail}
1997
2032
  onAcquireImage={onAcquireImage}
2033
+ onResend={onResend}
2034
+ resendDisabled={resendDisabled}
1998
2035
  />
1999
2036
  ) : null}
2000
2037
  <L3ConversationImageContext.Provider value={onAcquireImage}>
@@ -2020,6 +2057,8 @@ export const L3ConversationTurnView = memo(
2020
2057
  (previous, next) =>
2021
2058
  previous.cwd === next.cwd &&
2022
2059
  previous.logicalTail === next.logicalTail &&
2060
+ previous.onResend === next.onResend &&
2061
+ previous.resendDisabled === next.resendDisabled &&
2023
2062
  previous.onAcquireImage === next.onAcquireImage &&
2024
2063
  previous.onLoadDetail === next.onLoadDetail &&
2025
2064
  previous.onPreviewFile === next.onPreviewFile &&
@@ -1,7 +1,7 @@
1
1
  .document {
2
2
  box-sizing: border-box;
3
3
  width: 100%;
4
- max-width: 1200px;
4
+ max-width: 80ch;
5
5
  min-width: 0;
6
6
  margin-inline: auto;
7
7
  padding: 1.5rem;
@@ -4,19 +4,20 @@ import { useCallback, useEffect, useRef, useSyncExternalStore, type RefObject }
4
4
  import type { L3ProjectFileRuntime } from './l3-project-file-runtime'
5
5
  import type { L3ProjectGitBrowser } from './l3-project-git-runtime'
6
6
  import { findL3GitFile } from './l3-project-git-model'
7
+ import { useL3ProjectRefresh } from './l3-use-project-refresh'
7
8
 
8
9
  export function useL3ProjectDocumentGit(
9
10
  runtime: L3ProjectFileRuntime,
10
11
  git: L3ProjectGitBrowser,
11
12
  host: RefObject<HTMLDivElement | null>,
12
13
  savePosition: () => void,
13
- active: boolean,
14
- refreshOnFocus = true
14
+ active: boolean
15
15
  ): { refresh: () => void; unavailable: boolean } {
16
16
  useSyncExternalStore(git.subscribe, git.getRevision, git.getRevision)
17
17
  const snapshot = git.getWorkspace(runtime.cwd)?.snapshot
18
18
  const path = runtime.state.activePath
19
- const diffActive = Boolean(runtime.state.activeDiff)
19
+ const diff = runtime.state.activeDiff
20
+ const diffActive = Boolean(diff)
20
21
  const document = path ? runtime.state.documents.get(path) : undefined
21
22
  const save = useRef(savePosition)
22
23
  useEffect(() => {
@@ -29,36 +30,19 @@ export function useL3ProjectDocumentGit(
29
30
  void git.refreshSnapshot(runtime.cwd)
30
31
  }, [diffActive, git, path, runtime])
31
32
 
32
- useEffect(() => {
33
- if (!refreshOnFocus || !active || !path || diffActive) return
34
- const visible = (): boolean =>
35
- window.document.visibilityState === 'visible' &&
36
- Boolean(host.current?.getClientRects().length) &&
37
- !host.current?.closest('[inert], [aria-hidden="true"]')
38
- let lastRefresh = Date.now()
39
- if (visible()) {
40
- // 已打开的标签重新展示时重读;首次打开仍复用正在进行的正文请求。
41
- if (runtime.state.documents.get(path)?.status === 'text') {
42
- save.current()
43
- runtime.reloadFile(path)
44
- }
45
- void git.refreshSnapshot(runtime.cwd)
46
- }
47
- const onFocus = (): void => {
48
- if (!visible() || Date.now() - lastRefresh < 1000) return
49
- lastRefresh = Date.now()
50
- refresh()
33
+ const refreshVisible = useCallback((): void => {
34
+ if (diff) runtime.refreshDiff()
35
+ else if (path) {
36
+ save.current()
37
+ void runtime.ensureDocument(path, true)
51
38
  }
52
- window.addEventListener('focus', onFocus)
53
- window.document.addEventListener('visibilitychange', onFocus)
54
- return () => {
55
- window.removeEventListener('focus', onFocus)
56
- window.document.removeEventListener('visibilitychange', onFocus)
57
- }
58
- }, [active, diffActive, git, host, path, refresh, refreshOnFocus, runtime])
39
+ void git.refreshSnapshot(runtime.cwd)
40
+ }, [diff, git, path, runtime])
41
+ useL3ProjectRefresh(host, refreshVisible, active)
59
42
 
60
43
  useEffect(() => {
61
44
  if (!active || !path || diffActive || document?.status !== 'text') return
45
+ if (snapshot?.status === 'loading') return
62
46
  const controller = new AbortController()
63
47
  const file =
64
48
  snapshot?.status === 'ready' ? findL3GitFile(runtime.cwd, path, snapshot.repositories) : null
@@ -54,7 +54,6 @@ export function L3ProjectDocumentView({
54
54
  gitRuntime,
55
55
  compact,
56
56
  visible = true,
57
- refreshOnFocus = true,
58
57
  onEscape,
59
58
  onSwitchPane,
60
59
  renderHeader
@@ -64,7 +63,6 @@ export function L3ProjectDocumentView({
64
63
  gitRuntime: L3ProjectGitBrowser
65
64
  compact: boolean
66
65
  visible?: boolean
67
- refreshOnFocus?: boolean
68
66
  onEscape: () => void
69
67
  onSwitchPane?: () => void
70
68
  renderHeader?: (actions: ReactNode) => ReactNode
@@ -112,8 +110,7 @@ export function L3ProjectDocumentView({
112
110
  gitRuntime,
113
111
  hostRef,
114
112
  savePosition,
115
- visible,
116
- refreshOnFocus
113
+ visible
117
114
  )
118
115
  const comparison = document?.status === 'text' ? document.comparison : undefined
119
116
  const [computed, setComputed] = useState<{
@@ -6,25 +6,21 @@
6
6
  padding: 0 4px;
7
7
  }
8
8
 
9
- .tree [data-slot='collapsible-content'] > div {
10
- border-left-color: color-mix(in oklab, var(--border) 50%, transparent);
9
+ .tree [role='treeitem']:not([aria-expanded]),
10
+ .tree [role='treeitem'][aria-expanded] > div:first-child {
11
+ min-height: 24px;
12
+ gap: 4px;
13
+ border-radius: 3px;
14
+ padding: 0 4px;
11
15
  }
12
16
 
13
- @media (pointer: fine) {
14
- .tree [role='treeitem']:not([aria-expanded]),
15
- .tree [role='treeitem'][aria-expanded] > div:first-child {
16
- min-height: 24px;
17
- gap: 4px;
18
- padding: 0 4px;
19
- }
20
-
21
- .tree [role='treeitem'][aria-expanded] > div:first-child > button {
22
- min-height: 24px;
23
- gap: 4px;
24
- }
17
+ .tree [role='treeitem'][aria-expanded] > div:first-child > button {
18
+ min-height: 24px;
19
+ gap: 4px;
20
+ }
25
21
 
26
- .tree [data-slot='collapsible-content'] > div {
27
- margin-left: 8px;
28
- padding-left: 3px;
29
- }
22
+ .tree [data-slot='collapsible-content'] > div {
23
+ margin-left: 8px;
24
+ border-left-color: color-mix(in oklab, var(--border) 35%, transparent);
25
+ padding-left: 3px;
30
26
  }
@@ -1,15 +1,10 @@
1
1
  'use client'
2
2
 
3
3
  import {
4
- BracesIcon,
5
4
  ChevronRightIcon,
6
- FileCode2Icon,
7
- FileIcon,
8
- FileTextIcon,
9
5
  FolderGit2Icon,
10
6
  FolderIcon,
11
7
  GitBranchIcon,
12
- ImageIcon,
13
8
  ListFilterIcon,
14
9
  LoaderCircleIcon,
15
10
  SearchIcon
@@ -23,11 +18,12 @@ import { cn } from '@client/l4_foundation/lib/l4-utils'
23
18
  import {
24
19
  FileTree,
25
20
  FileTreeFile,
26
- FileTreeFolder,
27
21
  FileTreeIcon,
28
22
  FileTreeName
29
23
  } from '@client/l4_foundation/ui/ai-elements/file-tree'
30
24
  import { L4ScrollArea } from '@client/l4_foundation/ui/l4-scroll-area'
25
+ import { L4FileIcon } from '@client/l4_foundation/ui/file-icons/l4-file-icon'
26
+ import { L3ProjectTreeFolder } from './views/l3-project-tree-folder'
31
27
  import { buttonVariants } from '@client/l4_foundation/ui/shadcn/button'
32
28
  import { L3ProjectSearchControls } from './views/l3-project-search-controls'
33
29
  import { L3ProjectSearchResults } from './views/l3-project-search-results'
@@ -43,6 +39,7 @@ import {
43
39
  } from './l3-project-git-model'
44
40
  import type { L3DirectoryState, L3ProjectFileRuntime } from './l3-project-file-runtime'
45
41
  import { L3ProjectPathMenu } from './l3-project-path-menu'
42
+ import { useL3ProjectRefresh } from './l3-use-project-refresh'
46
43
  import styles from './l3-project-file-browser.module.css'
47
44
  import {
48
45
  buildL3ProjectPathTree,
@@ -74,47 +71,7 @@ function compactPath(path: string): string {
74
71
  }
75
72
 
76
73
  function fileIcon(path: string): React.JSX.Element {
77
- const name = path.split('/').at(-1)?.toLocaleLowerCase() ?? ''
78
- const extension = name.includes('.') ? (name.split('.').at(-1) ?? '') : ''
79
- if (['png', 'jpg', 'jpeg', 'webp', 'gif'].includes(extension)) {
80
- return <ImageIcon className="size-4 text-muted-foreground" />
81
- }
82
- if (extension === 'json' || extension === 'jsonl') {
83
- return <BracesIcon className="size-4 text-muted-foreground" />
84
- }
85
- if (['md', 'mdx', 'txt'].includes(extension)) {
86
- return <FileTextIcon className="size-4 text-muted-foreground" />
87
- }
88
- if (
89
- [
90
- 'ts',
91
- 'tsx',
92
- 'js',
93
- 'jsx',
94
- 'mjs',
95
- 'cjs',
96
- 'py',
97
- 'go',
98
- 'rs',
99
- 'java',
100
- 'c',
101
- 'cpp',
102
- 'h',
103
- 'hpp',
104
- 'css',
105
- 'scss',
106
- 'html',
107
- 'xml',
108
- 'yaml',
109
- 'yml',
110
- 'toml',
111
- 'sql',
112
- 'sh'
113
- ].includes(extension)
114
- ) {
115
- return <FileCode2Icon className="size-4 text-muted-foreground" />
116
- }
117
- return <FileIcon className="size-4 text-muted-foreground" />
74
+ return <L4FileIcon path={path} className="size-4 text-muted-foreground" />
118
75
  }
119
76
 
120
77
  function changedFileNameClass(change: L3GitProjectChange | null): string | undefined {
@@ -166,6 +123,7 @@ export function L3ProjectFileBrowser({
166
123
  useSyncExternalStore(gitRuntime.subscribe, gitRuntime.getRevision, gitRuntime.getRevision)
167
124
  const workspace = runtime.state
168
125
  const gitWorkspace = gitRuntime.getWorkspace(cwd)
126
+ const hostRef = useRef<HTMLElement>(null)
169
127
  const scrollRef = useRef<HTMLDivElement>(null)
170
128
  const searchInputRef = useRef<HTMLInputElement>(null)
171
129
  const searchResultsRef = useRef<HTMLDivElement>(null)
@@ -210,10 +168,32 @@ export function L3ProjectFileBrowser({
210
168
  const changeByProjectPath = new Map(projectChanges.map((change) => [change.projectPath, change]))
211
169
  const readyRepositoryRoots = repositories.map((repository) => repository.root).filter(Boolean)
212
170
 
213
- useEffect(() => {
214
- void runtime.ensureRoot()
215
- void gitRuntime.ensureSnapshot(cwd)
171
+ const refreshVisible = useCallback((): void => {
172
+ void gitRuntime.refreshSnapshot(cwd)
173
+ const current = gitRuntime.getWorkspace(cwd)
174
+ if (runtime.state.searchOpen || current?.changesOnly) return
175
+ const repositoryLayout =
176
+ current?.layout === 'repository' &&
177
+ !(current.snapshot.repositories.length === 1 && current.snapshot.repositories[0]?.root === '')
178
+ const roots = repositoryLayout
179
+ ? [...current.expandedRepositories].sort((left, right) => right.length - left.length)
180
+ : ['']
181
+ const expanded = runtime.state.expandedPaths
182
+ const paths = new Set(roots)
183
+ for (const path of expanded) {
184
+ const root = roots.find((candidate) => !candidate || path.startsWith(`${candidate}/`))
185
+ if (root === undefined) continue
186
+ const parts = path.slice(root ? root.length + 1 : 0).split('/')
187
+ if (
188
+ parts
189
+ .slice(0, -1)
190
+ .every((_, index) => expanded.has(joinPath(root, parts.slice(0, index + 1).join('/'))))
191
+ )
192
+ paths.add(path)
193
+ }
194
+ runtime.refreshDirectories(paths)
216
195
  }, [cwd, gitRuntime, runtime])
196
+ useL3ProjectRefresh(hostRef, refreshVisible)
217
197
 
218
198
  useEffect(() => {
219
199
  const scrollElement = scrollRef.current
@@ -238,10 +218,6 @@ export function L3ProjectFileBrowser({
238
218
  }, [expandedRepositoryRootsKey, gitWorkspace, runtime])
239
219
 
240
220
  const boundaries = new Set(readyRepositoryRoots)
241
- const displayedDirectories = new Map<string, L3CompactDirectory>()
242
- const expandedKeys = new Set(
243
- [...workspace.expandedPaths].map((path) => keyL3ProjectTree('directory', path))
244
- )
245
221
  const toggleDirectory = (directory: L3CompactDirectory, expanded: boolean): void => {
246
222
  const next = new Set(workspace.expandedPaths)
247
223
  for (const path of directory.paths) {
@@ -249,16 +225,11 @@ export function L3ProjectFileBrowser({
249
225
  else next.delete(path)
250
226
  }
251
227
  runtime.setExpandedPaths(next, false)
252
- if (expanded && !gitWorkspace?.changesOnly)
253
- void runtime.expandDirectoryChain(directory.path, boundaries)
254
- }
255
- const applyExpanded = (keys: Set<string>): void => {
256
- const changed = [...displayedDirectories].filter(
257
- ([path]) =>
258
- keys.has(keyL3ProjectTree('directory', path)) !== workspace.expandedPaths.has(path)
259
- )
260
- for (const [path, directory] of changed)
261
- toggleDirectory(directory, keys.has(keyL3ProjectTree('directory', path)))
228
+ if (expanded && !gitWorkspace?.changesOnly) {
229
+ void Promise.all(directory.paths.map((path) => runtime.ensureDirectory(path, true))).then(
230
+ () => runtime.expandDirectoryChain(directory.path, boundaries)
231
+ )
232
+ }
262
233
  }
263
234
 
264
235
  const openPreview = (path: string, line?: number): void => {
@@ -391,13 +362,12 @@ export function L3ProjectFileBrowser({
391
362
  false
392
363
  )
393
364
  const directory = runtime.compactDirectory(childPath, boundaries)
394
- displayedDirectories.set(childPath, directory)
395
365
  return directoryMenu(
396
366
  directory,
397
- <FileTreeFolder
398
- path={keyL3ProjectTree('directory', childPath)}
399
- name={directory.label}
400
- title={directory.targetPath}
367
+ <L3ProjectTreeFolder
368
+ directory={directory}
369
+ expanded={workspace.expandedPaths.has(childPath)}
370
+ onToggle={() => toggleDirectory(directory, !workspace.expandedPaths.has(childPath))}
401
371
  data-testid={`project-folder-${childPath}`}
402
372
  >
403
373
  {renderDirectory(
@@ -405,7 +375,7 @@ export function L3ProjectFileBrowser({
405
375
  currentRepositoryRoot,
406
376
  respectRepositoryBoundaries
407
377
  )}
408
- </FileTreeFolder>
378
+ </L3ProjectTreeFolder>
409
379
  )
410
380
  })}
411
381
  {moreEntries(`directory:${path}`, entries.length)}
@@ -434,17 +404,16 @@ export function L3ProjectFileBrowser({
434
404
  <>
435
405
  {directories.slice(0, limit).map((childPath) => {
436
406
  const directory = compactL3PathTreeDirectory(childPath, tree, boundaries)
437
- displayedDirectories.set(childPath, directory)
438
407
  return directoryMenu(
439
408
  directory,
440
- <FileTreeFolder
441
- path={keyL3ProjectTree('directory', childPath)}
442
- name={directory.label}
443
- title={directory.targetPath}
409
+ <L3ProjectTreeFolder
410
+ directory={directory}
411
+ expanded={workspace.expandedPaths.has(childPath)}
412
+ onToggle={() => toggleDirectory(directory, !workspace.expandedPaths.has(childPath))}
444
413
  data-testid={`project-folder-${childPath}`}
445
414
  >
446
415
  {renderChangeNodes(tree, directory.targetPath)}
447
- </FileTreeFolder>
416
+ </L3ProjectTreeFolder>
448
417
  )
449
418
  })}
450
419
  {files
@@ -462,12 +431,7 @@ export function L3ProjectFileBrowser({
462
431
  )
463
432
  }
464
433
 
465
- const selectDirectoryPath = (key: string): void => {
466
- if (key.startsWith('directory:')) {
467
- const directory = displayedDirectories.get(key.slice('directory:'.length))
468
- if (directory) toggleDirectory(directory, !workspace.expandedPaths.has(directory.path))
469
- return
470
- }
434
+ const selectFile = (key: string): void => {
471
435
  const path = key.slice('file:'.length)
472
436
  const change = changeByProjectPath.get(path)
473
437
  if (gitWorkspace?.changesOnly && change) openDiff(change)
@@ -480,7 +444,6 @@ export function L3ProjectFileBrowser({
480
444
  return (
481
445
  <FileTree
482
446
  className="rounded-none border-0 bg-transparent"
483
- expanded={expandedKeys}
484
447
  selectedPath={
485
448
  workspace?.activeDiff
486
449
  ? keyL3ProjectTree(
@@ -494,8 +457,7 @@ export function L3ProjectFileBrowser({
494
457
  ? keyL3ProjectTree('file', workspace.activePath)
495
458
  : undefined
496
459
  }
497
- onExpandedChange={applyExpanded}
498
- onSelect={selectDirectoryPath}
460
+ onSelect={selectFile}
499
461
  >
500
462
  {projectChanges.length > 0 ? (
501
463
  renderChangeNodes(root, '')
@@ -513,12 +475,10 @@ export function L3ProjectFileBrowser({
513
475
  return (
514
476
  <FileTree
515
477
  className="rounded-none border-0 bg-transparent"
516
- expanded={expandedKeys}
517
478
  selectedPath={
518
479
  workspace.activePath ? keyL3ProjectTree('file', workspace.activePath) : undefined
519
480
  }
520
- onExpandedChange={applyExpanded}
521
- onSelect={selectDirectoryPath}
481
+ onSelect={selectFile}
522
482
  >
523
483
  {renderDirectory('', null, false)}
524
484
  </FileTree>
@@ -557,7 +517,7 @@ export function L3ProjectFileBrowser({
557
517
  onClick={() => {
558
518
  if (expanded) runtime.cancelDirectoryExpansion(root)
559
519
  gitRuntime.toggleRepository(cwd, root)
560
- if (!expanded) void runtime.ensureDirectory(root)
520
+ if (!expanded) void runtime.ensureDirectory(root, true)
561
521
  }}
562
522
  >
563
523
  <ChevronRightIcon
@@ -613,7 +573,6 @@ export function L3ProjectFileBrowser({
613
573
  gitWorkspace?.changesOnly ? (
614
574
  <FileTree
615
575
  className="rounded-none border-0 bg-transparent px-1 pb-1"
616
- expanded={expandedKeys}
617
576
  selectedPath={
618
577
  workspace?.activeDiff
619
578
  ? keyL3ProjectTree(
@@ -625,8 +584,7 @@ export function L3ProjectFileBrowser({
625
584
  )
626
585
  : undefined
627
586
  }
628
- onExpandedChange={applyExpanded}
629
- onSelect={selectDirectoryPath}
587
+ onSelect={selectFile}
630
588
  >
631
589
  {count > 0 ? (
632
590
  renderChangeNodes(changeRoot, root)
@@ -637,12 +595,10 @@ export function L3ProjectFileBrowser({
637
595
  ) : (
638
596
  <FileTree
639
597
  className="rounded-none border-0 bg-transparent px-1 pb-1"
640
- expanded={expandedKeys}
641
598
  selectedPath={
642
599
  workspace.activePath ? keyL3ProjectTree('file', workspace.activePath) : undefined
643
600
  }
644
- onExpandedChange={applyExpanded}
645
- onSelect={selectDirectoryPath}
601
+ onSelect={selectFile}
646
602
  >
647
603
  {renderDirectory(root, repository?.root ?? null, true)}
648
604
  </FileTree>
@@ -777,6 +733,7 @@ export function L3ProjectFileBrowser({
777
733
 
778
734
  return (
779
735
  <section
736
+ ref={hostRef}
780
737
  className="flex h-full min-h-0 flex-col bg-sidebar"
781
738
  aria-label={t('projectFiles', { name: projectName })}
782
739
  onKeyDown={(event) => {