@juspay/shooter 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/build/client/_app/immutable/assets/{0.B0O0vCnX.css → 0.BwNtE8TX.css} +1 -1
  2. package/build/client/_app/immutable/assets/0.BwNtE8TX.css.br +0 -0
  3. package/build/client/_app/immutable/assets/{0.B0O0vCnX.css.gz → 0.BwNtE8TX.css.gz} +0 -0
  4. package/build/client/_app/immutable/assets/8.BYgAX7hR.css +1 -0
  5. package/build/client/_app/immutable/assets/8.BYgAX7hR.css.br +0 -0
  6. package/build/client/_app/immutable/assets/8.BYgAX7hR.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/9.DV6pZunn.css +1 -0
  8. package/build/client/_app/immutable/assets/9.DV6pZunn.css.br +0 -0
  9. package/build/client/_app/immutable/assets/9.DV6pZunn.css.gz +0 -0
  10. package/build/client/_app/immutable/chunks/{DZQMsHM5.js → 2rBV5OkJ.js} +1 -1
  11. package/build/client/_app/immutable/chunks/2rBV5OkJ.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/2rBV5OkJ.js.gz +0 -0
  13. package/build/client/_app/immutable/chunks/BB2l8o4X.js +1 -0
  14. package/build/client/_app/immutable/chunks/BB2l8o4X.js.br +0 -0
  15. package/build/client/_app/immutable/chunks/BB2l8o4X.js.gz +0 -0
  16. package/build/client/_app/immutable/chunks/{Cg3dlX05.js → BPDiEZo0.js} +2 -2
  17. package/build/client/_app/immutable/chunks/BPDiEZo0.js.br +0 -0
  18. package/build/client/_app/immutable/chunks/BPDiEZo0.js.gz +0 -0
  19. package/build/client/_app/immutable/chunks/{C_9BZILB.js → BcpydfqI.js} +1 -1
  20. package/build/client/_app/immutable/chunks/BcpydfqI.js.br +0 -0
  21. package/build/client/_app/immutable/chunks/BcpydfqI.js.gz +0 -0
  22. package/build/client/_app/immutable/chunks/BcqA7eKM.js +3 -0
  23. package/build/client/_app/immutable/chunks/BcqA7eKM.js.br +0 -0
  24. package/build/client/_app/immutable/chunks/BcqA7eKM.js.gz +0 -0
  25. package/build/client/_app/immutable/chunks/BdtLzPpO.js +1 -0
  26. package/build/client/_app/immutable/chunks/BdtLzPpO.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/BdtLzPpO.js.gz +0 -0
  28. package/build/client/_app/immutable/chunks/{BRqaaL5D.js → BvmdJful.js} +1 -1
  29. package/build/client/_app/immutable/chunks/BvmdJful.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/BvmdJful.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/{C5VOyQCG.js → ClIPTXf3.js} +1 -1
  32. package/build/client/_app/immutable/chunks/ClIPTXf3.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/ClIPTXf3.js.gz +0 -0
  34. package/build/client/_app/immutable/chunks/{BctvtE4d.js → DA4Zt9Me.js} +1 -1
  35. package/build/client/_app/immutable/chunks/DA4Zt9Me.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/{BctvtE4d.js.gz → DA4Zt9Me.js.gz} +0 -0
  37. package/build/client/_app/immutable/chunks/{CjfxuHdN.js → DCDL_9ys.js} +1 -1
  38. package/build/client/_app/immutable/chunks/DCDL_9ys.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/DCDL_9ys.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/{DYuMZGL5.js → DWmC0QM7.js} +1 -1
  41. package/build/client/_app/immutable/chunks/DWmC0QM7.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/DWmC0QM7.js.gz +0 -0
  43. package/build/client/_app/immutable/chunks/{DZvnhU_8.js → ZS5XYDx_.js} +2 -2
  44. package/build/client/_app/immutable/chunks/ZS5XYDx_.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/ZS5XYDx_.js.gz +0 -0
  46. package/build/client/_app/immutable/entry/app.D4TXlu7A.js +2 -0
  47. package/build/client/_app/immutable/entry/app.D4TXlu7A.js.br +0 -0
  48. package/build/client/_app/immutable/entry/app.D4TXlu7A.js.gz +0 -0
  49. package/build/client/_app/immutable/entry/start.BBQhtURO.js +1 -0
  50. package/build/client/_app/immutable/entry/start.BBQhtURO.js.br +0 -0
  51. package/build/client/_app/immutable/entry/start.BBQhtURO.js.gz +0 -0
  52. package/build/client/_app/immutable/nodes/0.1zylwAPT.js +10 -0
  53. package/build/client/_app/immutable/nodes/0.1zylwAPT.js.br +0 -0
  54. package/build/client/_app/immutable/nodes/0.1zylwAPT.js.gz +0 -0
  55. package/build/client/_app/immutable/nodes/{1.Fqso94b3.js → 1.BVnLUSs-.js} +1 -1
  56. package/build/client/_app/immutable/nodes/1.BVnLUSs-.js.br +0 -0
  57. package/build/client/_app/immutable/nodes/1.BVnLUSs-.js.gz +0 -0
  58. package/build/client/_app/immutable/nodes/{8.BjKgvSie.js → 10.D1wl2wPX.js} +2 -2
  59. package/build/client/_app/immutable/nodes/10.D1wl2wPX.js.br +0 -0
  60. package/build/client/_app/immutable/nodes/10.D1wl2wPX.js.gz +0 -0
  61. package/build/client/_app/immutable/nodes/{9.BRT6HOXB.js → 11.C18nMGmp.js} +1 -1
  62. package/build/client/_app/immutable/nodes/11.C18nMGmp.js.br +0 -0
  63. package/build/client/_app/immutable/nodes/11.C18nMGmp.js.gz +0 -0
  64. package/build/client/_app/immutable/nodes/{2.BusCVJWk.js → 2.D1Mm0DUX.js} +2 -2
  65. package/build/client/_app/immutable/nodes/2.D1Mm0DUX.js.br +0 -0
  66. package/build/client/_app/immutable/nodes/2.D1Mm0DUX.js.gz +0 -0
  67. package/build/client/_app/immutable/nodes/{3.DUlpocIc.js → 3.Wfz3TcJd.js} +3 -3
  68. package/build/client/_app/immutable/nodes/3.Wfz3TcJd.js.br +0 -0
  69. package/build/client/_app/immutable/nodes/3.Wfz3TcJd.js.gz +0 -0
  70. package/build/client/_app/immutable/nodes/{4.BSVqdrrD.js → 4.CBX9A3ka.js} +2 -2
  71. package/build/client/_app/immutable/nodes/4.CBX9A3ka.js.br +0 -0
  72. package/build/client/_app/immutable/nodes/4.CBX9A3ka.js.gz +0 -0
  73. package/build/client/_app/immutable/nodes/{5.Cfj35gpY.js → 5.DIVKuZc9.js} +1 -1
  74. package/build/client/_app/immutable/nodes/5.DIVKuZc9.js.br +0 -0
  75. package/build/client/_app/immutable/nodes/5.DIVKuZc9.js.gz +0 -0
  76. package/build/client/_app/immutable/nodes/{6.CG4eKRH0.js → 6.DtZAEPXb.js} +1 -1
  77. package/build/client/_app/immutable/nodes/6.DtZAEPXb.js.br +0 -0
  78. package/build/client/_app/immutable/nodes/6.DtZAEPXb.js.gz +0 -0
  79. package/build/client/_app/immutable/nodes/{7.DHilxD1o.js → 7.MfBRh32I.js} +1 -1
  80. package/build/client/_app/immutable/nodes/7.MfBRh32I.js.br +0 -0
  81. package/build/client/_app/immutable/nodes/7.MfBRh32I.js.gz +0 -0
  82. package/build/client/_app/immutable/nodes/8.DVE6LnOC.js +1 -0
  83. package/build/client/_app/immutable/nodes/8.DVE6LnOC.js.br +0 -0
  84. package/build/client/_app/immutable/nodes/8.DVE6LnOC.js.gz +0 -0
  85. package/build/client/_app/immutable/nodes/9.BCel5OqI.js +2 -0
  86. package/build/client/_app/immutable/nodes/9.BCel5OqI.js.br +0 -0
  87. package/build/client/_app/immutable/nodes/9.BCel5OqI.js.gz +0 -0
  88. package/build/client/_app/version.json +1 -1
  89. package/build/client/_app/version.json.br +0 -0
  90. package/build/client/_app/version.json.gz +0 -0
  91. package/build/server/chunks/{0-BWFSL107.js → 0-DJqyZZTr.js} +4 -4
  92. package/build/server/chunks/{0-BWFSL107.js.map → 0-DJqyZZTr.js.map} +1 -1
  93. package/build/server/chunks/1-2YUVen1F.js +9 -0
  94. package/build/server/chunks/{1-Bw5KlAjL.js.map → 1-2YUVen1F.js.map} +1 -1
  95. package/build/server/chunks/10-D1X7LB3v.js +9 -0
  96. package/build/server/chunks/10-D1X7LB3v.js.map +1 -0
  97. package/build/server/chunks/11-qXSPdF5j.js +9 -0
  98. package/build/server/chunks/11-qXSPdF5j.js.map +1 -0
  99. package/build/server/chunks/{2-CQ3yYSVK.js → 2-BD7kj1mt.js} +3 -3
  100. package/build/server/chunks/{2-CQ3yYSVK.js.map → 2-BD7kj1mt.js.map} +1 -1
  101. package/build/server/chunks/{3-DZ4H9hPs.js → 3-oNjv-BhZ.js} +3 -3
  102. package/build/server/chunks/{3-DZ4H9hPs.js.map → 3-oNjv-BhZ.js.map} +1 -1
  103. package/build/server/chunks/{4-BtYdKCVW.js → 4-Bb5VFhsO.js} +3 -3
  104. package/build/server/chunks/{4-BtYdKCVW.js.map → 4-Bb5VFhsO.js.map} +1 -1
  105. package/build/server/chunks/{5-CvJK3PiH.js → 5-oNoWuIsn.js} +3 -3
  106. package/build/server/chunks/{5-CvJK3PiH.js.map → 5-oNoWuIsn.js.map} +1 -1
  107. package/build/server/chunks/6-DRJGUqHG.js +9 -0
  108. package/build/server/chunks/{6-BZ0enR6b.js.map → 6-DRJGUqHG.js.map} +1 -1
  109. package/build/server/chunks/7-_giJiu0L.js +9 -0
  110. package/build/server/chunks/{7-Lg8imTZn.js.map → 7-_giJiu0L.js.map} +1 -1
  111. package/build/server/chunks/8-zvWAVNT5.js +9 -0
  112. package/build/server/chunks/8-zvWAVNT5.js.map +1 -0
  113. package/build/server/chunks/9-DVyDL445.js +9 -0
  114. package/build/server/chunks/9-DVyDL445.js.map +1 -0
  115. package/build/server/chunks/Banner-BgaAs1rs.js +90 -0
  116. package/build/server/chunks/Banner-BgaAs1rs.js.map +1 -0
  117. package/build/server/chunks/{Button-B5dU-ntz.js → Button-D0hZ7JYt.js} +2 -2
  118. package/build/server/chunks/Button-D0hZ7JYt.js.map +1 -0
  119. package/build/server/chunks/{Icon-C7Ml3GX6.js → Icon-D0GBnDcs.js} +3 -3
  120. package/build/server/chunks/Icon-D0GBnDcs.js.map +1 -0
  121. package/build/server/chunks/{Input-CPGO0sbS.js → Input-OmIiydSx.js} +2 -2
  122. package/build/server/chunks/Input-OmIiydSx.js.map +1 -0
  123. package/build/server/chunks/{Pill-CcrtCejm.js → Pill-4xJ-VhAA.js} +3 -3
  124. package/build/server/chunks/Pill-4xJ-VhAA.js.map +1 -0
  125. package/build/server/chunks/{Shimmer-C5jkvGr1.js → Shimmer-Dw2uvTC1.js} +2 -2
  126. package/build/server/chunks/Shimmer-Dw2uvTC1.js.map +1 -0
  127. package/build/server/chunks/{_error.svelte-CSIxs-ab.js → _error.svelte-CZnkxeLr.js} +8 -8
  128. package/build/server/chunks/{_error.svelte-CSIxs-ab.js.map → _error.svelte-CZnkxeLr.js.map} +1 -1
  129. package/build/server/chunks/{_layout.svelte-noB4j-v2.js → _layout.svelte-DfgNGGiM.js} +16 -11
  130. package/build/server/chunks/_layout.svelte-DfgNGGiM.js.map +1 -0
  131. package/build/server/chunks/{_page.svelte-DnTpPnPR.js → _page.svelte-BLo2v_8E.js} +7 -88
  132. package/build/server/chunks/_page.svelte-BLo2v_8E.js.map +1 -0
  133. package/build/server/chunks/_page.svelte-BTlfUsBp.js +43 -0
  134. package/build/server/chunks/_page.svelte-BTlfUsBp.js.map +1 -0
  135. package/build/server/chunks/{_page.svelte-C60lAagP.js → _page.svelte-BUBLUSGo.js} +8 -8
  136. package/build/server/chunks/_page.svelte-BUBLUSGo.js.map +1 -0
  137. package/build/server/chunks/{_page.svelte-BV0XyYJZ.js → _page.svelte-BX2FMgSg.js} +4 -4
  138. package/build/server/chunks/{_page.svelte-BV0XyYJZ.js.map → _page.svelte-BX2FMgSg.js.map} +1 -1
  139. package/build/server/chunks/{_page.svelte-BUkm2304.js → _page.svelte-C7B0qdrC.js} +5 -5
  140. package/build/server/chunks/{_page.svelte-BUkm2304.js.map → _page.svelte-C7B0qdrC.js.map} +1 -1
  141. package/build/server/chunks/{_page.svelte-Dmg-RFCg.js → _page.svelte-CE7COWnF.js} +7 -7
  142. package/build/server/chunks/{_page.svelte-Dmg-RFCg.js.map → _page.svelte-CE7COWnF.js.map} +1 -1
  143. package/build/server/chunks/{_page.svelte-BfB8maoc.js → _page.svelte-CWsjjd4l.js} +9 -9
  144. package/build/server/chunks/{_page.svelte-BfB8maoc.js.map → _page.svelte-CWsjjd4l.js.map} +1 -1
  145. package/build/server/chunks/_page.svelte-D5S2hkBk.js +104 -0
  146. package/build/server/chunks/_page.svelte-D5S2hkBk.js.map +1 -0
  147. package/build/server/chunks/{_page.svelte-B6qyh-K-.js → _page.svelte-D_Ey8QRG.js} +11 -11
  148. package/build/server/chunks/{_page.svelte-B6qyh-K-.js.map → _page.svelte-D_Ey8QRG.js.map} +1 -1
  149. package/build/server/chunks/{_page.svelte-DuzZr5dA.js → _page.svelte-tBuIq8Pg.js} +11 -11
  150. package/build/server/chunks/{_page.svelte-DuzZr5dA.js.map → _page.svelte-tBuIq8Pg.js.map} +1 -1
  151. package/build/server/chunks/_server.ts-BaaY7Z9D.js +77 -0
  152. package/build/server/chunks/_server.ts-BaaY7Z9D.js.map +1 -0
  153. package/build/server/chunks/{_server.ts-5wx4ZppI.js → _server.ts-Bi0Oe4PF.js} +7 -4
  154. package/build/server/chunks/_server.ts-Bi0Oe4PF.js.map +1 -0
  155. package/build/server/chunks/_server.ts-C0317RBD.js +57 -0
  156. package/build/server/chunks/_server.ts-C0317RBD.js.map +1 -0
  157. package/build/server/chunks/{_server.ts-CKXVBbwb.js → _server.ts-CRVNEOd2.js} +10 -8
  158. package/build/server/chunks/_server.ts-CRVNEOd2.js.map +1 -0
  159. package/build/server/chunks/_server.ts-CVPZOpiv.js +23 -0
  160. package/build/server/chunks/_server.ts-CVPZOpiv.js.map +1 -0
  161. package/build/server/chunks/{_server.ts-CyjDrcZN.js → _server.ts-C_OOUqsd.js} +9 -1
  162. package/build/server/chunks/_server.ts-C_OOUqsd.js.map +1 -0
  163. package/build/server/chunks/{_server.ts-BMMTS86y.js → _server.ts-D9ir7u24.js} +3 -4
  164. package/build/server/chunks/{_server.ts-BMMTS86y.js.map → _server.ts-D9ir7u24.js.map} +1 -1
  165. package/build/server/chunks/{_server.ts-DZ5naqSL.js → _server.ts-DMm0hBP4.js} +5 -1
  166. package/build/server/chunks/_server.ts-DMm0hBP4.js.map +1 -0
  167. package/build/server/chunks/{_server.ts-CgHc1Zpx.js → _server.ts-DhJx0DLr.js} +7 -4
  168. package/build/server/chunks/_server.ts-DhJx0DLr.js.map +1 -0
  169. package/build/server/chunks/_server.ts-DkZX_O9a.js +39 -0
  170. package/build/server/chunks/_server.ts-DkZX_O9a.js.map +1 -0
  171. package/build/server/chunks/{_server.ts-B1z0q6qZ.js → _server.ts-DxT9IlZF.js} +6 -5
  172. package/build/server/chunks/_server.ts-DxT9IlZF.js.map +1 -0
  173. package/build/server/chunks/{_server.ts-Bt7EAfjo.js → _server.ts-MbnroWEF.js} +25 -48
  174. package/build/server/chunks/_server.ts-MbnroWEF.js.map +1 -0
  175. package/build/server/chunks/_server.ts-Mttr0-Sl.js +48 -0
  176. package/build/server/chunks/_server.ts-Mttr0-Sl.js.map +1 -0
  177. package/build/server/chunks/_server.ts-jtqWDWcf.js +45 -0
  178. package/build/server/chunks/_server.ts-jtqWDWcf.js.map +1 -0
  179. package/build/server/chunks/{cache-Me3zUAaD.js → cache-BlMaDsHi.js} +2 -2
  180. package/build/server/chunks/{cache-Me3zUAaD.js.map → cache-BlMaDsHi.js.map} +1 -1
  181. package/build/server/chunks/{client-CfNnl32g.js → client-Ds1brw-8.js} +4 -4
  182. package/build/server/chunks/{client-CfNnl32g.js.map → client-Ds1brw-8.js.map} +1 -1
  183. package/build/server/chunks/client2-DngLdcUc.js +7 -0
  184. package/build/server/chunks/{client2-DDP30_vY.js.map → client2-DngLdcUc.js.map} +1 -1
  185. package/build/server/chunks/coordinator-DMU_ADXf.js +530 -0
  186. package/build/server/chunks/coordinator-DMU_ADXf.js.map +1 -0
  187. package/build/server/chunks/{index-CJrGuxuM.js → index-CoYB03g7.js} +2 -2
  188. package/build/server/chunks/{index-CJrGuxuM.js.map → index-CoYB03g7.js.map} +1 -1
  189. package/build/server/chunks/{index-server--49oHtA0.js → index-server-Bq3cnK69.js} +2 -2
  190. package/build/server/chunks/{index-server--49oHtA0.js.map → index-server-Bq3cnK69.js.map} +1 -1
  191. package/build/server/chunks/{index2-MY7PXeAc.js → index2-dSGQ9Eaa.js} +2 -2
  192. package/build/server/chunks/{index2-MY7PXeAc.js.map → index2-dSGQ9Eaa.js.map} +1 -1
  193. package/build/server/chunks/{pty-manager-RmhVe2Ez.js → pty-manager-41h3IK8K.js} +100 -2
  194. package/build/server/chunks/pty-manager-41h3IK8K.js.map +1 -0
  195. package/build/server/chunks/qwen-reader-DGfUbKaJ.js +2112 -0
  196. package/build/server/chunks/qwen-reader-DGfUbKaJ.js.map +1 -0
  197. package/build/server/chunks/{registry-DzJj2E6I.js → registry-D4J_CuzW.js} +56 -24
  198. package/build/server/chunks/registry-D4J_CuzW.js.map +1 -0
  199. package/build/server/chunks/{root-xvQIR1Bt.js → root-D4IoFC8F.js} +2 -2
  200. package/build/server/chunks/root-D4IoFC8F.js.map +1 -0
  201. package/build/server/chunks/{state.svelte-RCtlkrNH.js → state.svelte-CmHqngc_.js} +3 -3
  202. package/build/server/chunks/{state.svelte-RCtlkrNH.js.map → state.svelte-CmHqngc_.js.map} +1 -1
  203. package/build/server/chunks/{stores-C-LqoonT.js → stores-CRYxfF0o.js} +4 -4
  204. package/build/server/chunks/stores-CRYxfF0o.js.map +1 -0
  205. package/build/server/chunks/super-session-handler-DPyxFgmz.js +22 -0
  206. package/build/server/chunks/super-session-handler-DPyxFgmz.js.map +1 -0
  207. package/build/server/index.js +4 -4
  208. package/build/server/index.js.map +1 -1
  209. package/build/server/manifest.js +79 -21
  210. package/build/server/manifest.js.map +1 -1
  211. package/package.json +2 -2
  212. package/scripts/e2e-all-features.sh +204 -0
  213. package/scripts/e2e-cross-terminal.sh +168 -0
  214. package/server.ts +37 -0
  215. package/src/lib/modules/client/common/provider.ts +0 -2
  216. package/src/lib/modules/client/terminal/ChatView.svelte +9 -2
  217. package/src/lib/modules/client/terminal/LaunchSheet.svelte +3 -0
  218. package/src/lib/modules/server/sessions/amp-reader.ts +439 -0
  219. package/src/lib/modules/server/sessions/copilot-reader.ts +542 -0
  220. package/src/lib/modules/server/sessions/cursor-reader.ts +634 -0
  221. package/src/lib/modules/server/sessions/gemini-reader.ts +48 -25
  222. package/src/lib/modules/server/sessions/opencode-reader.ts +13 -12
  223. package/src/lib/modules/server/sessions/process-detector.ts +37 -60
  224. package/src/lib/modules/server/sessions/provider-paths.ts +173 -0
  225. package/src/lib/modules/server/sessions/qwen-reader.ts +41 -15
  226. package/src/lib/modules/server/sessions/registry.ts +55 -14
  227. package/src/lib/modules/server/sos/coordinator.ts +492 -0
  228. package/src/lib/modules/server/sos/policy-gate.ts +56 -0
  229. package/src/lib/modules/server/sos/relay-store.ts +159 -0
  230. package/src/lib/modules/server/terminal/generic-session-watcher.ts +163 -0
  231. package/src/lib/modules/server/terminal/pty-input.ts +37 -0
  232. package/src/lib/modules/server/terminal/pty-manager.ts +51 -0
  233. package/src/lib/modules/server/ws/server.ts +6 -1
  234. package/src/lib/modules/server/ws/session-handler.ts +17 -2
  235. package/src/lib/modules/server/ws/super-session-handler.ts +200 -0
  236. package/src/lib/theme.css +1 -2
  237. package/src/lib/types/generated/Sessions.ts +1 -4
  238. package/src/lib/types/index.ts +2 -1
  239. package/src/lib/types/server.ts +23 -6
  240. package/src/lib/types/sessions.ts +1 -10
  241. package/src/lib/types/sos.ts +134 -0
  242. package/src/routes/+layout.svelte +9 -2
  243. package/src/routes/api/sessions/connect/+server.ts +7 -3
  244. package/src/routes/api/sos/+server.ts +36 -0
  245. package/src/routes/api/sos/[id]/+server.ts +55 -0
  246. package/src/routes/api/sos/[id]/inject/+server.ts +44 -0
  247. package/src/routes/api/sos/[id]/members/+server.ts +47 -0
  248. package/src/routes/api/sos/[id]/members/[mid]/+server.ts +17 -0
  249. package/src/routes/api/sos/[id]/rules/+server.ts +85 -0
  250. package/src/routes/sos/+page.svelte +195 -0
  251. package/src/routes/sos/[id]/+page.svelte +677 -0
  252. package/build/client/_app/immutable/assets/0.B0O0vCnX.css.br +0 -0
  253. package/build/client/_app/immutable/chunks/BRqaaL5D.js.br +0 -0
  254. package/build/client/_app/immutable/chunks/BRqaaL5D.js.gz +0 -0
  255. package/build/client/_app/immutable/chunks/BctvtE4d.js.br +0 -0
  256. package/build/client/_app/immutable/chunks/BxFShcQO.js +0 -1
  257. package/build/client/_app/immutable/chunks/BxFShcQO.js.br +0 -0
  258. package/build/client/_app/immutable/chunks/BxFShcQO.js.gz +0 -0
  259. package/build/client/_app/immutable/chunks/ByzqAuXw.js +0 -3
  260. package/build/client/_app/immutable/chunks/ByzqAuXw.js.br +0 -0
  261. package/build/client/_app/immutable/chunks/ByzqAuXw.js.gz +0 -0
  262. package/build/client/_app/immutable/chunks/C5VOyQCG.js.br +0 -0
  263. package/build/client/_app/immutable/chunks/C5VOyQCG.js.gz +0 -0
  264. package/build/client/_app/immutable/chunks/C_9BZILB.js.br +0 -0
  265. package/build/client/_app/immutable/chunks/C_9BZILB.js.gz +0 -0
  266. package/build/client/_app/immutable/chunks/Cg3dlX05.js.br +0 -0
  267. package/build/client/_app/immutable/chunks/Cg3dlX05.js.gz +0 -0
  268. package/build/client/_app/immutable/chunks/CjfxuHdN.js.br +0 -0
  269. package/build/client/_app/immutable/chunks/CjfxuHdN.js.gz +0 -0
  270. package/build/client/_app/immutable/chunks/DYuMZGL5.js.br +0 -0
  271. package/build/client/_app/immutable/chunks/DYuMZGL5.js.gz +0 -0
  272. package/build/client/_app/immutable/chunks/DZQMsHM5.js.br +0 -0
  273. package/build/client/_app/immutable/chunks/DZQMsHM5.js.gz +0 -0
  274. package/build/client/_app/immutable/chunks/DZvnhU_8.js.br +0 -0
  275. package/build/client/_app/immutable/chunks/DZvnhU_8.js.gz +0 -0
  276. package/build/client/_app/immutable/chunks/Pw0jDB7M.js +0 -1
  277. package/build/client/_app/immutable/chunks/Pw0jDB7M.js.br +0 -0
  278. package/build/client/_app/immutable/chunks/Pw0jDB7M.js.gz +0 -0
  279. package/build/client/_app/immutable/entry/app.CNaTe-zm.js +0 -2
  280. package/build/client/_app/immutable/entry/app.CNaTe-zm.js.br +0 -0
  281. package/build/client/_app/immutable/entry/app.CNaTe-zm.js.gz +0 -0
  282. package/build/client/_app/immutable/entry/start.hxYnjcDu.js +0 -1
  283. package/build/client/_app/immutable/entry/start.hxYnjcDu.js.br +0 -0
  284. package/build/client/_app/immutable/entry/start.hxYnjcDu.js.gz +0 -0
  285. package/build/client/_app/immutable/nodes/0.C3ELOf4c.js +0 -7
  286. package/build/client/_app/immutable/nodes/0.C3ELOf4c.js.br +0 -0
  287. package/build/client/_app/immutable/nodes/0.C3ELOf4c.js.gz +0 -0
  288. package/build/client/_app/immutable/nodes/1.Fqso94b3.js.br +0 -0
  289. package/build/client/_app/immutable/nodes/1.Fqso94b3.js.gz +0 -0
  290. package/build/client/_app/immutable/nodes/2.BusCVJWk.js.br +0 -0
  291. package/build/client/_app/immutable/nodes/2.BusCVJWk.js.gz +0 -0
  292. package/build/client/_app/immutable/nodes/3.DUlpocIc.js.br +0 -0
  293. package/build/client/_app/immutable/nodes/3.DUlpocIc.js.gz +0 -0
  294. package/build/client/_app/immutable/nodes/4.BSVqdrrD.js.br +0 -0
  295. package/build/client/_app/immutable/nodes/4.BSVqdrrD.js.gz +0 -0
  296. package/build/client/_app/immutable/nodes/5.Cfj35gpY.js.br +0 -0
  297. package/build/client/_app/immutable/nodes/5.Cfj35gpY.js.gz +0 -0
  298. package/build/client/_app/immutable/nodes/6.CG4eKRH0.js.br +0 -0
  299. package/build/client/_app/immutable/nodes/6.CG4eKRH0.js.gz +0 -0
  300. package/build/client/_app/immutable/nodes/7.DHilxD1o.js.br +0 -0
  301. package/build/client/_app/immutable/nodes/7.DHilxD1o.js.gz +0 -0
  302. package/build/client/_app/immutable/nodes/8.BjKgvSie.js.br +0 -0
  303. package/build/client/_app/immutable/nodes/8.BjKgvSie.js.gz +0 -0
  304. package/build/client/_app/immutable/nodes/9.BRT6HOXB.js.br +0 -0
  305. package/build/client/_app/immutable/nodes/9.BRT6HOXB.js.gz +0 -0
  306. package/build/server/chunks/1-Bw5KlAjL.js +0 -9
  307. package/build/server/chunks/6-BZ0enR6b.js +0 -9
  308. package/build/server/chunks/7-Lg8imTZn.js +0 -9
  309. package/build/server/chunks/8-DKs4yOL7.js +0 -9
  310. package/build/server/chunks/8-DKs4yOL7.js.map +0 -1
  311. package/build/server/chunks/9-UNmpUWDY.js +0 -9
  312. package/build/server/chunks/9-UNmpUWDY.js.map +0 -1
  313. package/build/server/chunks/Button-B5dU-ntz.js.map +0 -1
  314. package/build/server/chunks/Icon-C7Ml3GX6.js.map +0 -1
  315. package/build/server/chunks/Input-CPGO0sbS.js.map +0 -1
  316. package/build/server/chunks/Pill-CcrtCejm.js.map +0 -1
  317. package/build/server/chunks/Shimmer-C5jkvGr1.js.map +0 -1
  318. package/build/server/chunks/_layout.svelte-noB4j-v2.js.map +0 -1
  319. package/build/server/chunks/_page.svelte-C60lAagP.js.map +0 -1
  320. package/build/server/chunks/_page.svelte-DnTpPnPR.js.map +0 -1
  321. package/build/server/chunks/_server.ts-5wx4ZppI.js.map +0 -1
  322. package/build/server/chunks/_server.ts-B1z0q6qZ.js.map +0 -1
  323. package/build/server/chunks/_server.ts-Bt7EAfjo.js.map +0 -1
  324. package/build/server/chunks/_server.ts-CKXVBbwb.js.map +0 -1
  325. package/build/server/chunks/_server.ts-CgHc1Zpx.js.map +0 -1
  326. package/build/server/chunks/_server.ts-CyjDrcZN.js.map +0 -1
  327. package/build/server/chunks/_server.ts-DZ5naqSL.js.map +0 -1
  328. package/build/server/chunks/client2-DDP30_vY.js +0 -7
  329. package/build/server/chunks/opencode-db-path-BwaPufWf.js +0 -411
  330. package/build/server/chunks/opencode-db-path-BwaPufWf.js.map +0 -1
  331. package/build/server/chunks/pty-manager-RmhVe2Ez.js.map +0 -1
  332. package/build/server/chunks/qwen-reader-2fTFuC_D.js +0 -622
  333. package/build/server/chunks/qwen-reader-2fTFuC_D.js.map +0 -1
  334. package/build/server/chunks/registry-DzJj2E6I.js.map +0 -1
  335. package/build/server/chunks/root-xvQIR1Bt.js.map +0 -1
  336. package/build/server/chunks/stores-C-LqoonT.js.map +0 -1
  337. /package/build/client/_app/immutable/assets/{8.BhoBXADL.css → 10.BhoBXADL.css} +0 -0
  338. /package/build/client/_app/immutable/assets/{8.BhoBXADL.css.br → 10.BhoBXADL.css.br} +0 -0
  339. /package/build/client/_app/immutable/assets/{8.BhoBXADL.css.gz → 10.BhoBXADL.css.gz} +0 -0
  340. /package/build/client/_app/immutable/assets/{9.v5KA95xm.css → 11.v5KA95xm.css} +0 -0
  341. /package/build/client/_app/immutable/assets/{9.v5KA95xm.css.br → 11.v5KA95xm.css.br} +0 -0
  342. /package/build/client/_app/immutable/assets/{9.v5KA95xm.css.gz → 11.v5KA95xm.css.gz} +0 -0
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Amp session reader — listing + conversation retrieval.
3
+ *
4
+ * Amp stores one JSON document per thread at:
5
+ * ~/.local/share/amp/threads/T-<id>.json
6
+ *
7
+ * Document shape:
8
+ * { id, title, created, messages: [{role, content}],
9
+ * meta: { traces: [{endTime}] },
10
+ * env: { initial: { trees: [{displayName}] } } }
11
+ *
12
+ * `content` is either a plain string or an array of Anthropic-style blocks
13
+ * (text / thinking / tool_use / tool_result), so we handle both paths.
14
+ * The file is a single JSON document — skip files larger than 64 MB.
15
+ */
16
+
17
+ import type { ConversationMessage, MessagePart, ProjectGroup, SessionInfo } from '$lib/types';
18
+
19
+ import * as crypto from 'crypto';
20
+ import * as fs from 'fs';
21
+ import { homedir } from 'os';
22
+ import * as path from 'path';
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Constants
26
+ // ---------------------------------------------------------------------------
27
+
28
+ const AMP_THREADS = path.join(homedir(), '.local', 'share', 'amp', 'threads');
29
+
30
+ /** Single JSON document — skip (do not truncate) if larger than this. */
31
+ const MAX_FILE_BYTES = 64 * 1024 * 1024;
32
+
33
+ /** Pattern for valid thread file names: T-<id>.json */
34
+ const THREAD_FILE_RE = /^T-(.+)\.json$/;
35
+
36
+ /** Only allow these chars in a sessionId used to build a path. */
37
+ const SESSION_ID_RE = /^[A-Za-z0-9_.-]+$/;
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Public API
41
+ // ---------------------------------------------------------------------------
42
+
43
+ /**
44
+ * Return sessions whose thread file mtime is within `thresholdMs` of now —
45
+ * i.e. sessions that are currently (or very recently) active.
46
+ */
47
+ export function detectActiveAmpSessions(
48
+ thresholdMs: number
49
+ ): { cwd: string; id: string; startedAt: number }[] {
50
+ const cutoff = Date.now() - thresholdMs;
51
+ const out: { cwd: string; id: string; startedAt: number }[] = [];
52
+ for (const filePath of collectThreadFiles()) {
53
+ try {
54
+ const stat = fs.statSync(filePath);
55
+ if (stat.mtimeMs < cutoff) {
56
+ continue;
57
+ }
58
+ const doc = readThreadDoc(filePath);
59
+ if (!doc) {
60
+ continue;
61
+ }
62
+ const id = threadId(filePath, doc);
63
+ const cwd = projectCwd(doc);
64
+ if (id && cwd) {
65
+ out.push({ cwd, id, startedAt: stat.birthtimeMs });
66
+ }
67
+ } catch {
68
+ // skip unreadable files
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+
74
+ /**
75
+ * Return the conversation messages for a given Amp thread ID.
76
+ * Mirrors the pagination pattern from codex-reader / qwen-reader.
77
+ */
78
+ export function getAmpConversation(
79
+ sessionId: string,
80
+ offset = 0,
81
+ limit = 200
82
+ ): ConversationMessage[] {
83
+ if (!SESSION_ID_RE.test(sessionId)) {
84
+ return [];
85
+ }
86
+ const filePath = path.join(AMP_THREADS, `T-${sessionId}.json`);
87
+ if (!fs.existsSync(filePath)) {
88
+ return [];
89
+ }
90
+ try {
91
+ const doc = readThreadDoc(filePath);
92
+ if (!doc) {
93
+ return [];
94
+ }
95
+ const rawMessages = Array.isArray(doc.messages) ? (doc.messages as unknown[]) : [];
96
+ const messages: ConversationMessage[] = [];
97
+ let idx = 0;
98
+ for (const raw of rawMessages) {
99
+ const msg = ampMessageToConversationMessage(raw, idx);
100
+ if (msg) {
101
+ messages.push(msg);
102
+ idx++;
103
+ }
104
+ }
105
+ if (offset === 0 && messages.length > limit) {
106
+ let startIdx = messages.length - limit;
107
+ while (startIdx > 0 && messages[startIdx]?.role !== 'user') {
108
+ startIdx--;
109
+ }
110
+ return messages.slice(startIdx);
111
+ }
112
+ return messages.slice(offset, offset + limit);
113
+ } catch (err) {
114
+ console.error('[amp] Failed to read conversation:', err);
115
+ return [];
116
+ }
117
+ }
118
+
119
+ /**
120
+ * List all Amp threads grouped by project (env.initial.trees[0].displayName),
121
+ * sorted by most-recently-modified first.
122
+ */
123
+ export function listAmpProjects(): ProjectGroup[] {
124
+ const byCwd = new Map<string, SessionInfo[]>();
125
+ for (const filePath of collectThreadFiles()) {
126
+ let stat: fs.Stats;
127
+ try {
128
+ stat = fs.statSync(filePath);
129
+ } catch {
130
+ continue;
131
+ }
132
+ const doc = readThreadDoc(filePath);
133
+ if (!doc) {
134
+ continue;
135
+ }
136
+ const id = threadId(filePath, doc);
137
+ if (!id) {
138
+ continue;
139
+ }
140
+ const cwd = projectCwd(doc) || id;
141
+ const modified = lastModified(doc, stat);
142
+ const created =
143
+ typeof doc.created === 'string' && doc.created ? doc.created : stat.birthtime.toISOString();
144
+ const rawMessages = Array.isArray(doc.messages) ? (doc.messages as unknown[]) : [];
145
+ const session: SessionInfo = {
146
+ created,
147
+ gitBranch: '',
148
+ id,
149
+ messageCount: rawMessages.length,
150
+ modified,
151
+ projectPath: cwd,
152
+ source: 'amp' as const,
153
+ summary: '',
154
+ title: cleanTitle(typeof doc.title === 'string' ? doc.title : ''),
155
+ };
156
+ const bucket = byCwd.get(cwd);
157
+ if (bucket) {
158
+ bucket.push(session);
159
+ } else {
160
+ byCwd.set(cwd, [session]);
161
+ }
162
+ }
163
+
164
+ const projects: ProjectGroup[] = [];
165
+ for (const [cwd, sessions] of byCwd) {
166
+ sessions.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
167
+ const segments = cwd.split('/').filter(Boolean);
168
+ projects.push({
169
+ fullPath: cwd,
170
+ id: shortHash(cwd),
171
+ lastModified: sessions[0]?.modified ?? '',
172
+ name: segments.slice(-2).join('/') || cwd,
173
+ sessionCount: sessions.length,
174
+ sessions,
175
+ });
176
+ }
177
+ return projects.sort(
178
+ (a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime()
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Parse the Amp thread JSON file at `filePath` and return the full list of
184
+ * ConversationMessage — no pagination or tail-limit applied.
185
+ * Returns `[]` on any error (missing file, malformed JSON, oversized file).
186
+ */
187
+ export function parseAmpSessionFile(filePath: string): ConversationMessage[] {
188
+ try {
189
+ const doc = readThreadDoc(filePath);
190
+ if (!doc) {
191
+ return [];
192
+ }
193
+ const rawMessages = Array.isArray(doc.messages) ? (doc.messages as unknown[]) : [];
194
+ const messages: ConversationMessage[] = [];
195
+ let idx = 0;
196
+ for (const raw of rawMessages) {
197
+ const msg = ampMessageToConversationMessage(raw, idx);
198
+ if (msg) {
199
+ messages.push(msg);
200
+ idx++;
201
+ }
202
+ }
203
+ return messages;
204
+ } catch {
205
+ return [];
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Return the absolute path of the Amp thread file for `sessionId`, or `null`
211
+ * if the session ID is invalid or the file does not exist.
212
+ */
213
+ export function resolveAmpSessionFile(sessionId: string): null | string {
214
+ if (!SESSION_ID_RE.test(sessionId)) {
215
+ return null;
216
+ }
217
+ const filePath = path.join(AMP_THREADS, `T-${sessionId}.json`);
218
+ return fs.existsSync(filePath) ? filePath : null;
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Block → MessagePart mapping (Anthropic-style blocks)
223
+ // ---------------------------------------------------------------------------
224
+
225
+ /** Map one Anthropic-style content block to a MessagePart, or null to skip. */
226
+ function ampBlockToPart(block: Record<string, unknown>): MessagePart | null {
227
+ switch (block.type) {
228
+ case 'text':
229
+ return { content: typeof block.text === 'string' ? block.text : '', type: 'text' };
230
+ case 'thinking':
231
+ return {
232
+ content: typeof block.thinking === 'string' ? block.thinking : '',
233
+ type: 'thinking',
234
+ };
235
+ case 'tool_result': {
236
+ const output = extractToolResultText(block.content);
237
+ return {
238
+ isError: typeof block.is_error === 'boolean' ? block.is_error : false,
239
+ output: output.slice(0, 2000),
240
+ toolUseId: typeof block.tool_use_id === 'string' ? block.tool_use_id : '',
241
+ type: 'tool_result',
242
+ };
243
+ }
244
+ case 'tool_use':
245
+ return {
246
+ id: typeof block.id === 'string' ? block.id : '',
247
+ input: isRecord(block.input) ? block.input : {},
248
+ toolName: typeof block.name === 'string' ? block.name : 'tool',
249
+ type: 'tool_use',
250
+ };
251
+ default:
252
+ return null;
253
+ }
254
+ }
255
+
256
+ /** Map one raw Amp message object to a ConversationMessage, or null to skip. */
257
+ function ampMessageToConversationMessage(raw: unknown, index: number): ConversationMessage | null {
258
+ if (!isRecord(raw)) {
259
+ return null;
260
+ }
261
+ const role = raw.role;
262
+ if (role !== 'user' && role !== 'assistant') {
263
+ return null;
264
+ }
265
+ const parts = contentToParts(raw.content);
266
+ if (parts.length === 0) {
267
+ return null;
268
+ }
269
+ const msgRole: 'assistant' | 'user' = role === 'user' ? 'user' : 'assistant';
270
+ return {
271
+ id: `amp-${msgRole}-${index}`,
272
+ parts,
273
+ role: msgRole,
274
+ timestamp: '',
275
+ };
276
+ }
277
+
278
+ // ---------------------------------------------------------------------------
279
+ // File I/O helpers
280
+ // ---------------------------------------------------------------------------
281
+
282
+ function cleanTitle(raw: string): string {
283
+ const first = raw.replace(/\s+/g, ' ').trim().split('\n')[0]?.trim() ?? '';
284
+ if (!first) {
285
+ return 'Untitled Session';
286
+ }
287
+ return first.length > 80 ? `${first.slice(0, 77)}...` : first;
288
+ }
289
+
290
+ /** Collect all T-*.json files under the Amp threads directory, sorted by mtime desc. */
291
+ function collectThreadFiles(): string[] {
292
+ let entries: fs.Dirent[];
293
+ try {
294
+ entries = fs.readdirSync(AMP_THREADS, { withFileTypes: true });
295
+ } catch {
296
+ return [];
297
+ }
298
+ const files: { mtime: number; path: string }[] = [];
299
+ for (const entry of entries) {
300
+ if (!entry.isFile() || !THREAD_FILE_RE.test(entry.name)) {
301
+ continue;
302
+ }
303
+ const full = path.join(AMP_THREADS, entry.name);
304
+ try {
305
+ const stat = fs.statSync(full);
306
+ files.push({ mtime: stat.mtimeMs, path: full });
307
+ } catch {
308
+ // skip
309
+ }
310
+ }
311
+ files.sort((a, b) => b.mtime - a.mtime);
312
+ return files.map((f) => f.path);
313
+ }
314
+
315
+ /** Map a `content` field (string or block array) to MessagePart[]. */
316
+ function contentToParts(content: unknown): MessagePart[] {
317
+ if (typeof content === 'string' && content) {
318
+ return [{ content, type: 'text' }];
319
+ }
320
+ if (!Array.isArray(content)) {
321
+ return [];
322
+ }
323
+ const parts: MessagePart[] = [];
324
+ for (const item of content as unknown[]) {
325
+ if (!isRecord(item)) {
326
+ continue;
327
+ }
328
+ const part = ampBlockToPart(item);
329
+ if (part) {
330
+ parts.push(part);
331
+ }
332
+ }
333
+ return parts;
334
+ }
335
+
336
+ // ---------------------------------------------------------------------------
337
+ // Metadata helpers
338
+ // ---------------------------------------------------------------------------
339
+
340
+ /** Extract plain text from a tool_result content field (string or text-block array). */
341
+ function extractToolResultText(content: unknown): string {
342
+ if (typeof content === 'string') {
343
+ return content;
344
+ }
345
+ if (!Array.isArray(content)) {
346
+ return '';
347
+ }
348
+ return (content as unknown[])
349
+ .filter((c): c is Record<string, unknown> => isRecord(c) && c.type === 'text')
350
+ .map((c) => (typeof c.text === 'string' ? c.text : ''))
351
+ .join('\n');
352
+ }
353
+
354
+ /** Narrow an unknown value to a plain object with string keys. */
355
+ function isRecord(value: unknown): value is Record<string, unknown> {
356
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
357
+ }
358
+
359
+ /**
360
+ * Derive the modified timestamp: last trace endTime or file mtime.
361
+ * Amp records execution traces in meta.traces[].endTime (ISO string or ms number).
362
+ */
363
+ function lastModified(doc: Record<string, unknown>, stat: fs.Stats): string {
364
+ if (isRecord(doc.meta)) {
365
+ const traces = doc.meta.traces;
366
+ if (Array.isArray(traces) && traces.length > 0) {
367
+ const last: unknown = traces[traces.length - 1];
368
+ if (isRecord(last)) {
369
+ const et = last.endTime;
370
+ if (typeof et === 'string' && et) {
371
+ return et;
372
+ }
373
+ if (typeof et === 'number' && et > 0) {
374
+ return new Date(et).toISOString();
375
+ }
376
+ }
377
+ }
378
+ }
379
+ return stat.mtime.toISOString();
380
+ }
381
+
382
+ /**
383
+ * Extract the project cwd/name from env.initial.trees[0].displayName.
384
+ * May be an absolute path or just a display name — surface it as-is.
385
+ */
386
+ function projectCwd(doc: Record<string, unknown>): string {
387
+ if (isRecord(doc.env) && isRecord(doc.env.initial)) {
388
+ const trees = doc.env.initial.trees;
389
+ if (Array.isArray(trees) && trees.length > 0 && isRecord(trees[0])) {
390
+ const dn = trees[0].displayName;
391
+ if (typeof dn === 'string' && dn) {
392
+ return dn;
393
+ }
394
+ }
395
+ }
396
+ return '';
397
+ }
398
+
399
+ /**
400
+ * Read and parse a thread JSON file.
401
+ * Returns null if the file is too large or malformed.
402
+ */
403
+ function readThreadDoc(filePath: string): null | Record<string, unknown> {
404
+ try {
405
+ if (fs.statSync(filePath).size > MAX_FILE_BYTES) {
406
+ return null;
407
+ }
408
+ const parsed: unknown = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
409
+ return isRecord(parsed) ? parsed : null;
410
+ } catch {
411
+ return null;
412
+ }
413
+ }
414
+
415
+ function shortHash(input: string): string {
416
+ return crypto.createHash('sha256').update(input).digest('hex').slice(0, 8);
417
+ }
418
+
419
+ /**
420
+ * Derive the canonical session id from the filename stem (the part after
421
+ * "T-" in "T-<id>.json"). This must agree with what getAmpConversation
422
+ * expects: it reconstructs the file path as `T-${sessionId}.json`, so the
423
+ * id returned here must NOT include the leading "T-".
424
+ *
425
+ * The doc's `.id` field is accepted only as a last-resort fallback when the
426
+ * filename doesn't match the expected pattern — using doc.id first was the
427
+ * original bug (doc.id may contain or omit the "T-" prefix differently from
428
+ * the filename, causing a mismatch that produced zero messages on retrieval).
429
+ */
430
+ function threadId(filePath: string, doc: Record<string, unknown>): string {
431
+ const m = THREAD_FILE_RE.exec(path.basename(filePath));
432
+ if (m?.[1]) {
433
+ return m[1];
434
+ }
435
+ if (typeof doc.id === 'string' && doc.id) {
436
+ return doc.id;
437
+ }
438
+ return '';
439
+ }