@bryanhu/codexly 0.18.0 → 0.20.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 +36 -0
  2. package/README.md +4 -0
  3. package/README.zh-CN.md +4 -0
  4. package/dist/{chunk-NROPHBJ7.js → chunk-2J5P2EG2.js} +2508 -4038
  5. package/dist/{chunk-3PU3WPOK.js → chunk-AIACWU7L.js} +659 -72
  6. package/dist/chunk-B2673ODM.js +260 -0
  7. package/dist/chunk-GT7XTSEG.js +56 -0
  8. package/dist/{chunk-M6GWGUSX.js → chunk-X5JZ3VOF.js} +311 -77
  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
  ]);
@@ -9274,14 +9564,19 @@ var CodexAgentProviderBase = class {
9274
9564
  );
9275
9565
  this.runtime.projectTaskIds.add(task.id);
9276
9566
  this.runtime.resumedTaskIds.add(task.id);
9567
+ this.runtime.unmaterializedTasks.set(task.id, task);
9277
9568
  return task;
9278
9569
  }
9279
9570
  async renameTask(taskId, title) {
9280
9571
  this.assertKnownProjectTask(taskId);
9281
- expectRecord(
9282
- await this.client.request("thread/name/set", { name: title, threadId: taskId }),
9283
- "thread/name/set response"
9284
- );
9572
+ const rename3 = async () => {
9573
+ expectRecord(
9574
+ await this.client.request("thread/name/set", { name: title, threadId: taskId }),
9575
+ "thread/name/set response"
9576
+ );
9577
+ };
9578
+ if (this.taskTitles === void 0) await rename3();
9579
+ else await this.taskTitles.mutate(taskId, rename3);
9285
9580
  }
9286
9581
  async pinTask(taskId, pinned) {
9287
9582
  this.assertKnownProjectTask(taskId);
@@ -9655,6 +9950,10 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9655
9950
  this.runtime.ephemeralTaskIds.add(task.id);
9656
9951
  } else {
9657
9952
  this.runtime.unmaterializedTasks.set(task.id, task);
9953
+ const thread = expectRecord(response["thread"], "thread/start thread");
9954
+ if (typeof thread["name"] !== "string" || !thread["name"].trim()) {
9955
+ this.taskTitles?.register(task.id, this.project, expectString(thread["cwd"], "thread cwd"));
9956
+ }
9658
9957
  }
9659
9958
  return task;
9660
9959
  }
@@ -9710,7 +10009,9 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9710
10009
  }, 3e4);
9711
10010
  timeout.unref();
9712
10011
  });
9713
- return await Promise.race([startedTurn, timeoutTurn]);
10012
+ const turn2 = await Promise.race([startedTurn, timeoutTurn]);
10013
+ this.taskTitles?.start(taskId, input);
10014
+ return turn2;
9714
10015
  } finally {
9715
10016
  this.eventListeners.delete(listener);
9716
10017
  if (timeout !== void 0) {
@@ -9737,7 +10038,10 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9737
10038
  if (turn.status === "running") {
9738
10039
  this.runtime.runningTaskIds.add(taskId);
9739
10040
  }
9740
- return turn;
10041
+ const normalized = this.runtime.messageIdentities.snapshot(taskId, [turn])[0] ?? turn;
10042
+ this.runtime.skillMessages.seed(taskId, [normalized]);
10043
+ this.taskTitles?.start(taskId, input);
10044
+ return normalized;
9741
10045
  }
9742
10046
  async readGoalResponse(taskId) {
9743
10047
  const response = expectRecord(
@@ -9819,7 +10123,9 @@ var CodexAgentProviderTurns = class extends CodexAgentProviderQueue {
9819
10123
  this.runtime.activeReviewWorkerTaskIds.delete(taskId);
9820
10124
  this.runtime.reviewWorkerOutputTaskIds.delete(taskId);
9821
10125
  }
9822
- return turn;
10126
+ const normalized = this.runtime.messageIdentities.snapshot(taskId, [turn])[0] ?? turn;
10127
+ this.runtime.skillMessages.seed(taskId, [normalized]);
10128
+ return normalized;
9823
10129
  }
9824
10130
  async interruptTurn(taskId, turnId) {
9825
10131
  this.assertKnownProjectTask(taskId);
@@ -10215,12 +10521,16 @@ var CodexAgentProviderTasks = class extends CodexAgentProviderTurns {
10215
10521
  cursor.reviewCursor
10216
10522
  );
10217
10523
  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) ?? []));
