@pasko70/pibo 2.1.1 → 2.2.1

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 (376) hide show
  1. package/dist/agent-runtime/capabilities.js +68 -0
  2. package/dist/agent-runtime/context-build.js +13 -5
  3. package/dist/agent-runtime/portable-history.js +526 -0
  4. package/dist/agent-runtime/profile-validation.js +13 -7
  5. package/dist/agent-runtime/resource-files.js +26 -10
  6. package/dist/agent-runtime/resource-service.js +216 -13
  7. package/dist/agent-runtimes/codex-native/adapter.js +38 -1
  8. package/dist/agent-runtimes/codex-native/auth.js +24 -3
  9. package/dist/agent-runtimes/codex-native/portable-history.js +73 -0
  10. package/dist/agent-runtimes/codex-native/process.js +38 -27
  11. package/dist/agent-runtimes/codex-native/resource-delivery.js +39 -16
  12. package/dist/agent-runtimes/codex-native/turn.js +68 -5
  13. package/dist/agent-runtimes/omp/adapter.js +43 -8
  14. package/dist/agent-runtimes/omp/process.js +26 -10
  15. package/dist/agent-runtimes/omp/resource-delivery.js +150 -84
  16. package/dist/agent-runtimes/pi/adapter.js +32 -1
  17. package/dist/agent-runtimes/pi/auth.js +34 -29
  18. package/dist/agent-runtimes/pi/credentials.js +43 -0
  19. package/dist/agent-runtimes/pi/model-catalog.js +7 -3
  20. package/dist/agent-runtimes/pi/portable-history.js +99 -0
  21. package/dist/agent-runtimes/pi/routed-session.js +1 -1
  22. package/dist/agent-runtimes/pi/runtime.js +31 -15
  23. package/dist/apps/chat/agent-profiles.js +1 -0
  24. package/dist/apps/chat/agent-store.js +31 -11
  25. package/dist/apps/chat/chat-files.js +19 -6
  26. package/dist/apps/chat/chat-request-normalizers.js +19 -0
  27. package/dist/apps/chat/trace.js +5 -0
  28. package/dist/apps/chat/web-app.js +55 -6
  29. package/dist/apps/chat-ui/assets/{apl-14BqhLYK.js → apl-gfMMiTNf.js} +1 -1
  30. package/dist/apps/chat-ui/assets/asciiarmor-C_eisQCp.js +1 -0
  31. package/dist/apps/{context-files-ui/assets/asn1-Bg4FbdCg.js → chat-ui/assets/asn1-DCl_8MCW.js} +1 -1
  32. package/dist/apps/{context-files-ui/assets/asterisk-B2MO-X4d.js → chat-ui/assets/asterisk-BEn0Cwpx.js} +1 -1
  33. package/dist/apps/chat-ui/assets/clike-D_6L3tnO.js +1 -0
  34. package/dist/apps/chat-ui/assets/cmake-84nbDH0I.js +1 -0
  35. package/dist/apps/chat-ui/assets/cobol-DHLQUbN7.js +1 -0
  36. package/dist/apps/chat-ui/assets/coffeescript-De_zI4J0.js +1 -0
  37. package/dist/apps/chat-ui/assets/commonlisp-DgAKBe0r.js +1 -0
  38. package/dist/apps/chat-ui/assets/crystal-Bsdphhtm.js +1 -0
  39. package/dist/apps/chat-ui/assets/css-CnaYoQib.js +1 -0
  40. package/dist/apps/chat-ui/assets/{d-TPqSVaHM.js → d-DWkQyNnU.js} +1 -1
  41. package/dist/apps/{context-files-ui/assets/dist-B7gXtTZC.js → chat-ui/assets/dist-B7DmqUNk.js} +1 -1
  42. package/dist/apps/chat-ui/assets/dist-BJ-TIk3N.js +1 -0
  43. package/dist/apps/chat-ui/assets/dist-BxYxDl5K.js +1 -0
  44. package/dist/apps/chat-ui/assets/dist-CqM4On9D.js +13 -0
  45. package/dist/apps/chat-ui/assets/dist-CswnpKik.js +1 -0
  46. package/dist/apps/{context-files-ui/assets/dist-DxEGebCR.js → chat-ui/assets/dist-CvYwol1J.js} +1 -1
  47. package/dist/apps/chat-ui/assets/dist-DHvUPfrF.js +1 -0
  48. package/dist/apps/chat-ui/assets/dist-DLJCGrGQ.js +1 -0
  49. package/dist/apps/chat-ui/assets/{dist-DLMjd26T.js → dist-DMiglryg.js} +1 -1
  50. package/dist/apps/chat-ui/assets/dist-DTeLDijr.js +9 -0
  51. package/dist/apps/chat-ui/assets/{dist-DKoyMSNr.js → dist-DpF08Yd7.js} +1 -1
  52. package/dist/apps/chat-ui/assets/dist-Dx7GMMHU.js +1 -0
  53. package/dist/apps/chat-ui/assets/dist-LCx98fA_.js +11 -0
  54. package/dist/apps/chat-ui/assets/{dist-DotDq_kD.js → dist-RKTRnzGb.js} +1 -1
  55. package/dist/apps/chat-ui/assets/dist-S3zJGntM.js +1 -0
  56. package/dist/apps/chat-ui/assets/{dist-sZgJkWZb.js → dist-SF43opz6.js} +1 -1
  57. package/dist/apps/{context-files-ui/assets/dist-BkUONE3N.js → chat-ui/assets/dist-XVYGiB-c.js} +1 -1
  58. package/dist/apps/chat-ui/assets/dist-eddbbGyw.js +1 -0
  59. package/dist/apps/chat-ui/assets/dist-fPhZsAUX.js +1 -0
  60. package/dist/apps/chat-ui/assets/dist-mpRGeo_R.js +2 -0
  61. package/dist/apps/chat-ui/assets/{dockerfile-CJb2sekW.js → dockerfile-DJkHQgkl.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dylan-08Azy1NK.js → dylan-BCDoL_-p.js} +1 -1
  63. package/dist/apps/chat-ui/assets/{ecl-dhxjHL8y.js → ecl-BVIeWmwY.js} +1 -1
  64. package/dist/apps/{context-files-ui/assets/erlang-BD5LkVkR.js → chat-ui/assets/erlang-BV0c4Hdn.js} +1 -1
  65. package/dist/apps/chat-ui/assets/{factor-B2EMQZkP.js → factor-LKH5gN8L.js} +1 -1
  66. package/dist/apps/chat-ui/assets/groovy-CUpZ7dEl.js +1 -0
  67. package/dist/apps/chat-ui/assets/{haxe-BJVKtprM.js → haxe-DjVOVvNP.js} +1 -1
  68. package/dist/apps/chat-ui/assets/index-2qGRr2cm.js +226 -0
  69. package/dist/apps/chat-ui/assets/index-QkfBrh9Q.css +1 -0
  70. package/dist/apps/chat-ui/assets/javascript-DoL9Wb-Q.js +1 -0
  71. package/dist/apps/chat-ui/assets/{lua-BxuTHaF7.js → lua-CiA1ziua.js} +1 -1
  72. package/dist/apps/chat-ui/assets/{mumps-Ds_ZaumL.js → mumps-BSzj6Xyz.js} +1 -1
  73. package/dist/apps/{context-files-ui/assets/nsis-DOo3SJmd.js → chat-ui/assets/nsis-CfSuhXs5.js} +1 -1
  74. package/dist/apps/chat-ui/assets/{ntriples-DLHGTvHs.js → ntriples-B9h1VB_g.js} +1 -1
  75. package/dist/apps/chat-ui/assets/perl-BkSkiI9m.js +1 -0
  76. package/dist/apps/chat-ui/assets/{powershell-B4IPkVxR.js → powershell-BcIto6Sf.js} +1 -1
  77. package/dist/apps/{context-files-ui/assets/pug-QU72BPAa.js → chat-ui/assets/pug-Gsm0M45u.js} +1 -1
  78. package/dist/apps/chat-ui/assets/puppet-BZyAS7I4.js +1 -0
  79. package/dist/apps/chat-ui/assets/python-B_1Jd8HM.js +1 -0
  80. package/dist/apps/chat-ui/assets/r-CxDmU1I4.js +1 -0
  81. package/dist/apps/chat-ui/assets/ruby-BjXV7-Qa.js +1 -0
  82. package/dist/apps/chat-ui/assets/scheme-D9qYN0V5.js +1 -0
  83. package/dist/apps/chat-ui/assets/{shell-BjiMLAaM.js → shell-DwuoZtxw.js} +1 -1
  84. package/dist/apps/chat-ui/assets/{simple-mode-DnMbQuKW.js → simple-mode-DXiLM1-G.js} +1 -1
  85. package/dist/apps/chat-ui/assets/sql-DuQMFDvy.js +1 -0
  86. package/dist/apps/chat-ui/assets/{stex-BCRT8IJ3.js → stex-DNzd62Q_.js} +1 -1
  87. package/dist/apps/chat-ui/assets/{stylus-CARoeVE9.js → stylus-BOVgKnng.js} +1 -1
  88. package/dist/apps/chat-ui/assets/textile-C4jVoHG1.js +1 -0
  89. package/dist/apps/chat-ui/assets/tiki-AK6FwT8q.js +1 -0
  90. package/dist/apps/chat-ui/assets/toml-BPTmHmyx.js +1 -0
  91. package/dist/apps/chat-ui/assets/{ttcn-GvRgs2AT.js → ttcn-PPSTk1ow.js} +1 -1
  92. package/dist/apps/chat-ui/assets/{ttcn-cfg-CGCXz7Vo.js → ttcn-cfg-2b4Gb5sE.js} +1 -1
  93. package/dist/apps/chat-ui/assets/turtle-Cx3rYX2g.js +1 -0
  94. package/dist/apps/chat-ui/assets/{verilog-DVCHmufx.js → verilog-7LoJAqYT.js} +1 -1
  95. package/dist/apps/chat-ui/assets/vhdl-kS471soi.js +1 -0
  96. package/dist/apps/{context-files-ui/assets/xquery-5f0hn7cg.js → chat-ui/assets/xquery-BKJx4mf9.js} +1 -1
  97. package/dist/apps/chat-ui/assets/z80-Co3PbHdE.js +1 -0
  98. package/dist/apps/chat-ui/index.html +5 -3
  99. package/dist/apps/chat-vscode-web/assets/index-C0sMILFt.js +41 -0
  100. package/dist/apps/chat-vscode-web/assets/index-CF1-9PKU.css +2 -0
  101. package/dist/apps/chat-vscode-web/index.html +2 -2
  102. package/dist/apps/context-files-ui/assets/{apl-14BqhLYK.js → apl-gfMMiTNf.js} +1 -1
  103. package/dist/apps/context-files-ui/assets/asciiarmor-C_eisQCp.js +1 -0
  104. package/dist/apps/{chat-ui/assets/asn1-Bg4FbdCg.js → context-files-ui/assets/asn1-DCl_8MCW.js} +1 -1
  105. package/dist/apps/{chat-ui/assets/asterisk-B2MO-X4d.js → context-files-ui/assets/asterisk-BEn0Cwpx.js} +1 -1
  106. package/dist/apps/context-files-ui/assets/clike-D_6L3tnO.js +1 -0
  107. package/dist/apps/context-files-ui/assets/cmake-84nbDH0I.js +1 -0
  108. package/dist/apps/context-files-ui/assets/cobol-DHLQUbN7.js +1 -0
  109. package/dist/apps/context-files-ui/assets/coffeescript-De_zI4J0.js +1 -0
  110. package/dist/apps/context-files-ui/assets/commonlisp-DgAKBe0r.js +1 -0
  111. package/dist/apps/context-files-ui/assets/crystal-Bsdphhtm.js +1 -0
  112. package/dist/apps/context-files-ui/assets/css-CnaYoQib.js +1 -0
  113. package/dist/apps/context-files-ui/assets/{d-TPqSVaHM.js → d-DWkQyNnU.js} +1 -1
  114. package/dist/apps/{chat-ui/assets/dist-C6LPDFXU.js → context-files-ui/assets/dist-BAqbgxUS.js} +1 -1
  115. package/dist/apps/context-files-ui/assets/dist-BJ-TIk3N.js +1 -0
  116. package/dist/apps/context-files-ui/assets/dist-BcauuFwf.js +1 -0
  117. package/dist/apps/context-files-ui/assets/dist-BecMXs79.js +1 -0
  118. package/dist/apps/context-files-ui/assets/{dist-C-Jm45P4.js → dist-Ci2NSlf1.js} +1 -1
  119. package/dist/apps/context-files-ui/assets/dist-CqM4On9D.js +13 -0
  120. package/dist/apps/context-files-ui/assets/dist-CswnpKik.js +1 -0
  121. package/dist/apps/{chat-ui/assets/dist-I26VB0QO.js → context-files-ui/assets/dist-D-xpsbZI.js} +1 -1
  122. package/dist/apps/context-files-ui/assets/dist-DHvUPfrF.js +1 -0
  123. package/dist/apps/context-files-ui/assets/dist-DLJCGrGQ.js +1 -0
  124. package/dist/apps/context-files-ui/assets/{dist-DLMjd26T.js → dist-DMiglryg.js} +1 -1
  125. package/dist/apps/context-files-ui/assets/dist-DTeLDijr.js +9 -0
  126. package/dist/apps/context-files-ui/assets/{dist-DKoyMSNr.js → dist-DpF08Yd7.js} +1 -1
  127. package/dist/apps/context-files-ui/assets/dist-LCx98fA_.js +11 -0
  128. package/dist/apps/context-files-ui/assets/{dist-DotDq_kD.js → dist-RKTRnzGb.js} +1 -1
  129. package/dist/apps/context-files-ui/assets/dist-S3zJGntM.js +1 -0
  130. package/dist/apps/{chat-ui/assets/dist-BkUONE3N.js → context-files-ui/assets/dist-XVYGiB-c.js} +1 -1
  131. package/dist/apps/context-files-ui/assets/dist-eddbbGyw.js +1 -0
  132. package/dist/apps/context-files-ui/assets/dist-fPhZsAUX.js +1 -0
  133. package/dist/apps/context-files-ui/assets/dist-mpRGeo_R.js +2 -0
  134. package/dist/apps/context-files-ui/assets/{dockerfile-CJb2sekW.js → dockerfile-DJkHQgkl.js} +1 -1
  135. package/dist/apps/context-files-ui/assets/{dylan-08Azy1NK.js → dylan-BCDoL_-p.js} +1 -1
  136. package/dist/apps/context-files-ui/assets/{ecl-dhxjHL8y.js → ecl-BVIeWmwY.js} +1 -1
  137. package/dist/apps/{chat-ui/assets/erlang-BD5LkVkR.js → context-files-ui/assets/erlang-BV0c4Hdn.js} +1 -1
  138. package/dist/apps/context-files-ui/assets/{factor-B2EMQZkP.js → factor-LKH5gN8L.js} +1 -1
  139. package/dist/apps/context-files-ui/assets/groovy-CUpZ7dEl.js +1 -0
  140. package/dist/apps/context-files-ui/assets/{haxe-BJVKtprM.js → haxe-DjVOVvNP.js} +1 -1
  141. package/dist/apps/context-files-ui/assets/index-CkWXlBNn.js +191 -0
  142. package/dist/apps/context-files-ui/assets/{index-Cs4XQITe.css → index-D8TsUizd.css} +1 -1
  143. package/dist/apps/context-files-ui/assets/javascript-DoL9Wb-Q.js +1 -0
  144. package/dist/apps/context-files-ui/assets/{lua-BxuTHaF7.js → lua-CiA1ziua.js} +1 -1
  145. package/dist/apps/context-files-ui/assets/{mumps-Ds_ZaumL.js → mumps-BSzj6Xyz.js} +1 -1
  146. package/dist/apps/{chat-ui/assets/nsis-DOo3SJmd.js → context-files-ui/assets/nsis-CfSuhXs5.js} +1 -1
  147. package/dist/apps/context-files-ui/assets/{ntriples-DLHGTvHs.js → ntriples-B9h1VB_g.js} +1 -1
  148. package/dist/apps/context-files-ui/assets/perl-BkSkiI9m.js +1 -0
  149. package/dist/apps/context-files-ui/assets/{powershell-B4IPkVxR.js → powershell-BcIto6Sf.js} +1 -1
  150. package/dist/apps/{chat-ui/assets/pug-QU72BPAa.js → context-files-ui/assets/pug-Gsm0M45u.js} +1 -1
  151. package/dist/apps/context-files-ui/assets/puppet-BZyAS7I4.js +1 -0
  152. package/dist/apps/context-files-ui/assets/python-B_1Jd8HM.js +1 -0
  153. package/dist/apps/context-files-ui/assets/r-CxDmU1I4.js +1 -0
  154. package/dist/apps/context-files-ui/assets/ruby-BjXV7-Qa.js +1 -0
  155. package/dist/apps/context-files-ui/assets/scheme-D9qYN0V5.js +1 -0
  156. package/dist/apps/context-files-ui/assets/{shell-BjiMLAaM.js → shell-DwuoZtxw.js} +1 -1
  157. package/dist/apps/context-files-ui/assets/{simple-mode-DnMbQuKW.js → simple-mode-DXiLM1-G.js} +1 -1
  158. package/dist/apps/context-files-ui/assets/sql-DuQMFDvy.js +1 -0
  159. package/dist/apps/context-files-ui/assets/{stex-BCRT8IJ3.js → stex-DNzd62Q_.js} +1 -1
  160. package/dist/apps/context-files-ui/assets/{stylus-CARoeVE9.js → stylus-BOVgKnng.js} +1 -1
  161. package/dist/apps/context-files-ui/assets/textile-C4jVoHG1.js +1 -0
  162. package/dist/apps/context-files-ui/assets/tiki-AK6FwT8q.js +1 -0
  163. package/dist/apps/context-files-ui/assets/toml-BPTmHmyx.js +1 -0
  164. package/dist/apps/context-files-ui/assets/{ttcn-GvRgs2AT.js → ttcn-PPSTk1ow.js} +1 -1
  165. package/dist/apps/context-files-ui/assets/{ttcn-cfg-CGCXz7Vo.js → ttcn-cfg-2b4Gb5sE.js} +1 -1
  166. package/dist/apps/context-files-ui/assets/turtle-Cx3rYX2g.js +1 -0
  167. package/dist/apps/context-files-ui/assets/{verilog-DVCHmufx.js → verilog-7LoJAqYT.js} +1 -1
  168. package/dist/apps/context-files-ui/assets/vhdl-kS471soi.js +1 -0
  169. package/dist/apps/{chat-ui/assets/xquery-5f0hn7cg.js → context-files-ui/assets/xquery-BKJx4mf9.js} +1 -1
  170. package/dist/apps/context-files-ui/assets/z80-Co3PbHdE.js +1 -0
  171. package/dist/apps/context-files-ui/index.html +5 -3
  172. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  173. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.2.1.vsix +0 -0
  174. package/dist/auth/better-auth.js +223 -30
  175. package/dist/auth/cli.js +10 -1
  176. package/dist/auth/machine-keys.js +8 -4
  177. package/dist/auth/openai-codex-usage.js +4 -4
  178. package/dist/cli-session/fakeSessionSource.js +2 -2
  179. package/dist/cli-session/localSessionSource.js +2 -2
  180. package/dist/cli.js +3 -1
  181. package/dist/config/config.js +9 -4
  182. package/dist/core/compaction-prompt.js +3 -1
  183. package/dist/core/context-build.js +1 -0
  184. package/dist/core/pibo-home.js +24 -1
  185. package/dist/core/private-path.js +146 -0
  186. package/dist/core/profiles.js +17 -3
  187. package/dist/core/sensitive-data-redaction.js +36 -0
  188. package/dist/core/session-model.js +1 -0
  189. package/dist/core/session-router.js +226 -30
  190. package/dist/data/pibo-store.js +5 -1
  191. package/dist/gateway/server.js +9 -0
  192. package/dist/plugins/context-files.js +11 -0
  193. package/dist/plugins/registry.js +3 -0
  194. package/dist/providers/openai-gpt56.js +0 -11
  195. package/dist/reliability/store.js +5 -1
  196. package/dist/resources/lifecycle.js +13 -3
  197. package/dist/runs/resource-isolation.js +159 -8
  198. package/dist/runs/tools.js +44 -1
  199. package/dist/sessions/pibo-data-store.js +3 -0
  200. package/dist/tools/codex-browser-node-repl.js +4 -2
  201. package/dist/tools/codex-browser.js +1 -1
  202. package/dist/tools/codex-image-generation.js +4 -4
  203. package/dist/tools/runtime/node-backend.js +4 -1
  204. package/dist/tools/runtime/python-backend.js +4 -1
  205. package/dist/web-annotations/api.js +22 -2
  206. package/npm-shrinkwrap.json +16707 -0
  207. package/package.json +19 -14
  208. package/dist/apps/chat-ui/assets/asciiarmor-WLvjqI7d.js +0 -1
  209. package/dist/apps/chat-ui/assets/clike-CjmcUpt6.js +0 -1
  210. package/dist/apps/chat-ui/assets/cmake-i2VDNaRq.js +0 -1
  211. package/dist/apps/chat-ui/assets/cobol-BwO6DF08.js +0 -1
  212. package/dist/apps/chat-ui/assets/coffeescript-BtivDvRz.js +0 -1
  213. package/dist/apps/chat-ui/assets/commonlisp-DFkEQdLP.js +0 -1
  214. package/dist/apps/chat-ui/assets/crystal-CU0NkcVL.js +0 -1
  215. package/dist/apps/chat-ui/assets/css-CbMZAQ1W.js +0 -1
  216. package/dist/apps/chat-ui/assets/dist-9v2ZXT6V.js +0 -11
  217. package/dist/apps/chat-ui/assets/dist-B1LVAytl.js +0 -9
  218. package/dist/apps/chat-ui/assets/dist-B5PTVnox.js +0 -1
  219. package/dist/apps/chat-ui/assets/dist-B5ZAfwf5.js +0 -1
  220. package/dist/apps/chat-ui/assets/dist-D1KyNDg5.js +0 -13
  221. package/dist/apps/chat-ui/assets/dist-DVtXxfHc.js +0 -1
  222. package/dist/apps/chat-ui/assets/dist-DW4Qrfbd.js +0 -2
  223. package/dist/apps/chat-ui/assets/dist-DmbsHdMC.js +0 -1
  224. package/dist/apps/chat-ui/assets/dist-DyvwuSFO.js +0 -1
  225. package/dist/apps/chat-ui/assets/dist-QQuDy4KA.js +0 -1
  226. package/dist/apps/chat-ui/assets/dist-RtHbJRPV.js +0 -1
  227. package/dist/apps/chat-ui/assets/groovy-Cmduloe1.js +0 -1
  228. package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +0 -1
  229. package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +0 -237
  230. package/dist/apps/chat-ui/assets/javascript-C5pDVaoP.js +0 -1
  231. package/dist/apps/chat-ui/assets/perl-D6YJObi_.js +0 -1
  232. package/dist/apps/chat-ui/assets/puppet-B_0GFuyD.js +0 -1
  233. package/dist/apps/chat-ui/assets/python-Cs7sNzy_.js +0 -1
  234. package/dist/apps/chat-ui/assets/r-CN5s4f3o.js +0 -1
  235. package/dist/apps/chat-ui/assets/ruby-BVPradRk.js +0 -1
  236. package/dist/apps/chat-ui/assets/scheme-CvNgHAnh.js +0 -1
  237. package/dist/apps/chat-ui/assets/sql-DYI2GwJR.js +0 -1
  238. package/dist/apps/chat-ui/assets/textile-Yg_UWn-t.js +0 -1
  239. package/dist/apps/chat-ui/assets/tiki-CC_ic8g0.js +0 -1
  240. package/dist/apps/chat-ui/assets/toml-B7gGzVkJ.js +0 -1
  241. package/dist/apps/chat-ui/assets/turtle-CwIpz2yy.js +0 -1
  242. package/dist/apps/chat-ui/assets/vhdl-BGDk4f1d.js +0 -1
  243. package/dist/apps/chat-ui/assets/z80-B7Dfb4UO.js +0 -1
  244. package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +0 -41
  245. package/dist/apps/chat-vscode-web/assets/index-Dupu1DzQ.css +0 -2
  246. package/dist/apps/context-files-ui/assets/asciiarmor-WLvjqI7d.js +0 -1
  247. package/dist/apps/context-files-ui/assets/clike-CjmcUpt6.js +0 -1
  248. package/dist/apps/context-files-ui/assets/cmake-i2VDNaRq.js +0 -1
  249. package/dist/apps/context-files-ui/assets/cobol-BwO6DF08.js +0 -1
  250. package/dist/apps/context-files-ui/assets/coffeescript-BtivDvRz.js +0 -1
  251. package/dist/apps/context-files-ui/assets/commonlisp-DFkEQdLP.js +0 -1
  252. package/dist/apps/context-files-ui/assets/crystal-CU0NkcVL.js +0 -1
  253. package/dist/apps/context-files-ui/assets/css-CbMZAQ1W.js +0 -1
  254. package/dist/apps/context-files-ui/assets/dist-B5PTVnox.js +0 -1
  255. package/dist/apps/context-files-ui/assets/dist-B5ZAfwf5.js +0 -1
  256. package/dist/apps/context-files-ui/assets/dist-BD262Ouw.js +0 -1
  257. package/dist/apps/context-files-ui/assets/dist-BKuGdcnX.js +0 -9
  258. package/dist/apps/context-files-ui/assets/dist-CHdx1Jri.js +0 -1
  259. package/dist/apps/context-files-ui/assets/dist-CULMH-fB.js +0 -11
  260. package/dist/apps/context-files-ui/assets/dist-Cjq6RWEt.js +0 -1
  261. package/dist/apps/context-files-ui/assets/dist-CntqFySz.js +0 -1
  262. package/dist/apps/context-files-ui/assets/dist-D1KyNDg5.js +0 -13
  263. package/dist/apps/context-files-ui/assets/dist-QQuDy4KA.js +0 -1
  264. package/dist/apps/context-files-ui/assets/dist-kPuQud7t.js +0 -2
  265. package/dist/apps/context-files-ui/assets/groovy-Cmduloe1.js +0 -1
  266. package/dist/apps/context-files-ui/assets/index-DZWsbuvg.js +0 -202
  267. package/dist/apps/context-files-ui/assets/javascript-C5pDVaoP.js +0 -1
  268. package/dist/apps/context-files-ui/assets/perl-D6YJObi_.js +0 -1
  269. package/dist/apps/context-files-ui/assets/puppet-B_0GFuyD.js +0 -1
  270. package/dist/apps/context-files-ui/assets/python-Cs7sNzy_.js +0 -1
  271. package/dist/apps/context-files-ui/assets/r-CN5s4f3o.js +0 -1
  272. package/dist/apps/context-files-ui/assets/ruby-BVPradRk.js +0 -1
  273. package/dist/apps/context-files-ui/assets/scheme-CvNgHAnh.js +0 -1
  274. package/dist/apps/context-files-ui/assets/sql-DYI2GwJR.js +0 -1
  275. package/dist/apps/context-files-ui/assets/textile-Yg_UWn-t.js +0 -1
  276. package/dist/apps/context-files-ui/assets/tiki-CC_ic8g0.js +0 -1
  277. package/dist/apps/context-files-ui/assets/toml-B7gGzVkJ.js +0 -1
  278. package/dist/apps/context-files-ui/assets/turtle-CwIpz2yy.js +0 -1
  279. package/dist/apps/context-files-ui/assets/vhdl-BGDk4f1d.js +0 -1
  280. package/dist/apps/context-files-ui/assets/z80-B7Dfb4UO.js +0 -1
  281. /package/dist/apps/chat-ui/assets/{brainfuck-CV9kufud.js → brainfuck-D5EjA2JK.js} +0 -0
  282. /package/dist/apps/chat-ui/assets/{clojure-De3QGfx6.js → clojure-BflJGmDX.js} +0 -0
  283. /package/dist/apps/chat-ui/assets/{cypher-Dke5QOzv.js → cypher-p9eYesGn.js} +0 -0
  284. /package/dist/apps/chat-ui/assets/{diff-B365LSoZ.js → diff-ChtP43wD.js} +0 -0
  285. /package/dist/apps/chat-ui/assets/{dtd-CBMymJ7O.js → dtd-DTF72YNO.js} +0 -0
  286. /package/dist/apps/chat-ui/assets/{ebnf-Dkum_1J8.js → ebnf-D4c0_ac3.js} +0 -0
  287. /package/dist/apps/chat-ui/assets/{eiffel-C446m6dI.js → eiffel-BEjRio4Q.js} +0 -0
  288. /package/dist/apps/chat-ui/assets/{elm-po1E9de0.js → elm-Cshzl8qu.js} +0 -0
  289. /package/dist/apps/chat-ui/assets/{fcl-DkEOamHd.js → fcl-ClOhbFR7.js} +0 -0
  290. /package/dist/apps/chat-ui/assets/{forth-dCg2_HVB.js → forth-Cezjo90N.js} +0 -0
  291. /package/dist/apps/chat-ui/assets/{fortran-3ZpXLFh1.js → fortran-Bt6PBEDR.js} +0 -0
  292. /package/dist/apps/chat-ui/assets/{gas-DMmxLZRI.js → gas-BHEdbvp9.js} +0 -0
  293. /package/dist/apps/chat-ui/assets/{gherkin-DUSFg2R6.js → gherkin-oBAE_ms0.js} +0 -0
  294. /package/dist/apps/chat-ui/assets/{haskell-Cyr255R9.js → haskell-BRsoo5mP.js} +0 -0
  295. /package/dist/apps/chat-ui/assets/{http-DszHFpc-.js → http-CLVgA2GD.js} +0 -0
  296. /package/dist/apps/chat-ui/assets/{idl-Cati9Nrv.js → idl-BUZw3wgd.js} +0 -0
  297. /package/dist/apps/chat-ui/assets/{julia-DlqY1cTU.js → julia-CQfgDRfP.js} +0 -0
  298. /package/dist/apps/chat-ui/assets/{livescript-C6p8-2W1.js → livescript-BXxG0Yva.js} +0 -0
  299. /package/dist/apps/chat-ui/assets/{mathematica-nDHZUMJT.js → mathematica-u8YMmbU0.js} +0 -0
  300. /package/dist/apps/chat-ui/assets/{mbox-DAaR0Hcz.js → mbox-BEMVcqjs.js} +0 -0
  301. /package/dist/apps/chat-ui/assets/{mirc-CCA0FRfl.js → mirc-C9zpzAZU.js} +0 -0
  302. /package/dist/apps/chat-ui/assets/{mllike-Cw3Iccsb.js → mllike-B45xgp2S.js} +0 -0
  303. /package/dist/apps/chat-ui/assets/{modelica-Czx80fNR.js → modelica-CqHI_q-D.js} +0 -0
  304. /package/dist/apps/chat-ui/assets/{mscgen-BmfuTbzG.js → mscgen-qgSLujhx.js} +0 -0
  305. /package/dist/apps/chat-ui/assets/{nginx-D9M2PQ4U.js → nginx-BMaDbqW3.js} +0 -0
  306. /package/dist/apps/chat-ui/assets/{octave-8jj96JiC.js → octave-D2Q8cUp1.js} +0 -0
  307. /package/dist/apps/chat-ui/assets/{oz-BmMq7iC4.js → oz-BwTct_5T.js} +0 -0
  308. /package/dist/apps/chat-ui/assets/{pascal-BgMr6XpT.js → pascal-Dp_KdFgX.js} +0 -0
  309. /package/dist/apps/chat-ui/assets/{pig-nx7uchs8.js → pig-AF4Hwhju.js} +0 -0
  310. /package/dist/apps/chat-ui/assets/{properties-CoavQdLC.js → properties-C357ku5U.js} +0 -0
  311. /package/dist/apps/chat-ui/assets/{protobuf-D5EWhcmc.js → protobuf-D1ij_kNL.js} +0 -0
  312. /package/dist/apps/chat-ui/assets/{q-BIB9pPtI.js → q-B9NhS7L_.js} +0 -0
  313. /package/dist/apps/chat-ui/assets/{rpm-Ct_Ck8mQ.js → rpm-gpDK5sbt.js} +0 -0
  314. /package/dist/apps/chat-ui/assets/{sas-DN4j74IF.js → sas-C2OyD2Y6.js} +0 -0
  315. /package/dist/apps/chat-ui/assets/{sieve-C2U1O5Z4.js → sieve-BAxa3IjF.js} +0 -0
  316. /package/dist/apps/chat-ui/assets/{smalltalk-DkYwYufV.js → smalltalk-BLp5-jwC.js} +0 -0
  317. /package/dist/apps/chat-ui/assets/{solr-BopnSD-v.js → solr-BBopId9w.js} +0 -0
  318. /package/dist/apps/chat-ui/assets/{sparql-Cpg3YQfd.js → sparql-Dz-mlCAC.js} +0 -0
  319. /package/dist/apps/chat-ui/assets/{spreadsheet-kRxtVt9J.js → spreadsheet-CTIncYxj.js} +0 -0
  320. /package/dist/apps/chat-ui/assets/{swift-DKNaLAK6.js → swift-DKB6_1j6.js} +0 -0
  321. /package/dist/apps/chat-ui/assets/{tcl-CQyXkgMH.js → tcl-BGfruO1u.js} +0 -0
  322. /package/dist/apps/chat-ui/assets/{tiddlywiki-dqVbkfX4.js → tiddlywiki-VlUiK86J.js} +0 -0
  323. /package/dist/apps/chat-ui/assets/{troff-Bq3z6oAu.js → troff-C2dAgh7P.js} +0 -0
  324. /package/dist/apps/chat-ui/assets/{vb-BmcHUM2C.js → vb-BthdM_4N.js} +0 -0
  325. /package/dist/apps/chat-ui/assets/{vbscript-Cs9dylre.js → vbscript-D9f6rSsU.js} +0 -0
  326. /package/dist/apps/chat-ui/assets/{velocity-CBWU0VCy.js → velocity-CqftRsjg.js} +0 -0
  327. /package/dist/apps/chat-ui/assets/{webidl-egXQEWlC.js → webidl-D5jiJvOU.js} +0 -0
  328. /package/dist/apps/chat-ui/assets/{yacas-DNs9XkmQ.js → yacas-CXXgtw0p.js} +0 -0
  329. /package/dist/apps/context-files-ui/assets/{brainfuck-CV9kufud.js → brainfuck-D5EjA2JK.js} +0 -0
  330. /package/dist/apps/context-files-ui/assets/{clojure-De3QGfx6.js → clojure-BflJGmDX.js} +0 -0
  331. /package/dist/apps/context-files-ui/assets/{cypher-Dke5QOzv.js → cypher-p9eYesGn.js} +0 -0
  332. /package/dist/apps/context-files-ui/assets/{diff-B365LSoZ.js → diff-ChtP43wD.js} +0 -0
  333. /package/dist/apps/context-files-ui/assets/{dtd-CBMymJ7O.js → dtd-DTF72YNO.js} +0 -0
  334. /package/dist/apps/context-files-ui/assets/{ebnf-Dkum_1J8.js → ebnf-D4c0_ac3.js} +0 -0
  335. /package/dist/apps/context-files-ui/assets/{eiffel-C446m6dI.js → eiffel-BEjRio4Q.js} +0 -0
  336. /package/dist/apps/context-files-ui/assets/{elm-po1E9de0.js → elm-Cshzl8qu.js} +0 -0
  337. /package/dist/apps/context-files-ui/assets/{fcl-DkEOamHd.js → fcl-ClOhbFR7.js} +0 -0
  338. /package/dist/apps/context-files-ui/assets/{forth-dCg2_HVB.js → forth-Cezjo90N.js} +0 -0
  339. /package/dist/apps/context-files-ui/assets/{fortran-3ZpXLFh1.js → fortran-Bt6PBEDR.js} +0 -0
  340. /package/dist/apps/context-files-ui/assets/{gas-DMmxLZRI.js → gas-BHEdbvp9.js} +0 -0
  341. /package/dist/apps/context-files-ui/assets/{gherkin-DUSFg2R6.js → gherkin-oBAE_ms0.js} +0 -0
  342. /package/dist/apps/context-files-ui/assets/{haskell-Cyr255R9.js → haskell-BRsoo5mP.js} +0 -0
  343. /package/dist/apps/context-files-ui/assets/{http-DszHFpc-.js → http-CLVgA2GD.js} +0 -0
  344. /package/dist/apps/context-files-ui/assets/{idl-Cati9Nrv.js → idl-BUZw3wgd.js} +0 -0
  345. /package/dist/apps/context-files-ui/assets/{julia-DlqY1cTU.js → julia-CQfgDRfP.js} +0 -0
  346. /package/dist/apps/context-files-ui/assets/{livescript-C6p8-2W1.js → livescript-BXxG0Yva.js} +0 -0
  347. /package/dist/apps/context-files-ui/assets/{mathematica-nDHZUMJT.js → mathematica-u8YMmbU0.js} +0 -0
  348. /package/dist/apps/context-files-ui/assets/{mbox-DAaR0Hcz.js → mbox-BEMVcqjs.js} +0 -0
  349. /package/dist/apps/context-files-ui/assets/{mirc-CCA0FRfl.js → mirc-C9zpzAZU.js} +0 -0
  350. /package/dist/apps/context-files-ui/assets/{mllike-Cw3Iccsb.js → mllike-B45xgp2S.js} +0 -0
  351. /package/dist/apps/context-files-ui/assets/{modelica-Czx80fNR.js → modelica-CqHI_q-D.js} +0 -0
  352. /package/dist/apps/context-files-ui/assets/{mscgen-BmfuTbzG.js → mscgen-qgSLujhx.js} +0 -0
  353. /package/dist/apps/context-files-ui/assets/{nginx-D9M2PQ4U.js → nginx-BMaDbqW3.js} +0 -0
  354. /package/dist/apps/context-files-ui/assets/{octave-8jj96JiC.js → octave-D2Q8cUp1.js} +0 -0
  355. /package/dist/apps/context-files-ui/assets/{oz-BmMq7iC4.js → oz-BwTct_5T.js} +0 -0
  356. /package/dist/apps/context-files-ui/assets/{pascal-BgMr6XpT.js → pascal-Dp_KdFgX.js} +0 -0
  357. /package/dist/apps/context-files-ui/assets/{pig-nx7uchs8.js → pig-AF4Hwhju.js} +0 -0
  358. /package/dist/apps/context-files-ui/assets/{properties-CoavQdLC.js → properties-C357ku5U.js} +0 -0
  359. /package/dist/apps/context-files-ui/assets/{protobuf-D5EWhcmc.js → protobuf-D1ij_kNL.js} +0 -0
  360. /package/dist/apps/context-files-ui/assets/{q-BIB9pPtI.js → q-B9NhS7L_.js} +0 -0
  361. /package/dist/apps/context-files-ui/assets/{rpm-Ct_Ck8mQ.js → rpm-gpDK5sbt.js} +0 -0
  362. /package/dist/apps/context-files-ui/assets/{sas-DN4j74IF.js → sas-C2OyD2Y6.js} +0 -0
  363. /package/dist/apps/context-files-ui/assets/{sieve-C2U1O5Z4.js → sieve-BAxa3IjF.js} +0 -0
  364. /package/dist/apps/context-files-ui/assets/{smalltalk-DkYwYufV.js → smalltalk-BLp5-jwC.js} +0 -0
  365. /package/dist/apps/context-files-ui/assets/{solr-BopnSD-v.js → solr-BBopId9w.js} +0 -0
  366. /package/dist/apps/context-files-ui/assets/{sparql-Cpg3YQfd.js → sparql-Dz-mlCAC.js} +0 -0
  367. /package/dist/apps/context-files-ui/assets/{spreadsheet-kRxtVt9J.js → spreadsheet-CTIncYxj.js} +0 -0
  368. /package/dist/apps/context-files-ui/assets/{swift-DKNaLAK6.js → swift-DKB6_1j6.js} +0 -0
  369. /package/dist/apps/context-files-ui/assets/{tcl-CQyXkgMH.js → tcl-BGfruO1u.js} +0 -0
  370. /package/dist/apps/context-files-ui/assets/{tiddlywiki-dqVbkfX4.js → tiddlywiki-VlUiK86J.js} +0 -0
  371. /package/dist/apps/context-files-ui/assets/{troff-Bq3z6oAu.js → troff-C2dAgh7P.js} +0 -0
  372. /package/dist/apps/context-files-ui/assets/{vb-BmcHUM2C.js → vb-BthdM_4N.js} +0 -0
  373. /package/dist/apps/context-files-ui/assets/{vbscript-Cs9dylre.js → vbscript-D9f6rSsU.js} +0 -0
  374. /package/dist/apps/context-files-ui/assets/{velocity-CBWU0VCy.js → velocity-CqftRsjg.js} +0 -0
  375. /package/dist/apps/context-files-ui/assets/{webidl-egXQEWlC.js → webidl-D5jiJvOU.js} +0 -0
  376. /package/dist/apps/context-files-ui/assets/{yacas-DNs9XkmQ.js → yacas-CXXgtw0p.js} +0 -0
