@jetcrab/pi-desk 1.1.28-dev → 1.1.30-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 (362) hide show
  1. package/docs/plugins.md +2 -2
  2. package/package.json +1 -1
  3. package/src/app/api/work-sessions/search/route.ts +1 -0
  4. package/src/app/project-preview/page.tsx +1 -3
  5. package/src/client/l1_entry/pages/l1-error-page.tsx +1 -1
  6. package/src/client/l1_entry/providers/l1-app-providers.tsx +2 -0
  7. package/src/client/l2_biz/auth/l2-login.module.css +1 -1
  8. package/src/client/l2_biz/plugin-host/l2-plugin-composer-panel.tsx +1 -1
  9. package/src/client/l2_biz/plugin-host/l2-plugin-contribution-host.tsx +1 -1
  10. package/src/client/l2_biz/plugin-host/l2-plugin-session-header-layout.ts +6 -3
  11. package/src/client/l2_biz/plugin-host/l2-plugin-session-header.tsx +75 -18
  12. package/src/client/l2_biz/project-preview/hooks/l2-use-project-preview.ts +1 -14
  13. package/src/client/l2_biz/project-preview/l2-project-preview-dialog.tsx +2 -3
  14. package/src/client/l2_biz/project-preview/l2-project-preview-page.tsx +1 -2
  15. package/src/client/l2_biz/project-preview/l2-project-preview.tsx +1 -4
  16. package/src/client/l2_biz/project-preview/views/l2-project-branch-select.tsx +42 -3
  17. package/src/client/l2_biz/settings/l2-settings.tsx +1 -1
  18. package/src/client/l2_biz/settings/l2-skills-settings.tsx +1 -1
  19. package/src/client/l2_biz/task-center/l2-task-center.tsx +1 -1
  20. package/src/client/l2_biz/workbench/file-workspace/l2-plugin-standalone-file-preview.tsx +1 -1
  21. package/src/client/l2_biz/workbench/file-workspace/l2-work-session-file-preview.tsx +1 -1
  22. package/src/client/l2_biz/workbench/git-workspace/l2-git-workspace-runtime.ts +11 -10
  23. package/src/client/l2_biz/workbench/hooks/l2-work-session-search.ts +52 -0
  24. package/src/client/l2_biz/workbench/hooks/l2-workbench-branch-picker.ts +42 -7
  25. package/src/client/l2_biz/workbench/hooks/l2-workbench-session-history.ts +143 -131
  26. package/src/client/l2_biz/workbench/hooks/l2-workbench-session-search.ts +97 -0
  27. package/src/client/l2_biz/workbench/l2-work-session-columns.tsx +8 -0
  28. package/src/client/l2_biz/workbench/l2-work-session-sidebar.tsx +129 -10
  29. package/src/client/l2_biz/workbench/l2-workbench-biz.ts +20 -2
  30. package/src/client/l2_biz/workbench/l2-workbench-branch-filter-preferences.ts +34 -0
  31. package/src/client/l2_biz/workbench/l2-workbench-branch-picker.tsx +34 -71
  32. package/src/client/l2_biz/workbench/l2-workbench-chat-input-runtime.ts +38 -1
  33. package/src/client/l2_biz/workbench/l2-workbench-chat-view.tsx +11 -1
  34. package/src/client/l2_biz/workbench/l2-workbench-picker-dialog.tsx +55 -215
  35. package/src/client/l2_biz/workbench/l2-workbench.tsx +21 -39
  36. package/src/client/l2_biz/workbench/views/l2-workbench-session-search.tsx +123 -0
  37. package/src/client/l3_modules/conversation/l3-conversation-messages.tsx +43 -4
  38. package/src/client/l3_modules/project-files/l3-markdown-preview.module.css +1 -1
  39. package/src/client/l3_modules/project-files/l3-project-document-git.ts +13 -29
  40. package/src/client/l3_modules/project-files/l3-project-document-view.tsx +1 -4
  41. package/src/client/l3_modules/project-files/l3-project-file-browser.module.css +14 -18
  42. package/src/client/l3_modules/project-files/l3-project-file-browser.tsx +52 -95
  43. package/src/client/l3_modules/project-files/l3-project-file-runtime.ts +52 -21
  44. package/src/client/l3_modules/project-files/l3-project-file-tabs.tsx +41 -62
  45. package/src/client/l3_modules/project-files/l3-project-git-runtime.ts +5 -4
  46. package/src/client/l3_modules/project-files/l3-use-project-refresh.ts +36 -0
  47. package/src/client/l3_modules/project-files/views/l3-project-search-results.tsx +2 -2
  48. package/src/client/l3_modules/project-files/views/l3-project-tree-folder.tsx +86 -0
  49. package/src/client/l4_foundation/desktop-window/l4-desktop-titlebar.tsx +188 -0
  50. package/src/client/l4_foundation/desktop-window/l4-desktop-window.css +107 -0
  51. package/src/client/l4_foundation/desktop-window/l4-desktop-window.ts +20 -0
  52. package/src/client/l4_foundation/ui/file-icons/README.md +1 -1
  53. package/src/client/l4_foundation/ui/file-icons/l4-file-icon.tsx +49 -2
  54. package/src/client/l4_foundation/ui/l4-app-dialog.tsx +2 -2
  55. package/src/common/l2_biz/pi-session/l2-pi-session-contract.ts +11 -24
  56. package/src/common/l2_biz/project-preview/l2-project-preview-navigation.ts +5 -12
  57. package/src/common/l2_biz/work-session/l2-work-session-search-contract.ts +26 -0
  58. package/src/common/l2_biz/work-session/l2-work-session-tree-contract.ts +9 -1
  59. package/src/common/l2_biz/workbench/l2-workbench-locale-messages.ts +12 -0
  60. package/src/common/l2_biz/workbench/l2-workbench-picker-messages.ts +6 -2
  61. package/src/common/l3_modules/conversation/l3-conversation-locale-messages.ts +2 -0
  62. package/src/common/l3_modules/pi/l3-pi-session-search-contract.ts +26 -0
  63. package/src/common/l4_foundation/locale/l4-host-error-messages.ts +2 -0
  64. package/src/server/l1_entry/api/l1-work-session-branch-route.ts +21 -15
  65. package/src/server/l1_entry/api/l1-work-session-search-route.ts +38 -0
  66. package/src/server/l2_biz/work-session/l2-work-session-chat-runtime.ts +4 -2
  67. package/src/server/l2_biz/work-session/l2-work-session-manage.ts +46 -10
  68. package/src/server/l3_modules/work-session/l3-work-session.ts +11 -6
  69. package/src/server/l4_foundation/pi/l4-pi-chat-worker.ts +35 -2
  70. package/src/server/l4_foundation/pi/l4-pi-session-history-catalog.ts +62 -113
  71. package/src/server/l4_foundation/pi/l4-pi-session-search.ts +166 -0
  72. package/src/server/l4_foundation/pi/l4-pi-work-session-runtime.ts +66 -5
  73. package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
  74. package/temp/build/pi-desk/release/.next/app-path-routes-manifest.json +1 -0
  75. package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
  76. package/temp/build/pi-desk/release/.next/required-server-files.js +2 -2
  77. package/temp/build/pi-desk/release/.next/required-server-files.json +2 -2
  78. package/temp/build/pi-desk/release/.next/routes-manifest.json +6 -0
  79. package/temp/build/pi-desk/release/.next/server/app/_global-error/page.js +2 -2
  80. package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  81. package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
  82. package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +3 -3
  83. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
  84. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +3 -3
  85. package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  86. package/temp/build/pi-desk/release/.next/server/app/_not-found/page.js +1 -1
  87. package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  88. package/temp/build/pi-desk/release/.next/server/app/api/auth/login/route.js +2 -2
  89. package/temp/build/pi-desk/release/.next/server/app/api/auth/logout/route.js +1 -1
  90. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/get/route.js +1 -1
  91. package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/replace/route.js +1 -1
  92. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/get/route.js +1 -1
  93. package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/replace/route.js +1 -1
  94. package/temp/build/pi-desk/release/.next/server/app/api/chat/context/get/route.js +1 -1
  95. package/temp/build/pi-desk/release/.next/server/app/api/chat/images/get/route.js +1 -1
  96. package/temp/build/pi-desk/release/.next/server/app/api/chat/messages/get/route.js +1 -1
  97. package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
  98. package/temp/build/pi-desk/release/.next/server/app/api/mcp-check/get/route.js +1 -1
  99. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/del/route.js +1 -1
  100. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/get/route.js +1 -1
  101. package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/replace/route.js +1 -1
  102. package/temp/build/pi-desk/release/.next/server/app/api/model-catalog/list/route.js +1 -1
  103. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/get/route.js +1 -1
  104. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route.js +1 -1
  105. package/temp/build/pi-desk/release/.next/server/app/api/model-settings/replace/route.js +1 -1
  106. package/temp/build/pi-desk/release/.next/server/app/api/pi/directories/list/route.js +1 -1
  107. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-entries/list/route.js +1 -1
  108. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/list/route.js +1 -1
  109. package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/replace/route.js +1 -1
  110. package/temp/build/pi-desk/release/.next/server/app/api/pi/models/list/route.js +1 -1
  111. package/temp/build/pi-desk/release/.next/server/app/api/pi/session-user-messages/list/route.js +1 -1
  112. package/temp/build/pi-desk/release/.next/server/app/api/pi/sessions/list/route.js +1 -1
  113. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/get/route.js +1 -1
  114. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/search/route.js +1 -1
  115. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-get/route.js +1 -1
  116. package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-replace/route.js +1 -1
  117. package/temp/build/pi-desk/release/.next/server/app/api/plugins/add/route.js +1 -1
  118. package/temp/build/pi-desk/release/.next/server/app/api/plugins/apply/route.js +1 -1
  119. package/temp/build/pi-desk/release/.next/server/app/api/plugins/batch/route.js +1 -1
  120. package/temp/build/pi-desk/release/.next/server/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route.js +1 -1
  121. package/temp/build/pi-desk/release/.next/server/app/api/plugins/del/route.js +1 -1
  122. package/temp/build/pi-desk/release/.next/server/app/api/plugins/enabled-set/route.js +1 -1
  123. package/temp/build/pi-desk/release/.next/server/app/api/plugins/get/route.js +1 -1
  124. package/temp/build/pi-desk/release/.next/server/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route.js +1 -1
  125. package/temp/build/pi-desk/release/.next/server/app/api/plugins/list/route.js +1 -1
  126. package/temp/build/pi-desk/release/.next/server/app/api/plugins/reload/route.js +1 -1
  127. package/temp/build/pi-desk/release/.next/server/app/api/plugins/update/route.js +1 -1
  128. package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +2 -2
  129. package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +1 -1
  130. package/temp/build/pi-desk/release/.next/server/app/api/project-files/reveal/route.js +1 -1
  131. package/temp/build/pi-desk/release/.next/server/app/api/project-files/search/route.js +1 -1
  132. package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +2 -2
  133. package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +2 -2
  134. package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +1 -1
  135. package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +2 -2
  136. package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +1 -1
  137. package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +2 -2
  138. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/get/route.js +1 -1
  139. package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/replace/route.js +1 -1
  140. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/get/route.js +1 -1
  141. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/list/route.js +1 -1
  142. package/temp/build/pi-desk/release/.next/server/app/api/skill-files/replace/route.js +1 -1
  143. package/temp/build/pi-desk/release/.next/server/app/api/skills/list/route.js +1 -1
  144. package/temp/build/pi-desk/release/.next/server/app/api/task-center/images/get/route.js +1 -1
  145. package/temp/build/pi-desk/release/.next/server/app/api/task-center/messages/get/route.js +1 -1
  146. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/add/route.js +1 -1
  147. package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/replace/route.js +1 -1
  148. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree/get/route.js +1 -1
  149. package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree-entry/get/route.js +1 -1
  150. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/add/route.js +1 -1
  151. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/branch/route.js +1 -1
  152. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/del/route.js +1 -1
  153. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route.js +1 -1
  154. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/replace/route.js +1 -1
  155. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/search/route.js +1 -0
  156. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/search/route_client-reference-manifest.js +1 -0
  157. package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/sort/route.js +1 -1
  158. package/temp/build/pi-desk/release/.next/server/app/favicon.ico/route.js +1 -1
  159. package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
  160. package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
  161. package/temp/build/pi-desk/release/.next/server/app/page.js +138 -138
  162. package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
  163. package/temp/build/pi-desk/release/.next/server/app/project-preview/page.js +1 -1
  164. package/temp/build/pi-desk/release/.next/server/app/project-preview/page_client-reference-manifest.js +1 -1
  165. package/temp/build/pi-desk/release/.next/server/app-paths-manifest.json +1 -0
  166. package/temp/build/pi-desk/release/.next/server/chunks/23054.js +2 -2
  167. package/temp/build/pi-desk/release/.next/server/chunks/25406.js +8 -8
  168. package/temp/build/pi-desk/release/.next/server/chunks/27344.js +3 -3
  169. package/temp/build/pi-desk/release/.next/server/chunks/3108.js +3 -3
  170. package/temp/build/pi-desk/release/.next/server/chunks/35985.js +3 -3
  171. package/temp/build/pi-desk/release/.next/server/chunks/41856.js +1 -0
  172. package/temp/build/pi-desk/release/.next/server/chunks/62900.js +235 -0
  173. package/temp/build/pi-desk/release/.next/server/chunks/6917.js +1 -1
  174. package/temp/build/pi-desk/release/.next/server/chunks/81363.js +1 -1
  175. package/temp/build/pi-desk/release/.next/server/chunks/81912.js +3 -0
  176. package/temp/build/pi-desk/release/.next/server/chunks/92386.js +2 -2
  177. package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
  178. package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
  179. package/temp/build/pi-desk/release/.next/static/ErYBfYXAir5b-6rlacGvL/_buildManifest.js +1 -0
  180. package/temp/build/pi-desk/release/.next/static/chunks/10043-9d6c3735418ccaf9.js +238 -0
  181. package/temp/build/pi-desk/release/.next/static/chunks/11937-ac71fb0f7cef482a.js +1 -0
  182. package/temp/build/pi-desk/release/.next/static/chunks/30669-ffa76d39e0e25194.js +1 -0
  183. package/temp/build/pi-desk/release/.next/static/chunks/36643-f60e98278740073c.js +3 -0
  184. package/temp/build/pi-desk/release/.next/static/chunks/65232-f5b71cec787a30ec.js +15 -0
  185. package/temp/build/pi-desk/release/.next/static/chunks/{51474-8dc714cb76b2e60a.js → 65350-23bb961d87addf14.js} +3 -3
  186. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-295cb63da5f7262f.js +1 -0
  187. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-295cb63da5f7262f.js +1 -0
  188. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-295cb63da5f7262f.js +1 -0
  189. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-295cb63da5f7262f.js +1 -0
  190. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-295cb63da5f7262f.js +1 -0
  191. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-295cb63da5f7262f.js +1 -0
  192. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-295cb63da5f7262f.js +1 -0
  193. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-295cb63da5f7262f.js +1 -0
  194. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-295cb63da5f7262f.js +1 -0
  195. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-295cb63da5f7262f.js +1 -0
  196. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-295cb63da5f7262f.js +1 -0
  197. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-295cb63da5f7262f.js +1 -0
  198. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-295cb63da5f7262f.js +1 -0
  199. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-295cb63da5f7262f.js +1 -0
  200. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-295cb63da5f7262f.js +1 -0
  201. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-295cb63da5f7262f.js +1 -0
  202. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-295cb63da5f7262f.js +1 -0
  203. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-295cb63da5f7262f.js +1 -0
  204. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-295cb63da5f7262f.js +1 -0
  205. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-295cb63da5f7262f.js +1 -0
  206. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-295cb63da5f7262f.js +1 -0
  207. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-295cb63da5f7262f.js +1 -0
  208. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-295cb63da5f7262f.js +1 -0
  209. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-295cb63da5f7262f.js +1 -0
  210. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-295cb63da5f7262f.js +1 -0
  211. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-295cb63da5f7262f.js +1 -0
  212. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-295cb63da5f7262f.js +1 -0
  213. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-295cb63da5f7262f.js +1 -0
  214. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-295cb63da5f7262f.js +1 -0
  215. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-295cb63da5f7262f.js +1 -0
  216. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-295cb63da5f7262f.js +1 -0
  217. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-295cb63da5f7262f.js +1 -0
  218. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-295cb63da5f7262f.js +1 -0
  219. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-295cb63da5f7262f.js +1 -0
  220. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-295cb63da5f7262f.js +1 -0
  221. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-295cb63da5f7262f.js +1 -0
  222. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-295cb63da5f7262f.js +1 -0
  223. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-295cb63da5f7262f.js +1 -0
  224. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-295cb63da5f7262f.js +1 -0
  225. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-295cb63da5f7262f.js +1 -0
  226. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-295cb63da5f7262f.js +1 -0
  227. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-295cb63da5f7262f.js +1 -0
  228. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-295cb63da5f7262f.js +1 -0
  229. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-295cb63da5f7262f.js +1 -0
  230. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-295cb63da5f7262f.js +1 -0
  231. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-295cb63da5f7262f.js +1 -0
  232. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-295cb63da5f7262f.js +1 -0
  233. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-295cb63da5f7262f.js +1 -0
  234. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-295cb63da5f7262f.js +1 -0
  235. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-295cb63da5f7262f.js +1 -0
  236. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-295cb63da5f7262f.js +1 -0
  237. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-295cb63da5f7262f.js +1 -0
  238. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-295cb63da5f7262f.js +1 -0
  239. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-295cb63da5f7262f.js +1 -0
  240. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-295cb63da5f7262f.js +1 -0
  241. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-295cb63da5f7262f.js +1 -0
  242. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-295cb63da5f7262f.js +1 -0
  243. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-295cb63da5f7262f.js +1 -0
  244. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-295cb63da5f7262f.js +1 -0
  245. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-295cb63da5f7262f.js +1 -0
  246. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-295cb63da5f7262f.js +1 -0
  247. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-295cb63da5f7262f.js +1 -0
  248. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-295cb63da5f7262f.js +1 -0
  249. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-295cb63da5f7262f.js +1 -0
  250. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-295cb63da5f7262f.js +1 -0
  251. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-295cb63da5f7262f.js +1 -0
  252. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-295cb63da5f7262f.js +1 -0
  253. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-295cb63da5f7262f.js +1 -0
  254. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-295cb63da5f7262f.js +1 -0
  255. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/search/route-295cb63da5f7262f.js +1 -0
  256. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-295cb63da5f7262f.js +1 -0
  257. package/temp/build/pi-desk/release/.next/static/chunks/app/error-1ab62762c5f4144f.js +1 -0
  258. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-ca5ef5994165eb2e.js +1 -0
  259. package/temp/build/pi-desk/release/.next/static/chunks/app/login/{page-0d3d4827802108e5.js → page-0df9df996aa68060.js} +1 -1
  260. package/temp/build/pi-desk/release/.next/static/chunks/app/not-found-b8b9b7ef5ccb7601.js +1 -0
  261. package/temp/build/pi-desk/release/.next/static/chunks/app/page-978906de76a8dcfe.js +158 -0
  262. package/temp/build/pi-desk/release/.next/static/chunks/app/project-preview/{page-038b6c14e03ed878.js → page-aaa845016a934245.js} +1 -1
  263. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-295cb63da5f7262f.js +1 -0
  264. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-295cb63da5f7262f.js +1 -0
  265. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-295cb63da5f7262f.js +1 -0
  266. package/temp/build/pi-desk/release/.next/static/chunks/{webpack-c0b805df46fcf8b3.js → webpack-a84310d111797bef.js} +1 -1
  267. package/temp/build/pi-desk/release/.next/static/css/053a8d82c09326cd.css +1 -0
  268. package/temp/build/pi-desk/release/.next/static/css/1cc92eec583aa639.css +1 -0
  269. package/temp/build/pi-desk/release/.next/static/css/{1e780a4936aa6ba3.css → 2bb393927ba8f71d.css} +1 -1
  270. package/temp/build/pi-desk/release/.next/static/css/3a07dcc86ffdf88c.css +1 -0
  271. package/temp/build/pi-desk/release/.next/static/css/3c59ac068ae404da.css +1 -0
  272. package/temp/build/pi-desk/release/.next/trace-build +1 -1
  273. package/temp/build/pi-desk/release/.next/server/chunks/35348.js +0 -3
  274. package/temp/build/pi-desk/release/.next/server/chunks/56830.js +0 -235
  275. package/temp/build/pi-desk/release/.next/server/chunks/80780.js +0 -1
  276. package/temp/build/pi-desk/release/.next/static/bj2dB_Z10YB_CqK_VNhDx/_buildManifest.js +0 -1
  277. package/temp/build/pi-desk/release/.next/static/chunks/11937-1d0a9822f2c7995b.js +0 -1
  278. package/temp/build/pi-desk/release/.next/static/chunks/14197-3d3ddd426ac06c9c.js +0 -3
  279. package/temp/build/pi-desk/release/.next/static/chunks/37313-d5970e2d0c270d22.js +0 -238
  280. package/temp/build/pi-desk/release/.next/static/chunks/65232-ef4e5a4174f62faf.js +0 -15
  281. package/temp/build/pi-desk/release/.next/static/chunks/79267-7d21d7cdbd7cfca1.js +0 -1
  282. package/temp/build/pi-desk/release/.next/static/chunks/app/_global-error/page-9969fe0baa238786.js +0 -1
  283. package/temp/build/pi-desk/release/.next/static/chunks/app/_not-found/page-9969fe0baa238786.js +0 -1
  284. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/login/route-9969fe0baa238786.js +0 -1
  285. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth/logout/route-9969fe0baa238786.js +0 -1
  286. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/get/route-9969fe0baa238786.js +0 -1
  287. package/temp/build/pi-desk/release/.next/static/chunks/app/api/auth-settings/replace/route-9969fe0baa238786.js +0 -1
  288. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/get/route-9969fe0baa238786.js +0 -1
  289. package/temp/build/pi-desk/release/.next/static/chunks/app/api/capability-modes/replace/route-9969fe0baa238786.js +0 -1
  290. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/context/get/route-9969fe0baa238786.js +0 -1
  291. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/images/get/route-9969fe0baa238786.js +0 -1
  292. package/temp/build/pi-desk/release/.next/static/chunks/app/api/chat/messages/get/route-9969fe0baa238786.js +0 -1
  293. package/temp/build/pi-desk/release/.next/static/chunks/app/api/health/route-9969fe0baa238786.js +0 -1
  294. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-check/get/route-9969fe0baa238786.js +0 -1
  295. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/del/route-9969fe0baa238786.js +0 -1
  296. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/get/route-9969fe0baa238786.js +0 -1
  297. package/temp/build/pi-desk/release/.next/static/chunks/app/api/mcp-settings/replace/route-9969fe0baa238786.js +0 -1
  298. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-catalog/list/route-9969fe0baa238786.js +0 -1
  299. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/get/route-9969fe0baa238786.js +0 -1
  300. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/preview/route-9969fe0baa238786.js +0 -1
  301. package/temp/build/pi-desk/release/.next/static/chunks/app/api/model-settings/replace/route-9969fe0baa238786.js +0 -1
  302. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directories/list/route-9969fe0baa238786.js +0 -1
  303. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-entries/list/route-9969fe0baa238786.js +0 -1
  304. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/list/route-9969fe0baa238786.js +0 -1
  305. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/directory-ignores/replace/route-9969fe0baa238786.js +0 -1
  306. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/models/list/route-9969fe0baa238786.js +0 -1
  307. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/session-user-messages/list/route-9969fe0baa238786.js +0 -1
  308. package/temp/build/pi-desk/release/.next/static/chunks/app/api/pi/sessions/list/route-9969fe0baa238786.js +0 -1
  309. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/get/route-9969fe0baa238786.js +0 -1
  310. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/search/route-9969fe0baa238786.js +0 -1
  311. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-get/route-9969fe0baa238786.js +0 -1
  312. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugin-catalog/settings-replace/route-9969fe0baa238786.js +0 -1
  313. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/add/route-9969fe0baa238786.js +0 -1
  314. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/apply/route-9969fe0baa238786.js +0 -1
  315. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/batch/route-9969fe0baa238786.js +0 -1
  316. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route-9969fe0baa238786.js +0 -1
  317. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/del/route-9969fe0baa238786.js +0 -1
  318. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/enabled-set/route-9969fe0baa238786.js +0 -1
  319. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/get/route-9969fe0baa238786.js +0 -1
  320. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route-9969fe0baa238786.js +0 -1
  321. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/list/route-9969fe0baa238786.js +0 -1
  322. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/reload/route-9969fe0baa238786.js +0 -1
  323. package/temp/build/pi-desk/release/.next/static/chunks/app/api/plugins/update/route-9969fe0baa238786.js +0 -1
  324. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/get/route-9969fe0baa238786.js +0 -1
  325. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/list/route-9969fe0baa238786.js +0 -1
  326. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/reveal/route-9969fe0baa238786.js +0 -1
  327. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-files/search/route-9969fe0baa238786.js +0 -1
  328. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git/get/route-9969fe0baa238786.js +0 -1
  329. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-branches/list/route-9969fe0baa238786.js +0 -1
  330. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-changes/list/route-9969fe0baa238786.js +0 -1
  331. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-diff/get/route-9969fe0baa238786.js +0 -1
  332. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-heads/get/route-9969fe0baa238786.js +0 -1
  333. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-git-log/list/route-9969fe0baa238786.js +0 -1
  334. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/get/route-9969fe0baa238786.js +0 -1
  335. package/temp/build/pi-desk/release/.next/static/chunks/app/api/project-model-default/replace/route-9969fe0baa238786.js +0 -1
  336. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/get/route-9969fe0baa238786.js +0 -1
  337. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/list/route-9969fe0baa238786.js +0 -1
  338. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skill-files/replace/route-9969fe0baa238786.js +0 -1
  339. package/temp/build/pi-desk/release/.next/static/chunks/app/api/skills/list/route-9969fe0baa238786.js +0 -1
  340. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/images/get/route-9969fe0baa238786.js +0 -1
  341. package/temp/build/pi-desk/release/.next/static/chunks/app/api/task-center/messages/get/route-9969fe0baa238786.js +0 -1
  342. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/add/route-9969fe0baa238786.js +0 -1
  343. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-git-branch/replace/route-9969fe0baa238786.js +0 -1
  344. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree/get/route-9969fe0baa238786.js +0 -1
  345. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-session-tree-entry/get/route-9969fe0baa238786.js +0 -1
  346. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/add/route-9969fe0baa238786.js +0 -1
  347. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/branch/route-9969fe0baa238786.js +0 -1
  348. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/del/route-9969fe0baa238786.js +0 -1
  349. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/rename/route-9969fe0baa238786.js +0 -1
  350. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/replace/route-9969fe0baa238786.js +0 -1
  351. package/temp/build/pi-desk/release/.next/static/chunks/app/api/work-sessions/sort/route-9969fe0baa238786.js +0 -1
  352. package/temp/build/pi-desk/release/.next/static/chunks/app/error-216b14b5da089ed3.js +0 -1
  353. package/temp/build/pi-desk/release/.next/static/chunks/app/layout-20718f1503910291.js +0 -1
  354. package/temp/build/pi-desk/release/.next/static/chunks/app/not-found-720cdf6a606b821a.js +0 -1
  355. package/temp/build/pi-desk/release/.next/static/chunks/app/page-ce2ebf7d8ea7a330.js +0 -158
  356. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/app-error-9969fe0baa238786.js +0 -1
  357. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/forbidden-9969fe0baa238786.js +0 -1
  358. package/temp/build/pi-desk/release/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9969fe0baa238786.js +0 -1
  359. package/temp/build/pi-desk/release/.next/static/css/2bdcf40eca12b794.css +0 -1
  360. package/temp/build/pi-desk/release/.next/static/css/2c3b0c0ff1f49c68.css +0 -1
  361. package/temp/build/pi-desk/release/.next/static/css/c43b04c244a64fb4.css +0 -1
  362. /package/temp/build/pi-desk/release/.next/static/{bj2dB_Z10YB_CqK_VNhDx → ErYBfYXAir5b-6rlacGvL}/_ssgManifest.js +0 -0
