@p4code/cli 0.1.22 → 0.1.24

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 (220) hide show
  1. package/dist/bin.mjs +665 -47
  2. package/dist/client/assets/Diagram-CP713Hf0.js +3 -0
  3. package/dist/client/assets/DiffPanel-DeU85qmp.js +98 -0
  4. package/dist/client/assets/FilePreviewPanel-Ck-1V54G.js +1778 -0
  5. package/dist/client/assets/PreviewPanel-C9f2_i6J.js +2 -0
  6. package/dist/client/assets/abnfDiagram-N423BO3Z-BYQKJNsP.js +2 -0
  7. package/dist/client/assets/angular-html-BVBpGdXr.js +2 -0
  8. package/dist/client/assets/{angular-ts-CXoIeuGh.js → angular-ts-BfdufMKP.js} +2 -2
  9. package/dist/client/assets/{apl-C6oPUNZZ.js → apl-DWBSSoBH.js} +2 -2
  10. package/dist/client/assets/arc-BjSQqbzd.js +2 -0
  11. package/dist/client/assets/architecture-TIHT7OUA-DOwndo9a.js +1 -0
  12. package/dist/client/assets/architectureDiagram-T3A2C74G-Dkoxezw8.js +37 -0
  13. package/dist/client/assets/array-BifhSqXX.js +2 -0
  14. package/dist/client/assets/arrow-right-DdiaD_l3.js +2 -0
  15. package/dist/client/assets/{astro-Bq_n5uKv.js → astro-3LtMP0Sq.js} +2 -2
  16. package/dist/client/assets/{blade-DYe65h_C.js → blade-llJRbbtR.js} +2 -2
  17. package/dist/client/assets/blockDiagram-VBNYF7ZC-sVeCAPAa.js +133 -0
  18. package/dist/client/assets/c-Wt1voDr2.js +2 -0
  19. package/dist/client/assets/c4Diagram-5PPSVZJV-CW_Wfxep.js +11 -0
  20. package/dist/client/assets/channel-Cc8SQh1U.js +2 -0
  21. package/dist/client/assets/chunk-2GRJ4B5K-ChihPphX.js +2 -0
  22. package/dist/client/assets/chunk-2Q5K7J3B-C1jixKkw.js +2 -0
  23. package/dist/client/assets/chunk-3NCLNEKW-lgePDcrq.js +2 -0
  24. package/dist/client/assets/chunk-4I5QYGJK-CYvb6li-.js +2 -0
  25. package/dist/client/assets/chunk-5RXB4S5H-BzE89W2t.js +232 -0
  26. package/dist/client/assets/chunk-5VM5RSS4-ZNzvKenW.js +16 -0
  27. package/dist/client/assets/chunk-6Q2QTUOP-CyDe-FPc.js +89 -0
  28. package/dist/client/assets/chunk-7BUUIJ7U-Bb538aSH.js +2 -0
  29. package/dist/client/assets/chunk-7Z6QIM7H-kaZRbPTV.js +11 -0
  30. package/dist/client/assets/chunk-GF5L2VYU-CHJWyX-t.js +207 -0
  31. package/dist/client/assets/chunk-I66GZJ75-CJWXi3bs.js +128 -0
  32. package/dist/client/assets/chunk-J7OUQ5F2-D19QWtqC.js +3 -0
  33. package/dist/client/assets/chunk-JQJVKLGR-oHxUxbQ4.js +157 -0
  34. package/dist/client/assets/chunk-JWPE2WC7-DVXcaiue.js +2 -0
  35. package/dist/client/assets/chunk-KBJHAD2P-D81b6htr.js +2 -0
  36. package/dist/client/assets/chunk-KEIR6QF5-BfrZ3jm6.js +162 -0
  37. package/dist/client/assets/chunk-NSK5VX7P-CoeZ_Lgi.js +3 -0
  38. package/dist/client/assets/chunk-QR6OTTB3-D0IyLhez.js +63 -0
  39. package/dist/client/assets/chunk-RYQCIY6F-CZ4ia6G4.js +2 -0
  40. package/dist/client/assets/chunk-UBXNYLIW-F4hmeeiG.js +2 -0
  41. package/dist/client/assets/chunk-W5SLKNZC-Bwmo9x3j.js +2 -0
  42. package/dist/client/assets/chunk-WRU74C26-C2Rb3ATV.js +71 -0
  43. package/dist/client/assets/chunk-XXDRQBXY-BuE3VzE_.js +2 -0
  44. package/dist/client/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +2 -0
  45. package/dist/client/assets/chunk-ZIRB5QZD-C6fEPe3t.js +33 -0
  46. package/dist/client/assets/classDiagram-JCYQIIEL-oYJOinll.js +2 -0
  47. package/dist/client/assets/classDiagram-v2-OCEON4UE-oYJOinll.js +2 -0
  48. package/dist/client/assets/{cobol-CoC31Rpg.js → cobol-x_HIyl2P.js} +2 -2
  49. package/dist/client/assets/{coffee-DU1_O9cH.js → coffee-CThvmt4R.js} +2 -2
  50. package/dist/client/assets/compiler-runtime-CLAvuQ-D.js +2 -0
  51. package/dist/client/assets/cose-bilkent-JH36ORCC-CU59zlcZ.js +2 -0
  52. package/dist/client/assets/cpp-NtAeskI3.js +2 -0
  53. package/dist/client/assets/{crystal-3iIyvfhL.js → crystal-DNu_sX0G.js} +2 -2
  54. package/dist/client/assets/css-DJp_X0uY.js +2 -0
  55. package/dist/client/assets/cynefin-VYW2F7L2-CjLioxN7.js +1 -0
  56. package/dist/client/assets/cynefinDiagram-MW4NZA55-DvNvdTNB.js +63 -0
  57. package/dist/client/assets/cytoscape.esm-B3I8pqwA.js +322 -0
  58. package/dist/client/assets/dagre-CXRCoUWR.js +2 -0
  59. package/dist/client/assets/dagre-VZM6K2ZE-bNpBL3bS.js +5 -0
  60. package/dist/client/assets/defaultLocale-C8Fc0cco.js +2 -0
  61. package/dist/client/assets/diagram-7IWD3JNH-DJveh2nY.js +31 -0
  62. package/dist/client/assets/diagram-B4RE2ZJO-CslhjucF.js +4 -0
  63. package/dist/client/assets/diagram-LBJQPF4R-DrVsyR2w.js +25 -0
  64. package/dist/client/assets/diagram-Q27KOJAE-Dp_H6G_V.js +25 -0
  65. package/dist/client/assets/diagram-UB23O5K3-ttWj4O6A.js +42 -0
  66. package/dist/client/assets/dist-D9sYb5Oa.js +2 -0
  67. package/dist/client/assets/ebnfDiagram-BXEA7PRR-DU7xTW-M.js +2 -0
  68. package/dist/client/assets/{edge--YoYp8s_.js → edge-ozw5tpLl.js} +2 -2
  69. package/dist/client/assets/{elixir-CZ1wqlQn.js → elixir-VhA6FeZt.js} +2 -2
  70. package/dist/client/assets/{elm-DKdyYY92.js → elm-dREJmIFz.js} +2 -2
  71. package/dist/client/assets/erDiagram-JOGREHBK-J8OGMeJ9.js +86 -0
  72. package/dist/client/assets/{erb-PeUqy_9N.js → erb-CIg6G69l.js} +2 -2
  73. package/dist/client/assets/eventmodeling-45OFAUF4-bPdt--LC.js +1 -0
  74. package/dist/client/assets/fileCommentAnnotations-BZURe-eK.js +2 -0
  75. package/dist/client/assets/flowDiagram-UKHOOZJN-Xh4ZxM-b.js +1 -0
  76. package/dist/client/assets/ganttDiagram-PKOTCBZU-CTzbq3xg.js +293 -0
  77. package/dist/client/assets/{git-rebase-1Z5OxWid.js → git-rebase-B44mJPta.js} +2 -2
  78. package/dist/client/assets/gitGraph-TEB2WS4Q-D4WztIzM.js +1 -0
  79. package/dist/client/assets/gitGraphDiagram-DS77QQ5N-BYWChpgP.js +107 -0
  80. package/dist/client/assets/{glimmer-js-Br0y4u5b.js → glimmer-js-vH_gHG0-.js} +2 -2
  81. package/dist/client/assets/{glimmer-ts-Oh0AMNJv.js → glimmer-ts--abOzSAQ.js} +2 -2
  82. package/dist/client/assets/glsl-Dv5r7kPw.js +2 -0
  83. package/dist/client/assets/graphlib-B8gBHxth.js +2 -0
  84. package/dist/client/assets/graphql-CB4jsw2E.js +2 -0
  85. package/dist/client/assets/{hack-4xJQMtbZ.js → hack-DvEYX148.js} +2 -2
  86. package/dist/client/assets/haml-zE6W3STP.js +2 -0
  87. package/dist/client/assets/{handlebars-Znb8TzWA.js → handlebars-CzBR2SDs.js} +2 -2
  88. package/dist/client/assets/html-C8UlPnhE.js +2 -0
  89. package/dist/client/assets/{html-derivative-D6Fn1mLE.js → html-derivative-CY6NRz-J.js} +2 -2
  90. package/dist/client/assets/{http-CSdnm1Wh.js → http-Cyd7bS_S.js} +2 -2
  91. package/dist/client/assets/{hurl-DKOuNoWT.js → hurl-CWPsiEpf.js} +2 -2
  92. package/dist/client/assets/index-2NU5L8X3.css +1 -0
  93. package/dist/client/assets/index-coKrfdge.js +859 -0
  94. package/dist/client/assets/info-DKCQHKI2-a_IxCZlD.js +1 -0
  95. package/dist/client/assets/infoDiagram-6WML65LV-CNHt7MRQ.js +3 -0
  96. package/dist/client/assets/init-D6jRqBbL.js +2 -0
  97. package/dist/client/assets/ishikawaDiagram-WSZJBQD7-GfzwW5bv.js +71 -0
  98. package/dist/client/assets/java-CGc3VwQr.js +2 -0
  99. package/dist/client/assets/javascript-CUt1pgmJ.js +2 -0
  100. package/dist/client/assets/{jinja-CvJhR5Z5.js → jinja-CD-Z-FLd.js} +2 -2
  101. package/dist/client/assets/{jison-DSlj1sEU.js → jison-imPNup1l.js} +2 -2
  102. package/dist/client/assets/journeyDiagram-NVQOT4AX-BSwGpG7U.js +140 -0
  103. package/dist/client/assets/json-Bg9ijW3F.js +2 -0
  104. package/dist/client/assets/jsx-CY6oMTks.js +2 -0
  105. package/dist/client/assets/{julia-CmLSMgqX.js → julia-Dc3O-irA.js} +2 -2
  106. package/dist/client/assets/{just-D9KdTXpD.js → just-BhOq_Kbv.js} +2 -2
  107. package/dist/client/assets/kanban-definition-27J2QSJJ-D_T9V6VW.js +90 -0
  108. package/dist/client/assets/katex-CddkPoXu.js +258 -0
  109. package/dist/client/assets/{latex-BZoE-Z3X.js → latex-Cu4Y1d5w.js} +2 -2
  110. package/dist/client/assets/line-DSV8zekT.js +2 -0
  111. package/dist/client/assets/linear-B7l8qgEw.js +2 -0
  112. package/dist/client/assets/{liquid-DW5UrT3Q.js → liquid-CvXMrjlQ.js} +2 -2
  113. package/dist/client/assets/lua-BjLEUjKY.js +2 -0
  114. package/dist/client/assets/map-DsCK-0Cs.js +2 -0
  115. package/dist/client/assets/{marko-EN2dMS-t.js → marko-DvhNOisQ.js} +2 -2
  116. package/dist/client/assets/{mdc-DV5R0Zdp.js → mdc-Bm9TpL1X.js} +2 -2
  117. package/dist/client/assets/mdx-host-BSmJn2Ra.css +1 -0
  118. package/dist/client/assets/mdx-host-ykYobBl4.js +4 -0
  119. package/dist/client/assets/mermaid-parser.core-B5tsyPlM.js +8 -0
  120. package/dist/client/assets/mermaid.core-0eNWrEyK.js +12 -0
  121. package/dist/client/assets/mindmap-definition-FAOFIHXS-CCatf1G5.js +97 -0
  122. package/dist/client/assets/{nginx-BhF2pPjp.js → nginx-Bhc82uuv.js} +2 -2
  123. package/dist/client/assets/{nim-Ck0oR8VY.js → nim-DXTVBFnF.js} +2 -2
  124. package/dist/client/assets/ordinal-hYBb2elL.js +2 -0
  125. package/dist/client/assets/packet-7NZHBO7P-TVG5WLAg.js +1 -0
  126. package/dist/client/assets/path-BWPyau1x.js +2 -0
  127. package/dist/client/assets/pegDiagram-VL7TDLO6-cVET6VY2.js +2 -0
  128. package/dist/client/assets/{perl-B4V1RSOt.js → perl-C7veXV9z.js} +2 -2
  129. package/dist/client/assets/{php-BvwSzqRH.js → php-BRiuMnnr.js} +2 -2
  130. package/dist/client/assets/pie-RZYD4A2V-_HnCx0-n.js +1 -0
  131. package/dist/client/assets/pieDiagram-7S7Q4E2Y-my4weM7I.js +40 -0
  132. package/dist/client/assets/preload-helper-CEhsl8MR.js +10 -0
  133. package/dist/client/assets/{pug-DB3guzOM.js → pug-C5hz5LQ7.js} +2 -2
  134. package/dist/client/assets/{qml-CohVRZGq.js → qml-BdUV3aTS.js} +2 -2
  135. package/dist/client/assets/quadrantDiagram-CIZ2JOQS-DbbX4CCn.js +8 -0
  136. package/dist/client/assets/r-8R7vtdQc.js +2 -0
  137. package/dist/client/assets/radar-I7S5WNFK-CxNqBWNL.js +1 -0
  138. package/dist/client/assets/railroad-3IZDKUUU-x01a2S92.js +1 -0
  139. package/dist/client/assets/railroad-abnf-AHOZXSZD-CMSmMh88.js +1 -0
  140. package/dist/client/assets/railroad-ebnf-EBAXGLYW-BtYYxacN.js +1 -0
  141. package/dist/client/assets/railroad-peg-LSFZ7HO6-BlXAsNZI.js +1 -0
  142. package/dist/client/assets/railroadDiagram-AXF67PYL-CA2XP-eT.js +2 -0
  143. package/dist/client/assets/{razor-CtBV-RZa.js → razor-DRL52XO2.js} +2 -2
  144. package/dist/client/assets/regexp-Omp9DhTb.js +2 -0
  145. package/dist/client/assets/requirementDiagram-LRYGKXZP-DPky6FEM.js +85 -0
  146. package/dist/client/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  147. package/dist/client/assets/rough.esm-CSKSodPl.js +2 -0
  148. package/dist/client/assets/{rst-1GlNPFb8.js → rst-BHX71KW9.js} +2 -2
  149. package/dist/client/assets/{ruby-C_Jg-W0j.js → ruby-B--HzjGU.js} +2 -2
  150. package/dist/client/assets/sankeyDiagram-W5VNT64P-Im_lfZl5.js +41 -0
  151. package/dist/client/assets/{sas-IRPqQRQC.js → sas-DrLaYOK_.js} +2 -2
  152. package/dist/client/assets/scss-DdSxiZKl.js +2 -0
  153. package/dist/client/assets/sequenceDiagram-SI44F4Z6-DaepaQXs.js +163 -0
  154. package/dist/client/assets/shellscript-DwcUjJBL.js +2 -0
  155. package/dist/client/assets/{shellsession-bEniUyPe.js → shellsession-CPZkydE6.js} +2 -2
  156. package/dist/client/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +2 -0
  157. package/dist/client/assets/{soy-D0Pcy9LW.js → soy-Br5FhD7c.js} +2 -2
  158. package/dist/client/assets/sql-DNssxck8.js +2 -0
  159. package/dist/client/assets/src-_wZywoZs.js +2 -0
  160. package/dist/client/assets/{stata-BLI2BTCU.js → stata-DXn1tqOr.js} +2 -2
  161. package/dist/client/assets/stateDiagram-OKZ733FA-CfYrJbpr.js +2 -0
  162. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-Dj9TN_Qe.js +2 -0
  163. package/dist/client/assets/{surrealql-BjtO5tmi.js → surrealql-IeLNQw0f.js} +2 -2
  164. package/dist/client/assets/{svelte-IyvKNOcX.js → svelte-DOdLCIlh.js} +2 -2
  165. package/dist/client/assets/swimlanes-SLNWSIFB-DaoN2lsp.js +3 -0
  166. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-BKWIjosV.js +9 -0
  167. package/dist/client/assets/{templ-qRJlnfHP.js → templ-CIwIngms.js} +2 -2
  168. package/dist/client/assets/terminal-links-McQ4PMJM.js +46 -0
  169. package/dist/client/assets/{tex-CgYv5ALc.js → tex-D8QMumu5.js} +2 -2
  170. package/dist/client/assets/timeline-definition-Z64GVDOM-I6R4kaBM.js +121 -0
  171. package/dist/client/assets/treeView-QDETBFTQ-FHUGB9GE.js +1 -0
  172. package/dist/client/assets/treemap-6X3UGDF4-C2oSUZ4V.js +1 -0
  173. package/dist/client/assets/{ts-tags-YasuuPCT.js → ts-tags-BMVY4q-l.js} +2 -2
  174. package/dist/client/assets/tsx-5Eka4NBX.js +2 -0
  175. package/dist/client/assets/{twig-BF-FIMTp.js → twig-C8o_5mgw.js} +2 -2
  176. package/dist/client/assets/typescript-DOu2WMV5.js +2 -0
  177. package/dist/client/assets/vennDiagram-T6HMQDX7-uVbqilLL.js +35 -0
  178. package/dist/client/assets/{vue-BTbCYZab.js → vue-BU18DNDL.js} +2 -2
  179. package/dist/client/assets/{vue-html-1KQNz6IV.js → vue-html-BeluIYX0.js} +2 -2
  180. package/dist/client/assets/{vue-vine-BVHOJ5oI.js → vue-vine-DGUAbOCX.js} +2 -2
  181. package/dist/client/assets/wardley-OPB4EBWU-C8z79vwT.js +1 -0
  182. package/dist/client/assets/wardleyDiagram-T6FBY63Y-Bh4kXS4j.js +79 -0
  183. package/dist/client/assets/xml-DIqSwXR3.js +2 -0
  184. package/dist/client/assets/{xsl-DoQ9dHRM.js → xsl-Ct_-YIAy.js} +2 -2
  185. package/dist/client/assets/xychartDiagram-ELKLHX3M-aKLyYtge.js +8 -0
  186. package/dist/client/assets/yaml-DTtCYNlS.js +2 -0
  187. package/dist/client/index.html +6 -3
  188. package/dist/client/mdx-host.html +25 -0
  189. package/dist/client/mdx-jsx-runtime.js +23 -0
  190. package/package.json +4 -1
  191. package/dist/client/assets/DiffPanel-Cdf69_RS.js +0 -98
  192. package/dist/client/assets/FilePreviewPanel-CkKXCbcG.js +0 -1778
  193. package/dist/client/assets/PreviewPanel-BtqdQqtN.js +0 -2
  194. package/dist/client/assets/angular-html-BPHFZwgm.js +0 -2
  195. package/dist/client/assets/arrow-right-7YX6fLbL.js +0 -2
  196. package/dist/client/assets/c-BsDji_bt.js +0 -2
  197. package/dist/client/assets/cpp-D5_eYHZr.js +0 -2
  198. package/dist/client/assets/css-B4bpFXEv.js +0 -2
  199. package/dist/client/assets/fileCommentAnnotations-BTb-0nj3.js +0 -2
  200. package/dist/client/assets/glsl-DI6kM2gF.js +0 -2
  201. package/dist/client/assets/graphql-VCSJCQkl.js +0 -2
  202. package/dist/client/assets/haml-Bc0kPVkr.js +0 -2
  203. package/dist/client/assets/html-_Zw71zQT.js +0 -2
  204. package/dist/client/assets/index-CeztlSXj.js +0 -853
  205. package/dist/client/assets/index-eSuLivhH.css +0 -1
  206. package/dist/client/assets/java-Czo4Dn1f.js +0 -2
  207. package/dist/client/assets/javascript-fyReKHSS.js +0 -2
  208. package/dist/client/assets/json-fCB7n2pX.js +0 -2
  209. package/dist/client/assets/jsx-C1OJlXdb.js +0 -2
  210. package/dist/client/assets/lua-DMAjig-8.js +0 -2
  211. package/dist/client/assets/r-Doi-hRR2.js +0 -2
  212. package/dist/client/assets/regexp-DgF6jh6T.js +0 -2
  213. package/dist/client/assets/scss-BPKDbfld.js +0 -2
  214. package/dist/client/assets/shellscript-D5KbVhsx.js +0 -2
  215. package/dist/client/assets/sql-DF2TL966.js +0 -2
  216. package/dist/client/assets/textarea-B03Qe3NX.js +0 -46
  217. package/dist/client/assets/tsx-BF7eypTR.js +0 -2
  218. package/dist/client/assets/typescript-CtOBCMI7.js +0 -2
  219. package/dist/client/assets/xml-CftlzqvG.js +0 -2
  220. package/dist/client/assets/yaml-DMUX1MAF.js +0 -2
