@bryanhu/codexly 0.18.0 → 0.19.0

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 (223) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +4 -0
  3. package/README.zh-CN.md +4 -0
  4. package/dist/chunk-B2673ODM.js +260 -0
  5. package/dist/chunk-GT7XTSEG.js +56 -0
  6. package/dist/{chunk-NROPHBJ7.js → chunk-HMXTAIDF.js} +2467 -4020
  7. package/dist/{chunk-M6GWGUSX.js → chunk-X5JZ3VOF.js} +311 -77
  8. package/dist/{chunk-3PU3WPOK.js → chunk-YFWMYA6X.js} +658 -72
  9. package/dist/{chunk-2O7SN37L.js → chunk-ZUECHB6L.js} +1 -1
  10. package/dist/cli.js +113 -39
  11. package/dist/client/index.js +135 -11
  12. package/dist/core/index.js +1 -1
  13. package/dist/protocol/index.js +2 -1
  14. package/dist/providers/codex/index.js +4 -3
  15. package/dist/runtime-instance-worker.js +19 -0
  16. package/dist/scheduled-task-recurrence-worker.js +2969 -0
  17. package/dist/server/index.js +6 -5
  18. package/dist/sqlite-state-worker.js +156 -13
  19. package/dist/web/.vite/manifest.json +106 -106
  20. package/dist/web/.vite/manifest.json.br +0 -0
  21. package/dist/web/.vite/manifest.json.gz +0 -0
  22. package/dist/web/assets/{agent-settings-panel-BagNBAoe.js → agent-settings-panel-B3hoqvYI.js} +1 -1
  23. package/dist/web/assets/agent-settings-panel-B3hoqvYI.js.br +0 -0
  24. package/dist/web/assets/agent-settings-panel-B3hoqvYI.js.gz +0 -0
  25. package/dist/web/assets/background-image-picker-DV18Olkx.js +1 -0
  26. package/dist/web/assets/background-image-picker-DV18Olkx.js.br +0 -0
  27. package/dist/web/assets/background-image-picker-DV18Olkx.js.gz +0 -0
  28. package/dist/web/assets/{bing-wallpaper-queries-B-1L0OYP.js → bing-wallpaper-queries-CybCDdtr.js} +1 -1
  29. package/dist/web/assets/bing-wallpaper-queries-CybCDdtr.js.br +0 -0
  30. package/dist/web/assets/bing-wallpaper-queries-CybCDdtr.js.gz +0 -0
  31. package/dist/web/assets/{button-group-DIxa2Erp.js → button-group-DLm5MGrs.js} +1 -1
  32. package/dist/web/assets/button-group-DLm5MGrs.js.br +0 -0
  33. package/dist/web/assets/button-group-DLm5MGrs.js.gz +0 -0
  34. package/dist/web/assets/{commit-settings-panel-Co1u5Lzc.js → commit-settings-panel-RS1ax2vB.js} +1 -1
  35. package/dist/web/assets/commit-settings-panel-RS1ax2vB.js.br +0 -0
  36. package/dist/web/assets/commit-settings-panel-RS1ax2vB.js.gz +0 -0
  37. package/dist/web/assets/{context-menu-HaQeWpEd.js → context-menu-DP6ii80r.js} +1 -1
  38. package/dist/web/assets/context-menu-DP6ii80r.js.br +0 -0
  39. package/dist/web/assets/context-menu-DP6ii80r.js.gz +0 -0
  40. package/dist/web/assets/{file-review-dialog-B-0RkLZR.js → file-review-dialog-C3to4N_J.js} +1 -1
  41. package/dist/web/assets/file-review-dialog-C3to4N_J.js.br +0 -0
  42. package/dist/web/assets/file-review-dialog-C3to4N_J.js.gz +0 -0
  43. package/dist/web/assets/{git-history-panel-QiNKxo_n.js → git-history-panel-D2OdQ1Pg.js} +1 -1
  44. package/dist/web/assets/git-history-panel-D2OdQ1Pg.js.br +0 -0
  45. package/dist/web/assets/git-history-panel-D2OdQ1Pg.js.gz +0 -0
  46. package/dist/web/assets/{global-settings-about-DWXfIOas.js → global-settings-about-DYd77AOa.js} +1 -1
  47. package/dist/web/assets/global-settings-about-DYd77AOa.js.br +0 -0
  48. package/dist/web/assets/global-settings-about-DYd77AOa.js.gz +0 -0
  49. package/dist/web/assets/{global-settings-fields-CmEy5pOE.js → global-settings-fields-C0IfL3RQ.js} +1 -1
  50. package/dist/web/assets/global-settings-fields-C0IfL3RQ.js.br +0 -0
  51. package/dist/web/assets/global-settings-fields-C0IfL3RQ.js.gz +0 -0
  52. package/dist/web/assets/global-settings-model-dAGHIcU5.js +1 -0
  53. package/dist/web/assets/global-settings-model-dAGHIcU5.js.br +0 -0
  54. package/dist/web/assets/global-settings-model-dAGHIcU5.js.gz +0 -0
  55. package/dist/web/assets/global-settings-page-746-HK5D.js +2 -0
  56. package/dist/web/assets/global-settings-page-746-HK5D.js.br +0 -0
  57. package/dist/web/assets/global-settings-page-746-HK5D.js.gz +0 -0
  58. package/dist/web/assets/{global-settings-pets-DP2AxhJW.js → global-settings-pets-B6HRYnYq.js} +1 -1
  59. package/dist/web/assets/global-settings-pets-B6HRYnYq.js.br +0 -0
  60. package/dist/web/assets/global-settings-pets-B6HRYnYq.js.gz +0 -0
  61. package/dist/web/assets/{index-BGtID8VJ.css → index-DGp-a5pq.css} +1 -1
  62. package/dist/web/assets/index-DGp-a5pq.css.br +0 -0
  63. package/dist/web/assets/{index-BGtID8VJ.css.gz → index-DGp-a5pq.css.gz} +0 -0
  64. package/dist/web/assets/index-DwEl9mCY.js +4 -0
  65. package/dist/web/assets/index-DwEl9mCY.js.br +0 -0
  66. package/dist/web/assets/index-DwEl9mCY.js.gz +0 -0
  67. package/dist/web/assets/initial-deps-Bk3GSWTk.js +1 -0
  68. package/dist/web/assets/initial-deps-Bk3GSWTk.js.br +0 -0
  69. package/dist/web/assets/initial-deps-Bk3GSWTk.js.gz +0 -0
  70. package/dist/web/assets/installed-skills-pane-Gzaol8-B.js +1 -0
  71. package/dist/web/assets/installed-skills-pane-Gzaol8-B.js.br +0 -0
  72. package/dist/web/assets/installed-skills-pane-Gzaol8-B.js.gz +0 -0
  73. package/dist/web/assets/{lazy-message-response-3Fr_a8du.js → lazy-message-response-CZT51-go.js} +2 -2
  74. package/dist/web/assets/lazy-message-response-CZT51-go.js.br +0 -0
  75. package/dist/web/assets/lazy-message-response-CZT51-go.js.gz +0 -0
  76. package/dist/web/assets/mcp-management-pane-C0g0wk8t.js +1 -0
  77. package/dist/web/assets/mcp-management-pane-C0g0wk8t.js.br +0 -0
  78. package/dist/web/assets/mcp-management-pane-C0g0wk8t.js.gz +0 -0
  79. package/dist/web/assets/{message-response-D3YFwFiE.js → message-response-CA2hanqw.js} +1 -1
  80. package/dist/web/assets/message-response-CA2hanqw.js.br +0 -0
  81. package/dist/web/assets/message-response-CA2hanqw.js.gz +0 -0
  82. package/dist/web/assets/{official-plugins-pane-k8o9gVMR.js → official-plugins-pane-D6kbUBEm.js} +1 -1
  83. package/dist/web/assets/official-plugins-pane-D6kbUBEm.js.br +0 -0
  84. package/dist/web/assets/official-plugins-pane-D6kbUBEm.js.gz +0 -0
  85. package/dist/web/assets/personalization-settings-panel-DnWZEv6V.js +1 -0
  86. package/dist/web/assets/personalization-settings-panel-DnWZEv6V.js.br +0 -0
  87. package/dist/web/assets/personalization-settings-panel-DnWZEv6V.js.gz +0 -0
  88. package/dist/web/assets/{project-file-popup-page-0uRpUcFH.js → project-file-popup-page-C8zcwgkf.js} +1 -1
  89. package/dist/web/assets/project-file-popup-page-C8zcwgkf.js.br +0 -0
  90. package/dist/web/assets/project-file-popup-page-C8zcwgkf.js.gz +0 -0
  91. package/dist/web/assets/{project-source-panel-CEegjNVo.js → project-source-panel-ChVlP72p.js} +2 -2
  92. package/dist/web/assets/project-source-panel-ChVlP72p.js.br +0 -0
  93. package/dist/web/assets/project-source-panel-ChVlP72p.js.gz +0 -0
  94. package/dist/web/assets/{prompt-input-Bs_e51Ey.js → prompt-input-CcovKFMj.js} +1 -1
  95. package/dist/web/assets/prompt-input-CcovKFMj.js.br +0 -0
  96. package/dist/web/assets/prompt-input-CcovKFMj.js.gz +0 -0
  97. package/dist/web/assets/{prompt-input-controls-DMqyvYVY.js → prompt-input-controls-j_r9SnuL.js} +1 -1
  98. package/dist/web/assets/prompt-input-controls-j_r9SnuL.js.br +0 -0
  99. package/dist/web/assets/prompt-input-controls-j_r9SnuL.js.gz +0 -0
  100. package/dist/web/assets/{scheduled-task-date-time-picker-CHc9a7G1.js → scheduled-task-date-time-picker-CkLwYwGu.js} +1 -1
  101. package/dist/web/assets/scheduled-task-date-time-picker-CkLwYwGu.js.br +0 -0
  102. package/dist/web/assets/scheduled-task-date-time-picker-CkLwYwGu.js.gz +0 -0
  103. package/dist/web/assets/{scheduled-task-schedule-2Ugh5sqp.js → scheduled-task-schedule-f0nylWUa.js} +1 -1
  104. package/dist/web/assets/scheduled-task-schedule-f0nylWUa.js.br +0 -0
  105. package/dist/web/assets/scheduled-task-schedule-f0nylWUa.js.gz +0 -0
  106. package/dist/web/assets/scheduled-tasks-container-DxM30EEY.js +2 -0
  107. package/dist/web/assets/scheduled-tasks-container-DxM30EEY.js.br +0 -0
  108. package/dist/web/assets/scheduled-tasks-container-DxM30EEY.js.gz +0 -0
  109. package/dist/web/assets/{settings-personalization-b55VcvKr.js → settings-personalization-CPFvvwt7.js} +1 -1
  110. package/dist/web/assets/settings-personalization-CPFvvwt7.js.br +0 -0
  111. package/dist/web/assets/settings-personalization-CPFvvwt7.js.gz +0 -0
  112. package/dist/web/assets/{sheet-DbEBBgCs.js → sheet-Co357cup.js} +1 -1
  113. package/dist/web/assets/sheet-Co357cup.js.br +0 -0
  114. package/dist/web/assets/sheet-Co357cup.js.gz +0 -0
  115. package/dist/web/assets/{skills-market-container-BwT-U8XF.js → skills-market-container-CJ8k5fIO.js} +2 -2
  116. package/dist/web/assets/skills-market-container-CJ8k5fIO.js.br +0 -0
  117. package/dist/web/assets/skills-market-container-CJ8k5fIO.js.gz +0 -0
  118. package/dist/web/assets/{third-party-marketplace-pane-Cva9dfRn.js → third-party-marketplace-pane-BrosEBTn.js} +1 -1
  119. package/dist/web/assets/third-party-marketplace-pane-BrosEBTn.js.br +0 -0
  120. package/dist/web/assets/third-party-marketplace-pane-BrosEBTn.js.gz +0 -0
  121. package/dist/web/assets/workbench-composer-CxDyu4IJ.js +8 -0
  122. package/dist/web/assets/workbench-composer-CxDyu4IJ.js.br +0 -0
  123. package/dist/web/assets/workbench-composer-CxDyu4IJ.js.gz +0 -0
  124. package/dist/web/assets/workbench-inspector-changes-DXrYXxmV.js +2 -0
  125. package/dist/web/assets/workbench-inspector-changes-DXrYXxmV.js.br +0 -0
  126. package/dist/web/assets/workbench-inspector-changes-DXrYXxmV.js.gz +0 -0
  127. package/dist/web/assets/workbench-pet-canvas-C5NL9nOc.js +1 -0
  128. package/dist/web/assets/workbench-pet-canvas-C5NL9nOc.js.br +0 -0
  129. package/dist/web/assets/workbench-pet-canvas-C5NL9nOc.js.gz +0 -0
  130. package/dist/web/assets/workbench-shell-C3Zu4F9x.js +8 -0
  131. package/dist/web/assets/workbench-shell-C3Zu4F9x.js.br +0 -0
  132. package/dist/web/assets/workbench-shell-C3Zu4F9x.js.gz +0 -0
  133. package/dist/web/index.html +3 -3
  134. package/dist/web/index.html.br +0 -0
  135. package/dist/web/index.html.gz +0 -0
  136. package/package.json +1 -1
  137. package/dist/chunk-RNTA4MFS.js +0 -23
  138. package/dist/web/assets/agent-settings-panel-BagNBAoe.js.br +0 -0
  139. package/dist/web/assets/agent-settings-panel-BagNBAoe.js.gz +0 -0
  140. package/dist/web/assets/background-image-picker-CjpS0dIk.js +0 -1
  141. package/dist/web/assets/background-image-picker-CjpS0dIk.js.br +0 -0
  142. package/dist/web/assets/background-image-picker-CjpS0dIk.js.gz +0 -0
  143. package/dist/web/assets/bing-wallpaper-queries-B-1L0OYP.js.br +0 -0
  144. package/dist/web/assets/bing-wallpaper-queries-B-1L0OYP.js.gz +0 -0
  145. package/dist/web/assets/button-group-DIxa2Erp.js.br +0 -0
  146. package/dist/web/assets/button-group-DIxa2Erp.js.gz +0 -0
  147. package/dist/web/assets/commit-settings-panel-Co1u5Lzc.js.br +0 -0
  148. package/dist/web/assets/commit-settings-panel-Co1u5Lzc.js.gz +0 -0
  149. package/dist/web/assets/context-menu-HaQeWpEd.js.br +0 -0
  150. package/dist/web/assets/context-menu-HaQeWpEd.js.gz +0 -0
  151. package/dist/web/assets/file-review-dialog-B-0RkLZR.js.br +0 -0
  152. package/dist/web/assets/file-review-dialog-B-0RkLZR.js.gz +0 -0
  153. package/dist/web/assets/git-history-panel-QiNKxo_n.js.br +0 -0
  154. package/dist/web/assets/git-history-panel-QiNKxo_n.js.gz +0 -0
  155. package/dist/web/assets/global-settings-about-DWXfIOas.js.br +0 -0
  156. package/dist/web/assets/global-settings-about-DWXfIOas.js.gz +0 -0
  157. package/dist/web/assets/global-settings-fields-CmEy5pOE.js.br +0 -0
  158. package/dist/web/assets/global-settings-fields-CmEy5pOE.js.gz +0 -0
  159. package/dist/web/assets/global-settings-model-B49sZloO.js +0 -1
  160. package/dist/web/assets/global-settings-model-B49sZloO.js.br +0 -0
  161. package/dist/web/assets/global-settings-model-B49sZloO.js.gz +0 -0
  162. package/dist/web/assets/global-settings-page-DKXRkWmd.js +0 -2
  163. package/dist/web/assets/global-settings-page-DKXRkWmd.js.br +0 -0
  164. package/dist/web/assets/global-settings-page-DKXRkWmd.js.gz +0 -0
  165. package/dist/web/assets/global-settings-pets-DP2AxhJW.js.br +0 -0
  166. package/dist/web/assets/global-settings-pets-DP2AxhJW.js.gz +0 -0
  167. package/dist/web/assets/index-BGtID8VJ.css.br +0 -0
  168. package/dist/web/assets/index-mkWzMsjN.js +0 -4
  169. package/dist/web/assets/index-mkWzMsjN.js.br +0 -0
  170. package/dist/web/assets/index-mkWzMsjN.js.gz +0 -0
  171. package/dist/web/assets/initial-deps-CDAJF_GU.js +0 -1
  172. package/dist/web/assets/initial-deps-CDAJF_GU.js.br +0 -0
  173. package/dist/web/assets/initial-deps-CDAJF_GU.js.gz +0 -0
  174. package/dist/web/assets/installed-skills-pane-CR2LbYh9.js +0 -1
  175. package/dist/web/assets/installed-skills-pane-CR2LbYh9.js.br +0 -0
  176. package/dist/web/assets/installed-skills-pane-CR2LbYh9.js.gz +0 -0
  177. package/dist/web/assets/lazy-message-response-3Fr_a8du.js.br +0 -0
  178. package/dist/web/assets/lazy-message-response-3Fr_a8du.js.gz +0 -0
  179. package/dist/web/assets/mcp-management-pane-DEuUn7Y6.js +0 -1
  180. package/dist/web/assets/mcp-management-pane-DEuUn7Y6.js.br +0 -0
  181. package/dist/web/assets/mcp-management-pane-DEuUn7Y6.js.gz +0 -0
  182. package/dist/web/assets/message-response-D3YFwFiE.js.br +0 -0
  183. package/dist/web/assets/message-response-D3YFwFiE.js.gz +0 -0
  184. package/dist/web/assets/official-plugins-pane-k8o9gVMR.js.br +0 -0
  185. package/dist/web/assets/official-plugins-pane-k8o9gVMR.js.gz +0 -0
  186. package/dist/web/assets/personalization-settings-panel-Cl4_Y5Uk.js +0 -1
  187. package/dist/web/assets/personalization-settings-panel-Cl4_Y5Uk.js.br +0 -0
  188. package/dist/web/assets/personalization-settings-panel-Cl4_Y5Uk.js.gz +0 -0
  189. package/dist/web/assets/project-file-popup-page-0uRpUcFH.js.br +0 -0
  190. package/dist/web/assets/project-file-popup-page-0uRpUcFH.js.gz +0 -0
  191. package/dist/web/assets/project-source-panel-CEegjNVo.js.br +0 -0
  192. package/dist/web/assets/project-source-panel-CEegjNVo.js.gz +0 -0
  193. package/dist/web/assets/prompt-input-Bs_e51Ey.js.br +0 -0
  194. package/dist/web/assets/prompt-input-Bs_e51Ey.js.gz +0 -0
  195. package/dist/web/assets/prompt-input-controls-DMqyvYVY.js.br +0 -0
  196. package/dist/web/assets/prompt-input-controls-DMqyvYVY.js.gz +0 -0
  197. package/dist/web/assets/scheduled-task-date-time-picker-CHc9a7G1.js.br +0 -0
  198. package/dist/web/assets/scheduled-task-date-time-picker-CHc9a7G1.js.gz +0 -0
  199. package/dist/web/assets/scheduled-task-schedule-2Ugh5sqp.js.br +0 -0
  200. package/dist/web/assets/scheduled-task-schedule-2Ugh5sqp.js.gz +0 -0
  201. package/dist/web/assets/scheduled-tasks-container-Ddieo85Q.js +0 -2
  202. package/dist/web/assets/scheduled-tasks-container-Ddieo85Q.js.br +0 -0
  203. package/dist/web/assets/scheduled-tasks-container-Ddieo85Q.js.gz +0 -0
  204. package/dist/web/assets/settings-personalization-b55VcvKr.js.br +0 -0
  205. package/dist/web/assets/settings-personalization-b55VcvKr.js.gz +0 -0
  206. package/dist/web/assets/sheet-DbEBBgCs.js.br +0 -0
  207. package/dist/web/assets/sheet-DbEBBgCs.js.gz +0 -0
  208. package/dist/web/assets/skills-market-container-BwT-U8XF.js.br +0 -0
  209. package/dist/web/assets/skills-market-container-BwT-U8XF.js.gz +0 -0
  210. package/dist/web/assets/third-party-marketplace-pane-Cva9dfRn.js.br +0 -0
  211. package/dist/web/assets/third-party-marketplace-pane-Cva9dfRn.js.gz +0 -0
  212. package/dist/web/assets/workbench-composer-BxYlmKUq.js +0 -10
  213. package/dist/web/assets/workbench-composer-BxYlmKUq.js.br +0 -0
  214. package/dist/web/assets/workbench-composer-BxYlmKUq.js.gz +0 -0
  215. package/dist/web/assets/workbench-inspector-changes-DFZ_PDdt.js +0 -2
  216. package/dist/web/assets/workbench-inspector-changes-DFZ_PDdt.js.br +0 -0
  217. package/dist/web/assets/workbench-inspector-changes-DFZ_PDdt.js.gz +0 -0
  218. package/dist/web/assets/workbench-pet-canvas-DwkSGxpw.js +0 -1
  219. package/dist/web/assets/workbench-pet-canvas-DwkSGxpw.js.br +0 -0
  220. package/dist/web/assets/workbench-pet-canvas-DwkSGxpw.js.gz +0 -0
  221. package/dist/web/assets/workbench-shell-CnjG23lI.js +0 -8
  222. package/dist/web/assets/workbench-shell-CnjG23lI.js.br +0 -0
  223. package/dist/web/assets/workbench-shell-CnjG23lI.js.gz +0 -0
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from 'node:module';
2
- import { WorkbenchPetProviderError, PendingRequestResolutionError } from './chunk-RNTA4MFS.js';
3
- import { TEMPORARY_TASK_SCOPE_ID, MAX_AGENT_HISTORY_IMAGE_TOTAL_BYTES, isAgentFastModeAvailable, MAX_REALTIME_FILE_CHANGES, MAX_REALTIME_DIFF_BYTES, stripLeadingAgentSkillReferences, MAX_AGENT_HISTORY_IMAGES, MAX_AGENT_TEXT_BYTES } from './chunk-M6GWGUSX.js';
2
+ import { WorkbenchPetProviderError, PendingRequestResolutionError } from './chunk-B2673ODM.js';
3
+ import { TEMPORARY_TASK_SCOPE_ID, MAX_AGENT_HISTORY_IMAGE_TOTAL_BYTES, isAgentFastModeAvailable, MAX_REALTIME_FILE_CHANGES, MAX_REALTIME_DIFF_BYTES, stripLeadingAgentSkillReferences, MAX_AGENT_HISTORY_IMAGES, MAX_AGENT_TEXT_BYTES } from './chunk-X5JZ3VOF.js';
4
4
  import { __commonJS, __require, __toESM } from './chunk-K6J42667.js';