@@ -1,11 +1,12 @@
1
- import { mkdirSync } from "node:fs";
1
+ import { copyFileSync, existsSync, mkdirSync, rmSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
- import { DatabaseSync } from "node:sqlite";
3
+ import { backup, DatabaseSync } from "node:sqlite";
4
4
  import { betterAuth } from "better-auth";
5
5
  import { getMigrations } from "better-auth/db/migration";
6
6
  import { bearer } from "better-auth/plugins";
7
7
  import { loadPiboConfig } from "../config/config.js";
8
- import { piboHomePath } from "../core/pibo-home.js";
8
+ import { ensurePrivatePiboHomeForPath, piboHomePath } from "../core/pibo-home.js";
9
+ import { protectPrivateFileSync } from "../core/private-path.js";
9
10
  import { createMachineKeyAuthenticator } from "./machine-keys.js";
10
11
  import { createMachineSessionManager } from "./machine-session.js";
11
12
  import { createForbiddenAuthError, createUnauthenticatedError } from "./types.js";
@@ -42,10 +43,167 @@ function createAllowedEmailSet(emails) {
42
43
  }
43
44
  function createDatabase(path) {
44
45
  const resolvedPath = path === ":memory:" ? path : resolve(path);
45
- if (resolvedPath !== ":memory:") {
46
- mkdirSync(dirname(resolvedPath), { recursive: true });
46
+ if (resolvedPath === ":memory:")
47
+ return new DatabaseSync(resolvedPath);
48
+ ensurePrivatePiboHomeForPath(resolvedPath);
49
+ mkdirSync(dirname(resolvedPath), { recursive: true });
50
+ const database = new DatabaseSync(resolvedPath);
51
+ protectPrivateFileSync(resolvedPath);
52
+ return database;
53
+ }
54
+ const BETTER_AUTH_SQLITE_TABLES = new Set(["user", "session", "account", "verification"]);
55
+ function quoteSqlIdentifier(value) {
56
+ return `"${value.replaceAll('"', '""')}"`;
57
+ }
58
+ function sqliteColumnType(field) {
59
+ if (Array.isArray(field.type))
60
+ return "text";
61
+ switch (field.type) {
62
+ case "string":
63
+ case "json":
64
+ case "string[]":
65
+ case "number[]":
66
+ return "text";
67
+ case "number":
68
+ case "boolean":
69
+ return "integer";
70
+ case "date":
71
+ return "date";
72
+ default:
73
+ return undefined;
74
+ }
75
+ }
76
+ function sqliteDefaultLiteral(value) {
77
+ if (typeof value === "boolean")
78
+ return value ? "1" : "0";
79
+ if (typeof value === "number") {
80
+ if (!Number.isFinite(value))
81
+ throw new Error("Better Auth migration default must be finite");
82
+ return String(value);
83
+ }
84
+ return `'${value.replaceAll("'", "''")}'`;
85
+ }
86
+ function safeRequiredColumnDefault(fieldName, field, migrationTimestamp) {
87
+ if (field.required === false || field.references || field.unique)
88
+ return undefined;
89
+ const declaredDefault = field.defaultValue;
90
+ if (typeof declaredDefault === "string" || typeof declaredDefault === "boolean")
91
+ return declaredDefault;
92
+ if (typeof declaredDefault === "number" && Number.isFinite(declaredDefault))
93
+ return declaredDefault;
94
+ if (declaredDefault instanceof Date && Number.isFinite(declaredDefault.getTime()))
95
+ return declaredDefault.toISOString();
96
+ if ((fieldName === "createdAt" || fieldName === "updatedAt") && field.type === "date") {
97
+ return migrationTimestamp;
98
+ }
99
+ return undefined;
100
+ }
101
+ function tableRowCount(database, table) {
102
+ const row = database.prepare(`SELECT COUNT(*) AS count FROM ${quoteSqlIdentifier(table)}`).get();
103
+ return Number(row.count);
104
+ }
105
+ function repairSafeRequiredColumns(database, pendingAdditions) {
106
+ const migrationTimestamp = new Date().toISOString();
107
+ const statements = [];
108
+ const unsafeColumns = [];
109
+ for (const addition of pendingAdditions) {
110
+ if (tableRowCount(database, addition.table) === 0)
111
+ continue;
112
+ for (const [fieldName, field] of Object.entries(addition.fields)) {
113
+ if (field.required === false)
114
+ continue;
115
+ const columnType = sqliteColumnType(field);
116
+ const defaultValue = safeRequiredColumnDefault(fieldName, field, migrationTimestamp);
117
+ if (!columnType || defaultValue === undefined) {
118
+ unsafeColumns.push(`${addition.table}.${fieldName}`);
119
+ continue;
120
+ }
121
+ statements.push(`ALTER TABLE ${quoteSqlIdentifier(addition.table)} ADD COLUMN ${quoteSqlIdentifier(fieldName)} ${columnType} NOT NULL DEFAULT ${sqliteDefaultLiteral(defaultValue)}`);
122
+ if (field.index) {
123
+ const indexName = `${addition.table}_${fieldName}_idx`;
124
+ statements.push(`CREATE INDEX IF NOT EXISTS ${quoteSqlIdentifier(indexName)} ON ${quoteSqlIdentifier(addition.table)} (${quoteSqlIdentifier(fieldName)})`);
125
+ }
126
+ }
127
+ }
128
+ if (unsafeColumns.length > 0 || statements.length === 0)
129
+ return unsafeColumns;
130
+ database.exec("BEGIN IMMEDIATE");
131
+ try {
132
+ for (const statement of statements)
133
+ database.exec(statement);
134
+ database.exec("COMMIT");
135
+ }
136
+ catch (error) {
137
+ database.exec("ROLLBACK");
138
+ throw error;
139
+ }
140
+ return [];
141
+ }
142
+ function isSqliteRequiredColumnMigrationError(error) {
143
+ return error instanceof Error && error.message.includes("Cannot add a NOT NULL column with default value NULL");
144
+ }
145
+ function nextRecoveryBackupPath(databasePath) {
146
+ const timestamp = new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-");
147
+ const base = `${databasePath}.pibo-auth-recovery-${timestamp}`;
148
+ for (let attempt = 0; attempt < 100; attempt += 1) {
149
+ const suffix = attempt === 0 ? "" : `-${attempt + 1}`;
150
+ const candidate = `${base}${suffix}.sqlite`;
151
+ if (!existsSync(candidate))
152
+ return candidate;
153
+ }
154
+ throw new Error(`Could not allocate a unique Better Auth recovery backup beside ${databasePath}`);
155
+ }
156
+ function removeSqliteDatabaseFiles(databasePath) {
157
+ for (const path of [databasePath, `${databasePath}-wal`, `${databasePath}-shm`, `${databasePath}-journal`]) {
158
+ rmSync(path, { force: true });
159
+ }
160
+ }
161
+ function makePrivateFile(path) {
162
+ protectPrivateFileSync(path, { force: true });
163
+ }
164
+ function assertAuthOnlyRecoveryDatabase(database) {
165
+ const tables = database.prepare(`
166
+ SELECT name
167
+ FROM sqlite_master
168
+ WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
169
+ `).all();
170
+ if (tables.some((table) => !BETTER_AUTH_SQLITE_TABLES.has(table.name))) {
171
+ throw new Error("Better Auth SQLite recovery refused to replace a database that contains non-auth tables.");
172
+ }
173
+ }
174
+ /** @internal Exported for deterministic recovery failure injection. */
175
+ export async function recoverBetterAuthSqliteDatabase(input) {
176
+ if (input.databasePath === ":memory:") {
177
+ throw new Error("Better Auth SQLite schema requires recovery, but an in-memory database cannot be preserved");
178
+ }
179
+ assertAuthOnlyRecoveryDatabase(input.failedRuntime.database);
180
+ const backupPath = nextRecoveryBackupPath(input.databasePath);
181
+ await backup(input.failedRuntime.database, backupPath);
182
+ makePrivateFile(backupPath);
183
+ input.failedRuntime.database.close();
184
+ removeSqliteDatabaseFiles(input.databasePath);
185
+ let replacement;
186
+ try {
187
+ replacement = input.createRuntime();
188
+ await input.migrateRuntime(replacement);
189
+ makePrivateFile(input.databasePath);
190
+ return { runtime: replacement, backupPath };
191
+ }
192
+ catch (recoveryError) {
193
+ try {
194
+ replacement?.database.close();
195
+ }
196
+ catch { }
197
+ removeSqliteDatabaseFiles(input.databasePath);
198
+ try {
199
+ copyFileSync(backupPath, input.databasePath);
200
+ makePrivateFile(input.databasePath);
201
+ }
202
+ catch (restoreError) {
203
+ throw new AggregateError([recoveryError, restoreError], `Pibo could not create a fresh Better Auth database or restore the original. The protected recovery backup remains at "${backupPath}".`);
204
+ }
205
+ throw new Error(`Pibo could not create a fresh Better Auth database. The original was restored and the protected recovery backup remains at "${backupPath}".`, { cause: recoveryError });
47
206
  }
48
- return new DatabaseSync(resolvedPath);
49
207
  }
50
208
  function requiredAllowedEmails(options, configAllowedEmails) {
51
209
  const allowedEmails = options.allowedEmails !== undefined
@@ -68,28 +226,50 @@ export function createBetterAuthService(options = {}) {
68
226
  const allowedEmails = requiredAllowedEmails(options, authConfig?.allowedEmails);
69
227
  const machineKeys = createMachineKeyAuthenticator(options.machineKeyStorePath ?? authConfig?.machineKeyStorePath);
70
228
  const machineSessions = createMachineSessionManager({ secret, machineKeys });
71
- const database = createDatabase(options.databasePath ?? authConfig?.databasePath ?? piboHomePath("auth.sqlite"));
229
+ const configuredDatabasePath = options.databasePath ?? authConfig?.databasePath ?? piboHomePath("auth.sqlite");
230
+ const databasePath = configuredDatabasePath === ":memory:" ? configuredDatabasePath : resolve(configuredDatabasePath);
72
231
  const trustedOrigins = options.trustedOrigins ?? authConfig?.trustedOrigins;
73
- const authOptions = {
74
- appName: "Pibo",
75
- baseURL,
76
- secret,
77
- database,
78
- trustedOrigins: createTrustedOrigins(baseURL, trustedOrigins),
79
- session: {
80
- expiresIn: SESSION_EXPIRES_IN_SECONDS,
81
- updateAge: SESSION_UPDATE_AGE_SECONDS,
82
- },
83
- socialProviders: {
84
- google: {
85
- clientId: googleClientId,
86
- clientSecret: googleClientSecret,
87
- prompt: "select_account",
232
+ const createRuntime = () => {
233
+ const database = createDatabase(databasePath);
234
+ if (databasePath !== ":memory:")
235
+ makePrivateFile(databasePath);
236
+ const authOptions = {
237
+ appName: "Pibo",
238
+ baseURL,
239
+ secret,
240
+ database,
241
+ trustedOrigins: createTrustedOrigins(baseURL, trustedOrigins),
242
+ session: {
243
+ expiresIn: SESSION_EXPIRES_IN_SECONDS,
244
+ updateAge: SESSION_UPDATE_AGE_SECONDS,
88
245
  },
89
- },
90
- plugins: [bearer()],
246
+ socialProviders: {
247
+ google: {
248
+ clientId: googleClientId,
249
+ clientSecret: googleClientSecret,
250
+ prompt: "select_account",
251
+ },
252
+ },
253
+ plugins: [bearer()],
254
+ };
255
+ return { database, authOptions, auth: betterAuth(authOptions) };
256
+ };
257
+ let runtime = createRuntime();
258
+ const recoverAuthDatabase = async (failedRuntime) => {
259
+ const recovered = await recoverBetterAuthSqliteDatabase({
260
+ databasePath,
261
+ failedRuntime,
262
+ createRuntime,
263
+ migrateRuntime: async (replacement) => {
264
+ const migrations = await getMigrations(replacement.authOptions);
265
+ await migrations.runMigrations();
266
+ },
267
+ });
268
+ console.warn(`[pibo] Better Auth SQLite schema was incompatible with a safe in-place migration. `
269
+ + `Pibo preserved a protected backup at "${recovered.backupPath}", created a fresh authentication database, `
270
+ + "and reset existing browser sessions. Sign in again.");
271
+ return recovered.runtime;
91
272
  };
92
- const auth = betterAuth(authOptions);
93
273
  const requireAllowedMachineSession = (session) => {
94
274
  const email = session.identity.email?.toLowerCase();
95
275
  if (!email || !allowedEmails.has(email))
@@ -99,17 +279,30 @@ export function createBetterAuthService(options = {}) {
99
279
  return {
100
280
  name: "better-auth",
101
281
  async start() {
102
- const migrations = await getMigrations(authOptions);
103
- await migrations.runMigrations();
282
+ let migrations = await getMigrations(runtime.authOptions);
283
+ const unsafeColumns = repairSafeRequiredColumns(runtime.database, migrations.toBeAdded);
284
+ if (unsafeColumns.length > 0) {
285
+ runtime = await recoverAuthDatabase(runtime);
286
+ return;
287
+ }
288
+ migrations = await getMigrations(runtime.authOptions);
289
+ try {
290
+ await migrations.runMigrations();
291
+ }
292
+ catch (error) {
293
+ if (!isSqliteRequiredColumnMigrationError(error))
294
+ throw error;
295
+ runtime = await recoverAuthDatabase(runtime);
296
+ }
104
297
  },
105
298
  stop() {
106
- database.close();
299
+ runtime.database.close();
107
300
  },
108
301
  async getSession(headers) {
109
302
  const machineSession = machineKeys.getSession(headers) ?? machineSessions.getSession(headers);
110
303
  if (machineSession)
111
304
  return requireAllowedMachineSession(machineSession);
112
- const session = await auth.api.getSession({ headers });
305
+ const session = await runtime.auth.api.getSession({ headers });
113
306
  if (!session)
114
307
  return undefined;
115
308
  const user = session.user;
@@ -172,7 +365,7 @@ export function createBetterAuthService(options = {}) {
172
365
  },
173
366
  });
174
367
  }
175
- return auth.handler(request);
368
+ return runtime.auth.handler(request);
176
369
  },
177
370
  };
178
371
  }
package/dist/auth/cli.js CHANGED
@@ -4,6 +4,7 @@ import { dirname, resolve } from "node:path";
4
4
  import { Command } from "commander";
5
5
  import { loadPiboConfig } from "../config/config.js";
6
6
  import { piboHomePath } from "../core/pibo-home.js";
7
+ import { protectPrivateFileSync } from "../core/private-path.js";
7
8
  import { generateMachineKey, getDefaultMachineKeyStorePath, importMachineKeyRecord, listMachineKeys, parseMachineKeyRecord, revokeMachineKey, } from "./machine-keys.js";
8
9
  function printJson(value) {
9
10
  console.log(JSON.stringify(value, null, 2));
@@ -103,7 +104,15 @@ function requireNewOutputPath(path, label) {
103
104
  }
104
105
  function writePrivateNewFile(path, content) {
105
106
  mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
106
- writeFileSync(path, content, { encoding: "utf8", mode: 0o600, flag: "wx" });
107
+ try {
108
+ writeFileSync(path, content, { encoding: "utf8", mode: 0o600, flag: "wx" });
109
+ protectPrivateFileSync(path, { force: true });
110
+ }
111
+ catch (error) {
112
+ if (existsSync(path))
113
+ unlinkSync(path);
114
+ throw error;
115
+ }
107
116
  }
108
117
  function parseExpiresAt(value) {
109
118
  if (value === undefined)
@@ -1,7 +1,8 @@
1
1
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
- import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
- import { piboHomePath } from "../core/pibo-home.js";
4
+ import { ensurePrivatePiboHomeForPath, piboHomePath } from "../core/pibo-home.js";
5
+ import { protectPrivateFileSync } from "../core/private-path.js";
5
6
  export const PIBO_MACHINE_KEY_HEADER = "x-pibo-machine-key";
6
7
  export const MACHINE_KEY_STORE_VERSION = 1;
7
8
  const MACHINE_KEY_ID_PATTERN = /^[a-f0-9]{16}$/;
@@ -108,8 +109,10 @@ function parseMachineKeyStore(value) {
108
109
  return { version: MACHINE_KEY_STORE_VERSION, keys };
109
110
  }
110
111
  function assertPrivateStoreFile(path) {
111
- if (process.platform === "win32")
112
+ if (process.platform === "win32") {
113
+ protectPrivateFileSync(path, { force: true });
112
114
  return;
115
+ }
113
116
  const stat = statSync(path);
114
117
  if ((stat.mode & 0o077) !== 0) {
115
118
  throw new Error(`Machine-key store must not be accessible by group or other users: ${path}`);
@@ -128,12 +131,13 @@ export function readMachineKeyStore(path = getDefaultMachineKeyStorePath()) {
128
131
  }
129
132
  function writeMachineKeyStore(store, path) {
130
133
  const resolvedPath = resolve(path);
134
+ ensurePrivatePiboHomeForPath(resolvedPath);
131
135
  mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 });
132
136
  const temporaryPath = `${resolvedPath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
133
137
  try {
134
138
  writeFileSync(temporaryPath, `${JSON.stringify(store, null, 2)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
135
139
  renameSync(temporaryPath, resolvedPath);
136
- chmodSync(resolvedPath, 0o600);
140
+ protectPrivateFileSync(resolvedPath, { force: true });
137
141
  }
138
142
  finally {
139
143
  if (existsSync(temporaryPath))
@@ -1,4 +1,4 @@
1
- import { AuthStorage } from "@earendil-works/pi-coding-agent";
1
+ import { readPiCredential, resolvePiProviderAuth, } from "../agent-runtimes/pi/credentials.js";
2
2
  const OPENAI_CODEX_PROVIDER = "openai-codex";
3
3
  const OPENAI_CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
4
4
  const OPENAI_JWT_CLAIM_PATH = "https://api.openai.com/auth";
@@ -124,11 +124,11 @@ function normalizeUsagePayload(payload) {
124
124
  export async function getOpenAiCodexProviderUsageForActiveModel(activeModel) {
125
125
  if (activeModel?.provider !== OPENAI_CODEX_PROVIDER)
126
126
  return undefined;
127
- const authStorage = AuthStorage.create();
128
- const credential = authStorage.get(OPENAI_CODEX_PROVIDER);
127
+ const credential = await readPiCredential(OPENAI_CODEX_PROVIDER);
129
128
  if (credential?.type !== "oauth")
130
129
  return undefined;
131
- const accessToken = await authStorage.getApiKey(OPENAI_CODEX_PROVIDER, { includeFallback: false });
130
+ const resolvedAuth = await resolvePiProviderAuth(OPENAI_CODEX_PROVIDER);
131
+ const accessToken = resolvedAuth?.auth.apiKey;
132
132
  if (!accessToken)
133
133
  return undefined;
134
134
  const headers = {
@@ -774,10 +774,10 @@ function fakeUploadResult(args) {
774
774
  if (!target)
775
775
  return {
776
776
  supported: false,
777
- unsupportedReason: "Usage: /upload <path>. Browser file picker upload is Web-only; copy files to ~/.pibo/uploads from the shell.",
777
+ unsupportedReason: "Usage: /upload <path>. Browser file picker upload is Web-only; copy files to $PIBO_HOME/uploads (default ~/.pibo/uploads) from the shell.",
778
778
  };
779
779
  return {
780
- message: `Terminal upload for ${target}: copy the file to ~/.pibo/uploads or use Web /upload. The CLI did not copy file contents.`,
780
+ message: `Terminal upload for ${target}: copy the file to $PIBO_HOME/uploads (default ~/.pibo/uploads) or use Web /upload. The CLI did not copy file contents.`,
781
781
  };
782
782
  }
783
783
  function sessionIdFromActionResult(value) {
@@ -1113,10 +1113,10 @@ function terminalUploadResult(args) {
1113
1113
  if (!target)
1114
1114
  return {
1115
1115
  supported: false,
1116
- unsupportedReason: "Usage: /upload <path>. Browser file picker upload is Web-only; from SSH, copy files with scp/rsync or place them under ~/.pibo/uploads.",
1116
+ unsupportedReason: "Usage: /upload <path>. Browser file picker upload is Web-only; from SSH, copy files with scp/rsync or place them under $PIBO_HOME/uploads (default ~/.pibo/uploads).",
1117
1117
  };
1118
1118
  return {
1119
- message: `Terminal upload for ${target}: copy or move the file to ~/.pibo/uploads, or use Web /upload for browser file selection. The CLI did not copy file contents or echo secrets.`,
1119
+ message: `Terminal upload for ${target}: copy or move the file to $PIBO_HOME/uploads (default ~/.pibo/uploads), or use Web /upload for browser file selection. The CLI did not copy file contents or echo secrets.`,
1120
1120
  };
1121
1121
  }
1122
1122
  function sessionMetadataResult(session, defaultRoomId, roomTitle) {
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { Command } from "commander";
3
3
  import { PIBO_CONFIG_KEYS, getDefaultPiboConfigPath, deletePiboConfigValue, getDisplayPiboConfigValue, loadPiboConfig, redactPiboConfig, savePiboConfig, setPiboConfigValue, } from "./config/config.js";
4
4
  import { parsePiboThinkingLevel } from "./core/thinking.js";
5
- import { piboHomePath } from "./core/pibo-home.js";
5
+ import { ensurePrivatePiboHome, piboHomePath } from "./core/pibo-home.js";
6
6
  async function createCliProfile(profileName) {
7
7
  const { createDefaultPiboPluginRegistry, createGatewayProducerPiboProfile, createPiboProfileFromRegistryOrDefault } = await import("./plugins/builtin.js");
8
8
  if (profileName === "gateway-producer" || profileName === "pibo-gateway-producer") {
@@ -80,6 +80,8 @@ export async function runPiboCli(argv = process.argv) {
80
80
  printPiboVersion();
81
81
  return;
82
82
  }
83
+ if (argv.length > 2)
84
+ ensurePrivatePiboHome();
83
85
  if (argv[2] === "auth") {
84
86
  const { runAuthCli } = await import("./auth/cli.js");
85
87
  await runAuthCli([argv[0] ?? "node", "pibo auth", ...argv.slice(3)]);
@@ -1,6 +1,7 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
- import { piboHomePath } from "../core/pibo-home.js";
3
+ import { ensurePrivatePiboHomeForPath, piboHomePath } from "../core/pibo-home.js";
4
+ import { protectPrivateFileSync } from "../core/private-path.js";
4
5
  export const DEFAULT_PIBO_CONFIG_PATH = "config.json";
5
6
  export function getDefaultPiboConfigPath() {
6
7
  return piboHomePath(DEFAULT_PIBO_CONFIG_PATH);
@@ -104,13 +105,17 @@ export function loadPiboConfig(path) {
104
105
  const resolvedPath = resolve(path ?? getDefaultPiboConfigPath());
105
106
  if (!existsSync(resolvedPath))
106
107
  return {};
107
- const parsed = JSON.parse(readFileSync(resolvedPath, "utf-8"));
108
+ protectPrivateFileSync(resolvedPath);
109
+ const source = readFileSync(resolvedPath, "utf-8").replace(/^\uFEFF/, "");
110
+ const parsed = JSON.parse(source);
108
111
  return assertObject(parsed);
109
112
  }
110
113
  export function savePiboConfig(config, path) {
111
114
  const resolvedPath = resolve(path ?? getDefaultPiboConfigPath());
112
- mkdirSync(dirname(resolvedPath), { recursive: true });
113
- writeFileSync(resolvedPath, `${JSON.stringify(config, null, 2)}\n`);
115
+ ensurePrivatePiboHomeForPath(resolvedPath);
116
+ mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 });
117
+ writeFileSync(resolvedPath, `${JSON.stringify(config, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
118
+ protectPrivateFileSync(resolvedPath, { force: true });
114
119
  }
115
120
  export function getPiboConfigValue(config, key) {
116
121
  getKeyDefinition(key);
@@ -275,7 +275,9 @@ export function createPiboCompactionPromptExtension(options = {}) {
275
275
  spec: await readActivePiboCompactionPromptSpec(ctx.cwd),
276
276
  model: ctx.model,
277
277
  apiKey: auth.apiKey,
278
- headers: auth.headers,
278
+ headers: auth.headers
279
+ ? Object.fromEntries(Object.entries(auth.headers).filter((entry) => typeof entry[1] === "string"))
280
+ : undefined,
279
281
  customInstructions: event.customInstructions,
280
282
  signal: event.signal,
281
283
  thinkingLevel: sessionContext.thinkingLevel,
@@ -180,6 +180,7 @@ function withoutRequestedModels(profile) {
180
180
  builtinTools: profile.builtinTools,
181
181
  builtinToolNames: profile.builtinToolNames,
182
182
  autoContextFiles: profile.autoContextFiles,
183
+ nativeSubagents: profile.nativeSubagents,
183
184
  toolPackages: profile.toolPackages,
184
185
  });
185
186
  }
@@ -1,8 +1,31 @@
1
+ import { existsSync, mkdirSync, statSync } from "node:fs";
1
2
  import { homedir } from "node:os";
2
- import { join } from "node:path";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { protectPrivateDirectorySync } from "./private-path.js";
3
5
  export function getPiboHome() {
4
6
  return process.env.PIBO_HOME || join(homedir(), ".pibo");
5
7
  }
6
8
  export function piboHomePath(...segments) {
7
9
  return join(getPiboHome(), ...segments);
8
10
  }
11
+ export function ensurePrivatePiboHome(path = getPiboHome()) {
12
+ const resolvedPath = resolve(path);
13
+ if (existsSync(resolvedPath) && !statSync(resolvedPath).isDirectory()) {
14
+ throw new Error(`Pibo Home must be a directory: ${resolvedPath}`);
15
+ }
16
+ mkdirSync(resolvedPath, { recursive: true, mode: 0o700 });
17
+ protectPrivateDirectorySync(resolvedPath);
18
+ return resolvedPath;
19
+ }
20
+ export function ensurePrivatePiboHomeForPath(path) {
21
+ if (path === ":memory:")
22
+ return false;
23
+ const home = resolve(getPiboHome());
24
+ const target = resolve(path);
25
+ const relativePath = relative(home, target);
26
+ const outsideHome = relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath);
27
+ if (outsideHome)
28
+ return false;
29
+ ensurePrivatePiboHome(home);
30
+ return true;
31
+ }
@@ -0,0 +1,146 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { chmodSync, lstatSync, readdirSync, statSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ const protectedWindowsPaths = new Set();
5
+ const WINDOWS_PRIVATE_ACL_SCRIPT = `
6
+ $ErrorActionPreference = 'Stop'
7
+ $ProgressPreference = 'SilentlyContinue'
8
+ $entries = @((ConvertFrom-Json -InputObject $env:PIBO_PRIVATE_PATHS_JSON))
9
+ $current = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
10
+ $system = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-18')
11
+ $administrators = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
12
+ $allowed = @($current.Value, $system.Value, $administrators.Value)
13
+ $inheritBoth = [System.Security.AccessControl.InheritanceFlags]([int][System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [int][System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
14
+ foreach ($entry in $entries) {
15
+ $path = [System.IO.Path]::GetFullPath([string]$entry.path)
16
+ $kind = [string]$entry.kind
17
+ $sections = [System.Security.AccessControl.AccessControlSections]([int][System.Security.AccessControl.AccessControlSections]::Access -bor [int][System.Security.AccessControl.AccessControlSections]::Owner)
18
+ if ($kind -eq 'directory') {
19
+ if (-not [System.IO.Directory]::Exists($path)) { throw "Private directory does not exist" }
20
+ $security = [System.IO.Directory]::GetAccessControl($path, $sections)
21
+ $inheritance = $inheritBoth
22
+ } elseif ($kind -eq 'file') {
23
+ if (-not [System.IO.File]::Exists($path)) { throw "Private file does not exist" }
24
+ $security = [System.IO.File]::GetAccessControl($path, $sections)
25
+ $inheritance = [System.Security.AccessControl.InheritanceFlags]::None
26
+ } else {
27
+ throw "Unsupported private path kind"
28
+ }
29
+ if ($security.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $current.Value) { throw "Private path owner is not the current user" }
30
+ $security.SetAccessRuleProtection($true, $false)
31
+ foreach ($rule in @($security.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier]))) {
32
+ $security.RemoveAccessRuleAll($rule)
33
+ }
34
+ foreach ($sid in @($current, $system, $administrators)) {
35
+ $rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
36
+ $sid,
37
+ [System.Security.AccessControl.FileSystemRights]::FullControl,
38
+ $inheritance,
39
+ [System.Security.AccessControl.PropagationFlags]::None,
40
+ [System.Security.AccessControl.AccessControlType]::Allow
41
+ )
42
+ $security.AddAccessRule($rule) | Out-Null
43
+ }
44
+ if ($kind -eq 'directory') {
45
+ [System.IO.Directory]::SetAccessControl($path, $security)
46
+ } else {
47
+ [System.IO.File]::SetAccessControl($path, $security)
48
+ }
49
+ $applied = Get-Acl -LiteralPath $path
50
+ if (-not $applied.AreAccessRulesProtected) { throw "Private path still inherits access rules" }
51
+ if ($applied.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $current.Value) { throw "Private path owner is not the current user" }
52
+ $seen = @{}
53
+ foreach ($rule in $applied.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])) {
54
+ $sid = $rule.IdentityReference.Value
55
+ if ($allowed -notcontains $sid) { throw "Private path grants access to an unexpected principal" }
56
+ if ($rule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow) { throw "Private path contains a deny rule" }
57
+ if (($rule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl) { throw "Private path does not grant required full control" }
58
+ $seen[$sid] = $true
59
+ }
60
+ foreach ($sid in $allowed) {
61
+ if (-not $seen.ContainsKey($sid)) { throw "Private path is missing a required principal" }
62
+ }
63
+ }
64
+ `;
65
+ const WINDOWS_PRIVATE_ACL_COMMAND = Buffer.from(WINDOWS_PRIVATE_ACL_SCRIPT, "utf16le").toString("base64");
66
+ function protectWindowsPathBatchSync(paths) {
67
+ const result = spawnSync("powershell.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", WINDOWS_PRIVATE_ACL_COMMAND], {
68
+ encoding: "utf8",
69
+ env: { ...process.env, PIBO_PRIVATE_PATHS_JSON: JSON.stringify(paths) },
70
+ timeout: 15_000,
71
+ windowsHide: true,
72
+ });
73
+ if (result.error || result.status !== 0) {
74
+ const reason = result.error instanceof Error && result.error.message
75
+ ? ` (${result.error.message})`
76
+ : "";
77
+ throw new Error(`Could not apply a private Windows ACL${reason}`);
78
+ }
79
+ }
80
+ function protectWindowsPathsSync(paths) {
81
+ let batch = [];
82
+ let batchCharacters = 2;
83
+ for (const descriptor of paths) {
84
+ const characters = JSON.stringify(descriptor).length + 1;
85
+ if (batch.length > 0 && batchCharacters + characters > 24_000) {
86
+ protectWindowsPathBatchSync(batch);
87
+ batch = [];
88
+ batchCharacters = 2;
89
+ }
90
+ batch.push(descriptor);
91
+ batchCharacters += characters;
92
+ }
93
+ if (batch.length > 0)
94
+ protectWindowsPathBatchSync(batch);
95
+ }
96
+ function protectPosixPathSync(path, kind) {
97
+ const expectedMode = kind === "directory" ? 0o700 : 0o600;
98
+ chmodSync(path, expectedMode);
99
+ if ((statSync(path).mode & 0o077) !== 0) {
100
+ throw new Error(`Private ${kind} must not be accessible by group or other users: ${path}`);
101
+ }
102
+ }
103
+ export function protectPrivatePathsSync(paths, options = {}) {
104
+ if (paths.length === 0)
105
+ return;
106
+ const normalized = paths.map((descriptor) => ({ ...descriptor, path: resolve(descriptor.path) }));
107
+ if (process.platform === "win32") {
108
+ const pending = options.force
109
+ ? normalized
110
+ : normalized.filter((descriptor) => !protectedWindowsPaths.has(`${descriptor.kind}:${descriptor.path.toLowerCase()}`));
111
+ if (pending.length === 0)
112
+ return;
113
+ protectWindowsPathsSync(pending);
114
+ for (const descriptor of pending)
115
+ protectedWindowsPaths.add(`${descriptor.kind}:${descriptor.path.toLowerCase()}`);
116
+ return;
117
+ }
118
+ for (const descriptor of normalized)
119
+ protectPosixPathSync(descriptor.path, descriptor.kind);
120
+ }
121
+ export function protectPrivateDirectorySync(path, options) {
122
+ protectPrivatePathsSync([{ path, kind: "directory" }], options);
123
+ }
124
+ export function protectPrivateFileSync(path, options) {
125
+ protectPrivatePathsSync([{ path, kind: "file" }], options);
126
+ }
127
+ export function protectPrivateTreeSync(root) {
128
+ if (process.platform !== "win32")
129
+ return;
130
+ const paths = [];
131
+ const visit = (path) => {
132
+ const metadata = lstatSync(path);
133
+ if (metadata.isSymbolicLink())
134
+ throw new Error(`Private path tree contains a symbolic link: ${path}`);
135
+ if (metadata.isDirectory()) {
136
+ paths.push({ path, kind: "directory" });
137
+ for (const entry of readdirSync(path))
138
+ visit(resolve(path, entry));
139
+ return;
140
+ }
141
+ if (metadata.isFile())
142
+ paths.push({ path, kind: "file" });
143
+ };
144
+ visit(resolve(root));
145
+ protectPrivatePathsSync(paths, { force: true });
146
+ }