package/dist/bin.mjs CHANGED
@@ -77,6 +77,10 @@ import * as HttpClientResponse$1 from "effect/unstable/http/HttpClientResponse";
77
77
  import * as HttpApiBuilder from "effect/unstable/httpapi/HttpApiBuilder";
78
78
  import * as Tracer from "effect/Tracer";
79
79
  import "effect/unstable/observability";
80
+ import * as NodeFSP from "node:fs/promises";
81
+ import { compile } from "@mdx-js/mdx";
82
+ import remarkFrontmatter from "remark-frontmatter";
83
+ import remarkGfm from "remark-gfm";
80
84
  import * as Cookies from "effect/unstable/http/Cookies";
81
85
  import * as HttpEffect from "effect/unstable/http/HttpEffect";
82
86
  import { RpcSerialization, RpcServer } from "effect/unstable/rpc";
@@ -86,7 +90,6 @@ import * as TxQueue from "effect/TxQueue";
86
90
  import * as TxRef from "effect/TxRef";
87
91
  import * as Fiber from "effect/Fiber";
88
92
  import * as SynchronizedRef from "effect/SynchronizedRef";
89
- import * as NodeFSP from "node:fs/promises";
90
93
  import * as RcMap from "effect/RcMap";
91
94
  import { FileFinder } from "@ff-labs/fff-node";
