@prismshadow/penguin-server 0.2.13 → 0.2.15

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 (428) hide show
  1. package/dist/api/types.d.ts +2722 -159
  2. package/dist/api/types.js +3 -1
  3. package/dist/auth-token.d.ts +22 -1
  4. package/dist/auth-token.js +2 -2
  5. package/dist/auth-token.js.map +1 -1
  6. package/dist/benchmark-package.d.ts +39 -0
  7. package/dist/benchmark-package.js +97 -0
  8. package/dist/benchmark-package.js.map +1 -0
  9. package/dist/chunk-54E64LWB.js +63 -0
  10. package/dist/chunk-54E64LWB.js.map +1 -0
  11. package/dist/{chunk-3I2XOPJB.js → chunk-5Z4UCHDB.js} +95 -78
  12. package/dist/chunk-5Z4UCHDB.js.map +1 -0
  13. package/dist/chunk-HX3WBUYX.js +18 -0
  14. package/dist/chunk-HX3WBUYX.js.map +1 -0
  15. package/dist/chunk-JKJXQTHH.js +19 -0
  16. package/dist/chunk-JKJXQTHH.js.map +1 -0
  17. package/dist/{chunk-A3QANMU5.js → chunk-NVWAYYRX.js} +279 -9
  18. package/dist/chunk-NVWAYYRX.js.map +1 -0
  19. package/dist/chunk-Q4ON2L6E.js +52 -0
  20. package/dist/chunk-Q4ON2L6E.js.map +1 -0
  21. package/dist/chunk-QFV3ERQO.js +20 -0
  22. package/dist/chunk-QFV3ERQO.js.map +1 -0
  23. package/dist/index.js +69394 -36621
  24. package/dist/index.js.map +1 -1
  25. package/dist/install.ps1 +16 -6
  26. package/dist/install.sh +24 -10
  27. package/dist/machine-status.js +1 -1
  28. package/dist/plugin/index.d.ts +1061 -272
  29. package/dist/reset-admin-password.js +3 -2
  30. package/dist/reset-admin-password.js.map +1 -1
  31. package/dist/secret-file.js +3 -14
  32. package/dist/secret-file.js.map +1 -1
  33. package/dist/version-report.d.ts +3 -0
  34. package/dist/version-report.js +1 -1
  35. package/package.json +12 -6
  36. package/web-dist/assets/KaTeX_Size3-Regular-gV2CO0n9.woff2 +0 -0
  37. package/web-dist/assets/abnfDiagram-VCTEODGH-CKWh4hoA.js +1 -0
  38. package/web-dist/assets/{addon-clipboard-DrZY90Ks.js → addon-clipboard-DxLqat7q.js} +1 -1
  39. package/web-dist/assets/{addon-fit-CtEAdAax.js → addon-fit-B8oPGPkW.js} +1 -1
  40. package/web-dist/assets/{addon-web-links-DJL13cYY.js → addon-web-links-C0W5TcK0.js} +1 -1
  41. package/web-dist/assets/arc-Dp9EkaAH.js +1 -0
  42. package/web-dist/assets/architectureDiagram-5GKGNRK7-BQ3LUcle.js +36 -0
  43. package/web-dist/assets/blockDiagram-I7D4REHJ-CZzyU0Jj.js +129 -0
  44. package/web-dist/assets/c4Diagram-7LVT6UL2-Qps3jeAu.js +38 -0
  45. package/web-dist/assets/channel--PblgLlC.js +1 -0
  46. package/web-dist/assets/chunk-2Q5K7J3B-CQMntzuX.js +1 -0
  47. package/web-dist/assets/chunk-5VM5RSS4-2H2ZJAte.js +15 -0
  48. package/web-dist/assets/chunk-F27PBJKO-B30xCNBv.js +1 -0
  49. package/web-dist/assets/chunk-IMKFNOWR-Cyfx4zDs.js +231 -0
  50. package/web-dist/assets/chunk-JWPE2WC7-DADUytTh.js +1 -0
  51. package/web-dist/assets/chunk-POPQ4Y6H-9bjsAxLS.js +1 -0
  52. package/web-dist/assets/chunk-SVP7TREG-B9xO1VpN.js +88 -0
  53. package/web-dist/assets/chunk-TICWLB2K-B6oDkrep.js +206 -0
  54. package/web-dist/assets/chunk-XXDRQBXY-BbU8DR4B.js +1 -0
  55. package/web-dist/assets/classDiagram-ZZMXUADV-mn8tbuqa.js +1 -0
  56. package/web-dist/assets/classDiagram-v2-VYDZK3BY-mn8tbuqa.js +1 -0
  57. package/web-dist/assets/cose-bilkent-JH36ORCC-pkbuyec-.js +1 -0
  58. package/web-dist/assets/cynefin-OW5HDTMX-DU9YQQnc.js +166 -0
  59. package/web-dist/assets/cynefinDiagram-5FMLGOSQ-3a3XuhQq.js +62 -0
  60. package/web-dist/assets/cytoscape.esm-BB4DxJjf.js +321 -0
  61. package/web-dist/assets/dagre-GXQ25YYZ-BfZ9C5CZ.js +4 -0
  62. package/web-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  63. package/web-dist/assets/diagram-S7CK7UJ4-BoGhVBMn.js +30 -0
  64. package/web-dist/assets/diagram-UQ7AKVKN-zE67quty.js +41 -0
  65. package/web-dist/assets/diagram-VSXAHHWV-NihoXeXm.js +3 -0
  66. package/web-dist/assets/diagram-VX7I27RA-1627np0S.js +24 -0
  67. package/web-dist/assets/diagram-Z3DM3KII-Ddg_bUan.js +24 -0
  68. package/web-dist/assets/ebnfDiagram-PWID7BFC-CmPUOM4j.js +1 -0
  69. package/web-dist/assets/erDiagram-RLTQ6QDP-DiTnEK72.js +99 -0
  70. package/web-dist/assets/flowDiagram-HODETNUW-mGQ38tRM.js +168 -0
  71. package/web-dist/assets/ganttDiagram-EL5Y4UJY-DU7MlzpW.js +292 -0
  72. package/web-dist/assets/gitGraphDiagram-WWUBYQGX-CRE_3vjl.js +106 -0
  73. package/web-dist/assets/highlighter-CzfXQ6yd.js +2 -0
  74. package/web-dist/assets/{highlighter-core-CrBdruEx.js → highlighter-core-B5CvXcEK.js} +7 -7
  75. package/web-dist/assets/{highlighter.worker-CL6f9Fzw.js → highlighter.worker-D6D9fPma.js} +9 -9
  76. package/web-dist/assets/ibm-plex-sans-condensed-latin-600-normal-CRd5VyFf.woff2 +0 -0
  77. package/web-dist/assets/ibm-plex-sans-condensed-latin-ext-600-normal-CBdNZ9Ci.woff2 +0 -0
  78. package/web-dist/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
  79. package/web-dist/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
  80. package/web-dist/assets/index-BdG4qRyI.js +1275 -0
  81. package/web-dist/assets/index-W-xYFoIm.css +1 -0
  82. package/web-dist/assets/infoDiagram-27XIBGKW-Cdo6Ar-a.js +2 -0
  83. package/web-dist/assets/init-Gi6I4Gst.js +1 -0
  84. package/web-dist/assets/ishikawaDiagram-5VMMS53U-C27pgect.js +70 -0
  85. package/web-dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  86. package/web-dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  87. package/web-dist/assets/journeyDiagram-3NMN7TZE-CVxtKpLG.js +139 -0
  88. package/web-dist/assets/kanban-definition-UXKFOSKX-DWA31Da7.js +89 -0
  89. package/web-dist/assets/layout-DWKCU9PO.js +1 -0
  90. package/web-dist/assets/linear-BwCthj_k.js +1 -0
  91. package/web-dist/assets/mermaid.core-BcTrmPOv.js +310 -0
  92. package/web-dist/assets/mindmap-definition-YA3MSWOX-BLEDhbn1.js +96 -0
  93. package/web-dist/assets/misans-400-100-DHkMCix2.woff2 +0 -0
  94. package/web-dist/assets/misans-400-101-CwgSLsmc.woff2 +0 -0
  95. package/web-dist/assets/misans-400-102-BQgefHPQ.woff2 +0 -0
  96. package/web-dist/assets/misans-400-103-CP58Mc_T.woff2 +0 -0
  97. package/web-dist/assets/misans-400-104-Ta_Xu1gd.woff2 +0 -0
  98. package/web-dist/assets/misans-400-105-CDop11AR.woff2 +0 -0
  99. package/web-dist/assets/misans-400-106-Dv8y0ubk.woff2 +0 -0
  100. package/web-dist/assets/misans-400-107-CjnHtp9E.woff2 +0 -0
  101. package/web-dist/assets/misans-400-108-BA8nQUBw.woff2 +0 -0
  102. package/web-dist/assets/misans-400-109-B6uEN0pG.woff2 +0 -0
  103. package/web-dist/assets/misans-400-110-BQqnShrY.woff2 +0 -0
  104. package/web-dist/assets/misans-400-111-CHB-Jj5X.woff2 +0 -0
  105. package/web-dist/assets/misans-400-112-D1dh4Cjx.woff2 +0 -0
  106. package/web-dist/assets/misans-400-113-Bw_wNCFp.woff2 +0 -0
  107. package/web-dist/assets/misans-400-114-CUb-5IzE.woff2 +0 -0
  108. package/web-dist/assets/misans-400-115-BICOatsO.woff2 +0 -0
  109. package/web-dist/assets/misans-400-116-B3_gmYW6.woff2 +0 -0
  110. package/web-dist/assets/misans-400-117-B8k_y3cv.woff2 +0 -0
  111. package/web-dist/assets/misans-400-118-C-2Cf5C6.woff2 +0 -0
  112. package/web-dist/assets/misans-400-119-CmLP7xnX.woff2 +0 -0
  113. package/web-dist/assets/misans-400-21-DsSSD_Zj.woff2 +0 -0
  114. package/web-dist/assets/misans-400-22-rtkxWOv4.woff2 +0 -0
  115. package/web-dist/assets/misans-400-23-CDDB4M1H.woff2 +0 -0
  116. package/web-dist/assets/misans-400-24-Dqf_XeOL.woff2 +0 -0
  117. package/web-dist/assets/misans-400-25-C4U1tJ5J.woff2 +0 -0
  118. package/web-dist/assets/misans-400-26-CEXOK-nT.woff2 +0 -0
  119. package/web-dist/assets/misans-400-27-BrNOAScF.woff2 +0 -0
  120. package/web-dist/assets/misans-400-28-CPpEnCkG.woff2 +0 -0
  121. package/web-dist/assets/misans-400-29-C9JMVw8g.woff2 +0 -0
  122. package/web-dist/assets/misans-400-30-CD-QimXa.woff2 +0 -0
  123. package/web-dist/assets/misans-400-31-S4k06NbS.woff2 +0 -0
  124. package/web-dist/assets/misans-400-32-zRMBDkz6.woff2 +0 -0
  125. package/web-dist/assets/misans-400-33-sQ_tNZSM.woff2 +0 -0
  126. package/web-dist/assets/misans-400-34-8LEGljja.woff2 +0 -0
  127. package/web-dist/assets/misans-400-35-CxSPyuiU.woff2 +0 -0
  128. package/web-dist/assets/misans-400-36-BY1i4WtO.woff2 +0 -0
  129. package/web-dist/assets/misans-400-37-C0oF42pu.woff2 +0 -0
  130. package/web-dist/assets/misans-400-38-y7xcB90w.woff2 +0 -0
  131. package/web-dist/assets/misans-400-39-C307YgZx.woff2 +0 -0
  132. package/web-dist/assets/misans-400-40-ByZr736f.woff2 +0 -0
  133. package/web-dist/assets/misans-400-41-ChKEw5zV.woff2 +0 -0
  134. package/web-dist/assets/misans-400-42-CD__zJu5.woff2 +0 -0
  135. package/web-dist/assets/misans-400-43-CqNV6_TG.woff2 +0 -0
  136. package/web-dist/assets/misans-400-44-zE-akmW8.woff2 +0 -0
  137. package/web-dist/assets/misans-400-45-Du98otwc.woff2 +0 -0
  138. package/web-dist/assets/misans-400-46-B6JXbEy2.woff2 +0 -0
  139. package/web-dist/assets/misans-400-47-DpqW0kSq.woff2 +0 -0
  140. package/web-dist/assets/misans-400-48-BprON5Q_.woff2 +0 -0
  141. package/web-dist/assets/misans-400-49-N-ct3sN6.woff2 +0 -0
  142. package/web-dist/assets/misans-400-5-ton_4jCN.woff2 +0 -0
  143. package/web-dist/assets/misans-400-50-JgU49P0U.woff2 +0 -0
  144. package/web-dist/assets/misans-400-51-DSS3Moge.woff2 +0 -0
  145. package/web-dist/assets/misans-400-52-BMoXFmwE.woff2 +0 -0
  146. package/web-dist/assets/misans-400-53-BaLMGl4z.woff2 +0 -0
  147. package/web-dist/assets/misans-400-54-CaeSn3OR.woff2 +0 -0
  148. package/web-dist/assets/misans-400-55-BBqrtLxN.woff2 +0 -0
  149. package/web-dist/assets/misans-400-56-DAZ5BnbO.woff2 +0 -0
  150. package/web-dist/assets/misans-400-57-F-n3b0gI.woff2 +0 -0
  151. package/web-dist/assets/misans-400-58-DEUuPQAq.woff2 +0 -0
  152. package/web-dist/assets/misans-400-59-DXP5rhCL.woff2 +0 -0
  153. package/web-dist/assets/misans-400-6-DWCCUO_c.woff2 +0 -0
  154. package/web-dist/assets/misans-400-60-BE6IO6zJ.woff2 +0 -0
  155. package/web-dist/assets/misans-400-61-5Qb1gaxK.woff2 +0 -0
  156. package/web-dist/assets/misans-400-62-D_tJKNAj.woff2 +0 -0
  157. package/web-dist/assets/misans-400-63-hwmne8yB.woff2 +0 -0
  158. package/web-dist/assets/misans-400-64-BGedxReM.woff2 +0 -0
  159. package/web-dist/assets/misans-400-65-BaKPsugb.woff2 +0 -0
  160. package/web-dist/assets/misans-400-66-IdaOMzCz.woff2 +0 -0
  161. package/web-dist/assets/misans-400-67-BdWyS83H.woff2 +0 -0
  162. package/web-dist/assets/misans-400-68-DrZ_1swq.woff2 +0 -0
  163. package/web-dist/assets/misans-400-69-B3jsSD92.woff2 +0 -0
  164. package/web-dist/assets/misans-400-70-D6UZI2Ua.woff2 +0 -0
  165. package/web-dist/assets/misans-400-71-HFxyMCYg.woff2 +0 -0
  166. package/web-dist/assets/misans-400-72-CP5A-yQP.woff2 +0 -0
  167. package/web-dist/assets/misans-400-73-BoD_bu6s.woff2 +0 -0
  168. package/web-dist/assets/misans-400-74-CbJlhZlZ.woff2 +0 -0
  169. package/web-dist/assets/misans-400-75-BsbWuELX.woff2 +0 -0
  170. package/web-dist/assets/misans-400-76-DkwiQhof.woff2 +0 -0
  171. package/web-dist/assets/misans-400-77-6pVHXHnF.woff2 +0 -0
  172. package/web-dist/assets/misans-400-78-CfUF6pih.woff2 +0 -0
  173. package/web-dist/assets/misans-400-79-BCS3Dx4e.woff2 +0 -0
  174. package/web-dist/assets/misans-400-80-BEYSdQ_N.woff2 +0 -0
  175. package/web-dist/assets/misans-400-81-BzL-Gncx.woff2 +0 -0
  176. package/web-dist/assets/misans-400-82-CaENmdUU.woff2 +0 -0
  177. package/web-dist/assets/misans-400-83-Bvq1eBcA.woff2 +0 -0
  178. package/web-dist/assets/misans-400-84-Ctd90hiP.woff2 +0 -0
  179. package/web-dist/assets/misans-400-85-DWuOxfL1.woff2 +0 -0
  180. package/web-dist/assets/misans-400-86-D5niZS5c.woff2 +0 -0
  181. package/web-dist/assets/misans-400-87-DkOIADQJ.woff2 +0 -0
  182. package/web-dist/assets/misans-400-88-CGY4WTcC.woff2 +0 -0
  183. package/web-dist/assets/misans-400-89-CA3eoMTt.woff2 +0 -0
  184. package/web-dist/assets/misans-400-90-CzxR9MYb.woff2 +0 -0
  185. package/web-dist/assets/misans-400-91-Dyr85txc.woff2 +0 -0
  186. package/web-dist/assets/misans-400-97-qEZrCUNe.woff2 +0 -0
  187. package/web-dist/assets/misans-400-cyrillic--hFcG0Xp.woff2 +0 -0
  188. package/web-dist/assets/misans-400-extra-ZRI9n2Hu.woff2 +0 -0
  189. package/web-dist/assets/misans-400-latin-BRDR1WaL.woff2 +0 -0
  190. package/web-dist/assets/misans-400-latin-ext-6xS-MvHW.woff2 +0 -0
  191. package/web-dist/assets/misans-400-vietnamese-D7xD7kBB.woff2 +0 -0
  192. package/web-dist/assets/misans-500-100-BHuGA96E.woff2 +0 -0
  193. package/web-dist/assets/misans-500-101-CDMYUz0c.woff2 +0 -0
  194. package/web-dist/assets/misans-500-102-CWcqYYCV.woff2 +0 -0
  195. package/web-dist/assets/misans-500-103-BE1QSEzY.woff2 +0 -0
  196. package/web-dist/assets/misans-500-104-CDp743BV.woff2 +0 -0
  197. package/web-dist/assets/misans-500-105-y7dY6Foi.woff2 +0 -0
  198. package/web-dist/assets/misans-500-106-CP-kGZ6j.woff2 +0 -0
  199. package/web-dist/assets/misans-500-107-CUc8Hvle.woff2 +0 -0
  200. package/web-dist/assets/misans-500-108-ItN_x8jX.woff2 +0 -0
  201. package/web-dist/assets/misans-500-109-CEtf3R4D.woff2 +0 -0
  202. package/web-dist/assets/misans-500-110-BSZSHYRL.woff2 +0 -0
  203. package/web-dist/assets/misans-500-111-DfdArrjn.woff2 +0 -0
  204. package/web-dist/assets/misans-500-112-DRtNyrQw.woff2 +0 -0
  205. package/web-dist/assets/misans-500-113-CDT7tKuB.woff2 +0 -0
  206. package/web-dist/assets/misans-500-114-CCh4jwL8.woff2 +0 -0
  207. package/web-dist/assets/misans-500-115-DplUgPp0.woff2 +0 -0
  208. package/web-dist/assets/misans-500-116-C7eCklyK.woff2 +0 -0
  209. package/web-dist/assets/misans-500-117-BA0KabyT.woff2 +0 -0
  210. package/web-dist/assets/misans-500-118-V_M0eu2q.woff2 +0 -0
  211. package/web-dist/assets/misans-500-119-Cgf3Hszt.woff2 +0 -0
  212. package/web-dist/assets/misans-500-21-Di6DyR6O.woff2 +0 -0
  213. package/web-dist/assets/misans-500-22-CSnXvtL-.woff2 +0 -0
  214. package/web-dist/assets/misans-500-23-A06Hm9a6.woff2 +0 -0
  215. package/web-dist/assets/misans-500-24-Df97RCik.woff2 +0 -0
  216. package/web-dist/assets/misans-500-25-bOSJ6YXH.woff2 +0 -0
  217. package/web-dist/assets/misans-500-26-C65icgBb.woff2 +0 -0
  218. package/web-dist/assets/misans-500-27-C_GRm0va.woff2 +0 -0
  219. package/web-dist/assets/misans-500-28-CzZkqO0l.woff2 +0 -0
  220. package/web-dist/assets/misans-500-29-BReyeRyX.woff2 +0 -0
  221. package/web-dist/assets/misans-500-30-DzfjlROz.woff2 +0 -0
  222. package/web-dist/assets/misans-500-31-B2nLpgdU.woff2 +0 -0
  223. package/web-dist/assets/misans-500-32-Bz3rHm8X.woff2 +0 -0
  224. package/web-dist/assets/misans-500-33-AU3lZ1vY.woff2 +0 -0
  225. package/web-dist/assets/misans-500-34-CBAWkH-I.woff2 +0 -0
  226. package/web-dist/assets/misans-500-35-VgnGd14P.woff2 +0 -0
  227. package/web-dist/assets/misans-500-36-B2kfXv6A.woff2 +0 -0
  228. package/web-dist/assets/misans-500-37-DhKo8ykb.woff2 +0 -0
  229. package/web-dist/assets/misans-500-38-D8tTxFuc.woff2 +0 -0
  230. package/web-dist/assets/misans-500-39-DTm3aqJQ.woff2 +0 -0
  231. package/web-dist/assets/misans-500-40-C_akwj8_.woff2 +0 -0
  232. package/web-dist/assets/misans-500-41-RVM1JHQW.woff2 +0 -0
  233. package/web-dist/assets/misans-500-42-MVWIN_il.woff2 +0 -0
  234. package/web-dist/assets/misans-500-43-BtLZYNyD.woff2 +0 -0
  235. package/web-dist/assets/misans-500-44-D0QHMl6G.woff2 +0 -0
  236. package/web-dist/assets/misans-500-45-DRlclX7-.woff2 +0 -0
  237. package/web-dist/assets/misans-500-46-BEWswL4N.woff2 +0 -0
  238. package/web-dist/assets/misans-500-47-COSoxWaW.woff2 +0 -0
  239. package/web-dist/assets/misans-500-48-DZAISq3n.woff2 +0 -0
  240. package/web-dist/assets/misans-500-49-KSfi7MW0.woff2 +0 -0
  241. package/web-dist/assets/misans-500-5-h1SBcwuW.woff2 +0 -0
  242. package/web-dist/assets/misans-500-50-CIVMfG11.woff2 +0 -0
  243. package/web-dist/assets/misans-500-51-BdeNBhBL.woff2 +0 -0
  244. package/web-dist/assets/misans-500-52-CEW4e7ex.woff2 +0 -0
  245. package/web-dist/assets/misans-500-53-lmPCsEnt.woff2 +0 -0
  246. package/web-dist/assets/misans-500-54-B_7AqKQW.woff2 +0 -0
  247. package/web-dist/assets/misans-500-55-B-3RtUnH.woff2 +0 -0
  248. package/web-dist/assets/misans-500-56-g6D0e0cW.woff2 +0 -0
  249. package/web-dist/assets/misans-500-57-D5hp5Yqr.woff2 +0 -0
  250. package/web-dist/assets/misans-500-58-ilnDgEKt.woff2 +0 -0
  251. package/web-dist/assets/misans-500-59-DJYXz8tr.woff2 +0 -0
  252. package/web-dist/assets/misans-500-6-uCdpdDQy.woff2 +0 -0
  253. package/web-dist/assets/misans-500-60-B3Iaqx0p.woff2 +0 -0
  254. package/web-dist/assets/misans-500-61-CMxqg5hc.woff2 +0 -0
  255. package/web-dist/assets/misans-500-62-7FY8O2NQ.woff2 +0 -0
  256. package/web-dist/assets/misans-500-63-JP6vEuJf.woff2 +0 -0
  257. package/web-dist/assets/misans-500-64-Cdub62jh.woff2 +0 -0
  258. package/web-dist/assets/misans-500-65-DVHk_mlC.woff2 +0 -0
  259. package/web-dist/assets/misans-500-66-BX39wRtF.woff2 +0 -0
  260. package/web-dist/assets/misans-500-67-BcsepI3X.woff2 +0 -0
  261. package/web-dist/assets/misans-500-68-etUIUjrh.woff2 +0 -0
  262. package/web-dist/assets/misans-500-69-DfhVmnuA.woff2 +0 -0
  263. package/web-dist/assets/misans-500-70-D6dgy6-B.woff2 +0 -0
  264. package/web-dist/assets/misans-500-71-PkeKjcVn.woff2 +0 -0
  265. package/web-dist/assets/misans-500-72-D66Fnb30.woff2 +0 -0
  266. package/web-dist/assets/misans-500-73-jr9z9870.woff2 +0 -0
  267. package/web-dist/assets/misans-500-74-DsCkPKwe.woff2 +0 -0
  268. package/web-dist/assets/misans-500-75-Dkooq6KM.woff2 +0 -0
  269. package/web-dist/assets/misans-500-76-B0sfieHl.woff2 +0 -0
  270. package/web-dist/assets/misans-500-77-8tflq1ji.woff2 +0 -0
  271. package/web-dist/assets/misans-500-78-COKdMbdp.woff2 +0 -0
  272. package/web-dist/assets/misans-500-79-Bm0rBjSF.woff2 +0 -0
  273. package/web-dist/assets/misans-500-80-B9OoAnyy.woff2 +0 -0
  274. package/web-dist/assets/misans-500-81-DsQ9tpfX.woff2 +0 -0
  275. package/web-dist/assets/misans-500-82-VKsL2Tk2.woff2 +0 -0
  276. package/web-dist/assets/misans-500-83-Ce6mfHYD.woff2 +0 -0
  277. package/web-dist/assets/misans-500-84-D7kPSZLm.woff2 +0 -0
  278. package/web-dist/assets/misans-500-85-W5L0cEfd.woff2 +0 -0
  279. package/web-dist/assets/misans-500-86-DukGOEET.woff2 +0 -0
  280. package/web-dist/assets/misans-500-87-BJ_Lok6j.woff2 +0 -0
  281. package/web-dist/assets/misans-500-88-DbJ11zcA.woff2 +0 -0
  282. package/web-dist/assets/misans-500-89-LNKcEq6M.woff2 +0 -0
  283. package/web-dist/assets/misans-500-90-DNDDgSCd.woff2 +0 -0
  284. package/web-dist/assets/misans-500-91-rT8Q0evu.woff2 +0 -0
  285. package/web-dist/assets/misans-500-97-c8zW_WRq.woff2 +0 -0
  286. package/web-dist/assets/misans-500-cyrillic-CLHOGwgx.woff2 +0 -0
  287. package/web-dist/assets/misans-500-extra-CTAMEQ59.woff2 +0 -0
  288. package/web-dist/assets/misans-500-latin-Be606ott.woff2 +0 -0
  289. package/web-dist/assets/misans-500-latin-ext-BzDyL4sU.woff2 +0 -0
  290. package/web-dist/assets/misans-500-vietnamese-DBOLOqZH.woff2 +0 -0
  291. package/web-dist/assets/mona-sans-latin-ext-wght-normal-BqSk0Z3x.woff2 +0 -0
  292. package/web-dist/assets/mona-sans-latin-wght-normal-Pz49MTQZ.woff2 +0 -0
  293. package/web-dist/assets/noto-sans-sc-100-wght-normal-DrqXJETY.woff2 +0 -0
  294. package/web-dist/assets/noto-sans-sc-101-wght-normal-c94LAl5p.woff2 +0 -0
  295. package/web-dist/assets/noto-sans-sc-102-wght-normal-C1RtbCZr.woff2 +0 -0
  296. package/web-dist/assets/noto-sans-sc-103-wght-normal-DGHo20nu.woff2 +0 -0
  297. package/web-dist/assets/noto-sans-sc-104-wght-normal-CJT2ioDJ.woff2 +0 -0
  298. package/web-dist/assets/noto-sans-sc-105-wght-normal-BFoiJwz2.woff2 +0 -0
  299. package/web-dist/assets/noto-sans-sc-106-wght-normal-D6uUHw3w.woff2 +0 -0
  300. package/web-dist/assets/noto-sans-sc-107-wght-normal-kFQzJDLH.woff2 +0 -0
  301. package/web-dist/assets/noto-sans-sc-108-wght-normal-7aXvqIa2.woff2 +0 -0
  302. package/web-dist/assets/noto-sans-sc-109-wght-normal-CnjNbNmw.woff2 +0 -0
  303. package/web-dist/assets/noto-sans-sc-110-wght-normal-D2JBr045.woff2 +0 -0
  304. package/web-dist/assets/noto-sans-sc-111-wght-normal-ClFr5QXM.woff2 +0 -0
  305. package/web-dist/assets/noto-sans-sc-112-wght-normal-CiZxJMyY.woff2 +0 -0
  306. package/web-dist/assets/noto-sans-sc-113-wght-normal-OgQXOX6x.woff2 +0 -0
  307. package/web-dist/assets/noto-sans-sc-114-wght-normal-CRH9SDZu.woff2 +0 -0
  308. package/web-dist/assets/noto-sans-sc-115-wght-normal-BN__2iBG.woff2 +0 -0
  309. package/web-dist/assets/noto-sans-sc-116-wght-normal-vdFVzbO2.woff2 +0 -0
  310. package/web-dist/assets/noto-sans-sc-117-wght-normal-Dsz3vkzU.woff2 +0 -0
  311. package/web-dist/assets/noto-sans-sc-118-wght-normal-BPEb0gM9.woff2 +0 -0
  312. package/web-dist/assets/noto-sans-sc-119-wght-normal-BfzSEbFz.woff2 +0 -0
  313. package/web-dist/assets/noto-sans-sc-21-wght-normal-DIu_1ZBI.woff2 +0 -0
  314. package/web-dist/assets/noto-sans-sc-22-wght-normal-VXjdYcT-.woff2 +0 -0
  315. package/web-dist/assets/noto-sans-sc-23-wght-normal-4HrHKhpL.woff2 +0 -0
  316. package/web-dist/assets/noto-sans-sc-24-wght-normal-B58DWgHS.woff2 +0 -0
  317. package/web-dist/assets/noto-sans-sc-25-wght-normal-C3Jm6l7O.woff2 +0 -0
  318. package/web-dist/assets/noto-sans-sc-26-wght-normal-YNOygvr_.woff2 +0 -0
  319. package/web-dist/assets/noto-sans-sc-27-wght-normal-BP2pEGQH.woff2 +0 -0
  320. package/web-dist/assets/noto-sans-sc-28-wght-normal-BWPKDbtH.woff2 +0 -0
  321. package/web-dist/assets/noto-sans-sc-29-wght-normal-45aVmHn_.woff2 +0 -0
  322. package/web-dist/assets/noto-sans-sc-30-wght-normal-B8_s30jZ.woff2 +0 -0
  323. package/web-dist/assets/noto-sans-sc-31-wght-normal-DW0t445S.woff2 +0 -0
  324. package/web-dist/assets/noto-sans-sc-32-wght-normal-ShbWPcei.woff2 +0 -0
  325. package/web-dist/assets/noto-sans-sc-33-wght-normal-BOTZYTjM.woff2 +0 -0
  326. package/web-dist/assets/noto-sans-sc-34-wght-normal-BF1rqDSt.woff2 +0 -0
  327. package/web-dist/assets/noto-sans-sc-35-wght-normal-Bosspiyr.woff2 +0 -0
  328. package/web-dist/assets/noto-sans-sc-36-wght-normal-CtU9CyKw.woff2 +0 -0
  329. package/web-dist/assets/noto-sans-sc-37-wght-normal-ghDiyiuv.woff2 +0 -0
  330. package/web-dist/assets/noto-sans-sc-38-wght-normal-4Nz8k_dt.woff2 +0 -0
  331. package/web-dist/assets/noto-sans-sc-39-wght-normal-Ddtm1XVC.woff2 +0 -0
  332. package/web-dist/assets/noto-sans-sc-4-wght-normal-BRbPMj-C.woff2 +0 -0
  333. package/web-dist/assets/noto-sans-sc-40-wght-normal-BVn4-kgX.woff2 +0 -0
  334. package/web-dist/assets/noto-sans-sc-41-wght-normal-CZqajZnl.woff2 +0 -0
  335. package/web-dist/assets/noto-sans-sc-42-wght-normal-CQ4lY28u.woff2 +0 -0
  336. package/web-dist/assets/noto-sans-sc-43-wght-normal-psppu0d8.woff2 +0 -0
  337. package/web-dist/assets/noto-sans-sc-44-wght-normal-cbKJlTUe.woff2 +0 -0
  338. package/web-dist/assets/noto-sans-sc-45-wght-normal-MKIEVRIC.woff2 +0 -0
  339. package/web-dist/assets/noto-sans-sc-46-wght-normal-CErGc6Mt.woff2 +0 -0
  340. package/web-dist/assets/noto-sans-sc-47-wght-normal-C5Kgg1_m.woff2 +0 -0
  341. package/web-dist/assets/noto-sans-sc-48-wght-normal-DFMjDDY6.woff2 +0 -0
  342. package/web-dist/assets/noto-sans-sc-49-wght-normal-B7l_3BZr.woff2 +0 -0
  343. package/web-dist/assets/noto-sans-sc-5-wght-normal-DI846rD9.woff2 +0 -0
  344. package/web-dist/assets/noto-sans-sc-50-wght-normal-C5KfAmFp.woff2 +0 -0
  345. package/web-dist/assets/noto-sans-sc-51-wght-normal-C2bq6hC8.woff2 +0 -0
  346. package/web-dist/assets/noto-sans-sc-52-wght-normal-P18e_Y0j.woff2 +0 -0
  347. package/web-dist/assets/noto-sans-sc-53-wght-normal-Bgkuo2tF.woff2 +0 -0
  348. package/web-dist/assets/noto-sans-sc-54-wght-normal-DL5lmlUd.woff2 +0 -0
  349. package/web-dist/assets/noto-sans-sc-55-wght-normal-BV_Oy6IF.woff2 +0 -0
  350. package/web-dist/assets/noto-sans-sc-56-wght-normal-B4L7Hj8f.woff2 +0 -0
  351. package/web-dist/assets/noto-sans-sc-57-wght-normal-DU8YBsDj.woff2 +0 -0
  352. package/web-dist/assets/noto-sans-sc-58-wght-normal-CE0BKS9u.woff2 +0 -0
  353. package/web-dist/assets/noto-sans-sc-59-wght-normal-Azv2Ku9_.woff2 +0 -0
  354. package/web-dist/assets/noto-sans-sc-6-wght-normal-ozUCEY9O.woff2 +0 -0
  355. package/web-dist/assets/noto-sans-sc-60-wght-normal-C1lngC61.woff2 +0 -0
  356. package/web-dist/assets/noto-sans-sc-61-wght-normal-BxWkGF5M.woff2 +0 -0
  357. package/web-dist/assets/noto-sans-sc-62-wght-normal-CXXMAq-5.woff2 +0 -0
  358. package/web-dist/assets/noto-sans-sc-63-wght-normal-4La5uKvS.woff2 +0 -0
  359. package/web-dist/assets/noto-sans-sc-64-wght-normal-CbIuD2Eg.woff2 +0 -0
  360. package/web-dist/assets/noto-sans-sc-65-wght-normal-BGqvKda2.woff2 +0 -0
  361. package/web-dist/assets/noto-sans-sc-66-wght-normal-BvNozWOY.woff2 +0 -0
  362. package/web-dist/assets/noto-sans-sc-67-wght-normal-CC-WRBV-.woff2 +0 -0
  363. package/web-dist/assets/noto-sans-sc-68-wght-normal-c0FjfUaj.woff2 +0 -0
  364. package/web-dist/assets/noto-sans-sc-69-wght-normal-D596Jjl2.woff2 +0 -0
  365. package/web-dist/assets/noto-sans-sc-70-wght-normal-ColEcmtJ.woff2 +0 -0
  366. package/web-dist/assets/noto-sans-sc-71-wght-normal-ChZfXpdg.woff2 +0 -0
  367. package/web-dist/assets/noto-sans-sc-72-wght-normal-D1VyfEG3.woff2 +0 -0
  368. package/web-dist/assets/noto-sans-sc-73-wght-normal-DwSJRYPJ.woff2 +0 -0
  369. package/web-dist/assets/noto-sans-sc-74-wght-normal-Cte7o1QG.woff2 +0 -0
  370. package/web-dist/assets/noto-sans-sc-75-wght-normal-B0qL41rF.woff2 +0 -0
  371. package/web-dist/assets/noto-sans-sc-76-wght-normal-BPLMO_2x.woff2 +0 -0
  372. package/web-dist/assets/noto-sans-sc-77-wght-normal-Dkbi3pye.woff2 +0 -0
  373. package/web-dist/assets/noto-sans-sc-78-wght-normal-BFUXeSw6.woff2 +0 -0
  374. package/web-dist/assets/noto-sans-sc-79-wght-normal-DoJG4UTB.woff2 +0 -0
  375. package/web-dist/assets/noto-sans-sc-80-wght-normal-BEFypWOO.woff2 +0 -0
  376. package/web-dist/assets/noto-sans-sc-81-wght-normal-ed_TZlfo.woff2 +0 -0
  377. package/web-dist/assets/noto-sans-sc-82-wght-normal-DcxfR5OJ.woff2 +0 -0
  378. package/web-dist/assets/noto-sans-sc-83-wght-normal-C9UjAcMM.woff2 +0 -0
  379. package/web-dist/assets/noto-sans-sc-84-wght-normal-C7NxT478.woff2 +0 -0
  380. package/web-dist/assets/noto-sans-sc-85-wght-normal-DBcDBu1n.woff2 +0 -0
  381. package/web-dist/assets/noto-sans-sc-86-wght-normal-CLJIoPpl.woff2 +0 -0
  382. package/web-dist/assets/noto-sans-sc-87-wght-normal-DYfJ-vGE.woff2 +0 -0
  383. package/web-dist/assets/noto-sans-sc-88-wght-normal-ClNDOCGW.woff2 +0 -0
  384. package/web-dist/assets/noto-sans-sc-89-wght-normal-IQU_KQA8.woff2 +0 -0
  385. package/web-dist/assets/noto-sans-sc-90-wght-normal-BWcrRNoG.woff2 +0 -0
  386. package/web-dist/assets/noto-sans-sc-91-wght-normal-CGekvDdH.woff2 +0 -0
  387. package/web-dist/assets/noto-sans-sc-97-wght-normal-BsBHkXi3.woff2 +0 -0
  388. package/web-dist/assets/noto-sans-sc-98-wght-normal-BZqSA1r_.woff2 +0 -0
  389. package/web-dist/assets/noto-sans-sc-99-wght-normal-Q_IptJM5.woff2 +0 -0
  390. package/web-dist/assets/noto-sans-sc-cyrillic-wght-normal-CRA5_Pf1.woff2 +0 -0
  391. package/web-dist/assets/noto-sans-sc-latin-ext-wght-normal-CqPqLCfe.woff2 +0 -0
  392. package/web-dist/assets/noto-sans-sc-latin-wght-normal-DYAKOyvl.woff2 +0 -0
  393. package/web-dist/assets/noto-sans-sc-vietnamese-wght-normal-y5SU35Rl.woff2 +0 -0
  394. package/web-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  395. package/web-dist/assets/pegDiagram-XKGWAZYB-CLEM1SDU.js +1 -0
  396. package/web-dist/assets/pieDiagram-E7YTZNPT-B__g6eF0.js +39 -0
  397. package/web-dist/assets/quadrantDiagram-AXDQQJYC-C7VQ2LMY.js +7 -0
  398. package/web-dist/assets/railroadDiagram-O6MQD6OU-eWNnzjwS.js +1 -0
  399. package/web-dist/assets/requirementDiagram-BXWQKSXE-Bi5qeD4b.js +84 -0
  400. package/web-dist/assets/sankeyDiagram-P5KCCOFB-DG1VOpXX.js +40 -0
  401. package/web-dist/assets/sequenceDiagram-WJ2MYXX4-Fhkw73Th.js +162 -0
  402. package/web-dist/assets/sizeCapture-INFHLROL-D9E_17SF.js +1 -0
  403. package/web-dist/assets/stateDiagram-D77RDMKH-Cs5Y0xhW.js +1 -0
  404. package/web-dist/assets/stateDiagram-v2-MP3YSRHH-CEM51fAf.js +1 -0
  405. package/web-dist/assets/swimlanes-42K2YHIH-t-EocvKZ.js +1 -0
  406. package/web-dist/assets/swimlanesDiagram-VR7AAH4N-BrR66vrK.js +8 -0
  407. package/web-dist/assets/timeline-definition-24CTP7MA-CozGCxuA.js +120 -0
  408. package/web-dist/assets/vennDiagram-4TSXK5OY-ewU8ycSa.js +34 -0
  409. package/web-dist/assets/wardleyDiagram-VM6X3IG4-DuAhDu-0.js +78 -0
  410. package/web-dist/assets/{xterm-B2oS8Mg8.js → xterm-v5e56GC9.js} +1 -1
  411. package/web-dist/assets/xychartDiagram-S5SC5T6Z-BxGuZO23.js +7 -0
  412. package/web-dist/fonts-licenses/ibm-plex-sans-condensed.txt +93 -0
  413. package/web-dist/fonts-licenses/ibm-plex-sans.txt +93 -0
  414. package/web-dist/fonts-licenses/jetbrains-mono.txt +93 -0
  415. package/web-dist/fonts-licenses/misans.txt +119 -0
  416. package/web-dist/fonts-licenses/mona-sans.txt +93 -0
  417. package/web-dist/fonts-licenses/noto-sans-sc.txt +93 -0
  418. package/web-dist/index.html +18 -4
  419. package/web-dist/workflow-ui.css +261 -0
  420. package/dist/chunk-3I2XOPJB.js.map +0 -1
  421. package/dist/chunk-A3QANMU5.js.map +0 -1
  422. package/dist/chunk-L2H3K4DT.js +0 -7
  423. package/dist/chunk-L2H3K4DT.js.map +0 -1
  424. package/dist/chunk-S3BI6R7I.js +0 -14
  425. package/dist/chunk-S3BI6R7I.js.map +0 -1
  426. package/web-dist/assets/highlighter-CUb4XKtQ.js +0 -2
  427. package/web-dist/assets/index-CmfumtXy.js +0 -570
  428. package/web-dist/assets/index-Ywc2uM5u.css +0 -1