10524
+ const turns = this.runtime.messageIdentities.snapshot(
10525
+ taskId,
10526
+ mapAgentTurns(
10527
+ reviewPage.turns,
10528
+ (part, imageIndex) => this.mapMessageImage(taskId, part, imageIndex),
10529
+ (input2, textIndex) => this.mapMessageText(taskId, input2, textIndex)
10530
+ ).map((turn) => attachTranscriptSkills(turn, transcriptSkillsByTurnId.get(turn.id) ?? []))
10531
+ );
10223
10532
  const status = turns.some((turn) => turn.status === "running") ? "running" : mapThreadStatus(thread["status"]);
10533
+ this.runtime.skillMessages.seed(taskId, turns);
10224
10534
  const runningReviewTurn = turns.findLast(
10225
10535
  (turn) => turn.status === "running" && turn.items.some((item) => item.type === "review")
10226
10536
  );
@@ -10537,6 +10847,7 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10537
10847
  return this.runtime.hasLifecycleObligations(taskId, this.pendingLifecycle.hasForTask(taskId));
10538
10848
  }
10539
10849
  clearTaskRuntimeState(taskId) {
10850
+ this.taskTitles?.forget(taskId);
10540
10851
  this.historicalAttachments.clearTask(taskId);
10541
10852
  this.pendingLifecycle.clearTask(taskId);
10542
10853
  this.runtime.clearTask(taskId);
@@ -10672,9 +10983,12 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10672
10983
  }
10673
10984
  }