@@ -103,6 +103,7 @@ export const L4_HOST_ERROR_MESSAGES = {
103
103
  branchInputInvalid: 'Invalid branch operation request',
104
104
  branchEntryMissing: 'Branch entry not found or no longer available',
105
105
  branchForkUserOnly: 'Only user messages can start a new session',
106
+ branchResendUserOnly: 'Only user messages can be resent',
106
107
  branchCloneEmpty: 'There are no messages to clone yet',
107
108
  branchFailed: 'Could not perform branch operation',
108
109
  taskDetailInvalid: 'Invalid task detail request',
@@ -262,6 +263,7 @@ export const L4_HOST_ERROR_MESSAGES = {
262
263
  branchInputInvalid: '分支操作参数无效',
263
264
  branchEntryMissing: '分支节点不存在或已失效',
264
265
  branchForkUserOnly: '只有用户消息可以 Fork',
266
+ branchResendUserOnly: '只有用户消息可以重发',
265
267
  branchCloneEmpty: '当前会话还没有可克隆的消息',
266
268
  branchFailed: '执行分支操作失败',
267
269
  taskDetailInvalid: '任务详情参数无效',
@@ -1,14 +1,7 @@
1
1
  import 'server-only'
2
2
 
3
3
  import { L2WorkSessionBranchRequestSchema } from '@common/l2_biz/work-session/l2-work-session-tree-contract'
4
- import {
5
- getL2WorkSessionManage,
6
- WorkSessionBindingChangedError,
7
- WorkSessionBranchBlockedError,
8
- WorkSessionBranchEntryNotFoundError,
9
- WorkSessionBranchInvalidError,
10
- WorkSessionNotFoundError
11
- } from '@server/l2_biz/work-session/l2-work-session-manage'
4
+ import { getL2WorkSessionManage } from '@server/l2_biz/work-session/l2-work-session-manage'
12
5
  import { readL4ClientId } from '@server/l4_foundation/http/l4-client-id'
13
6
  import {
14
7
  createL4ApiErrorResponse,
@@ -33,27 +26,40 @@ export async function POST(request: Request): Promise<Response> {
33
26
 
34
27
  try {
35
28
  const data = await getL2WorkSessionManage().branchWorkSession(input.data)
36
- return createL4ApiSuccessResponse(data, input.data.action === 'tree' ? 200 : 201)
29
+ return createL4ApiSuccessResponse(
30
+ data,
31
+ input.data.action === 'tree' || input.data.action === 'resend' ? 200 : 201
32
+ )
37
33
  } catch (error) {
38
- if (error instanceof WorkSessionNotFoundError) {
34
+ // 管理器由 Node 与 Next 共享,业务异常构造器并非同一实例。
35
+ if (error instanceof Error && error.name === 'WorkSessionNotFoundError') {
39
36
  return createL4ApiErrorResponse(404, '工作会话不存在', { key: 'errors:sessionMissing' })
40
37
  }
41
- if (error instanceof WorkSessionBranchEntryNotFoundError) {
38
+ if (error instanceof Error && error.name === 'WorkSessionBranchEntryNotFoundError') {
42
39
  return createL4ApiErrorResponse(404, '分支节点不存在或已失效', {
43
40
  key: 'errors:branchEntryMissing'
44
41
  })
45
42
  }
46
- if (error instanceof WorkSessionBranchInvalidError) {
43
+ if (
44
+ error instanceof Error &&
45
+ error.name === 'WorkSessionBranchInvalidError' &&
46
+ 'kind' in error
47
+ ) {
47
48
  return createL4ApiErrorResponse(400, error.message, {
48
- key: error.kind === 'fork-target' ? 'errors:branchForkUserOnly' : 'errors:branchCloneEmpty'
49
+ key:
50
+ error.kind === 'fork-target'
51
+ ? 'errors:branchForkUserOnly'
52
+ : error.kind === 'resend-target'
53
+ ? 'errors:branchResendUserOnly'
54
+ : 'errors:branchCloneEmpty'
49
55
  })
50
56
  }
51
- if (error instanceof WorkSessionBindingChangedError) {
57
+ if (error instanceof Error && error.name === 'WorkSessionBindingChangedError') {
52
58
  return createL4ApiErrorResponse(409, '工作会话已切换,请重新打开会话树', {
53
59
  key: 'errors:sessionTreeChanged'
54
60
  })
55
61
  }
56
- if (error instanceof WorkSessionBranchBlockedError) {
62
+ if (error instanceof Error && error.name === 'WorkSessionBranchBlockedError') {
57
63
  return createL4ApiErrorResponse(409, error.message)
58
64
  }
59
65
  console.error('[Pi Desk][WorkSessionBranchApi] 执行分支操作失败', {
@@ -0,0 +1,38 @@
1
+ import 'server-only'
2
+
3
+ import { L2WorkSessionSearchRequestSchema } from '@common/l2_biz/work-session/l2-work-session-search-contract'
4
+ import { getL2WorkSessionManage } from '@server/l2_biz/work-session/l2-work-session-manage'
5
+ import { readL4ClientId } from '@server/l4_foundation/http/l4-client-id'
6
+ import {
7
+ createL4ApiErrorResponse,
8
+ createL4ApiSuccessResponse
9
+ } from '@server/l4_foundation/http/l4-api-response'
10
+
11
+ export async function POST(request: Request): Promise<Response> {
12
+ const clientId = readL4ClientId(request)
13
+ if (!clientId)
14
+ return createL4ApiErrorResponse(400, '客户端标识无效', { key: 'errors:invalidClient' })
15
+
16
+ let payload: unknown
17
+ try {
18
+ payload = await request.json()
19
+ } catch {
20
+ return createL4ApiErrorResponse(400, '请求 JSON 格式无效', { key: 'errors:invalidJson' })
21
+ }
22
+
23
+ const input = L2WorkSessionSearchRequestSchema.safeParse(payload)
24
+ if (!input.success) return createL4ApiErrorResponse(400, '工作会话搜索参数无效')
25
+
26
+ try {
27
+ return createL4ApiSuccessResponse(await getL2WorkSessionManage().searchWorkSessions(input.data))
28
+ } catch (error) {
29
+ console.error('[Pi Desk][WorkSessionSearchApi] 搜索工作会话失败', {
30
+ clientId,
31
+ queryLength: input.data.query.length,
32
+ searchIn: input.data.searchIn,
33
+ errorName: error instanceof Error ? error.name : 'UnknownError',
34
+ errorMessage: error instanceof Error ? error.message : String(error)
35
+ })
36
+ return createL4ApiErrorResponse(500, '搜索工作会话失败')
37
+ }
38
+ }
@@ -190,11 +190,13 @@ export class L2WorkSessionChatRuntime {
190
190
  await disposeL4PiWorkSessionRuntime(previous.sessionId)
191
191
  }
192
192
 
193
- async refreshWorkSession(workSession: WorkSession): Promise<void> {
193
+ async refreshWorkSession(workSession: WorkSession, acceptingCommands = true): Promise<void> {
194
194
  const previousSource = this.recordsByWorkId.get(workSession.workId)?.source
195
195
  await this.closeRecord(workSession.workId)
196
196
  if (previousSource) this.publish({ type: 'source_invalidated', source: previousSource })
197
- this.recordsByWorkId.set(workSession.workId, this.buildRecord(workSession))
197
+ const record = this.buildRecord(workSession)
198
+ record.acceptingCommands = acceptingCommands
199
+ this.recordsByWorkId.set(workSession.workId, record)
198
200
  }
199
201
 
200
202
  async removeWorkSession(workSession: WorkSession): Promise<void> {
@@ -72,6 +72,12 @@ import {
72
72
  type L2WorkSessionRecord,
73
73
  type L2WorkSessionStatus
74
74
  } from '@common/l2_biz/work-session/l2-work-session-contract'
75
+ import {
76
+ L2WorkSessionSearchRequestSchema,
77
+ L2WorkSessionSearchResponseSchema,
78
+ type L2WorkSessionSearchRequest,
79
+ type L2WorkSessionSearchResponse
80
+ } from '@common/l2_biz/work-session/l2-work-session-search-contract'
75
81
  import {
76
82
  L2WorkSessionChangesSchema,
77
83
  L2WorkSessionsUpdateSchema,
@@ -102,7 +108,8 @@ import { resolveL4PiSessionPath } from '@server/l4_foundation/pi/l4-pi-session-c
102
108
  import {
103
109
  getL4PiWorkSessionRuntime,
104
110
  L4PiSessionBranchBlockedError,
105
- L4PiSessionCloneEmptyError
111
+ L4PiSessionCloneEmptyError,
112
+ L4PiSessionResendTargetError
106
113
  } from '@server/l4_foundation/pi/l4-pi-work-session-runtime'
107
114
  import {
108
115
  L4PiSessionEntryNotFoundError,
@@ -196,7 +203,7 @@ export class WorkSessionBranchBlockedError extends Error {
196
203
 
197
204
  export class WorkSessionBranchInvalidError extends Error {
198
205
  constructor(
199
- readonly kind: 'fork-target' | 'clone-empty',
206
+ readonly kind: 'fork-target' | 'clone-empty' | 'resend-target',
200
207
  message: string
201
208
  ) {
202
209
  super(message)
@@ -250,6 +257,19 @@ export class WorkSessionManage {
250
257
  })
251
258
  }
252
259
 
260
+ searchWorkSessions(inputValue: L2WorkSessionSearchRequest): Promise<L2WorkSessionSearchResponse> {
261
+ const input = L2WorkSessionSearchRequestSchema.parse(inputValue)
262
+ return this.runExclusive(async () => {
263
+ await this.ensureHydrated()
264
+ return L2WorkSessionSearchResponseSchema.parse({
265
+ sessions: this.orderedWorkSessions().flatMap((workSession) => {
266
+ const matches = getL4PiWorkSessionRuntime(workSession.sessionId).search(input)
267
+ return matches.length > 0 ? [{ workId: workSession.workId, matches }] : []
268
+ })
269
+ })
270
+ })
271
+ }
272
+
253
273
  runPluginRestart<T>(operation: () => Promise<T>): Promise<T> {
254
274
  return this.runExclusive(async () => {
255
275
  await this.ensureHydrated()
@@ -681,23 +701,35 @@ export class WorkSessionManage {
681
701
  if (!source) throw new WorkSessionNotFoundError(input.workId)
682
702
  this.assertSessionBinding(source, input.sessionId)
683
703
 
684
- if (input.action === 'tree') {
704
+ if (input.action === 'tree' || input.action === 'resend') {
685
705
  const previousItem = this.toListItem(source)
686
706
  await this.chat.pauseWorkSession(source.workId)
707
+ let refreshed = false
687
708
  let result: Awaited<ReturnType<WorkSession['branch']>>
688
709
  try {
689
- result = await source.branch(input.entryId)
690
- if (result.changed) await this.chat.refreshWorkSession(source)
691
- else this.chat.resumeWorkSession(source.workId)
710
+ if (input.action === 'resend') {
711
+ await source.send({
712
+ mode: 'resend',
713
+ entryId: input.entryId,
714
+ onBranchChanged: async () => {
715
+ await this.chat.refreshWorkSession(source, false)
716
+ refreshed = true
717
+ }
718
+ })
719
+ result = { changed: true, editorText: null }
720
+ } else {
721
+ result = await source.branch(input.entryId)
722
+ if (result.changed) await this.chat.refreshWorkSession(source)
723
+ }
692
724
  } catch (error) {
693
- if (source.branchId !== previousItem.branchId) {
694
- await this.chat.refreshWorkSession(source)
725
+ if (source.branchId !== previousItem.branchId || refreshed) {
726
+ if (!refreshed) await this.chat.refreshWorkSession(source, false)
695
727
  const changes = this.toChanges(previousItem, this.toListItem(source))
696
728
  if (changes) this.publishUpdate({ type: 'update', workId: source.workId, changes })
697
- } else {
698
- this.chat.resumeWorkSession(source.workId)
699
729
  }
700
730
  this.throwBranchError(error, input.entryId)
731
+ } finally {
732
+ this.chat.resumeWorkSession(source.workId)
701
733
  }
702
734
 
703
735
  const item = this.toListItem(source)
@@ -710,6 +742,7 @@ export class WorkSessionManage {
710
742
  sessionId: source.sessionId,
711
743
  entryId: input.entryId,
712
744
  branchId: source.branchId,
745
+ action: input.action,
713
746
  changed: result.changed
714
747
  })
715
748
  return L2WorkSessionBranchResponseSchema.parse({
@@ -857,6 +890,9 @@ export class WorkSessionManage {
857
890
  if (error instanceof L4PiSessionForkTargetError) {
858
891
  throw new WorkSessionBranchInvalidError('fork-target', '只有用户消息可以 Fork')
859
892
  }
893
+ if (error instanceof L4PiSessionResendTargetError) {
894
+ throw new WorkSessionBranchInvalidError('resend-target', '只有用户消息可以重发')
895
+ }
860
896
  if (error instanceof L4PiSessionCloneEmptyError) {
861
897
  throw new WorkSessionBranchInvalidError('clone-empty', '当前会话还没有可克隆的消息')
862
898
  }
@@ -1,7 +1,10 @@
1
1
  import 'server-only'
2
2
 
3
3
  import type { ThinkingLevel } from '@earendil-works/pi-agent-core'
4
- import { L4PiWorkSessionRuntime } from '@server/l4_foundation/pi/l4-pi-work-session-runtime'
4
+ import {
5
+ L4PiWorkSessionRuntime,
6
+ type L4PiResendInput
7
+ } from '@server/l4_foundation/pi/l4-pi-work-session-runtime'
5
8
 
6
9
  export interface WorkSessionInputImage {
7
10
  mimeType: 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif'
@@ -10,11 +13,13 @@ export interface WorkSessionInputImage {
10
13
  height: number
11
14
  }
12
15
 
13
- export interface WorkSessionSendInput {
14
- mode: 'auto' | 'follow_up'
15
- text: string
16
- images: WorkSessionInputImage[]
17
- }
16
+ export type WorkSessionSendInput =
17
+ | {
18
+ mode: 'auto' | 'follow_up'
19
+ text: string
20
+ images: WorkSessionInputImage[]
21
+ }
22
+ | L4PiResendInput
18
23
 
19
24
  export interface WorkSessionModelInput {
20
25
  provider: string
@@ -899,7 +899,7 @@ export class L4PiChatWorker {
899
899
  await session.abort()
900
900
  }
901
901
 
902
- async navigateTree(entryId: string): Promise<boolean> {
902
+ async navigateTree(entryId: string, beforeUserMessage = false): Promise<boolean> {
903
903
  const session = await this.ensureSession()
904
904
  this.assertIdle()
905
905
  if (this.treeResumeImmediate) clearImmediate(this.treeResumeImmediate)
@@ -913,7 +913,10 @@ export class L4PiChatWorker {
913
913
  this.messageGate.pause()
914
914
  try {
915
915
  this.initialization.setStage('切换会话树')
916
- const result = await session.navigateTree(entryId, { summarize: false })
916
+ const result =
917
+ beforeUserMessage && previousLeaf === entryId
918
+ ? await this.navigateLeafUserMessage(session, entryId)
919
+ : await session.navigateTree(entryId, { summarize: false })
917
920
  changed = !result.cancelled
918
921
  if (changed) await this.capabilityRuntime.apply()
919
922
  } catch (error) {
@@ -948,6 +951,36 @@ export class L4PiChatWorker {
948
951
  }
949
952
  }
950
953
 
954
+ private async navigateLeafUserMessage(
955
+ session: AgentSession,
956
+ entryId: string
957
+ ): Promise<{ cancelled: boolean }> {
958
+ const entry = this.sessionManager.getEntry(entryId)!
959
+ // SDK 对当前 leaf 直接 no-op;重发仍需执行导航钩子并回到该用户消息之前。
960
+ const result = await session.extensionRunner.emit({
961
+ type: 'session_before_tree',
962
+ preparation: {
963
+ targetId: entryId,
964
+ oldLeafId: entryId,
965
+ commonAncestorId: entryId,
966
+ entriesToSummarize: [],
967
+ userWantsSummary: false
968
+ },
969
+ signal: this.commandLifetime.signal
970
+ })
971
+ if (result?.cancel || this.commandLifetime.signal.aborted) return { cancelled: true }
972
+ if (entry.parentId === null) this.sessionManager.resetLeaf()
973
+ else this.sessionManager.branch(entry.parentId)
974
+ if (result?.label) this.sessionManager.appendLabelChange(entryId, result.label)
975
+ session.refreshContext()
976
+ await session.extensionRunner.emit({
977
+ type: 'session_tree',
978
+ oldLeafId: entryId,
979
+ newLeafId: this.sessionManager.getLeafId()
980
+ })
981
+ return { cancelled: false }
982
+ }
983
+
951
984
  private resetBranchRuntime(): void {
952
985
  if (this.treeNavigation) this.treeNavigation.committed = true
953
986
  this.commandLifetime.abort()
@@ -26,13 +26,20 @@ import {
26
26
  } from '@earendil-works/pi-coding-agent'
27
27
  import { z } from 'zod'
28
28
  import { findL4PiSessionFile } from './l4-pi-session-discovery'
29
+ import {
30
+ compactL4PiSessionPreview as compactPreview,
31
+ matchL4PiSessionSearch,
32
+ normalizeL4PiSessionSearch as normalizeSearch,
33
+ readL4PiSessionMessageText as messageText,
34
+ readL4PiSessionTimestamp as timestampMs,
35
+ type L4PiSessionSearchMatch,
36
+ type L4PiSessionSearchScope
37
+ } from './l4-pi-session-search'
29
38
 
30
39
  const SCAN_CONCURRENCY = 10
31
- const MATCH_PREVIEW_MAX_LENGTH = 120
32
- const MATCH_PREVIEW_PREFIX_LENGTH = 16
33
40
  const FIRST_MESSAGE_PREVIEW_MAX_LENGTH = 160
34
41
  const CACHE_VALIDATION_INTERVAL_MS = 2_000
35
- const CACHE_IDLE_MS = 15 * 60_000
42
+ const CACHE_IDLE_MS = 60_000
36
43
  const CACHE_CWD_LIMIT = 8
37
44
  const CACHE_TEXT_BYTES_LIMIT = 32 * 1024 * 1024
38
45
  const CACHE_FILE_LIMIT = 4_096
@@ -41,7 +48,7 @@ const LEGACY_CACHE_FILE_NAME = 'pi-session-history.json'
41
48
  const PERSISTED_CACHE_VERSION = 2
42
49
  const CACHE_DISK_BYTES_LIMIT = 64 * 1024 * 1024
43
50
 
44
- export type L4PiSessionHistorySearchScope = 'title' | 'user' | 'assistant' | 'sessionId'
51
+ export type L4PiSessionHistorySearchScope = L4PiSessionSearchScope
45
52
 
46
53
  const DEFAULT_SEARCH_IN: readonly L4PiSessionHistorySearchScope[] = ['title', 'user']
47
54
 
@@ -72,13 +79,7 @@ interface L4PiSessionAssistantMessage {
72
79
  text: string
73
80
  }
74
81
 
75
- export interface L4PiSessionHistoryMatch {
76
- scope: L4PiSessionHistorySearchScope
77
- count: number
78
- entryId: string | null
79
- timestampMs: number | null
80
- preview: string
81
- }
82
+ export type L4PiSessionHistoryMatch = L4PiSessionSearchMatch
82
83
 
83
84
  export interface L4PiSessionHistoryItem {
84
85
  sessionId: string
@@ -184,6 +185,7 @@ interface L4PiSessionHistoryCatalogState {
184
185
  epochs: Map<string, number>
185
186
  activeLoads: Map<string, L4PiSessionHistoryCatalogLoad>
186
187
  catalogs: Map<string, L4PiSessionHistoryCatalog>
188
+ cleanupTimer: ReturnType<typeof setTimeout> | null
187
189
  }
188
190
 
189
191
  interface L4PiSessionScanState {
@@ -365,7 +367,8 @@ function historyCatalogState(): L4PiSessionHistoryCatalogState {
365
367
  globalThis.__piDeskPiSessionHistoryCatalogState = {
366
368
  epochs: new Map(),
367
369
  activeLoads: new Map(),
368
- catalogs: new Map()
370
+ catalogs: new Map(),
371
+ cleanupTimer: null
369
372
  }
370
373
  }
371
374
  return globalThis.__piDeskPiSessionHistoryCatalogState
@@ -375,37 +378,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
375
378
  return typeof value === 'object' && value !== null && !Array.isArray(value)
376
379
  }
377
380
 
378
- function timestampMs(value: unknown): number | null {
379
- if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) return value
380
- if (typeof value !== 'string') return null
381
- const parsed = Date.parse(value)
382
- return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null
383
- }
384
-
385
- function normalizeSearch(value: string): string {
386
- return value.trim().toLowerCase()
387
- }
388
-
389
- function compactPreview(text: string, maxLength: number): string {
390
- const content = text.replace(/\s+/g, ' ').trim()
391
- if (content.length <= maxLength) return content
392
- return `${content.slice(0, maxLength - 1).trimEnd()}…`
393
- }
394
-
395
- function messageText(message: unknown): string {
396
- if (!isRecord(message)) return ''
397
- const content = message.content
398
- if (typeof content === 'string') return content
399
- if (!Array.isArray(content)) return ''
400
-
401
- return content
402
- .flatMap((part) => {
403
- if (!isRecord(part) || part.type !== 'text' || typeof part.text !== 'string') return []
404
- return [part.text]
405
- })
406
- .join('\n')
407
- }
408
-
409
381
  function messageTimestamp(entry: Record<string, unknown>, fallback: number): number {
410
382
  const entryTimestamp = timestampMs(entry.timestamp)
411
383
  if (entryTimestamp !== null) return entryTimestamp
@@ -696,11 +668,31 @@ async function refreshCatalog(
696
668
  }
697
669
  }
698
670
 
699
- function pruneCatalogs(now: number): void {
700
- const state = historyCatalogState()
671
+ function scheduleCatalogRelease(state: L4PiSessionHistoryCatalogState): void {
672
+ if (state.cleanupTimer) clearTimeout(state.cleanupTimer)
673
+ state.cleanupTimer = null
674
+ if (state.catalogs.size === 0) return
675
+ const expiresAt = Math.min(
676
+ ...Array.from(state.catalogs.values(), (catalog) => catalog.lastAccessedAt + CACHE_IDLE_MS)
677
+ )
678
+ state.cleanupTimer = setTimeout(
679
+ () => {
680
+ state.cleanupTimer = null
681
+ pruneCatalogs(Date.now(), state)
682
+ },
683
+ Math.max(0, expiresAt - Date.now())
684
+ )
685
+ state.cleanupTimer.unref()
686
+ }
687
+
688
+ function pruneCatalogs(
689
+ now: number,
690
+ state: L4PiSessionHistoryCatalogState = historyCatalogState()
691
+ ): void {
701
692
  for (const [cwd, catalog] of state.catalogs) {
702
- if (now - catalog.lastAccessedAt > CACHE_IDLE_MS) state.catalogs.delete(cwd)
693
+ if (now - catalog.lastAccessedAt >= CACHE_IDLE_MS) state.catalogs.delete(cwd)
703
694
  }
695
+ scheduleCatalogRelease(state)
704
696
  }
705
697
 
706
698
  function touchCatalog(catalog: L4PiSessionHistoryCatalog, now: number): L4PiSessionHistoryCatalog {
@@ -708,6 +700,7 @@ function touchCatalog(catalog: L4PiSessionHistoryCatalog, now: number): L4PiSess
708
700
  const state = historyCatalogState()
709
701
  state.catalogs.delete(catalog.cwd)
710
702
  state.catalogs.set(catalog.cwd, catalog)
703
+ scheduleCatalogRelease(state)
711
704
  return catalog
712
705
  }
713
706
 
@@ -715,6 +708,7 @@ function storeCatalog(catalog: L4PiSessionHistoryCatalog, persist: boolean): voi
715
708
  const state = historyCatalogState()
716
709
  if (catalog.files.size > CACHE_FILE_LIMIT || catalog.textBytes > CACHE_TEXT_BYTES_LIMIT) {
717
710
  state.catalogs.delete(catalog.cwd)
711
+ scheduleCatalogRelease(state)
718
712
  if (persist) {
719
713
  const path = persistedHistoryCachePath(catalog.cwd)
720
714
  try {
@@ -747,6 +741,7 @@ function storeCatalog(catalog: L4PiSessionHistoryCatalog, persist: boolean): voi
747
741
  state.catalogs.delete(oldest[0])
748
742
  totalBytes -= oldest[1].textBytes
749
743
  }
744
+ scheduleCatalogRelease(state)
750
745
  if (persist) persistHistoryCatalog(catalog)
751
746
  }
752
747
 
@@ -768,8 +763,9 @@ async function getCatalog(
768
763
  const state = historyCatalogState()
769
764
  const now = Date.now()
770
765
  pruneCatalogs(now)
771
- const catalog = state.catalogs.get(cwd) ?? readPersistedHistoryCatalog(cwd)
772
- const epoch = forceRefresh ? incrementEpoch(cwd) : currentEpoch(cwd)
766
+ const cached = state.catalogs.get(cwd)
767
+ const catalog = cached ? touchCatalog(cached, now) : readPersistedHistoryCatalog(cwd)
768
+ const epoch = forceRefresh && state.activeLoads.has(cwd) ? incrementEpoch(cwd) : currentEpoch(cwd)
773
769
  if (forceRefresh && catalog) catalog.dirty = true
774
770
  const active = state.activeLoads.get(cwd)
775
771
  if (active && active.epoch === epoch) return active.promise
@@ -783,10 +779,12 @@ async function getCatalog(
783
779
  return touchCatalog(catalog, now)
784
780
  }
785
781
 
786
- const load = (async (): Promise<L4PiSessionHistoryCatalog> => {
782
+ const load: Promise<L4PiSessionHistoryCatalog> = Promise.resolve().then(async () => {
787
783
  const refresh = await refreshCatalog(cwd, catalog)
788
784
  const refreshed = refresh.catalog
789
- if (currentEpoch(cwd) === epoch) storeCatalog(refreshed, refresh.changed)
785
+ if (state.activeLoads.get(cwd)?.promise === load && currentEpoch(cwd) === epoch) {
786
+ storeCatalog(refreshed, refresh.changed)
787
+ }
790
788
  console.info('[Pi Desk][PiSessionHistoryCatalog] 已更新历史会话内存投影', {
791
789
  cwd,
792
790
  sessionCount: refreshed.sessions.length,
@@ -795,43 +793,15 @@ async function getCatalog(
795
793
  forceRefresh
796
794
  })
797
795
  return refreshed
798
- })()
796
+ })
799
797
  state.activeLoads.set(cwd, { epoch, promise: load })
800
798
  try {
801
799
  return await load
802
800
  } finally {
803
- if (state.activeLoads.get(cwd)?.promise === load) state.activeLoads.delete(cwd)
804
- }
805
- }
806
-
807
- function previewForMatch(text: string, normalizedQuery: string): string {
808
- const normalizedText = text.toLowerCase()
809
- const matchIndex = normalizedText.indexOf(normalizedQuery)
810
- if (matchIndex < 0) return ''
811
-
812
- const start = Math.max(0, matchIndex - MATCH_PREVIEW_PREFIX_LENGTH)
813
- const requiredEnd = matchIndex + normalizedQuery.length
814
- const end = Math.min(text.length, Math.max(start + MATCH_PREVIEW_MAX_LENGTH, requiredEnd))
815
- const content = text.slice(start, end).replace(/\s+/g, ' ').trim()
816
- return `${start > 0 ? '…' : ''}${content}${end < text.length ? '…' : ''}`
817
- }
818
-
819
- function messageMatch(
820
- scope: 'user' | 'assistant',
821
- messages: readonly L4PiSessionUserMessage[] | readonly L4PiSessionAssistantMessage[],
822
- normalizedQuery: string
823
- ): L4PiSessionHistoryMatch | null {
824
- const matching = messages.filter((message) =>
825
- message.text.toLowerCase().includes(normalizedQuery)
826
- )
827
- if (matching.length === 0) return null
828
- const latest = matching.at(-1)!
829
- return {
830
- scope,
831
- count: matching.length,
832
- entryId: latest.entryId,
833
- timestampMs: latest.timestampMs,
834
- preview: previewForMatch(latest.text, normalizedQuery)
801
+ if (state.activeLoads.get(cwd)?.promise === load) {
802
+ state.activeLoads.delete(cwd)
803
+ state.epochs.delete(cwd)
804
+ }
835
805
  }
836
806
  }
837
807
 
@@ -854,33 +824,7 @@ function projectHistoryItem(
854
824
  }
855
825
  }
856
826
 
857
- const matches: L4PiSessionHistoryMatch[] = []
858
- if (searchIn.has('title') && session.name?.toLowerCase().includes(normalizedQuery)) {
859
- matches.push({
860
- scope: 'title',
861
- count: 1,
862
- entryId: null,
863
- timestampMs: null,
864
- preview: compactPreview(session.name, FIRST_MESSAGE_PREVIEW_MAX_LENGTH)
865
- })
866
- }
867
- if (searchIn.has('user')) {
868
- const match = messageMatch('user', session.userMessages, normalizedQuery)
869
- if (match) matches.push(match)
870
- }
871
- if (searchIn.has('assistant')) {
872
- const match = messageMatch('assistant', session.assistantMessages, normalizedQuery)
873
- if (match) matches.push(match)
874
- }
875
- if (searchIn.has('sessionId') && session.sessionId.toLowerCase().includes(normalizedQuery)) {
876
- matches.push({
877
- scope: 'sessionId',
878
- count: 1,
879
- entryId: null,
880
- timestampMs: null,
881
- preview: session.sessionId
882
- })
883
- }
827
+ const matches = matchL4PiSessionSearch(session, normalizedQuery, searchIn)
884
828
  if (matches.length === 0) return null
885
829
 
886
830
  return {
@@ -917,7 +861,10 @@ async function getSessionRecord(
917
861
  ): Promise<L4PiSessionHistoryRecord | null> {
918
862
  const cwd = resolve(cwdInput)
919
863
  pruneCatalogs(Date.now())
920
- const catalog = historyCatalogState().catalogs.get(cwd) ?? readPersistedHistoryCatalog(cwd)
864
+ const memoryCatalog = historyCatalogState().catalogs.get(cwd)
865
+ const catalog = memoryCatalog
866
+ ? touchCatalog(memoryCatalog, Date.now())
867
+ : readPersistedHistoryCatalog(cwd)
921
868
  const previous = catalog?.sessions.find((session) => session.sessionId === sessionId)
922
869
  const path = await findL4PiSessionFile(cwd, sessionId, previous?.path)
923
870
  if (!path) return null
@@ -972,8 +919,10 @@ export function resolveCachedL4PiSessionHistoryPath(
972
919
  cwd: string,
973
920
  sessionId: string
974
921
  ): string | undefined {
922
+ pruneCatalogs(Date.now())
975
923
  const catalog = historyCatalogState().catalogs.get(resolve(cwd))
976
924
  if (!catalog || catalog.dirty) return undefined
925
+ touchCatalog(catalog, Date.now())
977
926
  return catalog.sessions.find((session) => session.sessionId === sessionId)?.path
978
927
  }
979
928
 
@@ -981,7 +930,7 @@ export function invalidateL4PiSessionHistoryCache(cwd?: string): void {
981
930
  const state = historyCatalogState()
982
931
  if (cwd) {
983
932
  const normalizedCwd = resolve(cwd)
984
- incrementEpoch(normalizedCwd)
933
+ if (state.activeLoads.has(normalizedCwd)) incrementEpoch(normalizedCwd)
985
934
  const catalog = state.catalogs.get(normalizedCwd)
986
935
  if (catalog) catalog.dirty = true
987
936
  return
@@ -989,7 +938,7 @@ export function invalidateL4PiSessionHistoryCache(cwd?: string): void {
989
938
 
990
939
  const affectedCwds = new Set([...state.catalogs.keys(), ...state.activeLoads.keys()])
991
940
  for (const catalogCwd of affectedCwds) {
992
- incrementEpoch(catalogCwd)
941
+ if (state.activeLoads.has(catalogCwd)) incrementEpoch(catalogCwd)
993
942
  const catalog = state.catalogs.get(catalogCwd)
994
943
  if (catalog) catalog.dirty = true
995
944
  }