@@ -1,29 +1,48 @@
1
- import { SpawnConfiner, ThinkingLevelName, OmniMessage, ToolCallPayload, ProjectConfig, ModelRef, ListEndpointModelsOptions, ProxyEnvPolicy, ControlEnvContext, ApproveFn, CompactAvailability, SessionTitleResult, BackgroundCommandInfo, ToolDetachResult, BackgroundSubagentInfo, SubagentMessageOptions, SubagentMessageOutcome } from '@prismshadow/penguin-core';
2
- import { SandboxProviderSource, SandboxSettings, SandboxDimension } from '@prismshadow/penguin-core/plugin';
1
+ import { SpawnConfiner, OmniMessage, ThinkingLevelName, ToolCallPayload, ApprovalDecision, ProjectConfig, ModelRef, PluginTables, ListEndpointModelsOptions, ModelRequestContext, ProxyEnvPolicy, ControlEnvContext, AgentAssembly, ApproveFn, StopReason, CompactAvailability, SessionTitleResult, BackgroundCommandInfo, ToolDetachResult, BackgroundSubagentInfo, SubagentMessageOptions, SubagentMessageOutcome } from '@prismshadow/penguin-core';
2
+ import { SandboxProviderSource, SandboxSettings, SandboxDimension, SandboxLimit } from '@prismshadow/penguin-core/plugin';
3
3
  import { Slot, Opaque } from '@prismshadow/penguin-core/kernel';