10674
10985
  publishEvent(event) {
10986
+ const normalizedEvent = this.runtime.messageIdentities.event(
10987
+ this.runtime.skillMessages.event(event)
10988
+ );
10675
10989
  const notify = (listener) => {
10676
10990
  try {
10677
- listener(event);
10991
+ listener(normalizedEvent);
10678
10992
  } catch {
10679
10993
  warnEventListenerFailure(this.logger, this.project.id, event);
10680
10994
  }
@@ -10768,6 +11082,274 @@ var CodexAgentProviderEvents = class extends CodexAgentProviderTasks {
10768
11082
  };
10769
11083
  var CodexAgentProvider = class extends CodexAgentProviderEvents {
10770
11084
  };
11085
+ function taskTitlePrompt(text) {
11086
+ let bounded = "";
11087
+ let count = 0;
11088
+ for (const character of text.trim()) {
11089
+ if (count++ === 1024) break;
11090
+ bounded += character;
11091
+ }
11092
+ 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
11093
+
11094
+ \u7528\u6237\u8BF7\u6C42\uFF1A
11095
+ ${bounded}`;
11096
+ }
11097
+ function parseTaskTitle(output) {
11098
+ if (Buffer$1.byteLength(output, "utf8") > 8192) throw new Error("Task title output exceeds limit");
11099
+ const value = expectRecord(JSON.parse(output), "task title output");
11100
+ const title = Array.from(
11101
+ expectString(value["title"], "task title").trim().replace(/^["'`“”‘’]+|["'`“”‘’]+$/gu, "").split(/\s+/u).join(" ").replace(/[.?!。?!]+$/u, "").trim()
11102
+ ).slice(0, 36).join("");
11103
+ if (!title) throw new Error("Task title is empty");
11104
+ return title;
11105
+ }
11106
+ function isolatedConfig(effective) {
11107
+ const config = {
11108
+ "tools.update_plan.enabled": true,
11109
+ web_search: "disabled",
11110
+ "skills.include_instructions": false,
11111
+ "orchestrator.skills.enabled": false,
11112
+ "tools.experimental_request_user_input.enabled": false,
11113
+ "token_budget.use_history_notes_extension": false
11114
+ };
11115
+ for (const feature of [
11116
+ "apps",
11117
+ "code_mode",
11118
+ "code_mode_only",
11119
+ "context_management",
11120
+ "current_time_reminder",
11121
+ "deferred_executor",
11122
+ "enable_fanout",
11123
+ "goals",
11124
+ "hooks",
11125
+ "image_generation",
11126
+ "memories",
11127
+ "multi_agent",
11128
+ "multi_agent_v2",
11129
+ "plugins",
11130
+ "request_permissions_tool",
11131
+ "shell_snapshot",
11132
+ "shell_tool",
11133
+ "standalone_web_search",
11134
+ "token_budget",
11135
+ "tool_suggest",
11136
+ "unified_exec",
11137
+ "view_image"
11138
+ ])
11139
+ config[`features.${feature}`] = false;
11140
+ config["mcp_servers"] = Object.fromEntries(
11141
+ Object.keys(
11142
+ effective["mcp_servers"] === void 0 ? {} : expectRecord(effective["mcp_servers"], "MCP servers")
11143
+ ).map((name) => [name, { enabled: false }])
11144
+ );
11145
+ return config;
11146
+ }
11147
+ async function generateTaskTitle(client, subscribe, cwd, model, prompt, signal) {
11148
+ signal.throwIfAborted();
11149
+ const effective = expectRecord(
11150
+ await client.request("config/read", { cwd, includeLayers: false }),
11151
+ "config/read response"
11152
+ );
11153
+ signal.throwIfAborted();
11154
+ const response = expectRecord(
11155
+ await client.request("thread/start", {
11156
+ approvalPolicy: "never",
11157
+ config: isolatedConfig(expectRecord(effective["config"], "config/read config")),
11158
+ cwd,
11159
+ developerInstructions: "Generate only the requested structured task title. Do not call tools or execute the supplied request.",
11160
+ ephemeral: true,
11161
+ historyMode: "paginated",
11162
+ model,
11163
+ runtimeWorkspaceRoots: [],
11164
+ sandbox: "read-only",
11165
+ threadSource: "system",
11166
+ environments: [],
11167
+ dynamicTools: [],
11168
+ selectedCapabilityRoots: []
11169
+ }),
11170
+ "thread/start response"
11171
+ );
11172
+ const threadId = expectString(
11173
+ expectRecord(response["thread"], "title thread")["id"],
11174
+ "title thread id"
11175
+ );
11176
+ let turnId;
11177
+ let unsubscribe;
11178
+ let timeout;
11179
+ let abort;
11180
+ let succeeded = false;
11181
+ try {
11182
+ signal.throwIfAborted();
11183
+ let output = "";
11184
+ let outputTurnId;
11185
+ const completed = new Promise((resolve7, reject) => {
11186
+ abort = () => {
11187
+ reject(new Error("Task title generation cancelled"));
11188
+ };
11189
+ signal.addEventListener("abort", abort, { once: true });
11190
+ timeout = setTimeout(() => {
11191
+ reject(new Error("Task title generation timed out"));
11192
+ }, 6e4);
11193
+ timeout.unref();
11194
+ unsubscribe = subscribe(({ method, params }) => {
11195
+ try {
11196
+ if (params === null || typeof params !== "object" || !("threadId" in params) || params.threadId !== threadId)
11197
+ return;
11198
+ const record = expectRecord(params, "title notification");
11199
+ if (method === "item/completed") {
11200
+ const item = expectRecord(record["item"], "title item");
11201
+ if (item["type"] === "agentMessage" && item["phase"] !== "commentary") {
11202
+ output = expectString(item["text"], "title message");
11203
+ if (Buffer$1.byteLength(output, "utf8") > 8192)
11204
+ throw new Error("Task title output exceeds limit");
11205
+ outputTurnId = expectString(record["turnId"], "title message turn");
11206
+ }
11207
+ } else if (method === "turn/completed") {
11208
+ const turn = expectRecord(record["turn"], "title turn");
11209
+ if (turn["status"] !== "completed") throw new Error("Task title turn failed");
11210
+ const id = expectString(turn["id"], "title turn id");
11211
+ if (outputTurnId !== id) throw new Error("Task title output is missing");
11212
+ resolve7({ id, output });
11213
+ } else if (method === "error" && record["willRetry"] !== true) {
11214
+ throw new Error("Task title provider failed");
11215
+ }
11216
+ } catch (error) {
11217
+ reject(error instanceof Error ? error : new Error("Invalid task title notification"));
11218
+ }
11219
+ });
11220
+ });
11221
+ void completed.catch(() => void 0);
11222
+ const started = expectRecord(
11223
+ await client.request("turn/start", {
11224
+ threadId,
11225
+ input: [{ type: "text", text: prompt, text_elements: [] }],
11226
+ outputSchema: {
11227
+ type: "object",
11228
+ additionalProperties: false,
11229
+ required: ["title"],
11230
+ properties: { title: { type: "string", minLength: 1, maxLength: 36 } }
11231
+ }
11232
+ }),
11233
+ "turn/start response"
11234
+ );
11235
+ turnId = expectString(
11236
+ expectRecord(started["turn"], "started title turn")["id"],
11237
+ "started title turn id"
11238
+ );
11239
+ const result = await completed;
11240
+ signal.throwIfAborted();
11241
+ if (result.id !== turnId) throw new Error("Task title turn identity mismatch");
11242
+ const title = parseTaskTitle(result.output);
11243
+ succeeded = true;
11244
+ return title;
11245
+ } finally {
11246
+ if (timeout !== void 0) clearTimeout(timeout);
11247
+ if (abort !== void 0) signal.removeEventListener("abort", abort);
11248
+ unsubscribe?.();
11249
+ if (!succeeded && turnId !== void 0) {
11250
+ await client.request("turn/interrupt", { threadId, turnId }).catch(() => void 0);
11251
+ }
11252
+ await client.request("thread/unsubscribe", { threadId }).catch(() => void 0);
11253
+ }
11254
+ }
11255
+
11256
+ // packages/provider-codex/src/task-titles.ts
11257
+ var CodexTaskTitles = class {
11258
+ constructor(client, readModel, logger) {
11259
+ this.client = client;
11260
+ this.readModel = readModel;
11261
+ this.logger = logger;
11262
+ }
11263
+ client;
11264
+ readModel;
11265
+ logger;
11266
+ #pending = /* @__PURE__ */ new Map();
11267
+ #active = /* @__PURE__ */ new Map();
11268
+ #mutations = /* @__PURE__ */ new Map();
11269
+ #listeners = /* @__PURE__ */ new Set();
11270
+ receiveNotification(notification) {
11271
+ for (const listener of this.#listeners) listener(notification);
11272
+ }
11273
+ register(taskId, project, cwd) {
11274
+ this.#pending.set(taskId, { project, cwd });
11275
+ }
11276
+ start(taskId, input) {
11277
+ const pending = this.#pending.get(taskId);
11278
+ if (pending === void 0) return;
11279
+ this.#pending.delete(taskId);
11280
+ const fallback = [...input.skills, ...input.files, ...input.textAttachments].map((item) => item.name.trim()).find(Boolean) ?? "\u65B0\u4EFB\u52A1";
11281
+ const prompt = taskTitlePrompt(input.text.trim() || fallback);
11282
+ const controller = new AbortController();
11283
+ const active = { ...pending, controller, done: Promise.resolve() };
11284
+ this.#active.set(taskId, active);
11285
+ active.done = Promise.resolve().then(async () => {
11286
+ const model = await this.readModel();
11287
+ controller.signal.throwIfAborted();
11288
+ const title = await generateTaskTitle(
11289
+ this.client,
11290
+ (listener) => {
11291
+ this.#listeners.add(listener);
11292
+ return () => {
11293
+ this.#listeners.delete(listener);
11294
+ };
11295
+ },
11296
+ pending.cwd,
11297
+ model,
11298
+ prompt,
11299
+ controller.signal
11300
+ );
11301
+ await this.mutate(taskId, async () => {
11302
+ controller.signal.throwIfAborted();
11303
+ const response = expectRecord(
11304
+ await this.client.request("thread/read", {
11305
+ threadId: taskId,
11306
+ includeTurns: false
11307
+ }),
11308
+ "thread/read response"
11309
+ );
11310
+ const thread = expectRecord(response["thread"], "task title thread");
11311
+ const projectId = pending.project.kind === "temporary" ? null : pending.project.id;
11312
+ if (thread["id"] !== taskId || thread["projectId"] !== projectId) {
11313
+ throw new Error("Task title ownership mismatch");
11314
+ }
11315
+ if (typeof thread["name"] === "string" && thread["name"].trim()) return;
11316
+ controller.signal.throwIfAborted();
11317
+ await this.client.request("thread/name/set", { threadId: taskId, name: title });
11318
+ });
11319
+ }).catch(() => {
11320
+ if (!controller.signal.aborted) {
11321
+ this.logger.warn(
11322
+ { diagnosticCode: "task_title_generation_failed" },
11323
+ "Automatic task title unavailable"
11324
+ );
11325
+ }
11326
+ }).finally(() => {
11327
+ if (this.#active.get(taskId) === active) this.#active.delete(taskId);
11328
+ });
11329
+ }
11330
+ async mutate(taskId, action) {
11331
+ const previous = this.#mutations.get(taskId) ?? Promise.resolve();
11332
+ const current = previous.catch(() => void 0).then(action);
11333
+ this.#mutations.set(taskId, current);
11334
+ try {
11335
+ return await current;
11336
+ } finally {
11337
+ if (this.#mutations.get(taskId) === current) this.#mutations.delete(taskId);
11338
+ }
11339
+ }
11340
+ forget(taskId) {
11341
+ this.#pending.delete(taskId);
11342
+ this.#active.get(taskId)?.controller.abort();
11343
+ }
11344
+ async releaseProject(projectId) {
11345
+ for (const [taskId, pending] of this.#pending) {
11346
+ if (pending.project.id === projectId) this.#pending.delete(taskId);
11347
+ }
11348
+ const active = [...this.#active.values()].filter((entry) => entry.project.id === projectId);
11349
+ for (const entry of active) entry.controller.abort();
11350
+ await Promise.all(active.map((entry) => entry.done));
11351
+ }
11352
+ };
10771
11353
 
10772
11354
  // packages/provider-codex/src/runtime-default-settings.ts
10773
11355
  var fields = {
@@ -10788,6 +11370,48 @@ async function writeRuntimeDefaultSettings(client, settings) {
10788
11370
  if (edits.length === 0) return;
10789
11371
  await client.request("config/batchWrite", { edits, reloadUserConfig: true });
10790
11372
  }
11373
+ function optionalNonEmptyString(value) {
11374
+ return typeof value === "string" && value.length > 0 ? value : void 0;
11375
+ }
11376
+ function optionalApprovalPolicy(value) {
11377
+ if (value === "on-request" || value === "never") {
11378
+ return value;
11379
+ }
11380
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
11381
+ return void 0;
11382
+ }
11383
+ const record = value;
11384
+ if (Object.keys(record).length !== 1 || !("granular" in record)) {
11385
+ return void 0;
11386
+ }
11387
+ const granular = record["granular"];
11388
+ if (typeof granular !== "object" || granular === null || Array.isArray(granular)) {
11389
+ return void 0;
11390
+ }
11391
+ const fields2 = granular;
11392
+ const knownFields = /* @__PURE__ */ new Set([
11393
+ "mcp_elicitations",
11394
+ "request_permissions",
11395
+ "rules",
11396
+ "sandbox_approval",
11397
+ "skill_approval"
11398
+ ]);
11399
+ 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") {
11400
+ return void 0;
11401
+ }
11402
+ return {
11403
+ granular: {
11404
+ mcp_elicitations: fields2["mcp_elicitations"],
11405
+ request_permissions: fields2["request_permissions"] ?? false,
11406
+ rules: fields2["rules"],
11407
+ sandbox_approval: fields2["sandbox_approval"],
11408
+ skill_approval: fields2["skill_approval"] ?? false
11409
+ }
11410
+ };
11411
+ }
11412
+ function optionalSandboxMode(value) {
11413
+ return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : void 0;
11414
+ }
10791
11415
  async function readOptional(path) {
10792
11416
  try {
10793
11417
  return await readFile(path, "utf8");
@@ -12435,52 +13059,11 @@ async function setCodexMcpServerEnabled(client, name, enabled) {
12435
13059
  }
12436
13060
 
12437
13061
  // 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
13062
  var CodexRuntimeProvider = class {
12481
13063
  personalization;
12482
13064
  fileSearch;
12483
13065
  #client;
13066
+ #taskTitles;
12484
13067
  #logger;
12485
13068
  #gitMetadataWatch;
12486
13069
  #providerConnection;
@@ -12491,6 +13074,7 @@ var CodexRuntimeProvider = class {
12491
13074
  #reviewWorkerOwners = /* @__PURE__ */ new Map();
12492
13075
  constructor(client, logger = DEFAULT_PROVIDER_LOGGER, options = {}) {
12493
13076
  this.#client = client;
13077
+ this.#taskTitles = options.readTaskTitleModel === void 0 ? void 0 : new CodexTaskTitles(client, options.readTaskTitleModel, logger);
12494
13078
  const instructions = createGlobalInstructionsStore(
12495
13079
  options.codexHome ?? process.env["CODEX_HOME"] ?? resolve(homedir(), ".codex")
12496
13080
  );
@@ -12513,6 +13097,7 @@ var CodexRuntimeProvider = class {
12513
13097
  }
12514
13098
  });
12515
13099
  client.onNotification((notification) => {
13100
+ this.#taskTitles?.receiveNotification(notification);
12516
13101
  this.#gitMetadataWatch.receiveNotification(notification.method, notification.params);
12517
13102
  if (notification.method === "fs/changed") return;
12518
13103
  this.fileSearch.receiveNotification(notification.method, notification.params);
@@ -12601,6 +13186,7 @@ var CodexRuntimeProvider = class {
12601
13186
  }
12602
13187
  const rawProvider = new CodexAgentProvider(this.#client, project, {
12603
13188
  logger: this.#logger,
13189
+ ...this.#taskTitles === void 0 ? {} : { taskTitles: this.#taskTitles },
12604
13190
  subscribeRpc: false
12605
13191
  });
12606
13192
  const provider = new CodexRuntimeProjectProvider(this, rawProvider, project);
@@ -12755,7 +13341,8 @@ var CodexRuntimeProvider = class {
12755
13341
  function createCodexRuntimeProvider(options) {
12756
13342
  return new CodexRuntimeProvider(options.client, options.logger, {
12757
13343
  ...options.codexHome === void 0 ? {} : { codexHome: options.codexHome },
12758
- ...options.fetch === void 0 ? {} : { fetch: options.fetch }
13344
+ ...options.fetch === void 0 ? {} : { fetch: options.fetch },
13345
+ ...options.readTaskTitleModel === void 0 ? {} : { readTaskTitleModel: options.readTaskTitleModel }
12759
13346
  });
12760
13347
  }
12761
13348
  var APP_SERVER_ARGUMENTS = ["app-server", "--enable", "plugins", "--listen", "stdio://"];