92
95
  import * as LayerMap from "effect/LayerMap";
@@ -233,7 +236,7 @@ const make$76 = () => {
233
236
  const layer$72 = Layer.sync(NetService, make$76);
234
237
  //#endregion
235
238
  //#region package.json
236
- var version = "0.1.22";
239
+ var version = "0.1.24";
237
240
  //#endregion
238
241
  //#region src/config.ts
239
242
  /**
@@ -261,6 +264,7 @@ const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
261
264
  const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
262
265
  const dbPath = join(stateDir, "state.sqlite");
263
266
  const attachmentsDir = join(stateDir, "attachments");
267
+ const mdxBuildsDir = join(stateDir, "mdx-builds");
264
268
  const logsDir = join(stateDir, "logs");
265
269
  const providerLogsDir = join(logsDir, "provider");
266
270
  const providerStatusCacheDir = join(baseDir, "caches");
@@ -272,6 +276,7 @@ const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
272
276
  providerStatusCacheDir,
273
277
  worktreesDir: join(baseDir, "worktrees"),
274
278
  attachmentsDir,
279
+ mdxBuildsDir,
275
280
  logsDir,
276
281
  serverLogPath: join(logsDir, "server.log"),
277
282
  serverTracePath: join(logsDir, "server.trace.ndjson"),
@@ -293,6 +298,7 @@ const ensureServerDirectories = Effect.fn(function* (derivedPaths) {
293
298
  fs.makeDirectory(derivedPaths.providerLogsDir, { recursive: true }),
294
299
  fs.makeDirectory(derivedPaths.terminalLogsDir, { recursive: true }),
295
300
  fs.makeDirectory(derivedPaths.attachmentsDir, { recursive: true }),
301
+ fs.makeDirectory(derivedPaths.mdxBuildsDir, { recursive: true }),
296
302
  fs.makeDirectory(derivedPaths.worktreesDir, { recursive: true }),
297
303
  fs.makeDirectory(path.dirname(derivedPaths.keybindingsConfigPath), { recursive: true }),
298
304
  fs.makeDirectory(path.dirname(derivedPaths.settingsPath), { recursive: true }),
@@ -5029,6 +5035,13 @@ const ThreadTokenUsageSnapshot = Schema$1.Struct({
5029
5035
  toolUses: Schema$1.optional(NonNegativeInt),
5030
5036
  durationMs: Schema$1.optional(NonNegativeInt),
5031
5037
  compactsAutomatically: Schema$1.optional(Schema$1.Boolean),
5038
+ /**
5039
+ * The compress mode the turn these deltas belong to actually ran under, not
5040
+ * the thread's mode now. Without it the per-turn output figures cannot be
5041
+ * attributed, and the whole question of what compression costs stays a guess.
5042
+ * Optional because snapshots recorded before it existed have no answer.
5043
+ */
5044
+ compressMode: Schema$1.optional(CompressMode),
5032
5045
  breakdown: Schema$1.optional(ContextWindowBreakdown)
5033
5046
  });
5034
5047
  const ThreadTokenUsageUpdatedPayload = Schema$1.Struct({ usage: ThreadTokenUsageSnapshot });
@@ -7773,13 +7786,18 @@ const ProjectReadFileResult = Schema$1.Struct({
7773
7786
  relativePath: TrimmedNonEmptyString,
7774
7787
  contents: Schema$1.String,
7775
7788
  byteLength: NonNegativeInt,
7776
- truncated: Schema$1.Boolean
7789
+ truncated: Schema$1.Boolean,
7790
+ /**
7791
+ * The file is not UTF-8 text, so `contents` is empty and only the metadata
7792
+ * is meaningful. Reported rather than raised because a `.docx` in a preview
7793
+ * panel is an ordinary file to describe, not a failed read to apologise for.
7794
+ */
7795
+ binary: Schema$1.Boolean
7777
7796
  });
7778
7797
  const ProjectFileFailure = Schema$1.Literals([
7779
7798
  "workspace_path_outside_root",
7780
7799
  "resolved_path_outside_root",
7781
7800
  "path_not_file",
7782
- "binary_file",
7783
7801
  "operation_failed"
7784
7802
  ]);
7785
7803
  const ProjectFileOperation = Schema$1.Literals([
@@ -8913,6 +8931,8 @@ const AssetResource = Schema$1.Union([
8913
8931
  threadId: ThreadId,
8914
8932
  path: TrimmedNonEmptyString.check(Schema$1.isMaxLength(ASSET_PATH_MAX_LENGTH))
8915
8933
  }),
8934
+ Schema$1.TaggedStruct("local-file", { path: TrimmedNonEmptyString.check(Schema$1.isMaxLength(ASSET_PATH_MAX_LENGTH)) }),
8935
+ Schema$1.TaggedStruct("mdx-preview", { path: TrimmedNonEmptyString.check(Schema$1.isMaxLength(ASSET_PATH_MAX_LENGTH)) }),
8916
8936
  Schema$1.TaggedStruct("attachment", { attachmentId: TrimmedNonEmptyString.check(Schema$1.isMaxLength(256)) }),
8917
8937
  Schema$1.TaggedStruct("project-favicon", { cwd: TrimmedNonEmptyString.check(Schema$1.isMaxLength(ASSET_PATH_MAX_LENGTH)) })
8918
8938
  ]);
@@ -9002,6 +9022,32 @@ var AssetProjectFaviconNotFoundError = class extends Schema$1.TaggedErrorClass()
9002
9022
  return "Project favicon was not found.";
9003
9023
  }
9004
9024
  };