4
- import { ApprovalMode, SessionSource, ModelRefDto, ChatDefaultsDto, CommandPolicyDto, ModelVisionDetectRequest, ModelVisionDetectResponse, ModelTestRequest, ModelTestResponse, ModelProtocolDetectRequest, ModelProtocolDetectResponse, EndpointModelListRequest, EndpointModelListResponse, ModelsResponse, ModelsUpdateRequest, MessagingChannel as MessagingChannel$1, SessionInfo, SessionCategory, SessionCategoryCounts, ServerEvent, SessionStatus, SessionBackgroundTasks, PendingSteeringInfo, PendingFollowUpInfo, AgentConfigDto, AgentConfigUpdateRequest, AgentKernelUpdateResponse, VaultResponse, VaultUpdateRequest, PluginUpdateRef, MessagingRuntimeStatus, ContributionsResponse, RendererRef } from '../api/types.js';
4
+ import { ApprovalMode, ModelRefDto, ChatDefaultsDto, CommandPolicyDto, ModelVisionDetectRequest, ModelVisionDetectResponse, ModelTestRequest, ModelTestResponse, ModelProtocolDetectRequest, ModelProtocolDetectResponse, EndpointModelListRequest, EndpointModelListResponse, ModelsResponse, ModelsUpdateRequest, ProviderConnectionUpdate, PresetSyncMode, PresetSyncResponse, ServerEvent, MessagingChannel, UnavailableSandboxBackend, SessionSandboxPreset, SessionSandbox, SessionInfo, SessionCategory, SessionCategoryCounts, ModelScopeAuthFlowStatusResponse, SessionStatus, PendingSteeringInfo, SessionBackgroundTasks, PendingFollowUpInfo, AgentConfigDto, AgentConfigUpdateRequest, AgentKernelUpdateResponse, VaultResponse, VaultUpdateRequest, PluginUpdateRef, MessagingRuntimeStatus, PluginConfiguration, ContributionsResponse, RendererRef } from '../api/types.js';
5
+ export { PluginConfigField } from '../api/types.js';
5
6
  import { ThinkingLevelName as ThinkingLevelName$1 } from '@prismshadow/penguin-core/interfaces';
7
+ import { SessionSource } from '@prismshadow/penguin-core/omnimessage';
6
8
  import { Hono } from 'hono';
7
- import '@prismshadow/penguin-core/omnimessage';
9
+ import '@prismshadow/penguin-hmr';
10
+
11
+ interface UserRow {
12
+ userId: string;
13
+ passwordHash: string;
14
+ isAdmin: boolean;
15
+ /** Still using the initial password (seeded / set by an admin); cleared to 0 once the user changes it. */
16
+ passwordIsInitial: boolean;
17
+ /** Nickname shown in place of the id; null = never set. */
18
+ displayName: string | null;
19
+ /** Avatar as a data URL; null = never set. */
20
+ avatar: string | null;
21
+ createdAt: string;
22
+ }
8
23
 
9
24
  /**
10
- * The sandbox service: owns the registered backends, routes each spawn's policy to a
11
- * backend that implements the dimensions it requires, and produces the SpawnConfiner
12
- * closure the runtime transports into core's command-session seam.
13
- *
14
- * Routing is by CAPABILITY, not by registration order alone: a policy requiring only
15
- * `fs-write` goes to the first backend that covers it (the DSH adaptor, which works on
16
- * Linux/macOS/Windows alike), while a policy also requiring `network` or `mask-paths`
17
- * goes to the first backend implementing those (penguin-bwrap). Registration order
18
- * only breaks ties between backends that both cover the request. A request nothing
19
- * covers fails closed — never a silent unconfined run, and never a silently dropped
20
- * dimension.
25
+ * "desktop" and "setup" may set a password without the old one (theirs is random and was never
26
+ * shown); desktop-only routes open to "desktop" alone. "token" is the local API token's Bearer
27
+ * header — per request, never a stored row. Anything else reads as "password".
21
28
  */
29
+ type SessionVia = "password" | "desktop" | "setup" | "token";
22
30
 
23
31
  declare class SandboxService {
24
- private readonly mounted;
25
- /** name → why it failed to load; surfaced in the fail-closed message. */
26
- private readonly loadErrors;
32
+ private mounted;
33
+ /**
34
+ * name → why it FAILED: it could not load, or failed its check on a host it is meant for —
35
+ * never silently absent. Surfaced in the fail-closed message and on the settings card.
36
+ */
37
+ private loadErrors;
38
+ /**
39
+ * The backends that declined: this host is not theirs (a Linux backend on Windows). Nothing
40
+ * is wrong with a deployment that installs one backend per platform, so a decline is not a
41
+ * failure — it is listed only when NO backend serves, where it is the explanation.
42
+ */
43
+ private declinedNames;
44
+ /** Every registration in routing order, with how its latest load settled. */
45
+ private readonly registrations;
27
46
  /**
28
47
  * Ships with confinement OFF (`danger-full-access`): the default flips to
29
48
  * workspace-write together with the deployment-facing config surface, so a
@@ -40,6 +59,14 @@ declare class SandboxService {
40
59
  * exists for deployments flipping the mode in the first milliseconds after boot.
41
60
  */
42
61
  constructor(registrations?: Iterable<[string, SandboxProviderSource]>);
62
+ /** Rebuilds the mounted / failed / declined views from the registrations, in routing order. */
63
+ private record;
64
+ /**
65
+ * Loads again every backend whose load failed and that registered a loader (a bare promise
66
+ * cannot be re-run). Called after the sandbox's settings are saved: a backend whose check
67
+ * failed on its own setting mounts once that setting is fixed. Resolves when those settle.
68
+ */
69
+ retryFailed(): Promise<void>;
43
70
  /** Resolves when every registered backend has loaded (or failed to). */
44
71
  whenReady(): Promise<void>;
45
72
  /** Replaces the active settings (the config surface's write path). */
@@ -55,10 +82,22 @@ declare class SandboxService {
55
82
  * refusing the swap beats a swap that silently un-confines the deployment.
56
83
  */
57
84
  parkedSettings(): SandboxSettings | undefined;
58
- /** The mounted backends and what each implements (diagnostics / the config surface). */
85
+ /** The backends that failed to load, each with why (diagnostics / the config surface). */
86
+ failures(): Array<{
87
+ name: string;
88
+ reason: string;
89
+ }>;
90
+ /** The backends that declined because this host is not theirs (the config surface). */
91
+ declined(): string[];
92
+ /**
93
+ * The mounted backends and what each implements, in routing preference: the one a policy
94
+ * goes to first (diagnostics / the config surface).
95
+ */
59
96
  backends(): Array<{
60
97
  name: string;
61
98
  dimensions: readonly SandboxDimension[];
99
+ mechanism?: string;
100
+ limits?: readonly SandboxLimit[];
62
101
  }>;
63
102
  /**
64
103
  * The closure handed to the runtime: rewrites each spawn's argv under the active
@@ -66,11 +105,19 @@ declare class SandboxService {
66
105
  * serving during a hot-swap freeze window.
67
106
  */
68
107
  confiner(): SpawnConfiner;
69
- /** The first mounted backend implementing every required dimension, or a fail-closed throw. */
108
+ /**
109
+ * The same closure under a policy the caller keeps — a Session's own snapshot. The
110
+ * backends are still this service's, so a backend change reaches every Session.
111
+ */
112
+ confinerFor(policyOf: () => SandboxSettings): SpawnConfiner;
113
+ /**
114
+ * The preferred mounted backend implementing every required dimension (byPreference), or a
115
+ * fail-closed throw.
116
+ */
70
117
  private pick;
71
118
  private failedSuffix;
72
119
  }
73
- declare const Sandbox_base: (abstract new () => Pick<SandboxService, "configure" | "currentSettings" | "parkedSettings" | "backends" | "confiner" | "whenReady">) & (<C>(target: C, context: ClassDecoratorContext) => C);
120
+ declare const Sandbox_base: (abstract new () => Pick<SandboxService, "failures" | "configure" | "currentSettings" | "parkedSettings" | "backends" | "declined" | "retryFailed" | "confiner" | "confinerFor" | "whenReady">) & (<C>(target: C, context: ClassDecoratorContext) => C);
74
121
  /** Confinement: settings, the active confiner, and which backends are mounted. */
75
122
  declare abstract class Sandbox extends Sandbox_base {
76
123
  }
@@ -85,6 +132,29 @@ interface SandboxSlots {
85
132
  }, SandboxProviderSource>;
86
133
  }
87
134
 
135
+ /** What a terminal puts first on PATH, where the startup files that do it live, and its first line. */
136
+ interface TerminalPathFirst {
137
+ /** The directories that must lead PATH once the shell is ready, in order: the CLI shim dir. */
138
+ dirs: readonly string[];
139
+ /** The directory holding the startup files, see {@link shellStartupDir}. */
140
+ startupDir: string;
141
+ /** A development instance's first line, for the shell to print at its first prompt. Absent or null: none. */
142
+ notice?: ShellNotice | null;
143
+ }
144
+ /**
145
+ * The first line of a development instance's terminal, printed by the shell itself at its first
146
+ * prompt, after its own startup files: `text` while `penguin` there still targets this instance,
147
+ * else `elsewhere`'s two halves around `VAR=value` — when those files set PENGUIN_API_URL, which
148
+ * names a server outright, or a PENGUIN_HOME that is not `root` (a trailing `/` aside), which the
149
+ * shim then leaves to the CLI.
150
+ */
151
+ interface ShellNotice {
152
+ text: string;
153
+ /** This instance's data root. */
154
+ root: string;
155
+ elsewhere: readonly [before: string, after: string];
156
+ }
157
+
88
158
  /**
89
159
  * Screen snapshot -> ANSI restore stream, plus plain-text capture.
90
160
  *
@@ -141,6 +211,42 @@ interface CreateTerminalSessionOptions {
141
211
  * absent falls back to the packaged require (see pty-module.ts).
142
212
  */
143
213
  assets?: () => string | null;
214
+ /**
215
+ * What leads PATH once the shell's own startup files have run: the server's CLI shim
216
+ * directory, so `penguin` here is the one the Agent's commands get (see shell-startup.ts).
217
+ * Absent or null, the shell starts with the inherited PATH as it is.
218
+ */
219
+ pathFirst?: TerminalPathFirst | null;
220
+ /**
221
+ * One line shown above everything the shell prints — on a development instance, which
222
+ * `penguin` this terminal runs, or why it is not this instance's (cli-notice.ts). Written to
223
+ * the screen, never to the shell: nothing runs, and the user's prompt follows it. A line with
224
+ * a `target` the shell prints itself instead, at its first prompt, where it can
225
+ * (shell-startup.ts ShellNotice): only then is it known what the user's own startup files left
226
+ * `penguin` pointing at.
227
+ */
228
+ notice?: TerminalNotice | null;
229
+ /**
230
+ * Whether the shell keeps the server process's `PENGUIN_HOME` and `PENGUIN_WEB_DB`. Only
231
+ * where no shim names this server's data root for `penguin` — a server with no CLI to offer,
232
+ * or a runtime older than the shim's root default — so that `penguin` there still finds this
233
+ * server the way it did before. Default false: every `PENGUIN_*` stays out.
234
+ */
235
+ inheritDataRoot?: boolean;
236
+ }
237
+ /** A line the server shows at the top of a new terminal; `warning` when something is wrong. */
238
+ interface TerminalNotice {
239
+ text: string;
240
+ tone: "info" | "warning";
241
+ /**
242
+ * What `text` takes for granted: that `penguin` here targets this data root. On a development
243
+ * instance's line, which then says otherwise — `elsewhere`'s two halves around `VAR=value` —
244
+ * when the shell's own startup files set PENGUIN_API_URL, or a PENGUIN_HOME that is not `root`.
245
+ */
246
+ target?: {
247
+ root: string;
248
+ elsewhere: readonly [before: string, after: string];
249
+ };
144
250
  }