5
5
  import { execFile, spawn } from 'child_process';
6
6
  import { constants, mkdtempSync, rmSync, createReadStream, mkdirSync, unlinkSync, renameSync, writeFileSync, openSync, readSync, closeSync, statSync } from 'fs';
@@ -6193,25 +6193,24 @@ function mapUserMessageContent(value, mapImage, mapText) {
6193
6193
  }
6194
6194
  return { attachments, skills, text: textParts.join("\n") };
6195
6195
  }
6196
+ function mergeMessageSkills(message, incoming) {
6197
+ const skills = [...message.skills ?? []];
6198
+ const names = new Set(skills.map((skill) => skill.name));
6199
+ for (const skill of incoming) {
6200
+ if (!names.has(skill.name)) {
6201
+ names.add(skill.name);
6202
+ skills.push(skill);
6203
+ }
6204
+ }
6205
+ return { ...message, skills, text: stripLeadingAgentSkillReferences(message.text, skills) };
6206
+ }
6196
6207
  function mergeExpandedSkillMessages(items) {
6197
6208
  const mergedItems = [];
6198
6209
  for (const item of items) {
6199
- const isSkillOnlyMessage = item.type === "message" && item.role === "user" && item.text.length === 0 && (item.skills?.length ?? 0) > 0;
6210
+ const isSkillOnlyMessage = item.type === "message" && item.role === "user" && item.text.length === 0 && (item.attachments?.length ?? 0) === 0 && (item.skills?.length ?? 0) > 0;
6200
6211
  const previousItem = mergedItems.at(-1);
6201
6212
  if (isSkillOnlyMessage && previousItem?.type === "message" && previousItem.role === "user") {
6202
- const skillNames = new Set((previousItem.skills ?? []).map((skill) => skill.name));
6203
- const mergedSkills = [...previousItem.skills ?? []];
6204
- for (const skill of item.skills ?? []) {
6205
- if (!skillNames.has(skill.name)) {
6206
- skillNames.add(skill.name);
6207
- mergedSkills.push(skill);
6208
- }
6209
- }
6210
- mergedItems[mergedItems.length - 1] = {
6211
- ...previousItem,
6212
- skills: mergedSkills,
6213
- text: stripLeadingAgentSkillReferences(previousItem.text, mergedSkills)
6214
- };
6213
+ mergedItems[mergedItems.length - 1] = mergeMessageSkills(previousItem, item.skills ?? []);
6215
6214
  continue;
6216
6215
  }
6217
6216
  mergedItems.push(item);
@@ -8706,8 +8705,292 @@ async function reloadCodexMcpServers(client, taskId) {
8706
8705
  return listCodexMcpServers(client, taskId);
8707
8706
  }
8708
8707
 
8708
+ // packages/provider-codex/src/message-identity-matching.ts
8709
+ function matchesMessageIdentity(current, incoming) {
8710
+ if (current.role !== incoming.role) return false;
8711
+ if (current.phase !== void 0 && incoming.phase !== void 0 && current.phase !== incoming.phase)
8712
+ return false;
8713
+ if (current.text.length > 0 && incoming.text.length > 0) {
8714
+ return current.text.startsWith(incoming.text) || incoming.text.startsWith(current.text);
8715
+ }
8716
+ if (current.role !== "user" || current.text.length > 0 || incoming.text.length > 0) return false;
8717
+ const attachments = current.attachments ?? [];
8718
+ const other = incoming.attachments ?? [];
8719
+ return attachments.length > 0 && attachments.length === other.length && attachments.every(
8720
+ (item, index) => item.kind === "image" && other[index]?.kind === "image" && item.mediaType === other[index].mediaType && item.size === other[index].size
8721
+ );
8722
+ }
8723
+
8724
+ // packages/provider-codex/src/message-identity.ts
8725
+ var MAX_TURNS = 128;
8726
+ var MAX_MESSAGES = 256;
8727
+ var MAX_TEXT = 16384;
8728
+ var MAX_RETAINED_TEXT = 1048576;
8729
+ var MessageIdentityRegistry = class {
8730
+ #turns = /* @__PURE__ */ new Map();
8731
+ #textSize = 0;
8732
+ #order = 0;
8733
+ turn(taskId, turnId) {
8734
+ const key = JSON.stringify([taskId, turnId]);
8735
+ const value = this.#turns.get(key) ?? {
8736
+ taskId,
8737
+ entries: /* @__PURE__ */ new Map(),
8738
+ running: false
8739
+ };
8740
+ this.#turns.delete(key);
8741
+ this.#turns.set(key, value);
8742
+ if (this.#turns.size > MAX_TURNS) {
8743
+ const oldest = [...this.#turns].find(([candidateKey, turn]) => candidateKey !== key && !turn.running) ?? this.#turns.entries().next().value;
8744
+ if (oldest !== void 0) {
8745
+ this.release(oldest[1]);
8746
+ this.#turns.delete(oldest[0]);
8747
+ }
8748
+ }
8749
+ return value;
8750
+ }
8751
+ find(turn, id) {
8752
+ return turn.entries.get(id) ?? [...turn.entries.values()].find((entry) => entry.aliases.has(id));
8753
+ }
8754
+ remember(turn, item, live, snapshot) {
8755
+ let entry = this.find(turn, item.id);
8756
+ if (entry === void 0) {
8757
+ if (turn.entries.size >= MAX_MESSAGES) return void 0;
8758
+ entry = {
8759
+ message: { id: item.id, type: "message", role: item.role, text: "" },
8760
+ aliases: /* @__PURE__ */ new Set(),
8761
+ live: false,
8762
+ snapshot: false,
8763
+ comparable: true,
8764
+ order: this.#order++
8765
+ };
8766
+ turn.entries.set(item.id, entry);
8767
+ }
8768
+ this.#textSize -= entry.message.text.length;
8769
+ entry.comparable = item.text.length <= MAX_TEXT && this.#textSize + item.text.length <= MAX_RETAINED_TEXT;
8770
+ const phase = item.phase ?? entry.message.phase;
8771
+ entry.message = {
8772
+ id: entry.message.id,
8773
+ type: "message",
8774
+ role: item.role,
8775
+ text: entry.comparable ? item.text : "",
8776
+ ...phase === void 0 ? {} : { phase },
8777
+ ...item.attachments === void 0 ? {} : { attachments: item.attachments }
8778
+ };
8779
+ this.#textSize += entry.message.text.length;
8780
+ entry.live ||= live;
8781
+ entry.snapshot ||= snapshot;
8782
+ return entry;
8783
+ }
8784
+ alias(entry, id) {
8785
+ if (entry.message.id === id || entry.aliases.has(id)) return true;
8786
+ if (entry.aliases.size >= 256) return false;
8787
+ entry.aliases.add(id);
8788
+ return true;
8789
+ }
8790
+ render(item, entry) {
8791
+ return {
8792
+ ...item,
8793
+ id: entry.message.id,
8794
+ ...entry.aliases.size === 0 ? {} : { identityAliases: [...entry.aliases] }
8795
+ };
8796
+ }
8797
+ snapshot(taskId, turns) {
8798
+ return turns.map((turn) => {
8799
+ const messages = turn.items.filter(
8800
+ (item) => item.type === "message"
8801
+ );
8802
+ if (messages.length === 0) return turn;
8803
+ const state = this.turn(taskId, turn.id);
8804
+ state.running = turn.status === "running";
8805
+ const matches = /* @__PURE__ */ new Map();
8806
+ const used = /* @__PURE__ */ new Set();
8807
+ for (const item of messages) {
8808
+ const known = this.find(state, item.id);
8809
+ if (known !== void 0) {
8810
+ matches.set(item.id, known);
8811
+ used.add(known);
8812
+ }
8813
+ }
8814
+ const candidates = /* @__PURE__ */ new Map();
8815
+ const counts = /* @__PURE__ */ new Map();
8816
+ for (const item of messages) {
8817
+ if (matches.has(item.id)) continue;
8818
+ const options = [...state.entries.values()].filter(
8819
+ (entry) => entry.live && entry.comparable && !used.has(entry) && matchesMessageIdentity(entry.message, item)
8820
+ );
8821
+ candidates.set(item.id, options);
8822
+ for (const entry of options) counts.set(entry, (counts.get(entry) ?? 0) + 1);
8823
+ }
8824
+ for (const [id, options] of candidates) {
8825
+ const entry = options.length === 1 ? options[0] : void 0;
8826
+ if (entry !== void 0 && counts.get(entry) === 1 && this.alias(entry, id))
8827
+ matches.set(id, entry);
8828
+ }
8829
+ return {
8830
+ ...turn,
8831
+ items: turn.items.map((item) => {
8832
+ if (item.type !== "message") return item;
8833
+ const entry = matches.get(item.id);
8834
+ const normalized = entry === void 0 ? item : this.render(item, entry);
8835
+ this.remember(state, normalized, false, true);
8836
+ return normalized;
8837
+ })
8838
+ };
8839
+ });
8840
+ }
8841
+ event(event) {
8842
+ if (event.type === "turn.started" || event.type === "turn.completed") {
8843
+ const items = event.payload.turn.items.map(
8844
+ (item) => item.type === "message" ? this.completed(event.taskId, event.turnId, item, event.payload.turn.items) : item
8845
+ );
8846
+ this.turn(event.taskId, event.turnId).running = event.type === "turn.started";
8847
+ return { ...event, payload: { ...event.payload, turn: { ...event.payload.turn, items } } };
8848
+ }
8849
+ if (event.type === "item.started" || event.type === "item.completed") {
8850
+ if (event.payload.item.type !== "message") return event;
8851
+ const item = this.completed(event.taskId, event.turnId, event.payload.item);
8852
+ return { ...event, itemId: item.id, payload: { item } };
8853
+ }
8854
+ if (event.type !== "message.delta") return event;
8855
+ const state = this.turn(event.taskId, event.turnId);
8856
+ state.running = true;
8857
+ const entry = this.find(state, event.itemId);
8858
+ const id = entry?.message.id ?? event.itemId;
8859
+ if (entry?.comparable !== false)
8860
+ this.remember(
8861
+ state,
8862
+ {
8863
+ id,
8864
+ type: "message",
8865
+ role: "assistant",
8866
+ text: (entry?.message.text ?? "") + event.payload.delta
8867
+ },
8868
+ true,
8869
+ false
8870
+ );
8871
+ return id === event.itemId ? event : { ...event, itemId: id };
8872
+ }
8873
+ completed(taskId, turnId, item, batch = [item]) {
8874
+ const state = this.turn(taskId, turnId);
8875
+ let entry = this.find(state, item.id);
8876
+ if (entry?.snapshot !== true) {
8877
+ const candidates = [...state.entries.values()].filter(
8878
+ (candidate2) => candidate2 !== entry && candidate2.snapshot && !candidate2.live && candidate2.comparable && matchesMessageIdentity(candidate2.message, item) && // 批量终态也要求反向唯一;其他消息已占用或同样匹配时禁止贪心归并。
8879
+ !batch.some(
8880
+ (other) => other.type === "message" && other.id !== item.id && (this.find(state, other.id) === candidate2 || matchesMessageIdentity(candidate2.message, other))
8881
+ )
8882
+ );
8883
+ const candidate = candidates.length === 1 ? candidates[0] : void 0;
8884
+ if (candidate !== void 0) {
8885
+ const keep = entry !== void 0 && entry.order < candidate.order ? entry : candidate;
8886
+ const remove = keep === entry ? candidate : entry;
8887
+ const aliases = /* @__PURE__ */ new Set([
8888
+ ...keep.aliases,
8889
+ item.id,
8890
+ ...remove === void 0 ? [] : [remove.message.id, ...remove.aliases]
8891
+ ]);
8892
+ aliases.delete(keep.message.id);
8893
+ if (aliases.size <= 256) {
8894
+ keep.aliases = aliases;
8895
+ keep.snapshot = true;
8896
+ if (remove !== void 0) {
8897
+ state.entries.delete(remove.message.id);
8898
+ this.#textSize -= remove.message.text.length;
8899
+ }
8900
+ entry = keep;
8901
+ }
8902
+ }
8903
+ }
8904
+ const normalized = entry === void 0 ? item : this.render(item, entry);
8905
+ this.remember(state, normalized, true, false);
8906
+ return normalized;
8907
+ }
8908
+ release(turn) {
8909
+ for (const entry of turn.entries.values()) this.#textSize -= entry.message.text.length;
8910
+ }
8911
+ clearTask(taskId) {
8912
+ for (const [key, turn] of this.#turns)
8913
+ if (turn.taskId === taskId) {
8914
+ this.release(turn);
8915
+ this.#turns.delete(key);
8916
+ }
8917
+ }
8918
+ clear() {
8919
+ this.#turns.clear();
8920
+ this.#textSize = 0;
8921
+ }
8922
+ };
8923
+
8924
+ // packages/provider-codex/src/realtime-skill-messages.ts
8925
+ var RealtimeSkillMessages = class {
8926
+ #tails = /* @__PURE__ */ new Map();
8927
+ #size = 0;
8928
+ key(taskId, turnId) {
8929
+ return JSON.stringify([taskId, turnId]);
8930
+ }
8931
+ remove(key) {
8932
+ this.#size -= this.#tails.get(key)?.size ?? 0;
8933
+ this.#tails.delete(key);
8934
+ }
8935
+ remember(taskId, turnId, item) {
8936
+ const key = this.key(taskId, turnId);
8937
+ this.remove(key);
8938
+ let retained = item?.type === "message" && item.role === "user" ? item : void 0;
8939
+ let size = retained === void 0 ? 0 : JSON.stringify(retained).length;
8940
+ if (size > 65536) {
8941
+ retained = void 0;
8942
+ size = 0;
8943
+ }
8944
+ this.#tails.set(key, { taskId, item: retained, size });
8945
+ this.#size += size;
8946
+ while (this.#tails.size > 128 || this.#size > 1048576) {
8947
+ const oldest = this.#tails.keys().next().value;
8948
+ if (oldest === void 0) break;
8949
+ this.remove(oldest);
8950
+ }
8951
+ }
8952
+ seed(taskId, turns) {
8953
+ for (const turn of turns) {
8954
+ if (turn.status === "running" && !this.#tails.has(this.key(taskId, turn.id)))
8955
+ this.remember(taskId, turn.id, turn.items.at(-1));
8956
+ }
8957
+ }
8958
+ event(event) {
8959
+ if (event.type === "turn.started") {
8960
+ this.remember(event.taskId, event.turnId, event.payload.turn.items.at(-1));
8961
+ return event;
8962
+ }
8963
+ if (event.type === "turn.completed") {
8964
+ this.remove(this.key(event.taskId, event.turnId));
8965
+ return event;
8966
+ }
8967
+ if (event.type === "message.delta") {
8968
+ this.remember(event.taskId, event.turnId, void 0);
8969
+ return event;
8970
+ }
8971
+ if (event.type !== "item.started" && event.type !== "item.completed") return event;
8972
+ const incoming = event.payload.item;
8973
+ const previous = this.#tails.get(this.key(event.taskId, event.turnId))?.item;
8974
+ const [first, second] = previous === void 0 ? [incoming] : mergeExpandedSkillMessages([previous, incoming]);
8975
+ let item = second ?? first ?? incoming;
8976
+ if (second !== void 0 && previous?.type === "message" && incoming.type === "message" && previous.id === incoming.id && incoming.role === "user" && previous.skills !== void 0)
8977
+ item = mergeMessageSkills(incoming, previous.skills);
8978
+ this.remember(event.taskId, event.turnId, item);
8979
+ return item === incoming ? event : { ...event, itemId: item.id, payload: { item } };
8980
+ }
8981
+ clearTask(taskId) {
8982
+ for (const [key, tail] of this.#tails) if (tail.taskId === taskId) this.remove(key);
8983
+ }
8984
+ clear() {
8985
+ this.#tails.clear();
8986
+ this.#size = 0;
8987
+ }
8988
+ };
8989
+
8709
8990
  // packages/provider-codex/src/task-runtime-state.ts
8710
8991
  var TaskRuntimeState = class {
8992
+ messageIdentities = new MessageIdentityRegistry();
8993
+ skillMessages = new RealtimeSkillMessages();
8711
8994
  activeReviewTargets = /* @__PURE__ */ new Map();
8712
8995
  activeReviewTurnIds = /* @__PURE__ */ new Map();
8713
8996
  activeReviewWorkerTaskIds = /* @__PURE__ */ new Set();
@@ -8745,6 +9028,8 @@ var TaskRuntimeState = class {
8745
9028
  return this.runningTaskIds.has(taskId) || this.pendingTaskReads.has(taskId) || this.resumePromises.has(taskId) || (this.pendingTaskServerRequests.get(taskId)?.length ?? 0) > 0 || hasPendingRequest;
8746
9029
  }
8747
9030
  clearTask(taskId) {
9031
+ this.messageIdentities.clearTask(taskId);
9032
+ this.skillMessages.clearTask(taskId);
8748
9033
  this.activeReviewTargets.delete(taskId);
8749
9034
  this.activeReviewTurnIds.delete(taskId);
8750
9035
  this.activeReviewWorkerTaskIds.delete(taskId);
@@ -8771,6 +9056,8 @@ var TaskRuntimeState = class {
8771
9056
  this.unmaterializedTasks.delete(taskId);
8772
9057
  }
8773
9058
  clear() {
9059
+ this.messageIdentities.clear();
9060
+ this.skillMessages.clear();
8774
9061
  this.activeReviewTargets.clear();
8775
9062
  this.activeReviewTurnIds.clear();
8776
9063
  this.activeReviewWorkerTaskIds.clear();
@@ -9135,6 +9422,7 @@ function createUnmaterializedTaskSnapshot(task) {
9135
9422
  }
9136
9423
  var CodexAgentProviderBase = class {
9137
9424
  client;
9425
+ taskTitles;
9138
9426
  eventListenersIncludingEphemeral = /* @__PURE__ */ new Set();
9139
9427
  eventListeners = /* @__PURE__ */ new Set();
9140
9428
  historicalAttachments = new CodexHistoricalAttachmentStore();
@@ -9175,6 +9463,7 @@ var CodexAgentProviderBase = class {
9175
9463
  }
9176
9464
  constructor(client, project, options = {}) {
9177
9465
  this.client = client;
9466
+ this.taskTitles = options.taskTitles;
9178
9467
  this.logger = options.logger ?? DEFAULT_PROVIDER_LOGGER;
9179
9468
  this.project = project;
9180
9469
  this.pendingLifecycle = new PendingRequestLifecycle({
@@ -9211,6 +9500,7 @@ var CodexAgentProviderBase = class {
9211
9500
  });
9212
9501
  }
9213
9502
  async releaseProject() {
9503
+ await this.taskTitles?.releaseProject(this.project.id);
9214
9504
  await releaseCodexProjectThreads(this.client, this.logger, this.project.id, [
9215
9505
  ...this.runtime.projectTaskIds
9216
9506
  ]);
@@ -9278,10 +9568,14 @@ var CodexAgentProviderBase = class {
9278
9568
  }
9279
9569
  async renameTask(taskId, title) {
9280
9570
  this.assertKnownProjectTask(taskId);
9281
- expectRecord(
9282
- await this.client.request("thread/name/set", { name: title, threadId: taskId }),
9283
- "thread/name/set response"
9284
- );
9571
+ const rename3 = async () => {
9572
+ expectRecord(
9573
+ await this.client.request("thread/name/set", { name: title, threadId: taskId }),
9574
+ "thread/name/set response"
9575
+ );
9576
+ };
9577
+ if (this.taskTitles === void 0) await rename3();
9578
+ else await this.taskTitles.mutate(taskId, rename3);
9285
9579
  }
9286
9580
  async pinTask(taskId, pinned) {
9287
9581
  this.assertKnownProjectTask(taskId);
@@ -9655,6 +9949,10 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9655
9949
  this.runtime.ephemeralTaskIds.add(task.id);
9656
9950
  } else {
9657
9951
  this.runtime.unmaterializedTasks.set(task.id, task);
9952
+ const thread = expectRecord(response["thread"], "thread/start thread");
9953
+ if (typeof thread["name"] !== "string" || !thread["name"].trim()) {
9954
+ this.taskTitles?.register(task.id, this.project, expectString(thread["cwd"], "thread cwd"));
9955
+ }
9658
9956
  }
9659
9957
  return task;
9660
9958
  }
@@ -9710,7 +10008,9 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9710
10008
  }, 3e4);
9711
10009
  timeout.unref();
9712
10010
  });
9713
- return await Promise.race([startedTurn, timeoutTurn]);
10011
+ const turn2 = await Promise.race([startedTurn, timeoutTurn]);
10012
+ this.taskTitles?.start(taskId, input);
10013
+ return turn2;
9714
10014
  } finally {
9715
10015
  this.eventListeners.delete(listener);
9716
10016
  if (timeout !== void 0) {
@@ -9737,7 +10037,10 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9737
10037
  if (turn.status === "running") {
9738
10038
  this.runtime.runningTaskIds.add(taskId);
9739
10039
  }
9740
- return turn;
10040
+ const normalized = this.runtime.messageIdentities.snapshot(taskId, [turn])[0] ?? turn;
10041
+ this.runtime.skillMessages.seed(taskId, [normalized]);
10042
+ this.taskTitles?.start(taskId, input);
10043
+ return normalized;
9741
10044
  }
9742
10045
  async readGoalResponse(taskId) {
9743
10046
  const response = expectRecord(
@@ -9819,7 +10122,9 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9819
10122
  this.runtime.activeReviewWorkerTaskIds.delete(taskId);
9820
10123
  this.runtime.reviewWorkerOutputTaskIds.delete(taskId);
9821
10124
  }
9822
- return turn;
10125
+ const normalized = this.runtime.messageIdentities.snapshot(taskId, [turn])[0] ?? turn;
10126
+ this.runtime.skillMessages.seed(taskId, [normalized]);
10127
+ return normalized;
9823
10128
  }
9824
10129
  async interruptTurn(taskId, turnId) {
9825
10130
  this.assertKnownProjectTask(taskId);
@@ -10215,12 +10520,16 @@ var CodexAgentProviderTasks = class extends CodexAgentProviderTurns {
10215
10520
  cursor.reviewCursor
10216
10521
  );
10217
10522
  const transcriptSkillsByTurnId = await readCodexTranscriptTurnSkills(taskId);
10218
- const turns = mapAgentTurns(
10219
- reviewPage.turns,
10220
- (part, imageIndex) => this.mapMessageImage(taskId, part, imageIndex),
10221
- (input2, textIndex) => this.mapMessageText(taskId, input2, textIndex)
10222
- ).map((turn) => attachTranscriptSkills(turn, transcriptSkillsByTurnId.get(turn.id) ?? []));
10523
+ const turns = this.runtime.messageIdentities.snapshot(
10524
+ taskId,
10525
+ mapAgentTurns(
10526
+ reviewPage.turns,
10527
+ (part, imageIndex) => this.mapMessageImage(taskId, part, imageIndex),
10528
+ (input2, textIndex) => this.mapMessageText(taskId, input2, textIndex)
10529
+ ).map((turn) => attachTranscriptSkills(turn, transcriptSkillsByTurnId.get(turn.id) ?? []))
10530
+ );
10223
10531
  const status = turns.some((turn) => turn.status === "running") ? "running" : mapThreadStatus(thread["status"]);
10532
+ this.runtime.skillMessages.seed(taskId, turns);
10224
10533
  const runningReviewTurn = turns.findLast(
10225
10534
  (turn) => turn.status === "running" && turn.items.some((item) => item.type === "review")
10226
10535
  );
@@ -10537,6 +10846,7 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10537
10846
  return this.runtime.hasLifecycleObligations(taskId, this.pendingLifecycle.hasForTask(taskId));
10538
10847
  }
10539
10848
  clearTaskRuntimeState(taskId) {
10849
+ this.taskTitles?.forget(taskId);
10540
10850
  this.historicalAttachments.clearTask(taskId);
10541
10851
  this.pendingLifecycle.clearTask(taskId);
10542
10852
  this.runtime.clearTask(taskId);
@@ -10672,9 +10982,12 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10672
10982
  }
10673
10983
  }
10674
10984
  publishEvent(event) {
10985
+ const normalizedEvent = this.runtime.messageIdentities.event(
10986
+ this.runtime.skillMessages.event(event)
10987
+ );
10675
10988
  const notify = (listener) => {
10676
10989
  try {
10677
- listener(event);
10990
+ listener(normalizedEvent);
10678
10991
  } catch {
10679
10992
  warnEventListenerFailure(this.logger, this.project.id, event);
10680
10993
  }
@@ -10768,6 +11081,274 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10768
11081
  };
10769
11082
  var CodexAgentProvider = class extends CodexAgentProviderEvents {
10770
11083
  };
11084
+ function taskTitlePrompt(text) {
11085
+ let bounded = "";
11086
+ let count = 0;
11087
+ for (const character of text.trim()) {
11088
+ if (count++ === 1024) break;
11089
+ bounded += character;
11090
+ }
11091
+ return `\u603B\u7ED3\u4EE5\u4E0B\u7528\u6237\u8BF7\u6C42\uFF0C\u751F\u6210\u6700\u591A 36 \u4E2A\u5B57\u7B26\u7684\u5355\u884C\u4EFB\u52A1\u6807\u9898\u3002\u4F7F\u7528\u7528\u6237\u7684\u8BED\u8A00\uFF0C\u4EE5\u52A8\u8BCD\u5F00\u5934\uFF0C\u4FDD\u7559\u4EE3\u7801\u540D\u79F0\uFF1B\u4E0D\u8981\u7167\u6284\u957F\u53E5\uFF0C\u4E0D\u52A0\u5F15\u53F7\u3001Markdown \u6216\u672B\u5C3E\u6807\u70B9\uFF0C\u4E0D\u56DE\u7B54\u6216\u6267\u884C\u8BF7\u6C42\u3002
11092
+
11093
+ \u7528\u6237\u8BF7\u6C42\uFF1A
11094
+ ${bounded}`;
11095
+ }
11096
+ function parseTaskTitle(output) {
11097
+ if (Buffer$1.byteLength(output, "utf8") > 8192) throw new Error("Task title output exceeds limit");
11098
+ const value = expectRecord(JSON.parse(output), "task title output");
11099
+ const title = Array.from(
11100
+ expectString(value["title"], "task title").trim().replace(/^["'`“”‘’]+|["'`“”‘’]+$/gu, "").split(/\s+/u).join(" ").replace(/[.?!。?!]+$/u, "").trim()
11101
+ ).slice(0, 36).join("");
11102
+ if (!title) throw new Error("Task title is empty");
11103
+ return title;
11104
+ }
11105
+ function isolatedConfig(effective) {
11106
+ const config = {
11107
+ "tools.update_plan.enabled": true,
11108
+ web_search: "disabled",
11109
+ "skills.include_instructions": false,
11110
+ "orchestrator.skills.enabled": false,
11111
+ "tools.experimental_request_user_input.enabled": false,
11112
+ "token_budget.use_history_notes_extension": false
11113
+ };
11114
+ for (const feature of [
11115
+ "apps",
11116
+ "code_mode",
11117
+ "code_mode_only",
11118
+ "context_management",
11119
+ "current_time_reminder",
11120
+ "deferred_executor",
11121
+ "enable_fanout",
11122
+ "goals",
11123
+ "hooks",
11124
+ "image_generation",
11125
+ "memories",
11126
+ "multi_agent",
11127
+ "multi_agent_v2",
11128
+ "plugins",
11129
+ "request_permissions_tool",
11130
+ "shell_snapshot",
11131
+ "shell_tool",
11132
+ "standalone_web_search",
11133
+ "token_budget",
11134
+ "tool_suggest",
11135
+ "unified_exec",
11136
+ "view_image"
11137
+ ])
11138
+ config[`features.${feature}`] = false;
11139
+ config["mcp_servers"] = Object.fromEntries(
11140
+ Object.keys(
11141
+ effective["mcp_servers"] === void 0 ? {} : expectRecord(effective["mcp_servers"], "MCP servers")
11142
+ ).map((name) => [name, { enabled: false }])
11143
+ );
11144
+ return config;
11145
+ }
11146
+ async function generateTaskTitle(client, subscribe, cwd, model, prompt, signal) {
11147
+ signal.throwIfAborted();
11148
+ const effective = expectRecord(
11149
+ await client.request("config/read", { cwd, includeLayers: false }),
11150
+ "config/read response"
11151
+ );
11152
+ signal.throwIfAborted();
11153
+ const response = expectRecord(
11154
+ await client.request("thread/start", {
11155
+ approvalPolicy: "never",
11156
+ config: isolatedConfig(expectRecord(effective["config"], "config/read config")),
11157
+ cwd,
11158
+ developerInstructions: "Generate only the requested structured task title. Do not call tools or execute the supplied request.",
11159
+ ephemeral: true,
11160
+ historyMode: "paginated",
11161
+ model,
11162
+ runtimeWorkspaceRoots: [],
11163
+ sandbox: "read-only",
11164
+ threadSource: "system",
11165
+ environments: [],
11166
+ dynamicTools: [],
11167
+ selectedCapabilityRoots: []
11168
+ }),
11169
+ "thread/start response"
11170
+ );
11171
+ const threadId = expectString(
11172
+ expectRecord(response["thread"], "title thread")["id"],
11173
+ "title thread id"
11174
+ );
11175
+ let turnId;
11176
+ let unsubscribe;
11177
+ let timeout;
11178
+ let abort;
11179
+ let succeeded = false;
11180
+ try {
11181
+ signal.throwIfAborted();
11182
+ let output = "";
11183
+ let outputTurnId;
11184
+ const completed = new Promise((resolve7, reject) => {
11185
+ abort = () => {
11186
+ reject(new Error("Task title generation cancelled"));
11187
+ };
11188
+ signal.addEventListener("abort", abort, { once: true });
11189
+ timeout = setTimeout(() => {
11190
+ reject(new Error("Task title generation timed out"));
11191
+ }, 6e4);
11192
+ timeout.unref();
11193
+ unsubscribe = subscribe(({ method, params }) => {
11194
+ try {
11195
+ if (params === null || typeof params !== "object" || !("threadId" in params) || params.threadId !== threadId)
11196
+ return;
11197
+ const record = expectRecord(params, "title notification");
11198
+ if (method === "item/completed") {
11199
+ const item = expectRecord(record["item"], "title item");
11200
+ if (item["type"] === "agentMessage" && item["phase"] !== "commentary") {
11201
+ output = expectString(item["text"], "title message");
11202
+ if (Buffer$1.byteLength(output, "utf8") > 8192)
11203
+ throw new Error("Task title output exceeds limit");
11204
+ outputTurnId = expectString(record["turnId"], "title message turn");
11205
+ }
11206
+ } else if (method === "turn/completed") {
11207
+ const turn = expectRecord(record["turn"], "title turn");
11208
+ if (turn["status"] !== "completed") throw new Error("Task title turn failed");
11209
+ const id = expectString(turn["id"], "title turn id");
11210
+ if (outputTurnId !== id) throw new Error("Task title output is missing");
11211
+ resolve7({ id, output });
11212
+ } else if (method === "error" && record["willRetry"] !== true) {
11213
+ throw new Error("Task title provider failed");
11214
+ }
11215
+ } catch (error) {
11216
+ reject(error instanceof Error ? error : new Error("Invalid task title notification"));
11217
+ }
11218
+ });
11219
+ });
11220
+ void completed.catch(() => void 0);
11221
+ const started = expectRecord(
11222
+ await client.request("turn/start", {
11223
+ threadId,
11224
+ input: [{ type: "text", text: prompt, text_elements: [] }],
11225
+ outputSchema: {
11226
+ type: "object",
11227
+ additionalProperties: false,
11228
+ required: ["title"],
11229
+ properties: { title: { type: "string", minLength: 1, maxLength: 36 } }
11230
+ }
11231
+ }),
11232
+ "turn/start response"
11233
+ );
11234
+ turnId = expectString(
11235
+ expectRecord(started["turn"], "started title turn")["id"],
11236
+ "started title turn id"
11237
+ );
11238
+ const result = await completed;
11239
+ signal.throwIfAborted();
11240
+ if (result.id !== turnId) throw new Error("Task title turn identity mismatch");
11241
+ const title = parseTaskTitle(result.output);
11242
+ succeeded = true;
11243
+ return title;
11244
+ } finally {
11245
+ if (timeout !== void 0) clearTimeout(timeout);
11246
+ if (abort !== void 0) signal.removeEventListener("abort", abort);
11247
+ unsubscribe?.();
11248
+ if (!succeeded && turnId !== void 0) {
11249
+ await client.request("turn/interrupt", { threadId, turnId }).catch(() => void 0);
11250
+ }
11251
+ await client.request("thread/unsubscribe", { threadId }).catch(() => void 0);
11252
+ }
11253
+ }
11254
+
11255
+ // packages/provider-codex/src/task-titles.ts
11256
+ var CodexTaskTitles = class {
11257
+ constructor(client, readModel, logger) {
11258
+ this.client = client;
11259
+ this.readModel = readModel;
11260
+ this.logger = logger;
11261
+ }
11262
+ client;
11263
+ readModel;
11264
+ logger;
11265
+ #pending = /* @__PURE__ */ new Map();
11266
+ #active = /* @__PURE__ */ new Map();
11267
+ #mutations = /* @__PURE__ */ new Map();
11268
+ #listeners = /* @__PURE__ */ new Set();
11269
+ receiveNotification(notification) {
11270
+ for (const listener of this.#listeners) listener(notification);
11271
+ }
11272
+ register(taskId, project, cwd) {
11273
+ this.#pending.set(taskId, { project, cwd });
11274
+ }
11275
+ start(taskId, input) {
11276
+ const pending = this.#pending.get(taskId);
11277
+ if (pending === void 0) return;
11278
+ this.#pending.delete(taskId);
11279
+ const fallback = [...input.skills, ...input.files, ...input.textAttachments].map((item) => item.name.trim()).find(Boolean) ?? "\u65B0\u4EFB\u52A1";
11280
+ const prompt = taskTitlePrompt(input.text.trim() || fallback);
11281
+ const controller = new AbortController();
11282
+ const active = { ...pending, controller, done: Promise.resolve() };
11283
+ this.#active.set(taskId, active);
11284
+ active.done = Promise.resolve().then(async () => {
11285
+ const model = await this.readModel();
11286
+ controller.signal.throwIfAborted();
11287
+ const title = await generateTaskTitle(
11288
+ this.client,
11289
+ (listener) => {
11290
+ this.#listeners.add(listener);
11291
+ return () => {
11292
+ this.#listeners.delete(listener);
11293
+ };
11294
+ },
11295
+ pending.cwd,
11296
+ model,
11297
+ prompt,
11298
+ controller.signal
11299
+ );
11300
+ await this.mutate(taskId, async () => {
11301
+ controller.signal.throwIfAborted();
11302
+ const response = expectRecord(
11303
+ await this.client.request("thread/read", {
11304
+ threadId: taskId,
11305
+ includeTurns: false
11306
+ }),
11307
+ "thread/read response"
11308
+ );
11309
+ const thread = expectRecord(response["thread"], "task title thread");
11310
+ const projectId = pending.project.kind === "temporary" ? null : pending.project.id;
11311
+ if (thread["id"] !== taskId || thread["projectId"] !== projectId) {
11312
+ throw new Error("Task title ownership mismatch");
11313
+ }
11314
+ if (typeof thread["name"] === "string" && thread["name"].trim()) return;
11315
+ controller.signal.throwIfAborted();
11316
+ await this.client.request("thread/name/set", { threadId: taskId, name: title });
11317
+ });
11318
+ }).catch(() => {
11319
+ if (!controller.signal.aborted) {
11320
+ this.logger.warn(
11321
+ { diagnosticCode: "task_title_generation_failed" },
11322
+ "Automatic task title unavailable"
11323
+ );
11324
+ }
11325
+ }).finally(() => {
11326
+ if (this.#active.get(taskId) === active) this.#active.delete(taskId);
11327
+ });
11328
+ }
11329
+ async mutate(taskId, action) {
11330
+ const previous = this.#mutations.get(taskId) ?? Promise.resolve();
11331
+ const current = previous.catch(() => void 0).then(action);
11332
+ this.#mutations.set(taskId, current);
11333
+ try {
11334
+ return await current;
11335
+ } finally {
11336
+ if (this.#mutations.get(taskId) === current) this.#mutations.delete(taskId);
11337
+ }
11338
+ }
11339
+ forget(taskId) {
11340
+ this.#pending.delete(taskId);
11341
+ this.#active.get(taskId)?.controller.abort();
11342
+ }
11343
+ async releaseProject(projectId) {
11344
+ for (const [taskId, pending] of this.#pending) {
11345
+ if (pending.project.id === projectId) this.#pending.delete(taskId);
11346
+ }
11347
+ const active = [...this.#active.values()].filter((entry) => entry.project.id === projectId);
11348
+ for (const entry of active) entry.controller.abort();
11349
+ await Promise.all(active.map((entry) => entry.done));
11350
+ }
11351
+ };
10771
11352
 
10772
11353
  // packages/provider-codex/src/runtime-default-settings.ts
10773
11354
  var fields = {
@@ -10788,6 +11369,48 @@ async function writeRuntimeDefaultSettings(client, settings) {
10788
11369
  if (edits.length === 0) return;
10789
11370
  await client.request("config/batchWrite", { edits, reloadUserConfig: true });
10790
11371
  }
11372
+ function optionalNonEmptyString(value) {
11373
+ return typeof value === "string" && value.length > 0 ? value : void 0;
11374
+ }
11375
+ function optionalApprovalPolicy(value) {
11376
+ if (value === "on-request" || value === "never") {
11377
+ return value;
11378
+ }
11379
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
11380
+ return void 0;
11381
+ }
11382
+ const record = value;
11383
+ if (Object.keys(record).length !== 1 || !("granular" in record)) {
11384
+ return void 0;
11385
+ }
11386
+ const granular = record["granular"];
11387
+ if (typeof granular !== "object" || granular === null || Array.isArray(granular)) {
11388
+ return void 0;
11389
+ }
11390
+ const fields2 = granular;
11391
+ const knownFields = /* @__PURE__ */ new Set([
11392
+ "mcp_elicitations",
11393
+ "request_permissions",
11394
+ "rules",
11395
+ "sandbox_approval",
11396
+ "skill_approval"
11397
+ ]);
11398
+ if (Object.keys(fields2).some((key) => !knownFields.has(key)) || typeof fields2["mcp_elicitations"] !== "boolean" || typeof fields2["rules"] !== "boolean" || typeof fields2["sandbox_approval"] !== "boolean" || fields2["request_permissions"] !== void 0 && typeof fields2["request_permissions"] !== "boolean" || fields2["skill_approval"] !== void 0 && typeof fields2["skill_approval"] !== "boolean") {
11399
+ return void 0;
11400
+ }
11401
+ return {
11402
+ granular: {
11403
+ mcp_elicitations: fields2["mcp_elicitations"],
11404
+ request_permissions: fields2["request_permissions"] ?? false,
11405
+ rules: fields2["rules"],
11406
+ sandbox_approval: fields2["sandbox_approval"],
11407
+ skill_approval: fields2["skill_approval"] ?? false
11408
+ }
11409
+ };
11410
+ }
11411
+ function optionalSandboxMode(value) {
11412
+ return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
11413
+ }
10791
11414
  async function readOptional(path) {
10792
11415
  try {
10793
11416
  return await readFile(path, "utf8");
@@ -12435,52 +13058,11 @@ async function setCodexMcpServerEnabled(client, name, enabled) {
12435
13058
  }
12436
13059
 
12437
13060
  // packages/provider-codex/src/runtime-provider.ts
12438
- function optionalNonEmptyString(value) {
12439
- return typeof value === "string" && value.length > 0 ? value : void 0;
12440
- }
12441
- function optionalApprovalPolicy(value) {
12442
- if (value === "on-request" || value === "never") {
12443
- return value;
12444
- }
12445
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
12446
- return void 0;
12447
- }
12448
- const record = value;
12449
- if (Object.keys(record).length !== 1 || !("granular" in record)) {
12450
- return void 0;
12451
- }
12452
- const granular = record["granular"];
12453
- if (typeof granular !== "object" || granular === null || Array.isArray(granular)) {
12454
- return void 0;
12455
- }
12456
- const fields2 = granular;
12457
- const knownFields = /* @__PURE__ */ new Set([
12458
- "mcp_elicitations",
12459
- "request_permissions",
12460
- "rules",
12461
- "sandbox_approval",
12462
- "skill_approval"
12463
- ]);
12464
- if (Object.keys(fields2).some((key) => !knownFields.has(key)) || typeof fields2["mcp_elicitations"] !== "boolean" || typeof fields2["rules"] !== "boolean" || typeof fields2["sandbox_approval"] !== "boolean" || fields2["request_permissions"] !== void 0 && typeof fields2["request_permissions"] !== "boolean" || fields2["skill_approval"] !== void 0 && typeof fields2["skill_approval"] !== "boolean") {
12465
- return void 0;
12466
- }
12467
- return {
12468
- granular: {
12469
- mcp_elicitations: fields2["mcp_elicitations"],
12470
- request_permissions: fields2["request_permissions"] ?? false,
12471
- rules: fields2["rules"],
12472
- sandbox_approval: fields2["sandbox_approval"],
12473
- skill_approval: fields2["skill_approval"] ?? false
12474
- }
12475
- };
12476
- }
12477
- function optionalSandboxMode(value) {
12478
- return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
12479
- }
12480
13061
  var CodexRuntimeProvider = class {
12481
13062
  personalization;
12482
13063
  fileSearch;
12483
13064
  #client;
13065
+ #taskTitles;
12484
13066
  #logger;
12485
13067
  #gitMetadataWatch;
12486
13068
  #providerConnection;
@@ -12491,6 +13073,7 @@ var CodexRuntimeProvider = class {
12491
13073
  #reviewWorkerOwners = /* @__PURE__ */ new Map();
12492
13074
  constructor(client, logger = DEFAULT_PROVIDER_LOGGER, options = {}) {
12493
13075
  this.#client = client;
13076
+ this.#taskTitles = options.readTaskTitleModel === void 0 ? void 0 : new CodexTaskTitles(client, options.readTaskTitleModel, logger);
12494
13077
  const instructions = createGlobalInstructionsStore(
12495
13078
  options.codexHome ?? process.env["CODEX_HOME"] ?? resolve(homedir(), ".codex")
12496
13079
  );
@@ -12513,6 +13096,7 @@ var CodexRuntimeProvider = class {
12513
13096
  }
12514
13097
  });
12515
13098
  client.onNotification((notification) => {
13099
+ this.#taskTitles?.receiveNotification(notification);
12516
13100
  this.#gitMetadataWatch.receiveNotification(notification.method, notification.params);
12517
13101
  if (notification.method === "fs/changed") return;
12518
13102
  this.fileSearch.receiveNotification(notification.method, notification.params);
@@ -12601,6 +13185,7 @@ var CodexRuntimeProvider = class {
12601
13185
  }
12602
13186
  const rawProvider = new CodexAgentProvider(this.#client, project, {
12603
13187
  logger: this.#logger,
13188
+ ...this.#taskTitles === void 0 ? {} : { taskTitles: this.#taskTitles },
12604
13189
  subscribeRpc: false
12605
13190
  });
12606
13191
  const provider = new CodexRuntimeProjectProvider(this, rawProvider, project);
@@ -12755,7 +13340,8 @@ var CodexRuntimeProvider = class {
12755
13340
  function createCodexRuntimeProvider(options) {
12756
13341
  return new CodexRuntimeProvider(options.client, options.logger, {
12757
13342
  ...options.codexHome === void 0 ? {} : { codexHome: options.codexHome },
12758
- ...options.fetch === void 0 ? {} : { fetch: options.fetch }
13343
+ ...options.fetch === void 0 ? {} : { fetch: options.fetch },
13344
+ ...options.readTaskTitleModel === void 0 ? {} : { readTaskTitleModel: options.readTaskTitleModel }
12759
13345
  });
12760
13346
  }
12761
13347
  var APP_SERVER_ARGUMENTS = ["app-server", "--enable", "plugins", "--listen", "stdio://"];