9025
+ var AssetLocalFileNotFoundError = class extends Schema$1.TaggedErrorClass()("AssetLocalFileNotFoundError", { resource: AssetResource }) {
9026
+ get message() {
9027
+ return "Local file was not found.";
9028
+ }
9029
+ };
9030
+ var AssetLocalFileInspectionError = class extends Schema$1.TaggedErrorClass()("AssetLocalFileInspectionError", {
9031
+ resource: AssetResource,
9032
+ cause: Schema$1.Defect()
9033
+ }) {
9034
+ get message() {
9035
+ return "Failed to inspect the local file.";
9036
+ }
9037
+ };
9038
+ var AssetLocalPathValidationError = class extends Schema$1.TaggedErrorClass()("AssetLocalPathValidationError", { resource: AssetResource }) {
9039
+ get message() {
9040
+ return "Local file path must be absolute.";
9041
+ }
9042
+ };
9043
+ var AssetMdxBuildError = class extends Schema$1.TaggedErrorClass()("AssetMdxBuildError", {
9044
+ resource: AssetResource,
9045
+ cause: Schema$1.Defect()
9046
+ }) {
9047
+ get message() {
9048
+ return "Failed to prepare the MDX preview build.";
9049
+ }
9050
+ };
9005
9051
  var AssetSigningKeyLoadError = class extends Schema$1.TaggedErrorClass()("AssetSigningKeyLoadError", {
9006
9052
  resource: AssetResource,
9007
9053
  cause: Schema$1.Defect()
@@ -9023,6 +9069,10 @@ const AssetAccessError = Schema$1.Union([
9023
9069
  AssetProjectFaviconResolutionError,
9024
9070
  AssetProjectFaviconInspectionError,
9025
9071
  AssetProjectFaviconNotFoundError,
9072
+ AssetLocalFileNotFoundError,
9073
+ AssetLocalFileInspectionError,
9074
+ AssetLocalPathValidationError,
9075
+ AssetMdxBuildError,
9026
9076
  AssetSigningKeyLoadError
9027
9077
  ]);
9028
9078
  //#endregion
@@ -16107,7 +16157,7 @@ function buildSkillOverrides(disabled, discovered) {
16107
16157
  *
16108
16158
  * @module provider/Drivers/ClaudeSkills
16109
16159
  */
16110
- const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
16160
+ const FRONTMATTER_PATTERN$1 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
16111
16161
  /**
16112
16162
  * The `name`/`description` header a skill and a subagent definition both carry.
16113
16163
  *
@@ -16117,7 +16167,7 @@ const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
16117
16167
  * one question both callers are asking.
16118
16168
  */
16119
16169
  function parseMarkdownFrontmatter(contents) {
16120
- const match = FRONTMATTER_PATTERN.exec(contents);
16170
+ const match = FRONTMATTER_PATTERN$1.exec(contents);
16121
16171
  if (!match) return { kind: "missing" };
16122
16172
  let parsed;
16123
16173
  try {
@@ -18885,7 +18935,7 @@ const COMPRESS_SHARED_RULES = `Respond terse. All technical substance stays. Onl
18885
18935
 
18886
18936
  ## Persistence
18887
18937
 
18888
- Active every response. No revert after many turns. No filler drift. Still active if unsure.
18938
+ Active every response. No filler drift, no drifting back to verbose prose on your own. A later instruction that switches the response style off or changes its intensity replaces this block: obey the most recent one, not this one.
18889
18939
 
18890
18940
  ## Rules
18891
18941
 
@@ -18973,12 +19023,35 @@ const COMPRESS_TURN_REMINDERS = {
18973
19023
  full: "[response style: compressed full - terse fragments, drop articles/filler; keep negations and numbers exact; code/commits/security text normal]",
18974
19024
  ultra: "[response style: compressed ultra - maximum terseness, one word when enough; keep negations and numbers exact; code/commits/security text normal]"
18975
19025
  };
19026
+ /**
19027
+ * Sent when compression is switched off on a session that is still carrying a
19028
+ * ruleset it cannot un-send. Silence is not enough: the ruleset states its own
19029
+ * persistence, so the absence of a reminder reads to the model as "nothing
19030
+ * changed" rather than "stop".
19031
+ */
19032
+ const COMPRESS_REVERT_REMINDER = "[response style: compression off - any earlier response-compression instruction in this session no longer applies; write normal, complete prose from here on]";
18976
19033
  function compressRulesetFor(mode) {
18977
19034
  return mode === "off" ? void 0 : COMPRESS_RULESETS[mode];
18978
19035
  }
18979
19036
  function compressTurnReminderFor(mode) {
18980
19037
  return mode === "off" ? void 0 : COMPRESS_TURN_REMINDERS[mode];
18981
19038
  }
19039
+ /**
19040
+ * What to prepend to a turn's message so the running session ends up in the
19041
+ * requested compress mode.
19042
+ *
19043
+ * `staleRulesetMode` is the mode whose ruleset the session is still carrying in
19044
+ * a channel that cannot be rebuilt for this turn - Claude's system prompt is
19045
+ * frozen at session start, and a first-turn message prefix lives in the
19046
+ * conversation history forever. Codex rebuilds its developer instructions every
19047
+ * turn, so callers pass `undefined` for it and no revert line is spent.
19048
+ */
19049
+ function compressTurnPrefixFor(input) {
19050
+ if (input.injectRuleset) return compressRulesetFor(input.mode);
19051
+ const reminder = compressTurnReminderFor(input.mode);
19052
+ if (reminder !== void 0) return reminder;
19053
+ return input.staleRulesetMode !== void 0 && input.staleRulesetMode !== "off" ? COMPRESS_REVERT_REMINDER : void 0;
19054
+ }
18982
19055
  //#endregion
18983
19056
  //#region src/sync/agentPresets.ts
18984
19057
  /**
@@ -30504,6 +30577,374 @@ function isWorkspacePreviewEntryPath(path) {
30504
30577
  return isWorkspaceBrowserPreviewPath(path) || isWorkspaceImagePreviewPath(path);
30505
30578
  }
30506
30579
  //#endregion
30580
+ //#region src/assets/mdxCompile.ts
30581
+ /**
30582
+ * Pure MDX compilation for the preview renderer.
30583
+ *
30584
+ * Compilation only: nothing here touches the filesystem, resolves a module, or
30585
+ * runs a bundler. The output is a single ES module that imports only the host
30586
+ * page's runtime shim, so the build directory it lands in never needs a
30587
+ * `node_modules` beside it.
30588
+ *
30589
+ * @module mdxCompile
30590
+ */
30591
+ /**
30592
+ * Stable, unhashed module the host page publishes its React JSX runtime and
30593
+ * component provider on. Compiled documents are cached across app versions, so
30594
+ * this specifier must not carry a build hash.
30595
+ */
30596
+ const MDX_RUNTIME_SPECIFIER = "/mdx-jsx-runtime.js";
30597
+ /**
30598
+ * Scheme the compiler rewrites relative asset references to.
30599
+ *
30600
+ * The compiled module is served from the build directory, so `./diagram.png`
30601
+ * would resolve against the wrong origin path. Rather than copying referenced
30602
+ * files into the build directory, the reference is rewritten to a marker the
30603
+ * host page resolves against the source-directory grant carried by the same
30604
+ * asset token. Cached builds therefore stay valid when the token rotates.
30605
+ */
30606
+ const MDX_ASSET_SCHEME = "p4-asset:";
30607
+ const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
30608
+ const EMPTY_FRONTMATTER = {
30609
+ title: null,
30610
+ created: null,
30611
+ status: null,
30612
+ rest: {}
30613
+ };
30614
+ function scalarToString(value) {
30615
+ if (typeof value === "string") return value;
30616
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
30617
+ if (value instanceof Date) return value.toISOString().slice(0, 10);
30618
+ return null;
30619
+ }
30620
+ /**
30621
+ * Read the leading YAML block.
30622
+ *
30623
+ * Parsed here rather than through a remark plugin because the renderer needs
30624
+ * the values as data for the document header, while remark-frontmatter's job
30625
+ * is only to keep the block from reaching the body as literal text.
30626
+ */
30627
+ function parseMdxFrontmatter(source) {
30628
+ const match = FRONTMATTER_PATTERN.exec(source);
30629
+ if (!match?.[1]) return EMPTY_FRONTMATTER;
30630
+ let parsed;
30631
+ try {
30632
+ parsed = parse(match[1]);
30633
+ } catch {
30634
+ return EMPTY_FRONTMATTER;
30635
+ }
30636
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return EMPTY_FRONTMATTER;
30637
+ const entries = Object.entries(parsed);
30638
+ const rest = {};
30639
+ for (const [key, value] of entries) {
30640
+ if (key === "title" || key === "created" || key === "status") continue;
30641
+ const scalar = scalarToString(value);
30642
+ if (scalar !== null) rest[key] = scalar;
30643
+ }
30644
+ return {
30645
+ title: scalarToString(parsed.title),
30646
+ created: scalarToString(parsed.created),
30647
+ status: scalarToString(parsed.status),
30648
+ rest
30649
+ };
30650
+ }
30651
+ function isRewritableAssetUrl(url) {
30652
+ if (url.length === 0) return false;
30653
+ if (url.startsWith("#") || url.startsWith("/")) return false;
30654
+ if (url.startsWith("data:") || url.startsWith("p4-asset:")) return false;
30655
+ return !/^[A-Za-z][A-Za-z\d+.-]*:/.test(url);
30656
+ }
30657
+ function walk(node, visit) {
30658
+ const stack = [{
30659
+ node,
30660
+ parent: null
30661
+ }];
30662
+ while (stack.length > 0) {
30663
+ const current = stack.pop();
30664
+ if (!current) break;
30665
+ if (!visit(current.node, current.parent)) continue;
30666
+ for (const child of current.node.children ?? []) stack.push({
30667
+ node: child,
30668
+ parent: current.node
30669
+ });
30670
+ }
30671
+ }
30672
+ /**
30673
+ * Drop `import`/`export` statements before compilation.
30674
+ *
30675
+ * Dropping rather than rejecting is deliberate: authored plans never contain
30676
+ * imports, third-party `.mdx` found on disk usually does, and a dropped import
30677
+ * is never resolved or executed either way. The component that would have come
30678
+ * from the import is then undefined, which the host page's fallback renders as
30679
+ * a labeled placeholder instead of blanking the document.
30680
+ */
30681
+ function remarkDropEsm(state) {
30682
+ return (tree) => {
30683
+ walk(tree, (node) => {
30684
+ if (!node.children) return true;
30685
+ const kept = node.children.filter((child) => child.type !== "mdxjsEsm");
30686
+ if (kept.length !== node.children.length) {
30687
+ state.droppedImports = true;
30688
+ node.children = kept;
30689
+ }
30690
+ return true;
30691
+ });
30692
+ };
30693
+ }
30694
+ /**
30695
+ * Collect every capitalised element the document renders.
30696
+ *
30697
+ * MDX resolves components through `{...provideComponents(), ...props.components}`,
30698
+ * a plain object, and throws `Expected component X to be defined` for a name
30699
+ * neither supplies — which would blank the whole document over one unresolved
30700
+ * tag. A proxy cannot help, because the spread copies own keys only. Naming
30701
+ * the components at compile time lets the host page put a real placeholder in
30702
+ * the map for each one it does not provide.
30703
+ */
30704
+ function remarkCollectComponentNames(state) {
30705
+ return (tree) => {
30706
+ walk(tree, (node) => {
30707
+ if (node.type !== "mdxJsxFlowElement" && node.type !== "mdxJsxTextElement") return true;
30708
+ const name = node.name;
30709
+ if (typeof name !== "string" || name.length === 0) return true;
30710
+ const base = name.split(".")[0] ?? name;
30711
+ if (base[0] === base[0]?.toUpperCase()) state.names.add(base);
30712
+ return true;
30713
+ });
30714
+ };
30715
+ }
30716
+ /** Rewrite relative image references to the host page's asset marker. */
30717
+ function remarkRewriteRelativeAssets() {
30718
+ return (tree) => {
30719
+ walk(tree, (node) => {
30720
+ if (node.type === "image" && typeof node.url === "string" && isRewritableAssetUrl(node.url)) {
30721
+ node.url = `${MDX_ASSET_SCHEME}${node.url}`;
30722
+ return true;
30723
+ }
30724
+ if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") for (const attribute of node.attributes ?? []) {
30725
+ if (attribute.type !== "mdxJsxAttribute") continue;
30726
+ if (attribute.name !== "src" && attribute.name !== "poster") continue;
30727
+ if (typeof attribute.value !== "string" || !isRewritableAssetUrl(attribute.value)) continue;
30728
+ attribute.value = `${MDX_ASSET_SCHEME}${attribute.value}`;
30729
+ }
30730
+ return true;
30731
+ });
30732
+ };
30733
+ }
30734
+ /**
30735
+ * Point every surviving import at the host page's runtime shim.
30736
+ *
30737
+ * After the author's statements are dropped, the only imports left are the
30738
+ * ones MDX itself emits (the JSX runtime and the component provider). Both are
30739
+ * satisfied by one unhashed module, which is what lets the compiled output be
30740
+ * cached independently of the app build.
30741
+ */
30742
+ function recmaPinRuntimeImports() {
30743
+ return (tree) => {
30744
+ for (const statement of tree.body) {
30745
+ if (statement.type !== "ImportDeclaration" || !statement.source) continue;
30746
+ statement.source.value = MDX_RUNTIME_SPECIFIER;
30747
+ statement.source.raw = JSON.stringify(MDX_RUNTIME_SPECIFIER);
30748
+ }
30749
+ };
30750
+ }
30751
+ function errorPosition(error) {
30752
+ const place = error?.place;
30753
+ const point = place?.start ?? place;
30754
+ const line = point?.line ?? error.line;
30755
+ const column = point?.column ?? error.column;
30756
+ return {
30757
+ line: typeof line === "number" ? line : null,
30758
+ column: typeof column === "number" ? column : null
30759
+ };
30760
+ }
30761
+ /** Compile MDX source into a single self-contained ES module. */
30762
+ async function compileMdxDocument(source) {
30763
+ const frontmatter = parseMdxFrontmatter(source);
30764
+ const state = { droppedImports: false };
30765
+ const collected = { names: /* @__PURE__ */ new Set() };
30766
+ try {
30767
+ const compiled = await compile(source, {
30768
+ development: false,
30769
+ jsx: false,
30770
+ outputFormat: "program",
30771
+ providerImportSource: MDX_RUNTIME_SPECIFIER,
30772
+ remarkPlugins: [
30773
+ remarkFrontmatter,
30774
+ remarkGfm,
30775
+ () => remarkDropEsm(state),
30776
+ () => remarkCollectComponentNames(collected),
30777
+ remarkRewriteRelativeAssets
30778
+ ],
30779
+ recmaPlugins: [recmaPinRuntimeImports]
30780
+ });
30781
+ return {
30782
+ ok: true,
30783
+ code: String(compiled),
30784
+ droppedImports: state.droppedImports,
30785
+ componentNames: [...collected.names],
30786
+ frontmatter
30787
+ };
30788
+ } catch (cause) {
30789
+ const { line, column } = errorPosition(cause);
30790
+ return {
30791
+ ok: false,
30792
+ message: cause instanceof Error ? cause.message : "Failed to compile MDX.",
30793
+ line,
30794
+ column,
30795
+ frontmatter
30796
+ };
30797
+ }
30798
+ }
30799
+ //#endregion
30800
+ //#region src/assets/mdxPreviewStore.ts
30801
+ /**
30802
+ * On-disk cache of compiled MDX previews.
30803
+ *
30804
+ * A build is keyed by the source file's real path, mtime and size, so opening
30805
+ * the same unchanged document twice reuses the cached output and touching the
30806
+ * file invalidates it. Output lives under the server state directory, next to
30807
+ * `attachments`, because it is generated data that must never be written back
30808
+ * into the user's workspace.
30809
+ *
30810
+ * @module mdxPreviewStore
30811
+ */
30812
+ /** Bumping this invalidates every cached build after a renderer change. */
30813
+ const BUILD_FORMAT_VERSION = 1;
30814
+ const MDX_BUILD_DOCUMENT_FILE = "document.js";
30815
+ const MDX_BUILD_META_FILE = "meta.json";
30816
+ /** Only these two names resolve inside a build directory. */
30817
+ const MDX_BUILD_FILES = /* @__PURE__ */ new Set([MDX_BUILD_DOCUMENT_FILE, MDX_BUILD_META_FILE]);
30818
+ const BUILD_ID_PATTERN = /^[0-9a-f]{32}$/;
30819
+ const CACHE_MAX_AGE_MS = 10080 * 60 * 1e3;
30820
+ const CACHE_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
30821
+ function isMdxBuildId(value) {
30822
+ return BUILD_ID_PATTERN.test(value);
30823
+ }
30824
+ function buildIdFor(input) {
30825
+ return NodeCrypto.createHash("sha256").update(`${BUILD_FORMAT_VERSION}\0${input.realPath}\0${input.mtimeMs}\0${input.size}`).digest("hex").slice(0, 32);
30826
+ }
30827
+ function metaFor(input) {
30828
+ return {
30829
+ title: input.frontmatter.title,
30830
+ created: input.frontmatter.created,
30831
+ status: input.frontmatter.status,
30832
+ rest: input.frontmatter.rest,
30833
+ sourceName: input.sourceName,
30834
+ droppedImports: input.droppedImports,
30835
+ componentNames: input.componentNames,
30836
+ error: input.error,
30837
+ source: input.source
30838
+ };
30839
+ }
30840
+ async function directorySize(path) {
30841
+ const entries = await NodeFSP.readdir(path, { withFileTypes: true }).catch(() => []);
30842
+ let total = 0;
30843
+ for (const entry of entries) {
30844
+ if (!entry.isFile()) continue;
30845
+ const info = await NodeFSP.stat(NodePath.join(path, entry.name)).catch(() => null);
30846
+ total += info?.size ?? 0;
30847
+ }
30848
+ return total;
30849
+ }
30850
+ /**
30851
+ * Drop builds that aged out, then oldest-first until the directory fits.
30852
+ *
30853
+ * Both bounds exist because either alone leaks: a TTL lets a burst of large
30854
+ * documents blow past any disk budget within the window, and a size cap alone
30855
+ * keeps stale builds alive indefinitely on a quiet machine.
30856
+ */
30857
+ async function evictStaleBuilds(buildsDir, keepBuildId, now) {
30858
+ const entries = await NodeFSP.readdir(buildsDir, { withFileTypes: true }).catch(() => []);
30859
+ const surviving = [];
30860
+ for (const entry of entries) {
30861
+ if (!entry.isDirectory() || entry.name === keepBuildId) continue;
30862
+ const path = NodePath.join(buildsDir, entry.name);
30863
+ if (!isMdxBuildId(entry.name)) {
30864
+ await NodeFSP.rm(path, {
30865
+ recursive: true,
30866
+ force: true
30867
+ }).catch(() => void 0);
30868
+ continue;
30869
+ }
30870
+ const info = await NodeFSP.stat(path).catch(() => null);
30871
+ if (!info) continue;
30872
+ if (now - info.mtimeMs > CACHE_MAX_AGE_MS) {
30873
+ await NodeFSP.rm(path, {
30874
+ recursive: true,
30875
+ force: true
30876
+ }).catch(() => void 0);
30877
+ continue;
30878
+ }
30879
+ surviving.push({
30880
+ path,
30881
+ mtimeMs: info.mtimeMs,
30882
+ size: await directorySize(path)
30883
+ });
30884
+ }
30885
+ let total = surviving.reduce((sum, entry) => sum + entry.size, 0);
30886
+ if (total <= CACHE_MAX_TOTAL_BYTES) return;
30887
+ for (const entry of surviving.toSorted((a, b) => a.mtimeMs - b.mtimeMs)) {
30888
+ if (total <= CACHE_MAX_TOTAL_BYTES) break;
30889
+ await NodeFSP.rm(entry.path, {
30890
+ recursive: true,
30891
+ force: true
30892
+ }).catch(() => void 0);
30893
+ total -= entry.size;
30894
+ }
30895
+ }
30896
+ /**
30897
+ * Compile `sourcePath` if needed and return the build that serves it.
30898
+ *
30899
+ * A compile failure is not an error here: it produces a build whose `meta.json`
30900
+ * carries the diagnostic, so the renderer can show an error card with the
30901
+ * source rather than a blank page.
30902
+ */
30903
+ async function prepareMdxBuild(input) {
30904
+ const realPath = await NodeFSP.realpath(input.sourcePath);
30905
+ const stat = await NodeFSP.stat(realPath);
30906
+ if (!stat.isFile()) throw new Error(`MDX preview source is not a file: ${realPath}`);
30907
+ const buildId = buildIdFor({
30908
+ realPath,
30909
+ mtimeMs: stat.mtimeMs,
30910
+ size: stat.size
30911
+ });
30912
+ const buildDir = NodePath.join(input.buildsDir, buildId);
30913
+ const sourceDir = NodePath.dirname(realPath);
30914
+ const metaPath = NodePath.join(buildDir, MDX_BUILD_META_FILE);
30915
+ if ((await NodeFSP.stat(metaPath).catch(() => null))?.isFile()) {
30916
+ const touchedAtSeconds = input.now / 1e3;
30917
+ await NodeFSP.utimes(buildDir, touchedAtSeconds, touchedAtSeconds).catch(() => void 0);
30918
+ await evictStaleBuilds(input.buildsDir, buildId, input.now);
30919
+ return {
30920
+ buildId,
30921
+ sourceDir
30922
+ };
30923
+ }
30924
+ const source = await NodeFSP.readFile(realPath, "utf8");
30925
+ const outcome = await compileMdxDocument(source);
30926
+ const sourceName = NodePath.basename(realPath);
30927
+ await NodeFSP.mkdir(buildDir, { recursive: true });
30928
+ if (outcome.ok) await NodeFSP.writeFile(NodePath.join(buildDir, MDX_BUILD_DOCUMENT_FILE), outcome.code, "utf8");
30929
+ const meta = metaFor({
30930
+ frontmatter: outcome.frontmatter,
30931
+ sourceName,
30932
+ droppedImports: outcome.ok ? outcome.droppedImports : false,
30933
+ componentNames: outcome.ok ? outcome.componentNames : [],
30934
+ error: outcome.ok ? null : {
30935
+ message: outcome.message,
30936
+ line: outcome.line
30937
+ },
30938
+ source: outcome.ok ? null : source
30939
+ });
30940
+ await NodeFSP.writeFile(metaPath, JSON.stringify(meta), "utf8");
30941
+ await evictStaleBuilds(input.buildsDir, buildId, input.now);
30942
+ return {
30943
+ buildId,
30944
+ sourceDir
30945
+ };
30946
+ }
30947
+ //#endregion
30507
30948
  //#region ../../packages/shared/src/projectFavicon.ts
30508
30949
  const PROJECT_FAVICON_FALLBACK_MARKER = "project-favicon-missing";
30509
30950
  //#endregion
@@ -30722,6 +31163,10 @@ const PREVIEW_ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
30722
31163
  ".woff",
30723
31164
  ".woff2"
30724
31165
  ]);
31166
+ /** Relative references inside a compiled MDX document resolve to images only. */
31167
+ const MDX_SOURCE_ASSET_EXTENSIONS = new Set(WORKSPACE_IMAGE_PREVIEW_EXTENSIONS);
31168
+ /** Path prefix under an MDX build token that maps to the source directory. */
31169
+ const MDX_SOURCE_ASSET_PREFIX = "assets/";
30725
31170
  const AssetClaimsSchema = Schema$1.Union([
30726
31171
  Schema$1.Struct({
30727
31172
  version: Schema$1.Literal(1),
@@ -30737,6 +31182,25 @@ const AssetClaimsSchema = Schema$1.Union([
30737
31182
  relativePath: Schema$1.String,
30738
31183
  expiresAt: Schema$1.Number
30739
31184
  }),
31185
+ Schema$1.Struct({
31186
+ version: Schema$1.Literal(1),
31187
+ kind: Schema$1.Literal("local-file"),
31188
+ baseDirectory: Schema$1.String,
31189
+ expiresAt: Schema$1.Number
31190
+ }),
31191
+ Schema$1.Struct({
31192
+ version: Schema$1.Literal(1),
31193
+ kind: Schema$1.Literal("local-file-exact"),
31194
+ filePath: Schema$1.String,
31195
+ expiresAt: Schema$1.Number
31196
+ }),
31197
+ Schema$1.Struct({
31198
+ version: Schema$1.Literal(1),
31199
+ kind: Schema$1.Literal("mdx-build"),
31200
+ buildId: Schema$1.String,
31201
+ sourceDirectory: Schema$1.String,
31202
+ expiresAt: Schema$1.Number
31203
+ }),
30740
31204
  Schema$1.Struct({
30741
31205
  version: Schema$1.Literal(1),
30742
31206
  kind: Schema$1.Literal("attachment"),
@@ -30786,6 +31250,41 @@ const resolveCanonicalWorkspaceFileForRequest = (input) => resolveCanonicalWorks
30786
31250
  relativePath: input.relativePath,
30787
31251
  cause
30788
31252
  })), Effect.orElseSucceed(() => null));
31253
+ /**
31254
+ * Reject anything that could walk out of a directory grant.
31255
+ *
31256
+ * Shared by every directory-scoped claim so the workspace grant and the two
31257
+ * new local grants cannot drift apart: a rule relaxed for one of them would
31258
+ * otherwise silently relax for none of the others, which is how the
31259
+ * out-of-workspace path becomes the weak one.
31260
+ */
31261
+ function isSafeGrantRelativePath(decodedPath, allowedExtensions, extname) {
31262
+ if (decodedPath.length === 0 || decodedPath.includes("\0")) return false;
31263
+ if (decodedPath.split(/[\\/]/).some((segment) => segment === "." || segment === ".." || segment.startsWith("."))) return false;
31264
+ return allowedExtensions.has(extname(decodedPath).toLowerCase());
31265
+ }
31266
+ /**
31267
+ * Resolve a relative path inside a directory grant, following symlinks.
31268
+ *
31269
+ * The realpath comparison is the point: without it a symlink inside the
31270
+ * granted directory would hand out any file on disk while every textual check
31271
+ * above still passed.
31272
+ */
31273
+ const resolveCanonicalFileWithinDirectory = Effect.fn("AssetAccess.resolveCanonicalFileWithinDirectory")(function* (input) {
31274
+ const fileSystem = yield* FileSystem.FileSystem;
31275
+ const path = yield* Path.Path;
31276
+ const [canonicalBase, canonicalFile] = yield* Effect.all([optionOnNotFound(fileSystem.realPath(input.baseDirectory)), optionOnNotFound(fileSystem.realPath(path.join(input.baseDirectory, input.relativePath)))]);
31277
+ if (Option.isNone(canonicalBase) || Option.isNone(canonicalFile)) return null;
31278
+ const relative = path.relative(canonicalBase.value, canonicalFile.value);
31279
+ if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) return null;
31280
+ const info = yield* optionOnNotFound(fileSystem.stat(canonicalFile.value));
31281
+ return Option.isSome(info) && info.value.type === "File" ? canonicalFile.value : null;
31282
+ });
31283
+ const resolveCanonicalFileWithinDirectoryForRequest = (input) => resolveCanonicalFileWithinDirectory(input).pipe(Effect.tapError((cause) => Effect.logError("Failed to resolve a granted asset path.", {
31284
+ baseDirectory: input.baseDirectory,
31285
+ relativePath: input.relativePath,
31286
+ cause
31287
+ })), Effect.orElseSucceed(() => null));
30789
31288
  const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input) {
30790
31289
  const fileSystem = yield* FileSystem.FileSystem;
30791
31290
  const path = yield* Path.Path;
@@ -30836,6 +31335,59 @@ const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input) {
30836
31335
  fileName = path.basename(resolved.relativePath);
30837
31336
  break;
30838
31337
  }
31338
+ case "local-file": {
31339
+ if (!path.isAbsolute(input.resource.path)) return yield* new AssetLocalPathValidationError({ resource: input.resource });
31340
+ if (!isWorkspacePreviewEntryPath(input.resource.path)) return yield* new AssetPreviewTypeValidationError({ resource: input.resource });
31341
+ const canonicalFile = yield* optionOnNotFound(fileSystem.realPath(input.resource.path)).pipe(Effect.mapError((cause) => new AssetLocalFileInspectionError({
31342
+ resource: input.resource,
31343
+ cause
31344
+ })));
31345
+ if (Option.isNone(canonicalFile)) return yield* new AssetLocalFileNotFoundError({ resource: input.resource });
31346
+ const info = yield* optionOnNotFound(fileSystem.stat(canonicalFile.value)).pipe(Effect.mapError((cause) => new AssetLocalFileInspectionError({
31347
+ resource: input.resource,
31348
+ cause
31349
+ })));
31350
+ if (Option.isNone(info) || info.value.type !== "File") return yield* new AssetLocalFileNotFoundError({ resource: input.resource });
31351
+ claims = isWorkspaceImagePreviewPath(canonicalFile.value) ? {
31352
+ version: 1,
31353
+ kind: "local-file-exact",
31354
+ filePath: canonicalFile.value,
31355
+ expiresAt
31356
+ } : {
31357
+ version: 1,
31358
+ kind: "local-file",
31359
+ baseDirectory: path.dirname(canonicalFile.value),
31360
+ expiresAt
31361
+ };
31362
+ fileName = path.basename(canonicalFile.value);
31363
+ break;
31364
+ }
31365
+ case "mdx-preview": {
31366
+ if (!path.isAbsolute(input.resource.path)) return yield* new AssetLocalPathValidationError({ resource: input.resource });
31367
+ const config = yield* ServerConfig$1;
31368
+ const now = yield* Clock.currentTimeMillis;
31369
+ const sourcePath = input.resource.path;
31370
+ const build = yield* Effect.tryPromise({
31371
+ try: () => prepareMdxBuild({
31372
+ buildsDir: config.mdxBuildsDir,
31373
+ sourcePath,
31374
+ now
31375
+ }),
31376
+ catch: (cause) => new AssetMdxBuildError({
31377
+ resource: input.resource,
31378
+ cause
31379
+ })
31380
+ });
31381
+ claims = {
31382
+ version: 1,
31383
+ kind: "mdx-build",
31384
+ buildId: build.buildId,
31385
+ sourceDirectory: build.sourceDir,
31386
+ expiresAt
31387
+ };
31388
+ fileName = "meta.json";
31389
+ break;
31390
+ }
30839
31391
  case "attachment": {
30840
31392
  const attachmentPath = resolveAttachmentPathById({
30841
31393
  attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
@@ -30932,6 +31484,54 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
30932
31484
  const decodedPath = decodeRelativePath(relativePath);
30933
31485
  if (decodedPath === null) return null;
30934
31486
  const path = yield* Path.Path;
31487
+ if (claims.kind === "local-file-exact") {
31488
+ if (decodedPath !== path.basename(claims.filePath)) return null;
31489
+ const fileSystem = yield* FileSystem.FileSystem;
31490
+ const info = yield* optionOnNotFound(fileSystem.stat(claims.filePath)).pipe(Effect.tapError((cause) => Effect.logError("Failed to inspect local asset.", {
31491
+ path: claims.filePath,
31492
+ cause
31493
+ })), Effect.orElseSucceed(() => Option.none()));
31494
+ return Option.isSome(info) && info.value.type === "File" ? {
31495
+ kind: "file",
31496
+ path: claims.filePath
31497
+ } : null;
31498
+ }
31499
+ if (claims.kind === "local-file") {
31500
+ if (!isSafeGrantRelativePath(decodedPath, PREVIEW_ASSET_EXTENSIONS, path.extname)) return null;
31501
+ const localFile = yield* resolveCanonicalFileWithinDirectoryForRequest({
31502
+ baseDirectory: claims.baseDirectory,
31503
+ relativePath: decodedPath
31504
+ });
31505
+ return localFile ? {
31506
+ kind: "file",
31507
+ path: localFile
31508
+ } : null;
31509
+ }
31510
+ if (claims.kind === "mdx-build") {
31511
+ if (!isMdxBuildId(claims.buildId)) return null;
31512
+ const config = yield* ServerConfig$1;
31513
+ if (MDX_BUILD_FILES.has(decodedPath)) {
31514
+ const buildFile = yield* resolveCanonicalFileWithinDirectoryForRequest({
31515
+ baseDirectory: path.join(config.mdxBuildsDir, claims.buildId),
31516
+ relativePath: decodedPath
31517
+ });
31518
+ return buildFile ? {
31519
+ kind: "file",
31520
+ path: buildFile
31521
+ } : null;
31522
+ }
31523
+ if (!decodedPath.startsWith(MDX_SOURCE_ASSET_PREFIX)) return null;
31524
+ const sourceRelativePath = decodedPath.slice(7);
31525
+ if (!isSafeGrantRelativePath(sourceRelativePath, MDX_SOURCE_ASSET_EXTENSIONS, path.extname)) return null;
31526
+ const sourceFile = yield* resolveCanonicalFileWithinDirectoryForRequest({
31527
+ baseDirectory: claims.sourceDirectory,
31528
+ relativePath: sourceRelativePath
31529
+ });
31530
+ return sourceFile ? {
31531
+ kind: "file",
31532
+ path: sourceFile
31533
+ } : null;
31534
+ }
30935
31535
  if (claims.kind === "workspace-file-exact") {
30936
31536
  if (decodedPath !== path.basename(claims.relativePath)) return null;
30937
31537
  const exactWorkspaceFile = yield* resolveCanonicalWorkspaceFileForRequest({
@@ -30943,8 +31543,7 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
30943
31543
  path: exactWorkspaceFile
30944
31544
  } : null;
30945
31545
  }
30946
- const segments = decodedPath.split(/[\\/]/);
30947
- if (decodedPath.length === 0 || decodedPath.includes("\0") || segments.some((segment) => segment === "." || segment === ".." || segment.startsWith(".")) || !PREVIEW_ASSET_EXTENSIONS.has(path.extname(decodedPath).toLowerCase())) return null;
31546
+ if (!isSafeGrantRelativePath(decodedPath, PREVIEW_ASSET_EXTENSIONS, path.extname)) return null;
30948
31547
  const joinedRelativePath = claims.baseRelativePath === "." ? decodedPath : path.join(claims.baseRelativePath, decodedPath);
30949
31548
  const workspaceFile = yield* resolveCanonicalWorkspaceFileForRequest({
30950
31549
  workspaceRoot: claims.workspaceRoot,
@@ -39822,20 +40421,10 @@ var WorkspacePathNotFileError = class extends Schema$1.TaggedErrorClass()("Works
39822
40421
  return `Workspace path '${this.relativePath}' in '${this.workspaceRoot}' is not a file: ${this.resolvedPath}`;
39823
40422
  }
39824
40423
  };
39825
- var WorkspaceBinaryFileError = class extends Schema$1.TaggedErrorClass()("WorkspaceBinaryFileError", {
39826
- workspaceRoot: Schema$1.String,
39827
- relativePath: Schema$1.String,
39828
- resolvedPath: Schema$1.String
39829
- }) {
39830
- get message() {
39831
- return `Workspace file '${this.relativePath}' in '${this.workspaceRoot}' is binary and cannot be previewed as text.`;
39832
- }
39833
- };
39834
40424
  Schema$1.Union([
39835
40425
  WorkspaceFileSystemOperationError,
39836
40426
  WorkspaceFilePathEscapeError,
39837
- WorkspacePathNotFileError,
39838
- WorkspaceBinaryFileError
40427
+ WorkspacePathNotFileError
39839
40428
  ]);
39840
40429
  /** Service tag for workspace file operations. */
39841
40430
  var WorkspaceFileSystem = class extends Context.Service()("@p4code/cli/workspace/WorkspaceFileSystem") {};
@@ -39919,16 +40508,19 @@ const make$29 = Effect.gen(function* () {
39919
40508
  })
39920
40509
  });
39921
40510
  const fileBytes = buffer.subarray(0, bytesRead);
39922
- if (fileBytes.includes(0)) return yield* new WorkspaceBinaryFileError({
39923
- workspaceRoot: input.cwd,
39924
- relativePath: input.relativePath,
39925
- resolvedPath: realTargetPath
39926
- });
40511
+ if (fileBytes.includes(0)) return {
40512
+ relativePath: target.relativePath,
40513
+ contents: "",
40514
+ byteLength: stat.size,
40515
+ truncated: false,
40516
+ binary: true
40517
+ };
39927
40518
  return {
39928
40519
  relativePath: target.relativePath,
39929
40520
  contents: new TextDecoder("utf-8").decode(fileBytes),
39930
40521
  byteLength: stat.size,
39931
- truncated: stat.size > PROJECT_READ_FILE_MAX_BYTES
40522
+ truncated: stat.size > PROJECT_READ_FILE_MAX_BYTES,
40523
+ binary: false
39932
40524
  };
39933
40525
  }), (handle) => Effect.tryPromise({
39934
40526
  try: () => handle.close(),
@@ -45757,10 +46349,6 @@ function projectFileFailureContext(error) {
45757
46349
  failure: "path_not_file",
45758
46350
  resolvedPath: error.resolvedPath
45759
46351
  };
45760
- case "WorkspaceBinaryFileError": return {
45761
- failure: "binary_file",
45762
- resolvedPath: error.resolvedPath
45763
- };
45764
46352
  default: return unexpectedCompatibilityError(error);
45765
46353
  }
45766
46354
  }
@@ -87807,6 +88395,8 @@ const BUFFERED_PROPOSED_PLAN_BY_ID_CACHE_CAPACITY = 1e4;
87807
88395
  const BUFFERED_PROPOSED_PLAN_BY_ID_TTL = Duration.minutes(120);
87808
88396
  const TASK_DESCRIPTION_BY_TASK_CACHE_CAPACITY = 1e4;
87809
88397
  const TASK_DESCRIPTION_BY_TASK_TTL = Duration.minutes(120);
88398
+ const COMPRESS_MODE_BY_THREAD_CACHE_CAPACITY = 1e4;
88399
+ const COMPRESS_MODE_BY_THREAD_TTL = Duration.minutes(120);
87810
88400
  const MAX_BUFFERED_ASSISTANT_CHARS = 24e3;
87811
88401
  const STRICT_PROVIDER_LIFECYCLE_GUARD = process.env.P4CODE_STRICT_PROVIDER_LIFECYCLE_GUARD !== "0";
87812
88402
  function toTurnId$1(value) {
@@ -87879,9 +88469,12 @@ function assistantSegmentBaseKeyFromEvent(event) {
87879
88469
  function assistantSegmentMessageId(baseKey, segmentIndex) {
87880
88470
  return MessageId.make(segmentIndex === 0 ? `assistant:${baseKey}` : `assistant:${baseKey}:segment:${segmentIndex}`);
87881
88471
  }
87882
- function buildContextWindowActivityPayload(event) {
88472
+ function buildContextWindowActivityPayload(event, compressMode) {
87883
88473
  if (event.type !== "thread.token-usage.updated" || event.payload.usage.usedTokens <= 0) return;
87884
- return event.payload.usage;
88474
+ return compressMode === void 0 ? event.payload.usage : {
88475
+ ...event.payload.usage,
88476
+ compressMode
88477
+ };
87885
88478
  }
87886
88479
  function normalizeRuntimeTurnState(value) {
87887
88480
  switch (value) {
@@ -87916,7 +88509,7 @@ function requestKindFromCanonicalRequestType(requestType) {
87916
88509
  default: return;
87917
88510
  }
87918
88511
  }
87919
- function runtimeEventToActivities(event, taskTitle) {
88512
+ function runtimeEventToActivities(event, taskTitle, compressMode) {
87920
88513
  const maybeSequence = (() => {
87921
88514
  const eventWithSequence = event;
87922
88515
  return eventWithSequence.sessionSequence !== void 0 ? { sequence: eventWithSequence.sessionSequence } : {};
@@ -88126,7 +88719,7 @@ function runtimeEventToActivities(event, taskTitle) {
88126
88719
  ...maybeSequence
88127
88720
  }];
88128
88721
  case "thread.token-usage.updated": {
88129
- const payload = buildContextWindowActivityPayload(event);
88722
+ const payload = buildContextWindowActivityPayload(event, compressMode);
88130
88723
  if (!payload) return [];
88131
88724
  return [{
88132
88725
  id: event.eventId,
@@ -88227,6 +88820,11 @@ const make$3 = Effect.gen(function* () {
88227
88820
  timeToLive: TASK_DESCRIPTION_BY_TASK_TTL,
88228
88821
  lookup: () => Effect.succeed("")
88229
88822
  });
88823
+ const compressModeByThreadId = yield* Cache.make({
88824
+ capacity: COMPRESS_MODE_BY_THREAD_CACHE_CAPACITY,
88825
+ timeToLive: COMPRESS_MODE_BY_THREAD_TTL,
88826
+ lookup: () => Effect.die(/* @__PURE__ */ new Error("compress mode should be read through getOption"))
88827
+ });
88230
88828
  const rememberTaskDescription = (threadId, taskId, description) => Cache.set(taskDescriptionByTaskKey, providerTaskKey(threadId, taskId), description);
88231
88829
  const lookupTaskDescription = (threadId, taskId) => Cache.getOption(taskDescriptionByTaskKey, providerTaskKey(threadId, taskId)).pipe(Effect.map((description) => Option.filter(description, (value) => value.length > 0).pipe(Option.getOrUndefined)));
88232
88830
  const resolveThreadDetail = Effect.fn("resolveThreadDetail")(function* (threadId) {
@@ -88733,7 +89331,9 @@ const make$3 = Effect.gen(function* () {
88733
89331
  taskTitle = yield* lookupTaskDescription(thread.id, event.payload.taskId);
88734
89332
  if (!taskTitle) taskTitle = findTaskTitleInActivities((yield* getLoadedThreadDetail())?.activities, event.payload.taskId);
88735
89333
  }
88736
- const activities = runtimeEventToActivities(event, taskTitle);
89334
+ if (event.type === "turn.started") yield* Cache.set(compressModeByThreadId, thread.id, thread.compressMode);
89335
+ const turnCompressMode = event.type === "thread.token-usage.updated" ? (yield* Cache.getOption(compressModeByThreadId, thread.id).pipe(Effect.map(Option.getOrUndefined))) ?? thread.compressMode : void 0;
89336
+ const activities = runtimeEventToActivities(event, taskTitle, turnCompressMode);
88737
89337
  yield* Effect.forEach(activities, (activity) => providerCommandId(event, "thread-activity-append").pipe(Effect.flatMap((commandId) => orchestrationEngine.dispatch({
88738
89338
  type: "thread.activity.append",
88739
89339
  commandId,
@@ -88857,6 +89457,15 @@ const make$2 = Effect.gen(function* () {
88857
89457
  });
88858
89458
  const hasHandledTurnStartRecently = (key) => Cache.getOption(handledTurnStartKeys, key).pipe(Effect.flatMap((cached) => Cache.set(handledTurnStartKeys, key, true).pipe(Effect.as(Option.isSome(cached)))));
88859
89459
  const threadModelSelections = /* @__PURE__ */ new Map();
89460
+ /**
89461
+ * The compress mode whose ruleset the thread's live session was handed at
89462
+ * start, kept because two of the three delivery channels cannot be rebuilt
89463
+ * afterwards: Claude bakes the ruleset into the system prompt of a
89464
+ * long-lived process, and the prefix providers put it in the first turn's
89465
+ * message. Toggling compression off has to send a counter-instruction, and
89466
+ * this is how the reactor knows there is something to counter.
89467
+ */
89468
+ const threadSessionRulesetModes = /* @__PURE__ */ new Map();
88860
89469
  const appendProviderFailureActivity = (input) => Effect.all({
88861
89470
  commandId: serverCommandId("provider-failure-activity"),
88862
89471
  eventId: serverEventId()
@@ -89055,17 +89664,20 @@ const make$2 = Effect.gen(function* () {
89055
89664
  thread,
89056
89665
  projects: project ? [project] : []
89057
89666
  });
89058
- const startProviderSession = (input) => providerService.startSession(threadId, {
89059
- threadId,
89060
- ...preferredProvider ? { provider: preferredProvider } : {},
89061
- providerInstanceId: desiredInstanceId,
89062
- ...effectiveCwd ? { cwd: effectiveCwd } : {},
89063
- modelSelection: desiredModelSelection,
89064
- ...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
89065
- runtimeMode: desiredRuntimeMode,
89066
- compressMode: thread.compressMode,
89067
- unpromptedSubagents: thread.unpromptedSubagents
89068
- });
89667
+ const startProviderSession = (input) => {
89668
+ threadSessionRulesetModes.set(threadId, thread.compressMode);
89669
+ return providerService.startSession(threadId, {
89670
+ threadId,
89671
+ ...preferredProvider ? { provider: preferredProvider } : {},
89672
+ providerInstanceId: desiredInstanceId,
89673
+ ...effectiveCwd ? { cwd: effectiveCwd } : {},
89674
+ modelSelection: desiredModelSelection,
89675
+ ...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
89676
+ runtimeMode: desiredRuntimeMode,
89677
+ compressMode: thread.compressMode,
89678
+ unpromptedSubagents: thread.unpromptedSubagents
89679
+ });
89680
+ };
89069
89681
  const bindSessionToThread = (session) => Effect.gen(function* () {
89070
89682
  if (session.providerInstanceId === void 0) return yield* new ProviderAdapterRequestError({
89071
89683
  provider: providerErrorLabel(session.provider),
@@ -89158,7 +89770,12 @@ const make$2 = Effect.gen(function* () {
89158
89770
  } : requestedModelSelection : input.modelSelection;
89159
89771
  const compressMode = thread.compressMode;
89160
89772
  const hasSessionLevelRuleset = activeSession?.provider === "claudeAgent" || activeSession?.provider === "codex";
89161
- const compressPrefix = !hadActiveSession && !hasSessionLevelRuleset ? compressRulesetFor(compressMode) : compressTurnReminderFor(compressMode);
89773
+ const rebuildsRulesetEachTurn = activeSession?.provider === "codex";
89774
+ const compressPrefix = compressTurnPrefixFor({
89775
+ mode: compressMode,
89776
+ injectRuleset: !hadActiveSession && !hasSessionLevelRuleset,
89777
+ staleRulesetMode: hadActiveSession && !rebuildsRulesetEachTurn ? threadSessionRulesetModes.get(input.threadId) : void 0
89778
+ });
89162
89779
  const inputWithCompressPrefix = normalizedInput !== void 0 && compressPrefix !== void 0 ? `${compressPrefix}\n\n${normalizedInput}` : normalizedInput;
89163
89780
  return {
89164
89781
  threadId: input.threadId,
@@ -89382,6 +89999,7 @@ const make$2 = Effect.gen(function* () {
89382
89999
  if (!thread) return;
89383
90000
  const now = event.payload.createdAt;
89384
90001
  if (thread.session && thread.session.status !== "stopped") yield* providerService.stopSession({ threadId: thread.id });
90002
+ threadSessionRulesetModes.delete(thread.id);
89385
90003
  yield* setThreadSession({
89386
90004
  threadId: thread.id,
89387
90005
  session: {