145
251
  interface TerminalSessionInfo {
146
252
  id: string;
@@ -223,20 +329,18 @@ interface CreateTerminalRequest {
223
329
  }
224
330
  /** A live pty: a host-like object (it owns a process), compared by name. */
225
331
  type Terminal = Opaque<"TerminalSession", TerminalSession>;
226
- declare const Terminals_base: (abstract new () => {
227
- create(request: CreateTerminalRequest): Promise<Terminal>;
228
- adopt(ids: readonly string[]): void;
229
- quiesce(): void;
230
- handleIds(): string[];
231
- require(id: string, userId: string): Terminal;
232
- get(id: string): Terminal | undefined;
233
- list(userId: string): Terminal[];
234
- listInfo(userId: string): TerminalSessionInfo[];
235
- kill(id: string, userId: string): void;
236
- disposeAll(): void;
237
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
238
332
  /** Live ptys: the spawn primitive behind /api/terminals and the terminal WebSocket. */
239
- declare abstract class Terminals extends Terminals_base {
333
+ declare abstract class Terminals {
334
+ abstract create(request: CreateTerminalRequest): Promise<Terminal>;
335
+ abstract adopt(ids: readonly string[]): void;
336
+ abstract quiesce(): void;
337
+ abstract handleIds(): string[];
338
+ abstract require(id: string, userId: string): Terminal;
339
+ abstract get(id: string): Terminal | undefined;
340
+ abstract list(userId: string): Terminal[];
341
+ abstract listInfo(userId: string): TerminalSessionInfo[];
342
+ abstract kill(id: string, userId: string): void;
343
+ abstract disposeAll(): void;
240
344
  }
241
345
 
242
346
  /**
@@ -264,37 +368,67 @@ interface RecallableFile {
264
368
  mime: string;
265
369
  }
266
370
 
267
- declare const SessionIndex_base: (abstract new () => {
268
- insert(row: SessionRow): void;
269
- insertOrIgnore(row: SessionRow): void;
270
- insertFork(sourceSessionId: string, row: SessionRow): SessionRow;
271
- markOrgClient(sessionIds: readonly string[]): void;
272
- markHasTrace(sessionId: string): void;
273
- markDriven(sessionId: string, at: string): void;
274
- touchLastActive(sessionId: string, at: string): void;
275
- findById(sessionId: string): SessionRow | null;
276
- listByAgent(projectId: string, agentId: string): SessionRow[];
277
- listByProject(projectId: string): SessionRow[];
278
- updateApprovalMode(sessionId: string, mode: ApprovalMode): void;
279
- updateThinkingLevel(sessionId: string, level: ThinkingLevelName): void;
280
- updateTitle(sessionId: string, title: string): void;
281
- updateTitleIfNull(sessionId: string, title: string): void;
282
- setArchived(sessionId: string, archivedAt: string | null): void;
283
- replaceId(oldSessionId: string, newSessionId: string): void;
284
- deleteByAgent(projectId: string, agentId: string): void;
285
- deleteByProject(projectId: string): void;
286
- deleteById(sessionId: string): void;
287
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
371
+ /** The open streaming fragments of running sessions, as their holder uses them — what {@link LiveTailTracker} implements. */
372
+ interface LiveTail {
373
+ observe(sessionId: string, msg: OmniMessage): void;
374
+ fragments(sessionId: string): OmniMessage[];
375
+ clear(sessionId: string): void;
376
+ }
377
+
288
378
  /** SessionIndex: the mechanism SessionsRepo implements. */
289
- declare abstract class SessionIndex extends SessionIndex_base {
379
+ declare abstract class SessionIndex {
380
+ abstract insert(row: SessionRow): void;
381
+ abstract insertOrIgnore(row: SessionRow): void;
382
+ abstract insertFork(sourceSessionId: string, row: SessionRow): SessionRow;
383
+ abstract markOrgClient(sessionIds: readonly string[]): void;
384
+ abstract markHasTrace(sessionId: string): void;
385
+ abstract markDriven(sessionId: string, at: string): void;
386
+ abstract touchLastActive(sessionId: string, at: string): void;
387
+ abstract findById(sessionId: string): SessionRow | null;
388
+ abstract listByAgent(projectId: string, agentId: string): SessionRow[];
389
+ abstract listByProject(projectId: string): SessionRow[];
390
+ abstract updateApprovalMode(sessionId: string, mode: ApprovalMode): void;
391
+ abstract updateSandbox(sessionId: string, sandbox: SandboxSettings): void;
392
+ abstract updateThinkingLevel(sessionId: string, level: ThinkingLevelName): void;
393
+ abstract updateTitle(sessionId: string, title: string): void;
394
+ abstract updateTitleIfNull(sessionId: string, title: string): void;
395
+ abstract updateModel(sessionId: string, provider: string, modelId: string): void;
396
+ abstract setListing(sessionIds: readonly string[], listing: "archived" | "kept", at: string): void;
397
+ abstract replaceId(oldSessionId: string, newSessionId: string): void;
398
+ abstract deleteByAgent(projectId: string, agentId: string): void;
399
+ abstract deleteByProject(projectId: string): void;
400
+ abstract deleteById(sessionId: string): void;
290
401
  }
291
- declare const SessionOrigins_base: (abstract new () => {
292
- set(sessionId: string, source: SessionSource | null): void;
293
- get(sessionId: string): SessionSource | null | undefined;
294
- delete(sessionId: string): void;
402
+ /**
403
+ * What a run that has just ended asks of the CURRENT generation: start the next queued
404
+ * follow-up, or deliver background notices that raced the run's exit. A run outlives the
405
+ * generation that launched it (see AgentState.current), and what it starts next is the
406
+ * current logic's to start.
407
+ */
408
+ interface RunStarter {
409
+ startQueuedFollowUp(sessionId: string): Promise<void>;
410
+ startBackgroundNoticeTask(sessionId: string): Promise<void>;
411
+ }
412
+ declare const AgentState_base: (abstract new () => {
413
+ readonly entries: Map<string, RuntimeEntry>;
414
+ readonly childRoots: Map<string, string>;
415
+ readonly locks: Map<string, Promise<unknown>>;
416
+ readonly deletingAgents: Set<string>;
417
+ readonly deletingSessions: Set<string>;
418
+ readonly agentGenerations: Map<string, number>;
419
+ readonly liveTail: LiveTail;
420
+ /** The generation working on this state right now; every generation points it at itself when it takes the state over. */
421
+ current: RunStarter | null;
295
422
  }) & (<C>(target: C, context: ClassDecoratorContext) => C);
423
+ /** AgentState: the mechanism AgentStateStore implements — the Session runtime's in-memory state, data only. */
424
+ declare abstract class AgentState extends AgentState_base {
425
+ }
296
426
  /** SessionOrigins: the mechanism SessionSources implements. */
297
- declare abstract class SessionOrigins extends SessionOrigins_base {
427
+ declare abstract class SessionOrigins {
428
+ /** `null`: the Session's Trace head records no source (written before it was required). */
429
+ abstract set(sessionId: string, source: SessionSource | null): void;
430
+ abstract get(sessionId: string): SessionSource | null | undefined;
431
+ abstract delete(sessionId: string): void;
298
432
  }
299
433
 
300
434
  /**
@@ -306,9 +440,13 @@ interface SessionRow {
306
440
  sessionId: string;
307
441
  projectId: string;
308
442
  agentId: string;
309
- /** Provider group of the session's model (pairs with `modelId` to form the model reference). */
443
+ /**
444
+ * Provider group of the session's **current** model (pairs with `modelId` to form the model
445
+ * reference). Moves with each in-session switch (`updateModel`); the Trace's latest
446
+ * `session_meta` is the durable truth, and the runtime reconciles a row it disagrees with.
447
+ */
310
448
  provider: string;
311
- /** Upstream model_id of the session's model (sent as-is to AgentHub; never concatenated). */
449
+ /** Upstream model_id of the session's current model (sent as-is to MMSP; never concatenated). */
312
450
  modelId: string;
313
451
  workspace: string;
314
452
  approvalMode: ApprovalMode;
@@ -320,21 +458,33 @@ interface SessionRow {
320
458
  thinkingLevel?: ThinkingLevelName$1 | null;
321
459
  /** Auto-generated session title; NULL = not yet generated (frontend shows "New Conversation"). */
322
460
  title: string | null;
323
- /** Archive timestamp, ISO; NULL = not archived (omitting on insert defaults to NULL). */
461
+ /**
462
+ * When the user archived it, ISO; NULL = not archived by hand (omitting on insert defaults to
463
+ * NULL). Archived or not is the listing rule's answer (runtime/session-sources.ts listCategory):
464
+ * a background Session without `keptAt` is filed away too.
465
+ */
324
466
  archivedAt?: string | null;
467
+ /**
468
+ * The "keep in sidebar" mark, ISO: written when the user unarchives the Session, cleared when
469
+ * they archive it, never written by a run. It is what keeps a background Session (api /
470
+ * schedule / cli) listed among the conversations; NULL = the listing rule decides.
471
+ */
472
+ keptAt?: string | null;
325
473
  /**
326
474
  * Creating client: "web" (created via the Web App), "cli" (created through the API by
327
475
  * the CLI, or adopted from a Trace a legacy CLI-direct run left behind), "org" (opened by
328
- * the organization runtime — a desk or a ticket session); NULL = legacy row from before
329
- * the column existed, treated as web. Free text in SQLite, so a new value needs no
330
- * migration. Provenance that outlives its organization: development mode's list is the
331
- * one reader that filters on it, and it hides "org" rows whether or not the organization
332
- * still exists. The schedule/subagent SOURCE is deliberately NOT a row field — core
476
+ * the organization runtime — a desk or a ticket session — or spawned as a sub-session of
477
+ * one, which inherits the stamp at registration), "api" (created by an Agent API run — the
478
+ * only rows the API may continue); NULL = legacy row from before the column existed,
479
+ * treated as web. Free text in SQLite, so a new value needs no migration.
480
+ * Provenance that outlives its organization: development mode's list is the one reader
481
+ * that filters on it (through the list's `excludeOrg`), and it hides "org" rows whether or
482
+ * not the organization still exists. The schedule/subagent SOURCE is deliberately NOT a row field — core
333
483
  * session_meta in the Trace stays the single source of truth for it
334
484
  * (runtime/session-sources.ts); `client` is a separate, DB-only axis that meta never
335
485
  * records.
336
486
  */
337
- client?: "web" | "cli" | "org" | null;
487
+ client?: "web" | "cli" | "org" | "api" | null;
338
488
  /** Cache: a Trace record exists (set at task start / adoption / subagent registration; backfilled by list hydration). */
339
489
  hasTrace?: boolean;
340
490
  /**
@@ -347,6 +497,11 @@ interface SessionRow {
347
497
  */
348
498
  lastActiveAt: string;
349
499
  createdAt: string;
500
+ /**
501
+ * The Session's own sandbox policy, snapshotted from the server's settings at creation.
502
+ * NULL = a row from before the column: it takes the settings at its next command.
503
+ */
504
+ sandbox?: SandboxSettings | null;
350
505
  }
351
506
 
352
507
  /**
@@ -361,6 +516,9 @@ interface SessionRow {
361
516
  * `POST /approvals/:toolCallId`; no timeout — pending approvals are resolved to deny
362
517
  * when the Task is interrupted (then proceeds through the abort flow).
363
518
  *
519
+ * An unattended Session takes that one route differently: there is no frontend to ask, so
520
+ * the call is denied on the spot instead of suspending forever (see `unattended` below).
521
+ *
364
522
  * Every approval decision re-reads the current approval_mode (`getMode` reads the DB),
365
523
  * so mode changes take effect immediately.
366
524
  * Docs: /docs/tools § "Approval".
@@ -370,6 +528,15 @@ interface PendingApproval {
370
528
  toolCall: OmniMessage<ToolCallPayload>;
371
529
  origin?: string[];
372
530
  }
531
+ /** A Session runtime's pending approvals, as its holder uses them — what {@link ApprovalRegistry} implements. */
532
+ interface Approvals {
533
+ readonly size: number;
534
+ list(): PendingApproval[];
535
+ wait(toolCall: OmniMessage<ToolCallPayload>): Promise<ApprovalDecision>;
536
+ decide(toolCallId: string, decision: ApprovalDecision): boolean;
537
+ denyAll(): void;
538
+ denyMain(): void;
539
+ }
373
540
 
374
541
  /** A numbered channel event; `id` is `<epoch>-<seq>`, `data` is serialized single-line JSON. */
375
542
  interface ChannelEvent {
@@ -518,15 +685,13 @@ interface TieredRates {
518
685
  offPeak: PricingRates;
519
686
  }
520
687
 
521
- declare const Errors_base: (abstract new () => {
522
- record(args: ErrorRecordArgs): void;
523
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
524
688
  /** Errors: the mechanism ErrorRecorder implements. */
525
- declare abstract class Errors extends Errors_base {
689
+ declare abstract class Errors {
690
+ abstract record(args: ErrorRecordArgs): void;
526
691
  }
527
692
 
528
693
  /** Capture-site source (maps one-to-one to error_records.source). */
529
- type ErrorSource = "http" | "organization" | "session" | "llm" | "environment" | "compaction" | "usage" | "title" | "subagent" | "process" | "schedule" | "messaging";
694
+ type ErrorSource = "http" | "organization" | "session" | "llm" | "environment" | "compaction" | "usage" | "title" | "subagent" | "process" | "schedule" | "messaging" | "id_suggest" | "plugin";
530
695
  /** Error classification: see file header — the criterion is "does a human need to step in". */
531
696
  type ErrorKind = "expected" | "unexpected";
532
697
  /** Attribution context (all optional: the login endpoint has no Project, and process-level fallback has no request at all). */
@@ -582,10 +747,25 @@ interface TitleNotifier {
582
747
  }
583
748
 
584
749
  /**
585
- * trace_files / trace_sessions repo: the Trace-tree derived cache (see schema.ts and
586
- * services/trace-index.ts for the cache rules). Pure row access — reconciliation
587
- * policy (mtime gates, head-reads) lives in the service.
750
+ * In-process registry of Session sources, derived from core `session_meta` — the single
751
+ * source of truth for what kind of conversation a Session is (the DB stores no `source`
752
+ * column).
753
+ *
754
+ * Populated wherever the server actually has the meta in hand: Session creation
755
+ * (SessionService reads the just-created core Session's meta), subagent registration
756
+ * (SessionManager reads the forwarded child meta), forks (always `user`), and Trace adoption /
757
+ * lazy list resolution (the trace index's head read). A value read back from a Trace is
758
+ * narrowed through core's `normalizeSessionSource` (the retired `benchmark` reads as `cli`),
759
+ * except that a head recording no source is kept as `null`: what it reads as depends on the
760
+ * Session's index row (`readRecordedSource`), which a head read does not have. An absent entry
761
+ * means "unknown": the list path resolves it from the Trace once per process lifetime.
762
+ */
763
+
764
+ /**
765
+ * What a Session's Trace head records as its source: one of the sources, or `null` for a head
766
+ * written before the source was required, which records none.
588
767
  */
768
+ type RecordedSource = SessionSource | null;
589
769
 
590
770
  /** One indexed Trace shard. */
591
771
  interface TraceFileRow {
@@ -601,7 +781,12 @@ interface TraceSessionRow {
601
781
  sessionId: string;
602
782
  projectId: string;
603
783
  agentId: string;
604
- source: SessionSource | null;
784
+ /**
785
+ * The head's session_meta source, narrowed; `null` when the head records none (written before
786
+ * the source was required; read it with the row's client, `readRecordedSource`). Meaningful
787
+ * only once `metaRead`.
788
+ */
789
+ source: RecordedSource;
605
790
  workspace: string;
606
791
  title: string | null;
607
792
  provider: string | null;
@@ -610,38 +795,37 @@ interface TraceSessionRow {
610
795
  metaRead: boolean;
611
796
  }
612
797
 
613
- declare const TraceIndexStore_base: (abstract new () => {
614
- upsertFile(row: TraceFileRow): void;
615
- updateFileSize(projectId: string, agentId: string, sessionId: string, fileIndex: number, sizeBytes: number): void;
616
- getPageStats(projectId: string, agentId: string, sessionId: string, fileIndex: number): string | null;
617
- setPageStats(projectId: string, agentId: string, sessionId: string, fileIndex: number, sizeBytes: number, pageStats: string): void;
618
- deleteFile(projectId: string, agentId: string, sessionId: string, fileIndex: number): void;
619
- listFilesByAgent(projectId: string, agentId: string): TraceFileRow[];
620
- listFilesBySession(projectId: string, agentId: string, sessionId: string): TraceFileRow[];
621
- findAgentBySession(projectId: string, sessionId: string): string | null;
622
- upsertSession(row: TraceSessionRow): void;
623
- getSession(sessionId: string): TraceSessionRow | null;
624
- listSessionsByAgent(projectId: string, agentId: string): TraceSessionRow[];
625
- deleteBySession(sessionId: string): void;
626
- deleteByAgent(projectId: string, agentId: string): void;
627
- deleteByProject(projectId: string): void;
628
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
629
798
  /** TraceIndexStore: the mechanism TraceIndexRepo implements. */
630
- declare abstract class TraceIndexStore extends TraceIndexStore_base {
799
+ declare abstract class TraceIndexStore {
800
+ abstract upsertFile(row: TraceFileRow): void;
801
+ abstract updateFileSize(projectId: string, agentId: string, sessionId: string, fileIndex: number, sizeBytes: number): void;
802
+ abstract getPageStats(projectId: string, agentId: string, sessionId: string, fileIndex: number): string | null;
803
+ abstract setPageStats(projectId: string, agentId: string, sessionId: string, fileIndex: number, sizeBytes: number, pageStats: string): void;
804
+ abstract deleteFile(projectId: string, agentId: string, sessionId: string, fileIndex: number): void;
805
+ abstract listFilesByAgent(projectId: string, agentId: string): TraceFileRow[];
806
+ abstract listFilesBySession(projectId: string, agentId: string, sessionId: string): TraceFileRow[];
807
+ abstract findAgentBySession(projectId: string, sessionId: string): string | null;
808
+ abstract upsertSession(row: TraceSessionRow): void;
809
+ abstract getSession(sessionId: string): TraceSessionRow | null;
810
+ abstract listSessionsByAgent(projectId: string, agentId: string): TraceSessionRow[];
811
+ abstract deleteBySession(sessionId: string): void;
812
+ abstract deleteByAgent(projectId: string, agentId: string): void;
813
+ abstract deleteByProject(projectId: string): void;
631
814
  }
632
- declare const TraceIndex_base: (abstract new () => {
633
- readonly counters: {
815
+ /** TraceIndex: the mechanism TraceIndexService implements. */
816
+ declare abstract class TraceIndex {
817
+ abstract readonly counters: {
634
818
  gateStats: number;
635
819
  dirScans: number;
636
820
  headReads: number;
637
821
  };
638
- reconcileAgent(projectId: string, agentId: string, opts?: {
822
+ abstract reconcileAgent(projectId: string, agentId: string, opts?: {
639
823
  force?: boolean;
640
824
  }): Promise<void>;
641
- reconcileProject(projectId: string, opts?: {
825
+ abstract reconcileProject(projectId: string, opts?: {
642
826
  force?: boolean;
643
827
  }): Promise<void>;
644
- registerImportedFile(args: {
828
+ abstract registerImportedFile(args: {
645
829
  projectId: string;
646
830
  agentId: string;
647
831
  sessionId: string;
@@ -650,32 +834,44 @@ declare const TraceIndex_base: (abstract new () => {
650
834
  sizeBytes: number;
651
835
  records: OmniMessage[];
652
836
  }): void;
653
- removeSession(projectId: string, agentId: string, sessionId: string): void;
654
- removeAgent(projectId: string, agentId: string): void;
655
- removeProject(projectId: string): void;
656
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
657
- /** TraceIndex: the mechanism TraceIndexService implements. */
658
- declare abstract class TraceIndex extends TraceIndex_base {
837
+ abstract removeSession(projectId: string, agentId: string, sessionId: string): void;
838
+ abstract removeAgent(projectId: string, agentId: string): void;
839
+ abstract removeProject(projectId: string): void;
659
840
  }
660
841
 
842
+ interface PlatformCatalogPricing {
843
+ unit: "usd_per_mtok";
844
+ cacheRead: number;
845
+ cacheWrite: number;
846
+ output: number;
847
+ }
848
+ /** A platform model normalized into the fields Penguin persists for a newly discovered row. */
849
+ interface PlatformCatalogModel {
850
+ modelId: string;
851
+ displayName: string;
852
+ contextWindow: number;
853
+ supportsVision: boolean;
854
+ /**
855
+ * List price, which is what a Project stores: the platform's `listPricing` when it runs a
856
+ * promotion on the model, its billed `pricing` otherwise.
857
+ */
858
+ pricing: PlatformCatalogPricing;
859
+ /** Fraction off `pricing` the platform is running (0.5 = half price); absent when none. */
860
+ discount?: number;
861
+ baseUrl: string;
862
+ clientType: "mmsp";
863
+ }
864
+ /** Validated snapshot returned by Penguin Go's client-model catalog. */
865
+ interface PlatformModelCatalog {
866
+ models: PlatformCatalogModel[];
867
+ }
661
868
  /**
662
- * "desktop" and "setup" may set a password without the old one (theirs is random and was never
663
- * shown); desktop-only routes open to "desktop" alone. "token" is the local API token's Bearer
664
- * header — per request, never a stored row. Anything else reads as "password".
869
+ * Catalog merge result. `updated` counts route migrations; existing metadata is preserved.
665
870
  */
666
- type SessionVia = "password" | "desktop" | "setup" | "token";
667
-
668
- interface UserRow {
669
- userId: string;
670
- passwordHash: string;
671
- isAdmin: boolean;
672
- /** Still using the initial password (seeded / set by an admin); cleared to 0 once the user changes it. */
673
- passwordIsInitial: boolean;
674
- /** Nickname shown in place of the id; null = never set. */
675
- displayName: string | null;
676
- /** Avatar as a data URL; null = never set. */
677
- avatar: string | null;
678
- createdAt: string;
871
+ interface PlatformModelApplyResult {
872
+ added: number;
873
+ updated: number;
874
+ applied: number;
679
875
  }
680
876
 
681
877
  type RawTable = Record<string, unknown>;
@@ -695,20 +891,26 @@ type UtilityCompletion = {
695
891
  error: string;
696
892
  };
697
893
 
698
- declare const ProjectConfigStore_base: (abstract new () => {
699
- readRaw(projectId: string): Promise<RawTable>;
700
- loadConfig(projectId: string): Promise<ProjectConfig>;
701
- writeRaw(projectId: string, data: RawTable): Promise<void>;
702
- writeInitialConfig(projectId: string, name: string): Promise<void>;
703
- ensurePresetModels(projectId: string): Promise<void>;
704
- getName(projectId: string): Promise<string | undefined>;
705
- setName(projectId: string, name: string): Promise<void>;
706
- getDefaultModelRef(projectId: string): Promise<ModelRef | undefined>;
707
- setDefaultModelRef(projectId: string, ref: ModelRefDto): Promise<ModelRefDto>;
708
- getChatDefaults(projectId: string): Promise<ChatDefaultsDto>;
709
- setChatDefaults(projectId: string, req: ChatDefaultsDto): Promise<ChatDefaultsDto>;
710
- getCommandPolicy(projectId: string): Promise<CommandPolicyDto>;
711
- setCommandPolicy(projectId: string, req: {
894
+ /** ProjectConfigStore: the mechanism ProjectConfigService implements. */
895
+ declare abstract class ProjectConfigStore {
896
+ abstract readRaw(projectId: string): Promise<RawTable>;
897
+ abstract loadConfig(projectId: string): Promise<ProjectConfig>;
898
+ abstract writeRaw(projectId: string, data: RawTable): Promise<void>;
899
+ abstract writeInitialConfig(projectId: string, name: string): Promise<void>;
900
+ abstract ensurePresetModels(projectId: string): Promise<boolean>;
901
+ abstract seedPresetPromotions(projectId: string): Promise<void>;
902
+ abstract getName(projectId: string): Promise<string | undefined>;
903
+ abstract setName(projectId: string, name: string): Promise<void>;
904
+ abstract getDefaultModelRef(projectId: string): Promise<ModelRef | undefined>;
905
+ abstract setDefaultModelRef(projectId: string, ref: ModelRefDto): Promise<ModelRefDto>;
906
+ abstract getChatDefaults(projectId: string): Promise<ChatDefaultsDto>;
907
+ abstract setChatDefaults(projectId: string, req: ChatDefaultsDto): Promise<ChatDefaultsDto>;
908
+ /** The `[plugins]` key: the shared table and each machine's own, package name → requirement, in the file's order. */
909
+ abstract getPluginTables(projectId: string): Promise<PluginTables>;
910
+ /** Replaces the tables (a declarative PUT); answers what was written. */
911
+ abstract setPluginTables(projectId: string, tables: PluginTables): Promise<PluginTables>;
912
+ abstract getCommandPolicy(projectId: string): Promise<CommandPolicyDto>;
913
+ abstract setCommandPolicy(projectId: string, req: {
712
914
  enabled?: boolean;
713
915
  rules: {
714
916
  name: string;
@@ -717,20 +919,74 @@ declare const ProjectConfigStore_base: (abstract new () => {
717
919
  enabled?: boolean;
718
920
  }[];
719
921
  }): Promise<CommandPolicyDto>;
720
- getPricing(projectId: string, provider: string, modelId: string): Promise<TieredRates | undefined>;
721
- detectVision(projectId: string, req: ModelVisionDetectRequest): Promise<ModelVisionDetectResponse>;
722
- testModel(projectId: string, req: ModelTestRequest): Promise<ModelTestResponse>;
723
- detectProtocol(projectId: string, req: ModelProtocolDetectRequest): Promise<ModelProtocolDetectResponse>;
724
- listEndpointModels(req: EndpointModelListRequest, listImpl?: (options: ListEndpointModelsOptions) => Promise<string[]>, timeoutMs?: number): Promise<EndpointModelListResponse>;
725
- getModels(projectId: string): Promise<ModelsResponse>;
726
- updateModels(projectId: string, req: ModelsUpdateRequest): Promise<ModelsResponse>;
727
- setGroupApiKey(projectId: string, provider: string, apiKey: string): Promise<number>;
728
- completeOnce(projectId: string, prompt: string): Promise<UtilityCompletion>;
729
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
730
- /** ProjectConfigStore: the mechanism ProjectConfigService implements. */
731
- declare abstract class ProjectConfigStore extends ProjectConfigStore_base {
922
+ abstract getPricing(projectId: string, provider: string, modelId: string): Promise<TieredRates | undefined>;
923
+ abstract detectVision(projectId: string, req: ModelVisionDetectRequest): Promise<ModelVisionDetectResponse>;
924
+ abstract testModel(projectId: string, req: ModelTestRequest): Promise<ModelTestResponse>;
925
+ abstract detectProtocol(projectId: string, req: ModelProtocolDetectRequest): Promise<ModelProtocolDetectResponse>;
926
+ abstract listEndpointModels(req: EndpointModelListRequest, listImpl?: (options: ListEndpointModelsOptions) => Promise<string[]>, timeoutMs?: number): Promise<EndpointModelListResponse>;
927
+ abstract getModels(projectId: string): Promise<ModelsResponse>;
928
+ abstract updateModels(projectId: string, req: ModelsUpdateRequest): Promise<ModelsResponse>;
929
+ /** One group's `[providers.<id>]` connection, merged per field; rows are never touched. */
930
+ abstract setProviderConnection(projectId: string, provider: string, patch: ProviderConnectionUpdate): Promise<ModelsResponse>;
931
+ /** "Add new models" (`add`) or "Restore defaults" (`restore`) against the built-in catalog. */
932
+ abstract syncPresets(projectId: string, mode: PresetSyncMode): Promise<PresetSyncResponse>;
933
+ /** Writes the group key; resolves to how many of the group's rows use it (none of their own). */
934
+ abstract setGroupApiKey(projectId: string, provider: string, apiKey: string): Promise<number>;
935
+ abstract setGroupApiKeyWithProviderAuthToken(projectId: string, provider: string, apiKey: string, token: Omit<ModelProviderAuthToken, "provider" | "updatedAt">, options?: {
936
+ expectedRefreshToken?: string;
937
+ }): Promise<number>;
938
+ /** The group key (`[providers.<id>].api_key`), never a row's own. Server-side only. */
939
+ abstract getGroupApiKey(projectId: string, provider: string): Promise<string | undefined>;
940
+ /** One row's own key (its override of the group's), or undefined. Server-side only. */
941
+ abstract getModelApiKey(projectId: string, provider: string, modelId: string): Promise<string | undefined>;
942
+ /**
943
+ * The key a group's account balance is read with: the group key (never a row's own), or
944
+ * else the environment key a Session on one of the group's rows would use on its effective
945
+ * endpoint, when that variable's official endpoint is the balance endpoint's own host.
946
+ * Server-side only.
947
+ */
948
+ abstract getGroupBalanceKey(projectId: string, provider: string): Promise<string | undefined>;
949
+ abstract setModelApiKeyResolver(resolver: (context: ModelRequestContext) => Promise<string | undefined>): void;
950
+ abstract mergePlatformModels(projectId: string, provider: string, catalog: PlatformModelCatalog, apiKey: string, applyKeyToExisting: boolean): Promise<PlatformModelApplyResult>;
951
+ abstract completeOnce(projectId: string, prompt: string): Promise<UtilityCompletion>;
952
+ }
953
+ interface ModelProviderAuthToken {
954
+ provider: string;
955
+ refreshToken: string;
956
+ accessTokenExpiresAt?: string;
957
+ updatedAt: string;
732
958
  }
733
959
 
960
+ /**
961
+ * The order a Session list is served in: `created` (the default) is newest creation first;
962
+ * `activity` is most recent `lastActiveAt` first — the order the sidebar displays, and the only
963
+ * one an {@link ActivityCursor} pages.
964
+ */
965
+ type SessionListOrder = "created" | "activity";
966
+ /** A row's place in the activity order; as a `before` cursor, the last row the client holds. */
967
+ interface ActivityCursor {
968
+ lastActiveAt: string;
969
+ sessionId: string;
970
+ }
971
+ /** One row the listing rule files as archived (SessionService.archivedRows). */
972
+ interface ArchivedRow {
973
+ row: SessionRow;
974
+ /** The source the row was classified by; absent while its Trace head is unread. */
975
+ source?: SessionSource;
976
+ /** Whether a Trace record exists: what toInfo takes for this row. */
977
+ hasTrace: boolean;
978
+ }
979
+ /**
980
+ * A slice of a Session list: `offset` rows skipped (the `created` contract, also accepted under
981
+ * `activity`), or every row strictly below `before` in the activity order.
982
+ */
983
+ type SessionListPaging = {
984
+ offset: number;
985
+ limit: number;
986
+ } | {
987
+ before: ActivityCursor;
988
+ limit: number;
989
+ };
734
990
  interface SessionServiceDeps {
735
991
  root: string;
736
992
  sessions: SessionIndex;
@@ -759,6 +1015,14 @@ interface SessionServiceDeps {
759
1015
  * this harness's own `penguin`, put in front of every command an Agent runs.
760
1016
  */
761
1017
  pathPrepend?: () => string[];
1018
+ /**
1019
+ * Tells every user of a Project that a Session now exists. The list only ever learns
1020
+ * about rows it did not create itself from this: a Session started by the CLI, by
1021
+ * another tab, by a schedule, or by an agent spawning a child sat invisible until the
1022
+ * next full reload without it. Optional so the service keeps unit-testing without a
1023
+ * channel registry; absent means nobody is told.
1024
+ */
1025
+ notifyProjectUsers?: (projectId: string, event: ServerEvent) => void;
762
1026
  /**
763
1027
  * The channel of the Session's ENABLED messaging binding, or null when none is enabled
764
1028
  * (SessionInfo.messagingChannel, the sidebar row's per-channel indicator — saved-but-
@@ -766,7 +1030,7 @@ interface SessionServiceDeps {
766
1030
  * service stays decoupled from the bindings table; absent (older assemblies/tests)
767
1031
  * means the field is never set.
768
1032
  */
769
- messagingChannel?: (sessionId: string) => MessagingChannel$1 | null;
1033
+ messagingChannel?: (sessionId: string) => MessagingChannel | null;
770
1034
  /**
771
1035
  * Company mode: the organization owning a Session (a desk session, or a session
772
1036
  * contributing to a ticket), for `SessionInfo.orgId` — development mode's list hides
@@ -779,44 +1043,99 @@ interface SessionServiceDeps {
779
1043
  orgIdOfSession?: (sessionId: string) => string | undefined;
780
1044
  orgIdsOfProject?: (projectId: string) => ReadonlyMap<string, string>;
781
1045
  /** Spawn-confinement getter (the sandbox module's), forwarded into core beside proxyEnv. */
782
- confineSpawn?: () => SpawnConfiner | null;
1046
+ confineSpawn?: (ctx: ControlEnvContext) => SpawnConfiner | null;
1047
+ /** The server's Sandbox settings: what a new Session's policy is snapshotted from. */
1048
+ sandboxDefaults?: () => SandboxSettings;
1049
+ /** Host-owned model-request hooks, forwarded to core for every Session LLM. */
1050
+ assembly?: AgentAssembly;
1051
+ /** The dimensions the mounted sandbox backends implement between them (none when absent). */
1052
+ sandboxDimensions?: () => readonly SandboxDimension[];
1053
+ /** The enabled sandbox backends that failed to load or failed their check, with why. */
1054
+ sandboxUnavailable?: () => readonly UnavailableSandboxBackend[];
1055
+ /** The names of the sandbox backends in use, in routing preference (none when absent). */
1056
+ sandboxBackends?: () => readonly string[];
1057
+ /** The Sandbox card's presets table, in table order (absent: the view carries none). */
1058
+ sandboxPresets?: () => readonly SessionSandboxPreset[];
1059
+ /** The Sandbox card's switch: whether new Sessions start confined (absent: not reported). */
1060
+ sandboxSwitchOn?: () => boolean;
1061
+ /** The approval mode a new Session starts with when its request names none (the default preset's). */
1062
+ sandboxDefaultApproval?: () => ApprovalMode | undefined;
783
1063
  }
784
1064
  declare class SessionService {
785
1065
  private readonly deps;
786
1066
  constructor(deps: SessionServiceDeps);
1067
+ /** The policy a new Session starts with: the server's Sandbox settings. */
1068
+ defaultSandbox(): SandboxSettings;
1069
+ /** Whether this server can enforce the `local` network level right now. */
1070
+ localNetworkSupported(): boolean;
1071
+ private sandboxDimensions;
1072
+ /** A policy as the composer sees it, with which of its levels this server can enforce. */
1073
+ sandboxView(policy: SandboxSettings): SessionSandbox;
1074
+ /**
1075
+ * What a new Session starts from, as the composer's draft reads it (the chat defaults): the
1076
+ * settings' policy, plus the approval mode the default preset gives a request naming none.
1077
+ */
1078
+ defaultsView(): SessionSandbox;
1079
+ /**
1080
+ * The approval mode a Session created without one starts with. An organization's Session
1081
+ * keeps `allow-all`: its runtime names the mode it wants, and nobody is there to answer an
1082
+ * ask a preset might bring. The other unattended creators — a scheduled run, a workflow —
1083
+ * pass `allow-all` themselves (scheduler.ts, workflows/service.ts).
1084
+ */
1085
+ private startApproval;
1086
+ /** A Session's policy: its snapshot, or — for a row from before snapshots — the settings. */
1087
+ sandboxOf(row: SessionRow): SandboxSettings;
1088
+ /**
1089
+ * The policy a pick would give one Session, checked — the non-admin ceiling and what this
1090
+ * server can enforce — and not written: a PATCH checks every field before it writes any.
1091
+ */
1092
+ pickSandbox(row: SessionRow, pick: Partial<SessionSandbox>, isAdmin: boolean): SandboxSettings;
1093
+ /** Stores one Session's policy (`pickSandbox`'s): its next command runs under it. */
1094
+ updateSandbox(sessionId: string, policy: SandboxSettings): void;
787
1095
  /**
788
1096
  * DB row -> SessionInfo (run status and pending approval count come from session-manager).
789
1097
  * Async because `source` is derived from session_meta: a registry miss (Session predating
790
1098
  * this process) falls back to reading the Trace head once (see sourceOf). `traces` is the
791
1099
  * list flow's one-walk discovery result; without it a miss locates the shard itself.
1100
+ * `archived` is the listing rule's answer (listCategory), not the bare mark: a background
1101
+ * Session the user never kept reads archived, and a subagent with a stray mark does not.
792
1102
  *
793
1103
  * `orgIds` is the list flow's one-query organization map (see listSessions); without it the
794
1104
  * organization is a point lookup, which is what the single-Session paths want.
795
1105
  */
796
1106
  toInfo(row: SessionRow, hasTrace: boolean, orgIds?: ReadonlyMap<string, string>): Promise<SessionInfo>;
797
1107
  /**
798
- * A Session's origin, with session_meta as the single source of truth: the in-process
799
- * registry answers first (populated at creation / subagent registration / adoption /
1108
+ * A Session's source, with session_meta as the single source of truth: the in-process
1109
+ * registry answers first (populated at creation / subagent registration / forks / adoption /
800
1110
  * index registration); on a miss (a Session created before this process started) the
801
1111
  * trace index's registration-time facts answer — the reconciler head-read the earliest
802
- * shard once when the file first appeared, so no file is touched here. A Session with
803
- * no Trace yet stays unknown and is NOT cached negatively — its meta may appear with
804
- * the first run.
1112
+ * shard once when the file first appeared, so no file is touched here. A head that records
1113
+ * no source is read with the row's client (readRecordedSource). A Session with no Trace yet
1114
+ * is NOT cached — its meta appears with the first run — and reads as its row says
1115
+ * (unrunSource): the organization runtime's as `company`, the Agent API's as `api`, any other
1116
+ * as unknown.
805
1117
  */
806
1118
  private sourceOf;
807
1119
  /** Whether this Session already has a Trace record (a Task has been run): answered by the index (reconciled first). */
808
1120
  hasTrace(row: SessionRow): Promise<boolean>;
809
1121
  /**
810
- * The list category of a row: archived wins (an explicit user action), then the
811
- * origin's bucket, and no/unknown source is `active` — the same precedence the
812
- * sidebar's partition applies to loaded rows, so server filtering and client
813
- * rendering can never disagree.
1122
+ * The list category of a row (see listCategory): none for a `subagent` or `company` Session,
1123
+ * whatever its marks, which the list never serves; otherwise archived when the user archived
1124
+ * it or when a program opened it and the user has not kept it, else active.
814
1125
  */
815
1126
  private categoryOf;
816
1127
  /**
817
- * List, sorted by createdAt descending. Every row is served **straight from the DB**,
818
- * whichever client created it, with no Trace directory scanning — the answer to
819
- * many-session sidebar reloads re-walking the filesystem on every request (#139).
1128
+ * Where one row is listed, for a caller holding just the row (a PATCH, the archive page's
1129
+ * batches). A row the registry already classified costs nothing; any other is looked up
1130
+ * through the trace index once (hasTrace reconciles the Agent), so a subagent Session is
1131
+ * known for one even before any list has walked it.
1132
+ */
1133
+ listingOf(row: SessionRow): Promise<SessionCategory | null>;
1134
+ /**
1135
+ * List, sorted by createdAt descending — or, with `order: "activity"`, by lastActiveAt
1136
+ * descending (ties by sessionId, see {@link compareActivityDesc}). Every row is served
1137
+ * **straight from the DB**, whichever client created it, with no Trace directory scanning —
1138
+ * the answer to many-session sidebar reloads re-walking the filesystem on every request (#139).
820
1139
  * Sessions living only in the Trace directory were adopted into the index by the
821
1140
  * boot-time sweep (`adoptUnmanagedTraceSessions`), so listing never discovers. One
822
1141
  * lazy discovery walk still runs for a list call that contains rows this process has
@@ -828,36 +1147,78 @@ declare class SessionService {
828
1147
  * "has more"); slicing happens before toInfo, so per-request source derivation (lazy
829
1148
  * Trace-head reads) stays bounded by the page size.
830
1149
  *
831
- * `category` filters to one sidebar bucket **before** paging, so offset/limit page
832
- * within the category. Filtering needs each walked row's category (a possible
833
- * Trace-head read per row, cached in the sources registry); without `withCounts`
834
- * the walk stops as soon as the requested page is complete. `withCounts` classifies
835
- * every row and returns per-category totals over the whole list — plus the same
836
- * totals broken down by Workspace path, and each path's newest Session's `createdAt` —
837
- * so the sidebar can label the collapsed folders, list every Workspace that holds
838
- * Sessions (not only the ones its loaded pages happen to touch) and place the groups
839
- * by recency, all without loading them.
1150
+ * The `before` form pages the activity order by cursor: only rows strictly below it are
1151
+ * walked and served. An offset cannot page that order, because a row below the offset that
1152
+ * becomes active moves above it and the next page would skip a row; a cursor stays put — the
1153
+ * moved row is simply not served again (the client learns of it from `session_state`). The
1154
+ * offset form keeps serving the `created` order exactly as before.
1155
+ *
1156
+ * `category` filters to one list (the sidebar's `active`, the archive page's `archived`)
1157
+ * **before** paging, so offset/limit page within the category. Filtering needs each walked
1158
+ * row's category (a possible Trace-head read per row, cached in the sources registry);
1159
+ * without `withCounts` the walk stops as soon as the requested page is complete.
1160
+ * `withCounts` classifies every row, a cursor or not, and returns per-category totals over
1161
+ * the whole list — plus the same totals broken down by Workspace path, and each path's
1162
+ * newest Session's `createdAt`, once over every category (`workspaceLatest`, the Workspace
1163
+ * picker's "recently used") and once over the active ones (`workspaceLatestActive`) — so the
1164
+ * sidebar can list every Workspace that holds active Sessions (not only the ones its loaded
1165
+ * pages happen to touch) and place the groups by the recency of what they show, all without
1166
+ * loading them.
840
1167
  *
841
1168
  * `workspaceGroup` filters the same way, to one Workspace group (see workspace-group.ts),
842
1169
  * so a sidebar grouped by Workspace pages each group down its OWN stream instead of
843
1170
  * sharing one per-Agent cursor — without it, one group's "load more" consumes the page
844
1171
  * its siblings were about to read, and their rows move on screen untouched. The two
845
1172
  * filters compose; the returned counts stay whole-Agent either way.
1173
+ *
1174
+ * A `subagent` or `company` Session — a child its parent's Agent panel opens, company mode's
1175
+ * desk and ticket Sessions — belongs to no category (listCategory), whatever its marks: every
1176
+ * classified form of the list (`category`, `workspaceGroup` or `withCounts`) leaves it out of
1177
+ * the page, the totals, the Workspace breakdown and its stamps alike. The plain form, which
1178
+ * classifies nothing, still serves every row.
1179
+ *
1180
+ * `excludeOrg` drops the rows an organization owns (its desk and ticket sessions, and the
1181
+ * sub-sessions they spawned) from the stream BEFORE anything else looks at it — the page,
1182
+ * `counts`, `workspaceCounts`, both Workspace stamps and the limit+1 "has more" all describe the
1183
+ * same own-rows stream. It is what development mode's list asks for: that list draws the
1184
+ * user's own conversations, and a total or a stamp that still counted a desk or a ticket
1185
+ * session would make its Workspace appear as a group the list can never fill. The rule above
1186
+ * does not replace it: a person's conversation attached to a ticket is stamped `org` but
1187
+ * stays `user`, and a row the organization caches name before the reconcile pass stamps it
1188
+ * reads as `user`. Without the flag every row is served, whichever client created it, but
1189
+ * for that rule.
846
1190
  */
847
1191
  listSessions(projectId: string, agentId: string, opts?: {
848
- paging?: {
849
- offset: number;
850
- limit: number;
851
- };
1192
+ paging?: SessionListPaging;
1193
+ order?: SessionListOrder;
852
1194
  category?: SessionCategory;
853
1195
  workspaceGroup?: string;
854
1196
  withCounts?: boolean;
1197
+ excludeOrg?: boolean;
855
1198
  }): Promise<{
856
1199
  sessions: SessionInfo[];
857
1200
  counts?: SessionCategoryCounts;
858
1201
  workspaceCounts?: Record<string, SessionCategoryCounts>;
859
1202
  workspaceLatest?: Record<string, string>;
1203
+ workspaceLatestActive?: Record<string, string>;
860
1204
  }>;
1205
+ /**
1206
+ * The archive page's walk (services/archived-sessions-service.ts): every row of the Agent the
1207
+ * listing rule files as archived — the rows `listSessions` serves with `category: "archived"`
1208
+ * and `excludeOrg`, classified the same way — with the source each was classified by and
1209
+ * whether it has a Trace. It builds no SessionInfo: the page makes one (toInfo) only for the
1210
+ * rows a response carries, so a request costs a classification per archived row, not a full
1211
+ * row view per archived row.
1212
+ */
1213
+ archivedRows(projectId: string, agentId: string): Promise<ArchivedRow[]>;
1214
+ /**
1215
+ * The rows a list walk starts from: the Agent's index rows, an organization's left out when
1216
+ * `excludeOrg` asks (see listSessions), with the Project's organization map; and when any row
1217
+ * predates this process, the one reconciled Trace discovery (`traces`) that lets every row be
1218
+ * classified without per-row work and backfills the `has_trace` cache. Steady state —
1219
+ * every row classified — skips the discovery and leaves `traces` absent.
1220
+ */
1221
+ private walkRows;
861
1222
  /**
862
1223
  * Session stats (Agents list card): total count = size of the union of DB index
863
1224
  * ∪ Trace directory discovery; activity = number of active Sessions per day over
@@ -887,20 +1248,28 @@ declare class SessionService {
887
1248
  provider?: string;
888
1249
  workspace?: string;
889
1250
  approvalMode?: ApprovalMode;
1251
+ /** The composer's sandbox picks; omitted halves take the server's settings. */
1252
+ sandbox?: Partial<SessionSandbox>;
1253
+ /** Whether the creator is an administrator (may loosen past the settings). Default false. */
1254
+ isAdmin?: boolean;
890
1255
  /**
891
- * Session source marker: `schedule` when triggered by a scheduled task, `benchmark` when
892
- * created by a Benchmark evaluation or optimization (the only value a client may send);
893
- * defaults to user-created.
1256
+ * What kind of conversation this is, recorded in the Session's session_meta: `schedule`
1257
+ * from the scheduler, `company` from the organization runtime, `cli` from `penguin run`
1258
+ * (the only source a request may name), `api` from an Agent API run; absent means `user`,
1259
+ * a person's conversation.
894
1260
  */
895
- source?: "schedule" | "benchmark";
1261
+ source?: SessionSource;
896
1262
  /**
897
1263
  * Creating-client hint stored on the index row (`POST .../sessions` body `client`):
898
- * "cli" from the CLI, defaulting to "web". "org" is not accepted over HTTP — the
899
- * organization runtime calls this method directly and is the only caller that passes
900
- * it, so no request can claim an organization's provenance for itself.
1264
+ * "cli" from the CLI, defaulting to "web". "org" and "api" are not accepted over HTTP —
1265
+ * the organization runtime and the Agent API's run handler call this method directly and
1266
+ * are the only callers that pass them, so no request can claim either provenance for
1267
+ * itself ("api" is what lets the Agent API continue a Session).
901
1268
  */
902
- client?: "web" | "cli" | "org";
1269
+ client?: "web" | "cli" | "org" | "api";
903
1270
  }): Promise<SessionInfo>;
1271
+ /** A new Session's snapshot: the settings, with the creator's picks (checked) on top. */
1272
+ private snapshotSandbox;
904
1273
  /**
905
1274
  * Absolute path of a Session's **latest** Trace file (the current context shard);
906
1275
  * undefined when no Trace exists. Costs a directory walk, so only the single-session
@@ -936,16 +1305,118 @@ declare class SessionService {
936
1305
  private adoptTraceSession;
937
1306
  }
938
1307
 
1308
+ type ModelScopeAuthStatusResult = ModelScopeAuthFlowStatusResponse & {
1309
+ changed?: true;
1310
+ };
1311
+ interface ModelScopeCredential {
1312
+ accessToken: string;
1313
+ refreshToken?: string;
1314
+ expiresAt?: string;
1315
+ }
1316
+ interface ModelScopeRefreshResult {
1317
+ changed: boolean;
1318
+ }
1319
+ interface ModelScopeAuthDeps {
1320
+ /** Base URL of the bridge, without a trailing slash (config.modelscopeBridgeUrl). */
1321
+ bridgeUrl: string;
1322
+ /**
1323
+ * Writes the delivered credential as the group key; resolves to how many of the group's rows
1324
+ * use the access token (0 also when a refresh lost to a newer authorization and wrote nothing).
1325
+ */
1326
+ applyCredential: (projectId: string, credential: ModelScopeCredential, options?: {
1327
+ expectedRefreshToken?: string;
1328
+ }) => Promise<number>;
1329
+ /** Reads the server-side refresh metadata for the group. */
1330
+ readStoredCredential?: (projectId: string) => ModelProviderAuthToken | undefined;
1331
+ fetchImpl?: typeof fetch;
1332
+ now?: () => number;
1333
+ }
1334
+ declare class ModelScopeAuthService {
1335
+ private readonly deps;
1336
+ private readonly flows;
1337
+ private readonly refreshes;
1338
+ private readonly refreshFailures;
1339
+ private readonly fetchImpl;
1340
+ private readonly now;
1341
+ constructor(deps: ModelScopeAuthDeps);
1342
+ private url;
1343
+ private isPending;
1344
+ private request;
1345
+ ensureFresh(input: {
1346
+ projectId: string;
1347
+ provider: string;
1348
+ }): Promise<ModelScopeRefreshResult>;
1349
+ start(input: {
1350
+ projectId: string;
1351
+ userId: string;
1352
+ }): Promise<{
1353
+ flowId: string;
1354
+ authorizeUrl: string;
1355
+ expiresAt: string;
1356
+ }>;
1357
+ status(input: {
1358
+ flowId: string;
1359
+ projectId: string;
1360
+ userId: string;
1361
+ }): Promise<ModelScopeAuthStatusResult>;
1362
+ retryApply(input: {
1363
+ flowId: string;
1364
+ projectId: string;
1365
+ userId: string;
1366
+ }): Promise<ModelScopeAuthStatusResult>;
1367
+ cancel(input: {
1368
+ flowId: string;
1369
+ projectId: string;
1370
+ userId: string;
1371
+ }): void;
1372
+ private refreshState;
1373
+ private refreshNow;
1374
+ private reauthorizationRequired;
1375
+ private pollBridge;
1376
+ private apply;
1377
+ private publicFlow;
1378
+ private requireFlow;
1379
+ private sweep;
1380
+ private evictOldest;
1381
+ }
1382
+ declare const ModelScopeAuth_base: (abstract new () => Pick<ModelScopeAuthService, "status" | "start" | "retryApply" | "cancel" | "ensureFresh">) & (<C>(target: C, context: ClassDecoratorContext) => C);
1383
+ /** The per-App ModelScope key authorization capability consumed by Project model routes. */
1384
+ declare abstract class ModelScopeAuth extends ModelScopeAuth_base {
1385
+ }
1386
+
939
1387
  /** Minimal interface for a runtime Session (satisfied by core Session; tests may inject a fake implementation). */
1388
+ /** What one run is started with: the approval callback and the interrupt signal. */
1389
+ type RunOpts = {
1390
+ approve: ApproveFn;
1391
+ signal: AbortSignal;
1392
+ };
940
1393
  interface RuntimeSession {
941
1394
  readonly sessionId: string;
942
- run(newMessages: OmniMessage[], opts: {
943
- approve: ApproveFn;
944
- signal: AbortSignal;
945
- }): AsyncGenerator<OmniMessage>;
1395
+ run(newMessages: OmniMessage[], opts: RunOpts): AsyncGenerator<OmniMessage>;
946
1396
  compact(opts: {
947
1397
  signal: AbortSignal;
948
1398
  }): AsyncGenerator<OmniMessage>;
1399
+ /**
1400
+ * The running context's model (core `Session.provider` / `Session.modelId`, getters over
1401
+ * the context's session_meta): the row's pair at creation, moved by each in-session switch
1402
+ * — and, after a restart, whatever the Trace resumed on. Optional: test fakes may omit them,
1403
+ * in which case the entry keeps the row's pair.
1404
+ */
1405
+ readonly provider?: string;
1406
+ readonly modelId?: string;
1407
+ /**
1408
+ * Switches the Session's model in place (core `Session.switchModel`): closes the running
1409
+ * context on the model it ran on, then opens the next one on the target. A completed switch
1410
+ * streams the new context's main-session `session_meta` last, and the getters above answer
1411
+ * the target by then; a refusal is thrown before the first event; a Session that never ran
1412
+ * switches without streaming anything. Optional: test fakes may omit it, reading as
1413
+ * "switching is not available".
1414
+ */
1415
+ switchModel?(opts: {
1416
+ provider: string;
1417
+ modelId: string;
1418
+ signal: AbortSignal;
1419
+ }): AsyncGenerator<OmniMessage, StopReason>;
949
1420
  /**
950
1421
  * The Session's thinking level (core `Session.thinkingLevel`, plain state): soft-limited —
951
1422
  * an assignment applies from the Session's very next LLM request. Optional: test fakes may
@@ -965,6 +1436,13 @@ interface RuntimeSession {
965
1436
  unsteer?(input: OmniMessage[]): boolean;
966
1437
  /** Skips the in-progress reconnect backoff, firing the next retry immediately (core `Session.skipReconnectWait`); false when no wait is in progress. */
967
1438
  skipReconnectWait(): boolean;
1439
+ /**
1440
+ * Whether a run with empty input would send anything (core `Session.hasPendingInput`): the
1441
+ * failed turn's input held as carry-over — in process, or rebuilt from the Trace after a
1442
+ * restart — or a compaction summary waiting for the next run. Optional: test fakes may omit
1443
+ * it, reading as nothing held.
1444
+ */
1445
+ hasPendingInput?(): boolean;
968
1446
  /**
969
1447
  * Runs the named package's `user_prompt` hook (core `Session.runUserPromptHook` — hooks
970
1448
  * run in core and nowhere else); null = the package is not installed or names no such
@@ -1041,6 +1519,8 @@ interface UsageRecorderLike {
1041
1519
  record(ctx: UsageContext, msg: OmniMessage): Promise<void>;
1042
1520
  }
1043
1521
  interface SessionManagerDeps {
1522
+ /** The in-memory state this manager works on (see agent-state.ts). Optional: a manager built without one — unit tests — gets an empty state of its own. */
1523
+ state?: AgentState;
1044
1524
  sessions: SessionIndex;
1045
1525
  channels: ChannelHub;
1046
1526
  loader: SessionLoader;
@@ -1051,6 +1531,8 @@ interface SessionManagerDeps {
1051
1531
  titles?: TitleNotifier;
1052
1532
  /** Error persistence (optional: without it, only logs — same as before this was wired up). */
1053
1533
  errors?: ErrorSink;
1534
+ /** Provider auth refresh (optional for tests that do not exercise external model credentials). */
1535
+ modelScopeAuth?: ModelScopeAuth;
1054
1536
  log?: (line: string) => void;
1055
1537
  /** Goal run-state persistence (optional like `titles`: without it, goals run but leave no restorable record). */
1056
1538
  /**
@@ -1087,9 +1569,120 @@ interface RecallStore {
1087
1569
  images: string[];
1088
1570
  files: RecallableFile[];
1089
1571
  }
1572
+ /** One queued follow-up task (`queueIfBusy`): the task input, held until the session is idle. */
1573
+ interface QueuedFollowUp {
1574
+ /** Recall handle (PendingFollowUpInfo.id), assigned at queue time. */
1575
+ id: string;
1576
+ input: OmniMessage[];
1577
+ /**
1578
+ * Original content for recall, and the content `task_state` shows on the queued line.
1579
+ * Always present: a caller that knows more than the input carries (the HTTP route, which
1580
+ * also knows where the file attachments landed on disk) supplies it, and every other
1581
+ * queueing path gets it derived from the input — what can be recalled must not depend on
1582
+ * which door the message came through.
1583
+ */
1584
+ recall: RecallStore;
1585
+ }
1586
+ /** One undelivered steering entry: the display info broadcast on task_state, plus what a recall needs — the exact input list core queued (its unsteer handle) and the original content. */
1587
+ interface PendingSteeringEntry {
1588
+ info: PendingSteeringInfo;
1589
+ input: OmniMessage[];
1590
+ recall: RecallStore;
1591
+ }
1592
+ /** Active-table entry: a loaded runtime Session plus its running state. */
1593
+ interface RuntimeEntry {
1594
+ sessionId: string;
1595
+ projectId: string;
1596
+ agentId: string;
1597
+ /**
1598
+ * The Session's current model (provider group paired with modelId): what the next drive
1599
+ * attributes usage to. The row's pair, kept in step with the runtime's own answer (see
1600
+ * `syncEntryModel`) — at load, and whenever a model switch moves it.
1601
+ */
1602
+ provider: string;
1603
+ modelId: string;
1604
+ session: RuntimeSession;
1605
+ status: SessionStatus;
1606
+ approvals: Approvals;
1607
+ abort: AbortController | null;
1608
+ /** The in-flight drive Promise (awaited during graceful shutdown). */
1609
+ running: Promise<void> | null;
1610
+ /**
1611
+ * Agent config generation this runtime was built under (see
1612
+ * invalidateAgentRuntimes): once it falls behind the Agent's current generation,
1613
+ * the entry is discarded on its next idle access and re-resumed via the loader.
1614
+ */
1615
+ generation: number;
1616
+ /**
1617
+ * Queued follow-up tasks (`queueIfBusy`): task inputs accepted while a Task/compaction was
1618
+ * in progress, auto-started one at a time (in order) once the session returns to idle —
1619
+ * ordinary tasks with normal semantics, unlike the mid-run steering queue.
1620
+ * Deliberately NOT discarded on abort: they are future tasks the user explicitly queued.
1621
+ */
1622
+ followUps: QueuedFollowUp[];
1623
+ /**
1624
+ * The running Task's input messages, held from launch until the run ends. The engine
1625
+ * writes these exact envelopes to the Trace only after the session bootstrap (MCP
1626
+ * connect + discovery on the first run), so a history read during that window would
1627
+ * miss the user's own message — and the draft flow subscribes to the stream only after
1628
+ * the input publish, so the live channel cannot backfill it either. GET /messages
1629
+ * appends the ones the Trace has not caught up to yet (exact-envelope dedup).
1630
+ */
1631
+ pendingInputs: OmniMessage[];
1632
+ /**
1633
+ * The running Task's streamed bootstrap records (mcp_connect begin/end,
1634
+ * tool_list_ready), held until the run ends. Their Trace writes are deferred by the
1635
+ * engine until after the input lands (turn attribution), and the draft flow subscribes
1636
+ * only after they were published — so a history rebuild during the MCP connect would
1637
+ * otherwise show nothing at all (a silent blank while a slow server times out).
1638
+ * GET /messages appends whichever of them the Trace has not caught up to.
1639
+ */
1640
+ pendingBootstrap: OmniMessage[];
1641
+ /**
1642
+ * Steering messages queued on core but not yet delivered to the model — a display mirror
1643
+ * of core's steering queue (same FIFO order), so the composer's "steering queued" hint and
1644
+ * its content survive reloads: pushed on `steer`, shifted as each `[user_steering]`
1645
+ * message appears on the drive stream, dropped wholesale when the run exits (core
1646
+ * discards undelivered steering on abort/completion). The `info` halves are broadcast on
1647
+ * every `task_state`; the rest is the recall handle (see recallSteering).
1648
+ */
1649
+ pendingSteering: PendingSteeringEntry[];
1650
+ /**
1651
+ * Steering the run ended without ever delivering — handed back to the user instead of
1652
+ * discarded (#287 follow-up). An interrupt mid-tool-call is the ordinary way to get here:
1653
+ * core drops its queue when the run exits, so the message would otherwise vanish with the
1654
+ * text the user had already typed.
1655
+ *
1656
+ * Entries move here from `pendingSteering` when the run exits and stay recallable by the
1657
+ * same handle, so the composer pulls them back into its draft (auto-recall on observing
1658
+ * them, a reload included). They are deliberately NOT cleared when the next run starts:
1659
+ * the message was never delivered whatever happens later, and dropping it there would
1660
+ * reintroduce exactly the loss this list exists to prevent. Only a recall — or the entry's
1661
+ * idle eviction — removes one.
1662
+ */
1663
+ returnedSteering: PendingSteeringEntry[];
1664
+ /** Timestamp of last activity (refreshed on load / status flip / drive completion / background-task change), used for idle-eviction checks. */
1665
+ lastActivityMs: number;
1666
+ /**
1667
+ * Background-task counts as last read from the runtime — at entry creation, then on every
1668
+ * background-state ping. The baseline `session_background` is published against: a ping
1669
+ * that leaves the counts where they were (a foreground-window child settling, an exited
1670
+ * process being removed from the list) publishes nothing.
1671
+ */
1672
+ backgroundTasks: SessionBackgroundTasks;
1673
+ }
1090
1674
  declare class SessionManager {
1091
1675
  private readonly deps;
1676
+ private readonly state;
1092
1677
  private readonly entries;
1678
+ /**
1679
+ * Each registered subagent Session's ROOT Session: a subagent runs under its root's
1680
+ * sandbox policy, as it runs under its root's approval mode, so a change the person makes
1681
+ * in the composer reaches the children already running.
1682
+ */
1683
+ private readonly childRoots;
1684
+ /** The Session whose policy governs `sessionId`: its root for a subagent, else itself. */
1685
+ rootSessionOf(sessionId: string): string;
1093
1686
  /** Per-Session mutex (serializes get-or-load and status flips); auto-cleaned once the chain drains. */
1094
1687
  private readonly locks;
1095
1688
  private readonly log;
@@ -1099,6 +1692,8 @@ declare class SessionManager {
1099
1692
  private readonly deletingAgents;
1100
1693
  /** Sessions currently being deleted (guards against the entry/Trace file being rebuilt and reviving it inside the deletion race window). */
1101
1694
  private readonly deletingSessions;
1695
+ /** Sessions whose runtime entry idle eviction leaves alone (see keepLoaded). */
1696
+ private readonly keptLoaded;
1102
1697
  /** Per-Agent config generation (key = agentKey), bumped by invalidateAgentRuntimes when a Project's credentials change. */
1103
1698
  private readonly agentGenerations;
1104
1699
  /** Open streaming fragments of running sessions (fed by drive, served to GET /messages; see live-tail.ts). */
@@ -1193,6 +1788,14 @@ declare class SessionManager {
1193
1788
  * The entry-lifetime approval callback: the registry, the per-decision approval-mode
1194
1789
  * re-read, and the SSE escalation are all entry-scoped, so one instance serves every run
1195
1790
  * of the entry and the children's session-lifetime fallback sink alike.
1791
+ *
1792
+ * This is also where the one cross-cutting approval override lives — wrapping the callback
1793
+ * handed to `Session.run` rather than teaching the engine anything: an organization's
1794
+ * sessions run with nobody watching, so a call their approval mode would hand to a person
1795
+ * is denied here instead of waiting for an answer that is never coming (see `unattended`
1796
+ * in approvals.ts). The marker is the row's durable `client = "org"` stamp — desk, ticket
1797
+ * and the sub-sessions that inherit it — read per decision, so a row the reconcile pass
1798
+ * stamps later is covered from its next decision on.
1196
1799
  */
1197
1800
  private entryApprove;
1198
1801
  /** Publishes one live background-subagent message and records its usage (fire-and-forget; the child's own Trace is the durable record). */
@@ -1256,6 +1859,20 @@ declare class SessionManager {
1256
1859
  sessionId: string;
1257
1860
  queued: boolean;
1258
1861
  }>;
1862
+ /**
1863
+ * Retry a failed run (`POST /retry`): a Task started with EMPTY input, so core sends the
1864
+ * input of the turn that failed — held as carry-over since the run ended `fatal` or gave
1865
+ * up reconnecting — and nothing else. No user message is published or recorded, and with no
1866
+ * Prompt there is no user_prompt consult. Gated like startTask (busy is the same 409) but
1867
+ * never queued, and refused with 409 `nothing_to_retry` when nothing is held — the user's
1868
+ * next message already resent that input, or no run failed — since the run would end at
1869
+ * once and the client would watch a Task start and stop with nothing sent. Not a person's
1870
+ * input for company mode's hop accounting: the turn it resends was counted, or not, when
1871
+ * it was first sent.
1872
+ */
1873
+ retryTask(sessionId: string): Promise<{
1874
+ sessionId: string;
1875
+ }>;
1259
1876
  /**
1260
1877
  * Start a goal run: like startTask, but the goal plugin composes the input and its stop
1261
1878
  * hook drives every later round inside this one `session.run` call — so the Session
@@ -1281,7 +1898,9 @@ declare class SessionManager {
1281
1898
  * Taps a goal run's stream for `drive`: round boundaries become goal_round events —
1282
1899
  * round 1 from the seeded input (core never yields a run's initial input, so it is
1283
1900
  * counted here, where startGoal published it), later rounds from the stop-hook continues
1284
- * core yields — and the goal hook's `stop` event becomes the
1901
+ * core yields, each announced by the hook's `continue` event; a harness-stamped input
1902
+ * nothing announced is another package's user_prompt context riding behind the
1903
+ * objective, not a round — and the goal hook's `stop` event becomes the
1285
1904
  * goal_finished server event. `used` is what the hook last recorded in its event's
1286
1905
  * `output` — the same number its budget check used — so the UI never shows a different
1287
1906
  * figure. A stream that ends without the hook's terminal event (a cut-off run, an
@@ -1290,7 +1909,12 @@ declare class SessionManager {
1290
1909
  private goalStream;
1291
1910
  /** Closes a goal as aborted for the UI (stream cut off / infrastructure failure). */
1292
1911
  private finishAborted;
1293
- /** Shared task launch (fresh tasks and auto-started follow-ups): flips to running, publishes the input, and drives the run. Caller holds the session lock and has verified idle. */
1912
+ /**
1913
+ * Shared task launch (fresh tasks, auto-started follow-ups and retries): flips to running,
1914
+ * publishes the input, and drives the run. Caller holds the session lock and has verified
1915
+ * idle. A retry's input is empty: nothing is published or held, and drive gets no title
1916
+ * material — the turn it resends already offered its text when it was first sent.
1917
+ */
1294
1918
  private launchTask;
1295
1919
  /**
1296
1920
  * Auto-start of queued follow-ups: called from drive's finally whenever a Task or
@@ -1305,6 +1929,53 @@ declare class SessionManager {
1305
1929
  startCompact(sessionId: string): Promise<{
1306
1930
  sessionId: string;
1307
1931
  }>;
1932
+ /**
1933
+ * Switches the Session's model in place (`POST /switch-model`) — core `Session.switchModel`,
1934
+ * gated like a compaction (open, not deleting, idle). Core decides everything before its
1935
+ * first event, so the head of its stream is pulled here, under the lock, and tells the three
1936
+ * outcomes apart:
1937
+ *
1938
+ * - it throws — a refusal, answered 409 with the code of its reason (see `switchRefusal`);
1939
+ * - it is already done — a Session that never ran has no context to close: core re-assembled
1940
+ * its first context on the target, nothing streams, and the row carries the new pair by
1941
+ * the time this returns (`switched: true`; the route answers with the fresh DTO);
1942
+ * - it yields — a driven run like a compaction (`switched: false`): status `compacting`,
1943
+ * idle when it ends. The head is a compaction's begin, the first record of a bootstrap (a
1944
+ * Session loaded from its Trace opens its context first), or — for a context with no
1945
+ * completed turn, which streams no pair — the opener's first record.
1946
+ *
1947
+ * The switch is the entry's run from that pull on — it can be stopped, and a deletion or a
1948
+ * shutdown waits for it — while the entry only reads `compacting` once there is something
1949
+ * to stream, so a refusal never flickers a state.
1950
+ *
1951
+ * The entry and the row follow the runtime as the new context's `session_meta` passes
1952
+ * through the drive (see `drive`); a switch that does not complete streams no meta and
1953
+ * leaves them where they were. Usage: a drive bills to the model it started on, so the
1954
+ * switch's compaction request goes to the model that served it and the next run to the new
1955
+ * one.
1956
+ */
1957
+ startSwitch(sessionId: string, ref: ModelRefDto): Promise<{
1958
+ sessionId: string;
1959
+ switched: boolean;
1960
+ }>;
1961
+ /** Who is told when a Session's model moves (see `onModelChanged`). */
1962
+ private readonly modelListeners;
1963
+ /**
1964
+ * Subscribes to a Session's model moving: an in-session switch completing, or a row brought
1965
+ * back in step with its Trace when the Session loads. The listener runs once the entry and
1966
+ * the row carry the new pair. Returns the unsubscribe. Company mode listens: an employee's
1967
+ * model is its desk Session's.
1968
+ */
1969
+ onModelChanged(listener: (sessionId: string, model: ModelRefDto) => void): () => void;
1970
+ /**
1971
+ * Moves the entry — and the row it caches into — to the model the runtime reports itself on,
1972
+ * when that differs: the pair the next drive attributes usage to, and the one
1973
+ * `GET /sessions/:id` describes. A runtime that reports none (test fakes) leaves the entry
1974
+ * alone. The row write is guarded like the other bookkeeping writes (see `touchRow`): a
1975
+ * switch must not be stranded mid-drive by a closed DB handle, and the entry is right either
1976
+ * way. The same holds for whoever listens: a listener that throws is recorded, not rethrown.
1977
+ */
1978
+ private syncEntryModel;
1308
1979
  /** Submit an approval decision; returns false if the pending approval doesn't exist (already decided/unknown). */
1309
1980
  decideApproval(sessionId: string, toolCallId: string, decision: "allow" | "deny"): boolean;
1310
1981
  /**
@@ -1436,6 +2107,15 @@ declare class SessionManager {
1436
2107
  */
1437
2108
  beginSessionDeletion(sessionId: string): Promise<void>[];
1438
2109
  endSessionDeletion(sessionId: string): void;
2110
+ /**
2111
+ * The hand-over's half of a swap: this generation stops working on the state and leaves
2112
+ * everything in it as it is — running Tasks keep running, pending approvals keep waiting —
2113
+ * for the next generation to take over (PRFC-0015). Only what is this instance's own stops:
2114
+ * the idle sweep. `shutdown` is the other ending, for a state nobody takes over.
2115
+ */
2116
+ detach(): void;
2117
+ /** The Sessions with a Task in flight right now — what a swap parks, so that a successor that cannot take the state over knows which ones to start again. */
2118
+ runningSessionIds(): string[];
1439
2119
  /** Graceful shutdown: reject new tasks (503), interrupt all active runs, and wait for them to finish (default ≤5s). */
1440
2120
  shutdown(timeoutMs?: number): Promise<void>;
1441
2121
  /**
@@ -1448,6 +2128,34 @@ declare class SessionManager {
1448
2128
  * tests and timers.
1449
2129
  */
1450
2130
  sweepIdle(now?: number, idleMs?: number): void;
2131
+ /**
2132
+ * Pins (`on`) or releases a Session's runtime entry against idle eviction (see sweepIdle).
2133
+ * The messaging bridge holds the pin for as long as a binding's connection is enabled: that
2134
+ * Session is where the bot lives on this server, and evicting it after half an hour of quiet
2135
+ * makes the next chat message wait for a resume from the Trace before anything else happens.
2136
+ *
2137
+ * It pins only what is loaded and loads nothing itself (preload does). A stale id pins
2138
+ * nothing: an entry a delete removed is gone from the table whatever this set says, and the
2139
+ * bridge releases the id when its connection goes.
2140
+ */
2141
+ keepLoaded(sessionId: string, on: boolean): void;
2142
+ /**
2143
+ * Loads a Session's runtime into the active table ahead of its first Task, through the same
2144
+ * get-or-resume path that Task would take, so the first message after a messaging connection
2145
+ * comes up — an enable, a server restart — does not pay for a resume from the Trace on top of
2146
+ * everything else. Only the load: no run starts, and the core bootstrap (session metadata,
2147
+ * MCP connections) still happens on the first run. Under the Session lock, like startTask, so
2148
+ * a Task arriving mid-load waits for this load instead of starting a second one.
2149
+ *
2150
+ * A Session that is gone or being deleted, alone or with its Agent, resolves quietly: there is
2151
+ * nothing to warm and the caller has nothing to do about it. So does one with no Trace yet,
2152
+ * because loading it is a self-heal REBUILD under a new session id — that would move the
2153
+ * Session out from under the binding that asked, and earlier than any Task would. The row's
2154
+ * `hasTrace` is a cache, so a row that has not caught up only misses the warm-up. Any other
2155
+ * load failure rejects; the first Task meets the same failure and reports it where a person
2156
+ * will see it.
2157
+ */
2158
+ preload(sessionId: string): Promise<void>;
1451
2159
  private assertOpen;
1452
2160
  /** The Agent owning this Session is being deleted → 409 (guards against directory recreation inside the deletion race window). */
1453
2161
  private assertAgentNotDeleting;
@@ -1455,6 +2163,7 @@ declare class SessionManager {
1455
2163
  private assertSessionNotDeleting;
1456
2164
  private assertIdle;
1457
2165
  private generationOf;
2166
+ private refreshProviderCredentialIfNeeded;
1458
2167
  /** get-or-resume-or-heal: use directly on an active-table hit; otherwise load via the loader, updating the index's primary key on self-heal. */
1459
2168
  private ensureEntry;
1460
2169
  /**
@@ -1504,14 +2213,21 @@ declare class SessionManager {
1504
2213
  * row is gone as well.
1505
2214
  */
1506
2215
  private publishBackgroundTasks;
2216
+ /**
2217
+ * Publishes `session_approvals` on the user channel: how many tool calls of this Session wait
2218
+ * for a person now. The Session's own stream carries the calls; this is what lets a list, or
2219
+ * a host watching every Session of a Project, see which one waits without subscribing to each.
2220
+ * Sent for an entry that is being disposed too, so a mark it had is cleared.
2221
+ */
2222
+ private publishApprovals;
1507
2223
  /** Serialize (mutually exclude) execution by sessionId; cleans up the lock-table entry once its chain drains (avoids unbounded growth). */
1508
2224
  private withLock;
1509
2225
  }
1510
- declare const Sessions_base: (abstract new () => Pick<SessionManager, "steer" | "pendingApprovalCount" | "pendingFollowUpCount" | "statusOf" | "pendingApprovals" | "pendingSteeringOf" | "subagentsOf" | "sendToSubagent" | "abortSubagentRun" | "pendingFollowUpsOf" | "liveFragments" | "pendingInputs" | "pendingBootstrap" | "activeCountForAgent" | "invalidateAgentRuntimes" | "invalidateProjectRuntimes" | "assertCanAcceptTask" | "startTask" | "startGoal" | "startCompact" | "decideApproval" | "recallSteering" | "recallFollowUp" | "retryNow" | "abortTask" | "listProcesses" | "probeProcessServices" | "killProcess" | "removeProcess" | "abortProject" | "beginAgentDeletion" | "endAgentDeletion" | "beginSessionDeletion" | "endSessionDeletion" | "atIdleBoundary" | "shutdown" | "sweepIdle">) & (<C>(target: C, context: ClassDecoratorContext) => C);
2226
+ declare const Sessions_base: (abstract new () => Pick<SessionManager, "steer" | "pendingApprovalCount" | "pendingFollowUpCount" | "statusOf" | "pendingApprovals" | "pendingSteeringOf" | "subagentsOf" | "sendToSubagent" | "abortSubagentRun" | "pendingFollowUpsOf" | "liveFragments" | "pendingInputs" | "pendingBootstrap" | "activeCountForAgent" | "invalidateAgentRuntimes" | "invalidateProjectRuntimes" | "assertCanAcceptTask" | "startTask" | "retryTask" | "startGoal" | "startCompact" | "startSwitch" | "onModelChanged" | "decideApproval" | "recallSteering" | "recallFollowUp" | "retryNow" | "abortTask" | "listProcesses" | "probeProcessServices" | "killProcess" | "removeProcess" | "abortProject" | "beginAgentDeletion" | "endAgentDeletion" | "beginSessionDeletion" | "endSessionDeletion" | "atIdleBoundary" | "shutdown" | "detach" | "runningSessionIds" | "sweepIdle" | "keepLoaded" | "preload">) & (<C>(target: C, context: ClassDecoratorContext) => C);
1511
2227
  /** The session runtime: one entry per live Session, task mutex, approvals, streaming. */
1512
2228
  declare abstract class Sessions extends Sessions_base {
1513
2229
  }
1514
- declare const SessionServiceIface_base: (abstract new () => Pick<SessionService, "hasTrace" | "toInfo" | "listSessions" | "sessionStats" | "createSession" | "latestTracePath" | "adoptUnmanagedTraceSessions">) & (<C>(target: C, context: ClassDecoratorContext) => C);
2230
+ declare const SessionServiceIface_base: (abstract new () => Pick<SessionService, "hasTrace" | "toInfo" | "listingOf" | "listSessions" | "archivedRows" | "sessionStats" | "createSession" | "defaultSandbox" | "pickSandbox" | "updateSandbox" | "latestTracePath" | "adoptUnmanagedTraceSessions">) & (<C>(target: C, context: ClassDecoratorContext) => C);
1515
2231
  declare abstract class SessionServiceIface extends SessionServiceIface_base {
1516
2232
  }
1517
2233
 
@@ -1586,42 +2302,40 @@ declare class AgentConfigService implements AgentConfig {
1586
2302
  updateVault(projectId: string, agentId: string, req: VaultUpdateRequest): Promise<VaultResponse>;
1587
2303
  }
1588
2304
 
1589
- declare const AgentConfig_base: (abstract new () => {
1590
- exists(projectId: string, agentId: string): Promise<boolean>;
1591
- requireExists(projectId: string, agentId: string): Promise<void>;
1592
- readCardMeta(projectId: string, agentId: string): Promise<{
2305
+ /** AgentConfig: the mechanism AgentConfigService implements. */
2306
+ declare abstract class AgentConfig {
2307
+ abstract exists(projectId: string, agentId: string): Promise<boolean>;
2308
+ abstract requireExists(projectId: string, agentId: string): Promise<void>;
2309
+ abstract readCardMeta(projectId: string, agentId: string): Promise<{
1593
2310
  name?: string;
1594
2311
  description?: string;
1595
2312
  toolCount: number;
1596
2313
  version: number;
1597
2314
  kernelOutdated: boolean;
1598
2315
  }>;
1599
- getConfig(projectId: string, agentId: string): Promise<AgentConfigView>;
1600
- updateConfig(projectId: string, agentId: string, req: AgentConfigUpdateRequest): Promise<void>;
1601
- resetConfig(projectId: string, agentId: string): Promise<void>;
1602
- kernelUpdate(projectId: string, agentId: string): Promise<AgentKernelUpdateResponse>;
1603
- insertTemplatePlaceholder(projectId: string, agentId: string, feature: "vault" | "skills" | "schedules"): Promise<AgentConfigView>;
1604
- getVault(projectId: string, agentId: string): Promise<VaultResponse>;
1605
- updateVault(projectId: string, agentId: string, req: VaultUpdateRequest): Promise<VaultResponse>;
1606
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
1607
- /** AgentConfig: the mechanism AgentConfigService implements. */
1608
- declare abstract class AgentConfig extends AgentConfig_base {
2316
+ abstract getConfig(projectId: string, agentId: string): Promise<AgentConfigView>;
2317
+ abstract updateConfig(projectId: string, agentId: string, req: AgentConfigUpdateRequest): Promise<void>;
2318
+ abstract resetConfig(projectId: string, agentId: string): Promise<void>;
2319
+ abstract kernelUpdate(projectId: string, agentId: string): Promise<AgentKernelUpdateResponse>;
2320
+ abstract insertTemplatePlaceholder(projectId: string, agentId: string, feature: "vault" | "skills" | "schedules"): Promise<AgentConfigView>;
2321
+ abstract getVault(projectId: string, agentId: string): Promise<VaultResponse>;
2322
+ abstract updateVault(projectId: string, agentId: string, req: VaultUpdateRequest): Promise<VaultResponse>;
1609
2323
  }
1610
- declare const AgentLifecycle_base: (abstract new () => {
1611
- listAgents(projectId: string): Promise<AgentListItem[]>;
1612
- deleteAgent(projectId: string, agentId: string): Promise<void>;
1613
- createAgent(projectId: string, agentId: string, name?: string, description?: string, skillNames?: readonly string[], directory?: {
2324
+ /** AgentLifecycle: the mechanism AgentService implements. */
2325
+ declare abstract class AgentLifecycle {
2326
+ abstract listAgents(projectId: string): Promise<AgentListItem[]>;
2327
+ /** Every id `createAgent` refuses as taken, as names only, including a folder that does not list. */
2328
+ abstract takenAgentIds(projectId: string): Promise<string[]>;
2329
+ abstract deleteAgent(projectId: string, agentId: string): Promise<void>;
2330
+ abstract createAgent(projectId: string, agentId: string, name?: string, description?: string, skillNames?: readonly string[], directory?: {
1614
2331
  path: string;
1615
2332
  names: readonly string[];
1616
2333
  }, archive?: Buffer<ArrayBufferLike>): Promise<AgentListItem>;
1617
- pluginVersion(projectId: string, agentId: string, pluginName: string): Promise<{
2334
+ abstract pluginVersion(projectId: string, agentId: string, pluginName: string): Promise<{
1618
2335
  installed: string | null;
1619
2336
  library: string | null;
1620
2337
  }>;
1621
- updatePlugin(projectId: string, agentId: string, pluginName: string): Promise<void>;
1622
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
1623
- /** AgentLifecycle: the mechanism AgentService implements. */
1624
- declare abstract class AgentLifecycle extends AgentLifecycle_base {
2338
+ abstract updatePlugin(projectId: string, agentId: string, pluginName: string): Promise<void>;
1625
2339
  }
1626
2340
 
1627
2341
  interface AgentListItem {
@@ -1658,6 +2372,12 @@ declare class AgentService implements AgentLifecycle {
1658
2372
  private readonly snapshots;
1659
2373
  /** Union of DB index ∪ directory scan; unmanaged directory Agents are backfilled into the DB. */
1660
2374
  listAgents(projectId: string): Promise<AgentListItem[]>;
2375
+ /**
2376
+ * Every id `createAgent` refuses as taken, as names only: the index rows and every entry under
2377
+ * `agents/`. Unlike `listAgents`, this includes a folder with no `system_config.yaml`, and it
2378
+ * opens no Agent.
2379
+ */
2380
+ takenAgentIds(projectId: string): Promise<string[]>;
1661
2381
  /** Number of vault keys (falls back to 0 on read failure). */
1662
2382
  private vaultKeyCount;
1663
2383
  /** Number of scheduled tasks: count of .toml files under schedule/ (0 if the directory doesn't exist). */
@@ -1665,7 +2385,9 @@ declare class AgentService implements AgentLifecycle {
1665
2385
  /**
1666
2386
  * One pass over `skills/` and one over `hooks/`, answering the card's questions: how many
1667
2387
  * skills and hook packages are installed, and which of them the plugin library has moved
1668
- * past — by plugin, since a plugin is what gets reinstalled to catch up.
2388
+ * past — each part against the library's same part (a skill's dated version against that
2389
+ * skill's, a hook package's against the plugin's `hooks.version`), reported by plugin, since
2390
+ * a plugin is what gets reinstalled to catch up.
1669
2391
  *
1670
2392
  * Only the HEAD of each SKILL.md is read, and that bound is load-bearing rather than a
1671
2393
  * micro-optimization: a preinstalled library is ~180 KB of SKILL.md across seventeen files
@@ -1686,18 +2408,20 @@ declare class AgentService implements AgentLifecycle {
1686
2408
  */
1687
2409
  private installedPlugins;
1688
2410
  /**
1689
- * Where one library plugin stands on one Agent: `installed` is the OLDEST version among the
1690
- * plugin's installed skills and its installed hook package — the same "any component behind
1691
- * the library is an update" rule {@link installedPlugins} draws the list cards' hints from —
1692
- * and null when the Agent carries none of them; `library` is the version the library offers
1693
- * now, null when the library has no such plugin. Only the head of each SKILL.md is read
1694
- * (see SKILL_HEAD_BYTES), so the answer costs one small read per skill the plugin ships.
2411
+ * Where one library plugin stands on one Agent, as one pair of dated versions of the same
2412
+ * part — so `library` newer than `installed` is exactly "some part is behind", the rule
2413
+ * {@link installedPlugins} draws the list cards' hints from. Each part the Agent carries (a
2414
+ * skill, the hook package) is paired with the library's same part; among the parts that are
2415
+ * behind — or, when none is, among all of them — the one with the OLDEST installed version
2416
+ * answers. `installed` is null when the Agent carries none of the plugin's parts, with
2417
+ * `library` then the plugin's content version; both are null when the library has no such
2418
+ * plugin. Only the head of each SKILL.md is read (see SKILL_HEAD_BYTES), so the answer costs
2419
+ * one small read per skill the plugin ships.
1695
2420
  *
1696
2421
  * The organization runtime asks this per employee per pass to keep company plugins current.
1697
2422
  * A skill the Agent does not carry — never installed, or removed by hand — counts for
1698
- * nothing: what is compared is the oldest version the Agent actually has, so a plugin whose
1699
- * skills are all current reads as current even where one of them is missing. Restoring a
1700
- * deleted skill is the Agents page's business, not a pass's.
2423
+ * nothing: a plugin whose carried skills are all current reads as current even where one of
2424
+ * them is missing. Restoring a deleted skill is the Agents page's business, not a pass's.
1701
2425
  */
1702
2426
  pluginVersion(projectId: string, agentId: string, pluginName: string): Promise<{
1703
2427
  installed: string | null;
@@ -1748,13 +2472,14 @@ declare class AgentService implements AgentLifecycle {
1748
2472
  }, archive?: Buffer): Promise<AgentListItem>;
1749
2473
  }
1750
2474
 
1751
- declare const MessagingBindings_base: (abstract new () => {
1752
- find(sessionId: string, channel: string): MessagingBindingRow | null;
1753
- findEnabled(sessionId: string): MessagingBindingRow | null;
1754
- listForSession(sessionId: string): MessagingBindingRow[];
1755
- findEnabledByAccount(channel: string, accountId: string): MessagingBindingRow | null;
1756
- listAll(): MessagingBindingRow[];
1757
- upsert(args: {
2475
+ /** MessagingBindings: the mechanism MessagingBindingsRepo implements. */
2476
+ declare abstract class MessagingBindings {
2477
+ abstract find(sessionId: string, channel: string): MessagingBindingRow | null;
2478
+ abstract findEnabled(sessionId: string): MessagingBindingRow | null;
2479
+ abstract listForSession(sessionId: string): MessagingBindingRow[];
2480
+ abstract findEnabledByAccount(channel: string, accountId: string): MessagingBindingRow | null;
2481
+ abstract listAll(): MessagingBindingRow[];
2482
+ abstract upsert(args: {
1758
2483
  sessionId: string;
1759
2484
  channel: string;
1760
2485
  accountId: string;
@@ -1763,14 +2488,11 @@ declare const MessagingBindings_base: (abstract new () => {
1763
2488
  finalReplyOnly?: boolean;
1764
2489
  renderMarkdown?: boolean;
1765
2490
  }): MessagingBindingRow;
1766
- setEnabled(sessionId: string, channel: string, enabled: boolean): void;
1767
- recordChat(sessionId: string, channel: string, chatId: string, isDirect: boolean): void;
1768
- recordInboundWatermark(sessionId: string, channel: string, messageId: string | null): void;
1769
- delete(sessionId: string, channel: string): void;
1770
- deleteSession(sessionId: string): void;
1771
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
1772
- /** MessagingBindings: the mechanism MessagingBindingsRepo implements. */
1773
- declare abstract class MessagingBindings extends MessagingBindings_base {
2491
+ abstract setEnabled(sessionId: string, channel: string, enabled: boolean): void;
2492
+ abstract recordChat(sessionId: string, channel: string, chatId: string, isDirect: boolean): void;
2493
+ abstract recordInboundWatermark(sessionId: string, channel: string, messageId: string | null): void;
2494
+ abstract delete(sessionId: string, channel: string): void;
2495
+ abstract deleteSession(sessionId: string): void;
1774
2496
  }
1775
2497
 
1776
2498
  interface MessagingBindingRow {
@@ -1846,8 +2568,7 @@ interface MessagingBindingRow {
1846
2568
  * every connector method validates its own shape and throws a readable error on a
1847
2569
  * malformed one — the bridge treats that like any other channel failure.
1848
2570
  */
1849
- /** Known messaging channels (the DB stores the discriminator as text; unknown values are skipped defensively). */
1850
- type MessagingChannel = "feishu" | "telegram" | "qq" | "wechat";
2571
+
1851
2572
  /** One inbound image's bytes, once fetched, with the MIME type the bridge needs for its data URL. */
1852
2573
  interface MessagingInboundImageData {
1853
2574
  data: Buffer;
@@ -1957,8 +2678,25 @@ interface MessagingConnectorHandlers {
1957
2678
  onMessage(msg: MessagingInboundMessage): void | Promise<void>;
1958
2679
  /** The connection completed a handshake (may fire again after an automatic reconnect). */
1959
2680
  onReady?(): void;
1960
- /** The connection failed and the channel gave up (or the initial connect failed). */
2681
+ /**
2682
+ * The connection failed and the channel gave up (or the initial connect failed). A
2683
+ * {@link MessagingChannelError} says whether the outage clears without anyone acting.
2684
+ */
1961
2685
  onError?(err: unknown): void;
2686
+ /**
2687
+ * The connection's account started or stopped holding replies it could not deliver yet
2688
+ * (see {@link MessagingReplyHeldError}): the ISO time since which it holds some, or null once
2689
+ * it holds none. Fired on every change, and once at connect for a backlog held from before.
2690
+ * Only a channel that holds replies (WeChat) ever calls it.
2691
+ */
2692
+ onHeldChange?(since: string | null): void;
2693
+ /**
2694
+ * A send the connector made on its OWN — a withheld tail flushed after the quiet period, held
2695
+ * replies delivered on the next inbound message — failed for good. No caller is waiting on
2696
+ * those sends, so this is the only way their failure reaches the binding's status and the
2697
+ * error table.
2698
+ */
2699
+ onSendFailed?(err: unknown): void;
1962
2700
  }
1963
2701
  /** A live inbound event stream; `close` ends it (idempotent). */
1964
2702
  interface MessagingConnection {
@@ -2020,6 +2758,13 @@ interface MessagingSendOptions {
2020
2758
  * reach the one message a user sends to check whether the binding works at all.
2021
2759
  */
2022
2760
  markdown?: boolean;
2761
+ /**
2762
+ * This send is a probe of the outbound leg ("send test message"), not a reply. A connector
2763
+ * that would HOLD a refused message for later delivery must throw
2764
+ * {@link MessagingNeedsRecentMessageError} instead: a held probe that arrives an hour later
2765
+ * proves nothing, and the person pressing the button needs to hear why it did not arrive now.
2766
+ */
2767
+ probe?: boolean;
2023
2768
  }
2024
2769
  /** Outbound half of one bound account. Every method throws on failure with a readable reason. */
2025
2770
  interface MessagingClient {
@@ -2071,7 +2816,8 @@ interface MessagingChannelConnector {
2071
2816
  * applies to every route behind this middleware, SSE endpoints included (the CLI
2072
2817
  * consumes SSE via fetch with headers). A Bearer header that does not match fails the
2073
2818
  * request rather than falling back to the cookie: silently downgrading a wrong explicit
2074
- * credential would mask misconfiguration.
2819
+ * credential would mask misconfiguration. A few writes refuse the token all the same and take a
2820
+ * person's sign-in (requireHuman).
2075
2821
  *
2076
2822
  * Accessing a protected API while logged out -> 401 `{error:{code:"unauthorized"}}`.
2077
2823
  * CSRF: SameSite=Lax plus a Content-Type an HTML form cannot forge (see jsonOnlyWrites).
@@ -2104,6 +2850,16 @@ interface MessagingTaskRunnerShape {
2104
2850
  sessionId: string;
2105
2851
  queued: boolean;
2106
2852
  }>;
2853
+ /**
2854
+ * Pins the Session's runtime against idle eviction while a connection is enabled (`on`), or
2855
+ * releases the pin.
2856
+ */
2857
+ keepLoaded(sessionId: string, on: boolean): void;
2858
+ /**
2859
+ * Loads the Session's runtime ahead of its first message, starting nothing; resolves quietly
2860
+ * for a Session that is gone or being deleted.
2861
+ */
2862
+ preload(sessionId: string): Promise<void>;
2107
2863
  }
2108
2864
  /**
2109
2865
  * Minimal dependency on the sessions index: existence checks for reconcile/cascade, the
@@ -2293,6 +3049,14 @@ declare class MessagingBridge {
2293
3049
  * the log, which is where "the replies moved to General a while ago" is answerable at all.
2294
3050
  */
2295
3051
  private noteSend;
3052
+ /** The connector's `onHeldChange`, behind the stale-entry guard every connector callback has. */
3053
+ private setHeldReplySince;
3054
+ /**
3055
+ * Whether a send's failure is the connector HOLDING the reply rather than losing it (see
3056
+ * MessagingReplyHeldError). Such a send is not a delivery failure — no error record, no
3057
+ * `lastDeliveryError` — and is logged once per holding episode, not once per message.
3058
+ */
3059
+ private wasHeld;
2296
3060
  private clientFor;
2297
3061
  /**
2298
3062
  * Has this binding already processed this message? A duplicate is a complete no-op —
@@ -2470,9 +3234,12 @@ declare class MessagingBridge {
2470
3234
  * A file the run did not write is dropped SILENTLY, and so is a name matching no file at
2471
3235
  * all: the rule reads prose, so a reply that mentions the config it read — or describes a
2472
3236
  * `hello-world.md` it never wrote — is the ordinary case, and announcing those puts an
2473
- * error-shaped line under correct answers. Both are logged instead. What IS named in the
2474
- * chat is a file that exists and whose upload failed: there the reply promised something
2475
- * that then did not arrive, which is the one case where silence reads as broken.
3237
+ * error-shaped line under correct answers. Both are logged instead. What IS recorded is a
3238
+ * file that exists and still did not go out — over a ceiling, past the count cap, or
3239
+ * refused on the way: the reply promised something that then did not arrive, so it is filed
3240
+ * under the Session's Project, once the batch is done, in one record per cause naming every
3241
+ * file it held back (see messagingFilesNotSentRecords). None of it is posted into the chat,
3242
+ * which carries the reply and its files and nothing about the ones that stayed behind.
2476
3243
  *
2477
3244
  * Always plain sends, never a threaded reply: a run that mentions a file has by
2478
3245
  * definition already sent the text that mentions it, and that message took the group's
@@ -2481,19 +3248,11 @@ declare class MessagingBridge {
2481
3248
  */
2482
3249
  private deliverFiles;
2483
3250
  /**
2484
- * Names one file that did not make it, in the chat.
2485
- *
2486
- * Every other way a file does not arrive is already visible there — over the byte cap,
2487
- * past the count cap, an inbound refusal. A failed upload reached `error_records` alone,
2488
- * which the person in the chat cannot open, so the feature just looked broken. A missing
2489
- * permission gets its own wording: it is the one failure they can fix themselves, in
2490
- * about ten seconds, given the scope name and the console link.
2491
- *
2492
- * Its own try/catch: a chat that will not take the notice must not take the rest of the
2493
- * batch down with it, and the upload failure behind it is already recorded.
3251
+ * One mirrored file: read under the outer ceiling, then sent as a picture or an attachment.
3252
+ * Resolves null once the file went out. A file over the ceiling for its kind is not sent and
3253
+ * resolves to that ceiling instead; a read or a send the channel refused throws. The caller
3254
+ * records both (see messagingFilesNotSentRecords).
2494
3255
  */
2495
- private noteFileFailure;
2496
- /** One mirrored file: read under the outer ceiling, then sent as a picture or an attachment. */
2497
3256
  private deliverOneFile;
2498
3257
  /** One-line notice (approval waiting) to the last known chat; silent before one exists. */
2499
3258
  private deliverNotice;
@@ -2521,7 +3280,7 @@ declare const MessagingTaskRunner_base: (abstract new () => MessagingTaskRunnerS
2521
3280
  /** What the bridge needs of the session runtime — declared at the consumer. */
2522
3281
  declare abstract class MessagingTaskRunner extends MessagingTaskRunner_base {
2523
3282
  }
2524
- declare const Messaging_base: (abstract new () => Pick<MessagingBridge, "start" | "stop" | "statusOf" | "sync" | "unbind" | "unbindSession" | "testCredentials" | "sendTestMessage">) & (<C>(target: C, context: ClassDecoratorContext) => C);
3283
+ declare const Messaging_base: (abstract new () => Pick<MessagingBridge, "stop" | "sync" | "start" | "statusOf" | "unbind" | "unbindSession" | "testCredentials" | "sendTestMessage">) & (<C>(target: C, context: ClassDecoratorContext) => C);
2525
3284
  /** The chat-channel bridge: bindings, delivery, status. */
2526
3285
  declare abstract class Messaging extends Messaging_base {
2527
3286
  }
@@ -2532,11 +3291,32 @@ interface MessagingSlots {
2532
3291
  }, MessagingChannelConnector>;
2533
3292
  }
2534
3293
 
2535
- declare const Http_base: (abstract new () => {
2536
- fetch(request: Opaque<"Request", Request>): Promise<Opaque<"Response", Response>>;
2537
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
3294
+ /** A settings group as a module declares it: a configuration, and where the page draws it. */
3295
+ interface SettingsGroupDecl extends PluginConfiguration {
3296
+ /** Another group's name (its contribution id): this one is drawn inside that card and saved with it. */
3297
+ parent?: string;
3298
+ /** Position among the groups: lower first (absent = 100), then declaration order. */
3299
+ order?: number;
3300
+ }
3301
+ /** What a module reads: the group it declared, and a watch on it. */
3302
+ declare abstract class PluginConfig {
3303
+ /** The stored values merged onto the declared defaults; `{}` for a name no group answers to. */
3304
+ abstract get(name: string): Record<string, unknown>;
3305
+ /** Fires with the new document after every save of `name`; returns the unsubscribe. */
3306
+ abstract watch(name: string, cb: (values: Record<string, unknown>) => void): () => void;
3307
+ /** Whether anything was ever saved under `name` — what tells a default from a choice. */
3308
+ abstract saved(name: string): boolean;
3309
+ /** The configuration `name` was declared with (what `resolveTable` reads a table by); undefined for none. */
3310
+ abstract schema(name: string): PluginConfiguration | undefined;
3311
+ }
3312
+ interface PluginConfigSlots {
3313
+ /** A settings group, as data: its id is its name, the data its configuration. */
3314
+ groups: Slot<SettingsGroupDecl>;
3315
+ }
3316
+
2538
3317
  /** The assembled business surface: one request in, one response (or a decline) out. */
2539
- declare abstract class Http extends Http_base {
3318
+ declare abstract class Http {
3319
+ abstract fetch(request: Opaque<"Request", Request>): Promise<Opaque<"Response", Response>>;
2540
3320
  }
2541
3321
  interface HttpSlots {
2542
3322
  /**
@@ -2557,10 +3337,6 @@ interface HttpSlots {
2557
3337
  * own module.json and renders what it has a renderer for.
2558
3338
  */
2559
3339
 
2560
- declare const WebShell_base: (abstract new () => {
2561
- /** Every contribution to the web slots, by slot, in module order. */
2562
- contributions(): ContributionsResponse;
2563
- }) & (<C>(target: C, context: ClassDecoratorContext) => C);
2564
3340
  /**
2565
3341
  * The frontend's slots, declared on the SERVER so a server module (or a plugin) can
2566
3342
  * contribute a page, an Agent settings tab or a Session tab as manifest data. The web
@@ -2568,7 +3344,9 @@ declare const WebShell_base: (abstract new () => {
2568
3344
  * renderer it knows: a `builtin` name from its own registry, or an `iframe`. No code
2569
3345
  * crosses this boundary — only data.
2570
3346
  */
2571
- declare abstract class WebShell extends WebShell_base {
3347
+ declare abstract class WebShell {
3348
+ /** Every contribution to the web slots, by slot, in module order. */
3349
+ abstract contributions(): ContributionsResponse;
2572
3350
  }
2573
3351
  interface WebShellSlots {
2574
3352
  /** A page: its route, whether it sits in the main nav, whether it is admin-only. */
@@ -2585,11 +3363,22 @@ interface WebShellSlots {
2585
3363
  order: number;
2586
3364
  renderer: RendererRef;
2587
3365
  };
2588
- /** A tab beside a Session's chat (a workflow UI lives here). */
3366
+ /**
3367
+ * A tab beside a Session's chat. A workflow contributes here too, from its own tree, where
3368
+ * the host publishes this slot under this module's name and scopes the tab to its Agent.
3369
+ */
2589
3370
  sessionTabs: {
2590
3371
  key: string;
2591
- renderer: RendererRef;
3372
+ title: string;
3373
+ titleZh?: string;
3374
+ renderer: {
3375
+ builtin: string;
3376
+ } | {
3377
+ iframe: {
3378
+ src: string;
3379
+ };
3380
+ };
2592
3381
  };
2593
3382
  }
2594
3383
 
2595
- export { AgentConfigService, AgentService, Http, type HttpSlots, Messaging, type MessagingSlots, Sandbox, type SandboxSlots, SessionServiceIface, Sessions, Terminals, WebShell, type WebShellSlots };
3384
+ export { AgentConfigService, AgentService, Http, type HttpSlots, Messaging, type MessagingSlots, PluginConfig, type PluginConfigSlots, PluginConfiguration, Sandbox, type SandboxSlots, SessionServiceIface, Sessions, type SettingsGroupDecl, Terminals, WebShell, type WebShellSlots };