@pasko70/pibo 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/README.md +106 -254
  2. package/context/codex-base-prompt.md +4 -0
  3. package/context/compute-worker.md +23 -0
  4. package/context/pibo-native-tooling.md +18 -0
  5. package/context/pibo-system-prompt.md +69 -8
  6. package/dist/api/simple-agent-api.js +136 -0
  7. package/dist/app-context.js +4 -0
  8. package/dist/apps/chat/agent-profiles.js +18 -3
  9. package/dist/apps/chat/agent-store.js +113 -16
  10. package/dist/apps/chat/chat-api-routes.js +311 -0
  11. package/dist/apps/chat/chat-capability-routes.js +90 -0
  12. package/dist/apps/chat/chat-files.js +178 -0
  13. package/dist/apps/chat/chat-request-normalizers.js +681 -0
  14. package/dist/apps/chat/chat-settings-routes.js +75 -0
  15. package/dist/apps/chat/chat-trace-helpers.js +94 -0
  16. package/dist/apps/chat/chat-user-skill-routes.js +149 -0
  17. package/dist/apps/chat/cron-api.js +213 -0
  18. package/dist/apps/chat/data/chat-data-mappers.js +74 -0
  19. package/dist/apps/chat/data/event-command-service.js +75 -0
  20. package/dist/apps/chat/data/navigation-query-service.js +11 -0
  21. package/dist/apps/chat/data/project-service.js +844 -0
  22. package/dist/apps/chat/data/read-state-service.js +42 -0
  23. package/dist/apps/chat/data/room-service.js +52 -0
  24. package/dist/apps/chat/data/session-query-service.js +63 -0
  25. package/dist/apps/chat/data/timeline-query-service.js +96 -0
  26. package/dist/apps/chat/event-log.js +1 -307
  27. package/dist/apps/chat/model-catalog.js +7 -2
  28. package/dist/apps/chat/output-compactor.js +126 -0
  29. package/dist/apps/chat/output-event-policy.js +17 -0
  30. package/dist/apps/chat/project-workflow-human-actions.js +347 -0
  31. package/dist/apps/chat/project-workflow-sessions.js +260 -0
  32. package/dist/apps/chat/provider-auth-actions.js +43 -0
  33. package/dist/apps/chat/ralph-api.js +156 -0
  34. package/dist/apps/chat/read-model.js +1 -218
  35. package/dist/apps/chat/rooms.js +1 -321
  36. package/dist/apps/chat/static-assets.js +996 -0
  37. package/dist/apps/chat/stream.js +29 -6
  38. package/dist/apps/chat/trace.js +179 -1003
  39. package/dist/apps/chat/types/event-store.js +1 -0
  40. package/dist/apps/chat/types/read-model.js +1 -0
  41. package/dist/apps/chat/types/rooms.js +36 -0
  42. package/dist/apps/chat/web-app.js +3131 -1959
  43. package/dist/apps/chat/workflow-catalog.js +572 -0
  44. package/dist/apps/chat/workflow-edge-compatibility.js +51 -0
  45. package/dist/apps/chat/workflow-json-schema-validation.js +335 -0
  46. package/dist/apps/chat/workflow-persistence-model.js +140 -0
  47. package/dist/apps/chat/workflow-persistence.js +633 -0
  48. package/dist/apps/chat/workflow-registered-ref-params.js +130 -0
  49. package/dist/apps/chat/workflow-registered-ref-pickers.js +179 -0
  50. package/dist/apps/chat/workflow-registered-ref-validation.js +210 -0
  51. package/dist/apps/chat/workflow-v2-security-validation.js +93 -0
  52. package/dist/apps/chat/workflow-validation-helpers.js +114 -0
  53. package/dist/apps/chat-ui/assets/{dist-CNLWH2qh.js → dist-B4lw9z4F.js} +1 -1
  54. package/dist/apps/chat-ui/assets/{dist-8e4L8ciw.js → dist-BbTaHWON.js} +1 -1
  55. package/dist/apps/chat-ui/assets/{dist-CMZOa5ik.js → dist-BcT_c1EJ.js} +1 -1
  56. package/dist/apps/chat-ui/assets/{dist-DNcnQRPF.js → dist-CGINd7XU.js} +1 -1
  57. package/dist/apps/chat-ui/assets/{dist-CqqUC8Ce.js → dist-CrBzZkUp.js} +1 -1
  58. package/dist/apps/chat-ui/assets/{dist-D2N4-LIc.js → dist-CyyISotB.js} +1 -1
  59. package/dist/apps/chat-ui/assets/{dist-CUqpST5w.js → dist-DFbnFNpX.js} +1 -1
  60. package/dist/apps/chat-ui/assets/{dist-CspjOeBj.js → dist-DGLWQLX8.js} +1 -1
  61. package/dist/apps/chat-ui/assets/{dist-B7bbI3Qz.js → dist-DfcIkFSN.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dist-v4pjHlB7.js → dist-sKDHTwaT.js} +1 -1
  63. package/dist/apps/chat-ui/assets/{dist-D9L4MSRF.js → dist-y9D6la48.js} +1 -1
  64. package/dist/apps/chat-ui/assets/index-C25VYnyb.css +1 -0
  65. package/dist/apps/chat-ui/assets/index-CUkuvI3v.js +165 -0
  66. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-144x144.png +0 -0
  67. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-192x192.png +0 -0
  68. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-48x48.png +0 -0
  69. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-512x512.png +0 -0
  70. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-72x72.png +0 -0
  71. package/dist/apps/chat-ui/assets/pwa-images/android/launchericon-96x96.png +0 -0
  72. package/dist/apps/chat-ui/assets/pwa-images/ios/100.png +0 -0
  73. package/dist/apps/chat-ui/assets/pwa-images/ios/1024.png +0 -0
  74. package/dist/apps/chat-ui/assets/pwa-images/ios/114.png +0 -0
  75. package/dist/apps/chat-ui/assets/pwa-images/ios/120.png +0 -0
  76. package/dist/apps/chat-ui/assets/pwa-images/ios/128.png +0 -0
  77. package/dist/apps/chat-ui/assets/pwa-images/ios/144.png +0 -0
  78. package/dist/apps/chat-ui/assets/pwa-images/ios/152.png +0 -0
  79. package/dist/apps/chat-ui/assets/pwa-images/ios/16.png +0 -0
  80. package/dist/apps/chat-ui/assets/pwa-images/ios/167.png +0 -0
  81. package/dist/apps/chat-ui/assets/pwa-images/ios/180.png +0 -0
  82. package/dist/apps/chat-ui/assets/pwa-images/ios/192.png +0 -0
  83. package/dist/apps/chat-ui/assets/pwa-images/ios/20.png +0 -0
  84. package/dist/apps/chat-ui/assets/pwa-images/ios/256.png +0 -0
  85. package/dist/apps/chat-ui/assets/pwa-images/ios/29.png +0 -0
  86. package/dist/apps/chat-ui/assets/pwa-images/ios/32.png +0 -0
  87. package/dist/apps/chat-ui/assets/pwa-images/ios/40.png +0 -0
  88. package/dist/apps/chat-ui/assets/pwa-images/ios/50.png +0 -0
  89. package/dist/apps/chat-ui/assets/pwa-images/ios/512.png +0 -0
  90. package/dist/apps/chat-ui/assets/pwa-images/ios/57.png +0 -0
  91. package/dist/apps/chat-ui/assets/pwa-images/ios/58.png +0 -0
  92. package/dist/apps/chat-ui/assets/pwa-images/ios/60.png +0 -0
  93. package/dist/apps/chat-ui/assets/pwa-images/ios/64.png +0 -0
  94. package/dist/apps/chat-ui/assets/pwa-images/ios/72.png +0 -0
  95. package/dist/apps/chat-ui/assets/pwa-images/ios/76.png +0 -0
  96. package/dist/apps/chat-ui/assets/pwa-images/ios/80.png +0 -0
  97. package/dist/apps/chat-ui/assets/pwa-images/ios/87.png +0 -0
  98. package/dist/apps/chat-ui/assets/pwa-images/windows/LargeTile.scale-100.png +0 -0
  99. package/dist/apps/chat-ui/assets/pwa-images/windows/LargeTile.scale-125.png +0 -0
  100. package/dist/apps/chat-ui/assets/pwa-images/windows/LargeTile.scale-150.png +0 -0
  101. package/dist/apps/chat-ui/assets/pwa-images/windows/LargeTile.scale-200.png +0 -0
  102. package/dist/apps/chat-ui/assets/pwa-images/windows/LargeTile.scale-400.png +0 -0
  103. package/dist/apps/chat-ui/assets/pwa-images/windows/SmallTile.scale-100.png +0 -0
  104. package/dist/apps/chat-ui/assets/pwa-images/windows/SmallTile.scale-125.png +0 -0
  105. package/dist/apps/chat-ui/assets/pwa-images/windows/SmallTile.scale-150.png +0 -0
  106. package/dist/apps/chat-ui/assets/pwa-images/windows/SmallTile.scale-200.png +0 -0
  107. package/dist/apps/chat-ui/assets/pwa-images/windows/SmallTile.scale-400.png +0 -0
  108. package/dist/apps/chat-ui/assets/pwa-images/windows/SplashScreen.scale-100.png +0 -0
  109. package/dist/apps/chat-ui/assets/pwa-images/windows/SplashScreen.scale-125.png +0 -0
  110. package/dist/apps/chat-ui/assets/pwa-images/windows/SplashScreen.scale-150.png +0 -0
  111. package/dist/apps/chat-ui/assets/pwa-images/windows/SplashScreen.scale-200.png +0 -0
  112. package/dist/apps/chat-ui/assets/pwa-images/windows/SplashScreen.scale-400.png +0 -0
  113. package/dist/apps/chat-ui/assets/pwa-images/windows/Square150x150Logo.scale-100.png +0 -0
  114. package/dist/apps/chat-ui/assets/pwa-images/windows/Square150x150Logo.scale-125.png +0 -0
  115. package/dist/apps/chat-ui/assets/pwa-images/windows/Square150x150Logo.scale-150.png +0 -0
  116. package/dist/apps/chat-ui/assets/pwa-images/windows/Square150x150Logo.scale-200.png +0 -0
  117. package/dist/apps/chat-ui/assets/pwa-images/windows/Square150x150Logo.scale-400.png +0 -0
  118. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-16.png +0 -0
  119. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-20.png +0 -0
  120. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-24.png +0 -0
  121. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-256.png +0 -0
  122. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-30.png +0 -0
  123. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-32.png +0 -0
  124. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-36.png +0 -0
  125. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-40.png +0 -0
  126. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-44.png +0 -0
  127. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-48.png +0 -0
  128. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-60.png +0 -0
  129. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-64.png +0 -0
  130. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-72.png +0 -0
  131. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-80.png +0 -0
  132. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-lightunplated_targetsize-96.png +0 -0
  133. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-16.png +0 -0
  134. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-20.png +0 -0
  135. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-24.png +0 -0
  136. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-256.png +0 -0
  137. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-30.png +0 -0
  138. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-32.png +0 -0
  139. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-36.png +0 -0
  140. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-40.png +0 -0
  141. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-44.png +0 -0
  142. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-48.png +0 -0
  143. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-60.png +0 -0
  144. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-64.png +0 -0
  145. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-72.png +0 -0
  146. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-80.png +0 -0
  147. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.altform-unplated_targetsize-96.png +0 -0
  148. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.scale-100.png +0 -0
  149. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.scale-125.png +0 -0
  150. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.scale-150.png +0 -0
  151. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.scale-200.png +0 -0
  152. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.scale-400.png +0 -0
  153. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-16.png +0 -0
  154. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-20.png +0 -0
  155. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-24.png +0 -0
  156. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-256.png +0 -0
  157. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-30.png +0 -0
  158. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-32.png +0 -0
  159. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-36.png +0 -0
  160. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-40.png +0 -0
  161. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-44.png +0 -0
  162. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-48.png +0 -0
  163. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-60.png +0 -0
  164. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-64.png +0 -0
  165. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-72.png +0 -0
  166. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-80.png +0 -0
  167. package/dist/apps/chat-ui/assets/pwa-images/windows/Square44x44Logo.targetsize-96.png +0 -0
  168. package/dist/apps/chat-ui/assets/pwa-images/windows/StoreLogo.scale-100.png +0 -0
  169. package/dist/apps/chat-ui/assets/pwa-images/windows/StoreLogo.scale-125.png +0 -0
  170. package/dist/apps/chat-ui/assets/pwa-images/windows/StoreLogo.scale-150.png +0 -0
  171. package/dist/apps/chat-ui/assets/pwa-images/windows/StoreLogo.scale-200.png +0 -0
  172. package/dist/apps/chat-ui/assets/pwa-images/windows/StoreLogo.scale-400.png +0 -0
  173. package/dist/apps/chat-ui/assets/pwa-images/windows/Wide310x150Logo.scale-100.png +0 -0
  174. package/dist/apps/chat-ui/assets/pwa-images/windows/Wide310x150Logo.scale-125.png +0 -0
  175. package/dist/apps/chat-ui/assets/pwa-images/windows/Wide310x150Logo.scale-150.png +0 -0
  176. package/dist/apps/chat-ui/assets/pwa-images/windows/Wide310x150Logo.scale-200.png +0 -0
  177. package/dist/apps/chat-ui/assets/pwa-images/windows/Wide310x150Logo.scale-400.png +0 -0
  178. package/dist/apps/chat-ui/index.html +8 -3
  179. package/dist/apps/chat-ui/manifest.webmanifest +25 -0
  180. package/dist/apps/chat-ui/sw.js +41 -0
  181. package/dist/apps/cli-ui/InkSessionApp.js +1218 -0
  182. package/dist/apps/cli-ui/InkTerminalLine.js +53 -0
  183. package/dist/apps/cli-ui/InkTerminalRow.js +304 -0
  184. package/dist/apps/cli-ui/InkTerminalView.js +25 -0
  185. package/dist/apps/cli-ui/cliSessionsCommand.js +232 -0
  186. package/dist/apps/cli-ui/index.js +8 -0
  187. package/dist/apps/cli-ui/inkColors.js +67 -0
  188. package/dist/apps/cli-ui/inkJson.js +244 -0
  189. package/dist/apps/cli-ui/inkMarkdown.js +122 -0
  190. package/dist/apps/context-files-ui/assets/{dist-DFi2YGux.js → dist-BOiGdrG-.js} +1 -1
  191. package/dist/apps/context-files-ui/assets/{dist-DyfSeBMu.js → dist-DK01b7x4.js} +1 -1
  192. package/dist/apps/context-files-ui/assets/{dist-CwbH_3RN.js → dist-DPG9jOQ-.js} +1 -1
  193. package/dist/apps/context-files-ui/assets/{dist-dTBsFYAl.js → dist-Dp5AH00p.js} +1 -1
  194. package/dist/apps/context-files-ui/assets/{dist-CxRLRmMx.js → dist-DqYw0LH7.js} +1 -1
  195. package/dist/apps/context-files-ui/assets/{dist-MyZgX9K2.js → dist-TF5iO5ML.js} +1 -1
  196. package/dist/apps/context-files-ui/assets/{dist-DQXzt2Ng.js → dist-TbjAhles.js} +1 -1
  197. package/dist/apps/context-files-ui/assets/{dist-YwR9dpb-.js → dist-ZsBbt0uY.js} +1 -1
  198. package/dist/apps/context-files-ui/assets/{dist-CKQF1zEu.js → dist-kmsvtHkH.js} +1 -1
  199. package/dist/apps/context-files-ui/assets/{dist-BJW3917N.js → dist-vnd7PMu3.js} +1 -1
  200. package/dist/apps/context-files-ui/assets/{index-BwRDoHMC.css → index-B92tL3Pp.css} +1 -1
  201. package/dist/apps/context-files-ui/assets/{index-GwvjXytt.js → index-BhAWD3dv.js} +2 -2
  202. package/dist/apps/context-files-ui/index.html +2 -2
  203. package/dist/auth/better-auth.js +2 -1
  204. package/dist/auth/login-actions.js +251 -0
  205. package/dist/auth/openai-codex-usage.js +147 -0
  206. package/dist/bin/pibo.js +0 -0
  207. package/dist/bin/rg.js +15 -0
  208. package/dist/cli-session/fakeSessionSource.js +804 -0
  209. package/dist/cli-session/index.js +3 -0
  210. package/dist/cli-session/localSessionSource.js +1144 -0
  211. package/dist/cli-session/sessionSource.js +13 -0
  212. package/dist/cli.js +142 -14
  213. package/dist/compute/cli.js +415 -0
  214. package/dist/compute/docker.js +827 -0
  215. package/dist/compute/resource-health.js +333 -0
  216. package/dist/compute/resource-policy.js +98 -0
  217. package/dist/config/config.js +9 -5
  218. package/dist/core/context-build.js +677 -0
  219. package/dist/core/model-defaults.js +51 -9
  220. package/dist/core/pibo-home.js +8 -0
  221. package/dist/core/profiles.js +48 -0
  222. package/dist/core/provider-telemetry.js +222 -0
  223. package/dist/core/routed-session.js +441 -47
  224. package/dist/core/runtime-telemetry.js +853 -0
  225. package/dist/core/runtime.js +103 -15
  226. package/dist/core/session-errors.js +47 -0
  227. package/dist/core/session-model.js +39 -0
  228. package/dist/core/session-router.js +292 -62
  229. package/dist/core/shared-app.js +17 -0
  230. package/dist/core/skill-expansion.js +43 -0
  231. package/dist/core/system-prompt-template.js +9 -9
  232. package/dist/core/telemetry-staleness.js +128 -0
  233. package/dist/core/test-output-compaction.js +145 -0
  234. package/dist/core/user-settings.js +73 -0
  235. package/dist/cron/channel.js +28 -0
  236. package/dist/cron/cli.js +230 -0
  237. package/dist/cron/plugin.js +11 -0
  238. package/dist/cron/schedule.js +214 -0
  239. package/dist/cron/service.js +177 -0
  240. package/dist/cron/store.js +349 -0
  241. package/dist/cron/types.js +1 -0
  242. package/dist/data/cli.js +184 -0
  243. package/dist/data/event-log.js +106 -0
  244. package/dist/data/final-app-space-cutover-migration.js +728 -0
  245. package/dist/data/ingest-service.js +389 -0
  246. package/dist/data/message-store.js +62 -0
  247. package/dist/data/navigation-store.js +75 -0
  248. package/dist/data/observation-store.js +46 -0
  249. package/dist/data/payload-store.js +144 -0
  250. package/dist/data/pibo-store.js +59 -0
  251. package/dist/data/schema.js +434 -0
  252. package/dist/data/session-store.js +63 -0
  253. package/dist/data/shared-app-migration.js +757 -0
  254. package/dist/data/sqlite-schema.js +12 -0
  255. package/dist/data/telemetry-preview.js +65 -0
  256. package/dist/data/telemetry-queries.js +212 -0
  257. package/dist/data/telemetry-retention.js +50 -0
  258. package/dist/data/telemetry-rows.js +158 -0
  259. package/dist/data/telemetry.js +357 -0
  260. package/dist/debug/delta-compaction.js +99 -0
  261. package/dist/debug/detail-format.js +86 -0
  262. package/dist/debug/events.js +149 -29
  263. package/dist/debug/failures.js +162 -0
  264. package/dist/debug/index.js +655 -30
  265. package/dist/debug/messages.js +185 -0
  266. package/dist/debug/next-commands.js +6 -0
  267. package/dist/debug/payloads.js +123 -0
  268. package/dist/debug/pty.js +924 -0
  269. package/dist/debug/session.js +45 -15
  270. package/dist/debug/sql.js +1 -1
  271. package/dist/debug/stores.js +18 -13
  272. package/dist/debug/summary.js +72 -0
  273. package/dist/debug/telemetry.js +649 -0
  274. package/dist/debug/tools.js +168 -0
  275. package/dist/debug/trace-render-check.js +151 -0
  276. package/dist/debug/trace.js +152 -27
  277. package/dist/debug/web-artifacts.js +63 -0
  278. package/dist/debug/web-options.js +313 -0
  279. package/dist/debug/web-render-analysis.js +310 -0
  280. package/dist/debug/web-snapshot-browser-scripts.js +303 -0
  281. package/dist/debug/web-streaming-benchmark-analysis.js +605 -0
  282. package/dist/debug/web-streaming-browser-library.js +928 -0
  283. package/dist/debug/web-streaming-browser-scripts.js +242 -0
  284. package/dist/debug/web-streaming-provider-telemetry.js +194 -0
  285. package/dist/debug/web-streaming-report.js +493 -0
  286. package/dist/debug/web-streaming-types.js +1 -0
  287. package/dist/debug/web.js +574 -0
  288. package/dist/gateway/backup.js +83 -0
  289. package/dist/gateway/cli.js +511 -0
  290. package/dist/gateway/fallback.js +155 -0
  291. package/dist/gateway/pidfile.js +84 -0
  292. package/dist/gateway/protocol.js +16 -0
  293. package/dist/gateway/server.js +172 -17
  294. package/dist/gateway/tool.js +54 -51
  295. package/dist/gateway/web.js +74 -2
  296. package/dist/index.js +3 -1
  297. package/dist/local/client.js +3 -3
  298. package/dist/local/extension.js +8 -5
  299. package/dist/plugins/builtin.js +251 -49
  300. package/dist/plugins/chat-vscode-web.js +28 -0
  301. package/dist/plugins/codex-compat.js +0 -41
  302. package/dist/plugins/context-files.js +98 -18
  303. package/dist/plugins/dev-auth.js +124 -0
  304. package/dist/plugins/native-tooling.js +15 -0
  305. package/dist/plugins/registry.js +49 -1
  306. package/dist/plugins/web-annotations.js +27 -0
  307. package/dist/providers/minimax.js +70 -0
  308. package/dist/providers/openai-compat.js +48 -0
  309. package/dist/ralph/channel.js +8 -0
  310. package/dist/ralph/cli.js +152 -0
  311. package/dist/ralph/plugin.js +14 -0
  312. package/dist/ralph/service.js +271 -0
  313. package/dist/ralph/stopping.js +151 -0
  314. package/dist/ralph/store.js +450 -0
  315. package/dist/ralph/templates.js +200 -0
  316. package/dist/ralph/types.js +1 -0
  317. package/dist/reliability/store.js +42 -26
  318. package/dist/runs/registry.js +72 -35
  319. package/dist/session-ui/commandCatalog.js +193 -0
  320. package/dist/session-ui/commandResults.js +95 -0
  321. package/dist/session-ui/index.js +7 -0
  322. package/dist/session-ui/ownerViewModel.js +27 -0
  323. package/dist/session-ui/roomSessionViewModel.js +69 -0
  324. package/dist/session-ui/statusViewModel.js +127 -0
  325. package/dist/session-ui/terminalCards.js +210 -0
  326. package/dist/session-ui/terminalRows.js +937 -0
  327. package/dist/session-ui/terminalValue.js +45 -0
  328. package/dist/sessions/pibo-data-store.js +178 -0
  329. package/dist/sessions/sqlite-store.js +78 -12
  330. package/dist/sessions/store.js +11 -4
  331. package/dist/sessions/workflow-session-kind.js +20 -0
  332. package/dist/setup/cli.js +567 -0
  333. package/dist/shared/trace-async-agent-runs.js +127 -0
  334. package/dist/shared/trace-engine.js +96 -0
  335. package/dist/shared/trace-event-projection.js +679 -0
  336. package/dist/shared/trace-live-reducer.js +191 -0
  337. package/dist/shared/trace-nodes.js +76 -0
  338. package/dist/shared/trace-order.js +11 -10
  339. package/dist/shared/trace-patch-nodes.js +83 -0
  340. package/dist/shared/trace-run-notifications.js +69 -0
  341. package/dist/shared/trace-subagent-links.js +46 -0
  342. package/dist/shared/trace-transcript.js +303 -0
  343. package/dist/shared/trace-types.js +1 -0
  344. package/dist/shared-app.js +4 -0
  345. package/dist/signals/aggregate.js +65 -0
  346. package/dist/signals/events.js +1 -0
  347. package/dist/signals/projector.js +158 -0
  348. package/dist/signals/registry.js +513 -0
  349. package/dist/signals/store.js +1 -0
  350. package/dist/signals/types.js +1 -0
  351. package/dist/skills/cli.js +117 -0
  352. package/dist/tools/agent-browser-leases.js +219 -0
  353. package/dist/tools/agent-browser-wrapper.js +99 -0
  354. package/dist/tools/browser-pool.js +623 -0
  355. package/dist/tools/browser-use-cdp.js +56 -4
  356. package/dist/tools/browser-use-leases.js +215 -37
  357. package/dist/tools/browser-use-wrapper.js +508 -65
  358. package/dist/tools/cdp-client.js +189 -0
  359. package/dist/tools/guides.js +203 -4
  360. package/dist/tools/index.js +666 -16
  361. package/dist/tools/npm-runtime.js +136 -0
  362. package/dist/tools/registry.js +107 -8
  363. package/dist/tools/runtime/index.js +3 -0
  364. package/dist/tools/runtime/node-backend.js +225 -0
  365. package/dist/tools/runtime/node-worker-source.js +206 -0
  366. package/dist/tools/runtime/python-backend.js +227 -0
  367. package/dist/tools/runtime/python-worker-source.js +178 -0
  368. package/dist/tools/runtime/registry.js +255 -0
  369. package/dist/tools/runtime/tool.js +168 -0
  370. package/dist/tools/runtime/types.js +1 -0
  371. package/dist/tools/web-search.js +2 -1
  372. package/dist/user-skills/installer.js +39 -36
  373. package/dist/user-skills/store.js +50 -11
  374. package/dist/web/auth.js +5 -1
  375. package/dist/web/channel.js +86 -0
  376. package/dist/web/http.js +79 -14
  377. package/dist/web-annotations/api.js +348 -0
  378. package/dist/web-annotations/attachments.js +201 -0
  379. package/dist/web-annotations/cdp.js +1107 -0
  380. package/dist/web-annotations/index.js +7 -0
  381. package/dist/web-annotations/store.js +407 -0
  382. package/dist/web-annotations/tools.js +350 -0
  383. package/dist/web-annotations/types.js +34 -0
  384. package/dist/web-annotations/validation.js +288 -0
  385. package/docs/README.md +23 -0
  386. package/docs/ops/install-developer-host.md +112 -0
  387. package/docs/ops/install-user-host.md +76 -0
  388. package/docs/ops/upgrade-user-to-developer-host.md +69 -0
  389. package/package.json +24 -10
  390. package/skills/builtin/pi-agent-harness/SKILL.md +24 -24
  391. package/skills/builtin/pibo-docker-system/SKILL.md +170 -0
  392. package/skills/builtin/pibo-spec-writing/SKILL.md +330 -0
  393. package/skills/builtin/prd/SKILL.md +143 -0
  394. package/skills/builtin/ralph-loop/SKILL.md +359 -0
  395. package/skills/builtin/ralph-prd-json/SKILL.md +123 -0
  396. package/skills/builtin/skill-creator/LICENSE.txt +202 -0
  397. package/skills/builtin/skill-creator/SKILL.md +513 -0
  398. package/skills/builtin/skill-creator/agents/analyzer.md +274 -0
  399. package/skills/builtin/skill-creator/agents/comparator.md +202 -0
  400. package/skills/builtin/skill-creator/agents/grader.md +223 -0
  401. package/skills/builtin/skill-creator/assets/eval_review.html +146 -0
  402. package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -0
  403. package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -0
  404. package/skills/builtin/skill-creator/references/schemas.md +430 -0
  405. package/skills/builtin/skill-creator/scripts/__init__.py +0 -0
  406. package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -0
  407. package/skills/builtin/skill-creator/scripts/generate_report.py +326 -0
  408. package/skills/builtin/skill-creator/scripts/improve_description.py +247 -0
  409. package/skills/builtin/skill-creator/scripts/package_skill.py +136 -0
  410. package/skills/builtin/skill-creator/scripts/quick_validate.py +103 -0
  411. package/skills/builtin/skill-creator/scripts/run_eval.py +310 -0
  412. package/skills/builtin/skill-creator/scripts/run_loop.py +328 -0
  413. package/skills/builtin/skill-creator/scripts/utils.py +47 -0
  414. package/skills/builtin/web-annotations/SKILL.md +93 -0
  415. package/dist/apps/chat-ui/assets/index-D2Qxambd.js +0 -151
  416. package/dist/apps/chat-ui/assets/index-DXx368XK.css +0 -1
  417. package/dist/env.js +0 -32
  418. package/dist/plugins/core-tools.js +0 -94
  419. package/dist/plugins/example.js +0 -67
  420. package/dist/plugins/remote-agent.js +0 -9
  421. package/dist/remote/channel.js +0 -176
  422. package/dist/remote/client.js +0 -92
  423. package/dist/remote/examples/tui-controller.js +0 -263
  424. package/dist/remote/protocol.js +0 -55
  425. package/dist/remote/session-client.js +0 -189
  426. package/dist/sessions/bindings.js +0 -41
@@ -0,0 +1,574 @@
1
+ import path from "node:path";
2
+ import { listBrowserUseCdpTargets, selectBestChatTarget, formatBrowserUseTargets } from "../tools/browser-use-cdp.js";
3
+ import { CdpClient } from "../tools/cdp-client.js";
4
+ import { diffSnapshots, formatSnapshot, formatSnapshotDiff, formatWatch } from "./web-render-analysis.js";
5
+ import { formatStreamingBenchmarkAssertionError, formatStreamingBenchmarkCompactReport, formatStreamingBenchmarkResult, streamingBenchmarkReportRows, } from "./web-streaming-report.js";
6
+ import { applyExpectedStreamingRegressions, attachStreamingProviderTelemetryToBenchmarks, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, readStreamingBenchmarkArtifact, readStreamingBenchmarkRuns, scoreStreamingBenchmark, streamingBenchmarkReportTarget, summarizeStreamingBenchmarkGroup, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingCadence, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation, } from "./web-streaming-benchmark-analysis.js";
7
+ import { collectStreamingProviderTelemetry, collectStreamingProviderTelemetryFromSelectedBrowserSession, collectStreamingProviderTelemetryFromSession, collectStreamingProviderTelemetryFromTurn, } from "./web-streaming-provider-telemetry.js";
8
+ import { buildStreamingBenchmarkExpression, streamingBenchmarkEventSourceProbeScript, streamingBenchmarkFixtureHtml } from "./web-streaming-browser-scripts.js";
9
+ import { buildSnapshotExpression, buildWatchExpression } from "./web-snapshot-browser-scripts.js";
10
+ import { compactTarget, limitStdout, readBaselineSnapshot, writeArtifact, writeLastSnapshot, writeReportOutput, writeTextArtifact } from "./web-artifacts.js";
11
+ import { applyNegativeStreamingProfile, DEFAULT_DEPTH_LIMIT, DEFAULT_EVENT_LIMIT, DEFAULT_NODE_LIMIT, DEFAULT_TEXT_LIMIT, parseDuration, parseFixtureMix, parseFixturePreludeMessages, parseFixtureProfile, parseNegativeProfile, parseOptions, parseRuns, presetScope, resolveScope, resolveStreamingBenchmarkCompareUrl, resolveStreamingBenchmarkHostedCompareUrl } from "./web-options.js";
12
+ export { formatStreamingBenchmarkAssertionSummary, formatStreamingBenchmarkUrlComparison, summarizeStreamingSelectedLiveEventSource } from "./web-streaming-report.js";
13
+ export { resolveStreamingBenchmarkHostedCompareUrlFromValues } from "./web-options.js";
14
+ export { attachStreamingProviderTelemetryToBenchmark, evaluateStreamingBenchmarkAssertion, evaluateStreamingBenchmarkUrlComparisonRegressions, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingBenchmarks, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation } from "./web-streaming-benchmark-analysis.js";
15
+ export { collectStreamingProviderTelemetryFromSelectedBrowserSession, collectStreamingProviderTelemetryFromSession, collectStreamingProviderTelemetryFromTurn, summarizeStreamingProviderTelemetry } from "./web-streaming-provider-telemetry.js";
16
+ export { formatWatch, inferWatchFlickers } from "./web-render-analysis.js";
17
+ export async function runDebugWeb(args) {
18
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
19
+ printWebDiscovery();
20
+ return;
21
+ }
22
+ const command = args[0];
23
+ const options = parseOptions(args.slice(1));
24
+ if (command === "targets") {
25
+ await runTargets(options);
26
+ return;
27
+ }
28
+ if (command === "attach-chat") {
29
+ await runAttachChat(options);
30
+ return;
31
+ }
32
+ if (command === "snapshot") {
33
+ await runSnapshot(options);
34
+ return;
35
+ }
36
+ if (command === "diff") {
37
+ await runDiff(options);
38
+ return;
39
+ }
40
+ if (command === "watch") {
41
+ await runWatch(options);
42
+ return;
43
+ }
44
+ if (command === "scenario") {
45
+ await runScenario(options);
46
+ return;
47
+ }
48
+ if (command === "report") {
49
+ await runReport(options);
50
+ return;
51
+ }
52
+ throw new Error(`Unknown pibo debug web command "${command}". Run pibo debug web --help.`);
53
+ }
54
+ function printWebDiscovery() {
55
+ console.log(`pibo debug web - inspect browser render state via CDP
56
+
57
+ Commands:
58
+ targets List Chrome CDP targets with Chat auth hints
59
+ attach-chat Show the best authenticated Chat Web target
60
+ snapshot Capture a scoped compact DOM snapshot
61
+ diff Compare current scoped snapshot against previous or artifact
62
+ watch Record a bounded scoped DOM/focus/route timeline
63
+ scenario Run guided Chat Web debug workflows
64
+ report Render saved debug artifacts as reviewer-friendly Markdown
65
+
66
+ Next:
67
+ pibo debug web targets
68
+ pibo debug web snapshot --preset session-list
69
+ pibo debug web watch --preset chat-shell --duration 5000
70
+ pibo debug web report streaming-benchmark --from artifact.json
71
+ `);
72
+ }
73
+ function printSnapshotHelp() {
74
+ console.log(`pibo debug web snapshot - capture a scoped compact DOM snapshot
75
+
76
+ Usage:
77
+ pibo debug web snapshot --scope <selector> [--target id|ws] [--json] [--artifact]
78
+ pibo debug web snapshot --preset session-list
79
+
80
+ Presets:
81
+ app | route-shell | sidebar | session-list | chat-shell | composer
82
+
83
+ Next:
84
+ pibo debug web diff --preset session-list
85
+ pibo debug web watch --preset chat-shell --duration 5000
86
+ `);
87
+ }
88
+ function printWatchHelp() {
89
+ console.log(`pibo debug web watch - record compact render-state changes
90
+
91
+ Usage:
92
+ pibo debug web watch --scope <selector> [--duration ms] [--target id|ws] [--json] [--artifact]
93
+ pibo debug web watch --preset chat-shell --duration 5000
94
+
95
+ Defaults:
96
+ duration=5000ms, max=30000ms, event budget=500
97
+
98
+ Next:
99
+ pibo debug web diff --preset chat-shell
100
+ pibo debug web scenario new-session --manual
101
+ `);
102
+ }
103
+ function printScenarioHelp() {
104
+ console.log(`pibo debug web scenario - guided Chat Web debug workflows
105
+
106
+ Usage:
107
+ pibo debug web scenario new-session [--manual|--act] [--duration ms] [--json] [--artifact]
108
+ pibo debug web scenario streaming-benchmark [--fixture|--backend-fixture] [--fixture-profile steady|jitter|burst|batch] [--fixture-mix text|reasoning-text|markdown|gfm-markdown|gfm-task-markdown|gfm-full-markdown] [--fixture-prelude-messages n] [--simulate-reconnect|--simulate-trace-catchup] [--duration ms] [--runs n] [--from artifact.json] [--provider-request-id pr_...|--provider-session-id ps_...|--provider-turn-id turn_...|--provider-selected-session] [--compare-url url|--compare-hosted|--compare-hosted-if-configured] [--assert] [--expect-regression text] [--negative-profile batch|overlay-drop] [--json] [--artifact]
109
+
110
+ Defaults:
111
+ new-session --manual waits while you click New Session yourself.
112
+ new-session --act clicks the discovered New Session button after the watcher starts.
113
+ streaming-benchmark enables debugStreaming for future events, observes assistant DOM increments, and snapshots window.__piboStreamingDebug.
114
+ streaming-benchmark --fixture navigates the target to a deterministic in-browser stream fixture before measuring.
115
+ streaming-benchmark --backend-fixture posts to /api/chat/debug/streaming-fixture and records EventSource metrics while the real app consumes deterministic /api/chat/events frames.
116
+ streaming-benchmark --fixture-profile selects steady cadence, deterministic jitter, bursty timing, or intentional batch stress.
117
+ streaming-benchmark --fixture-mix includes text-only, mixed reasoning/text, CommonMark Markdown, simple GFM Markdown, or full-parser GFM Markdown assistant deltas.
118
+ streaming-benchmark --fixture-prelude-messages seeds completed live assistant messages before counters reset so large live overlays can be measured without changing fixture preservation denominators.
119
+ streaming-benchmark --simulate-reconnect reloads the app with an EventSource probe, forces one live stream close, and verifies reconnect/transient ids.
120
+ streaming-benchmark --simulate-trace-catchup suppresses backend live text deltas and verifies trace snapshot recovery.
121
+ streaming-benchmark --runs repeats the same scenario and reports medians; --from compares against a prior benchmark artifact.
122
+ streaming-benchmark --compare-url runs the same backend fixture at another Chat URL, for direct-vs-hosted SSE comparison.
123
+ streaming-benchmark --compare-hosted uses PIBO_DEV_PUBLIC_URL or PIBO_DEV_BASE_URL from the environment or .env.developer-host as the compare URL.
124
+ streaming-benchmark --compare-hosted-if-configured runs the hosted comparison when a dev URL is configured; otherwise it records a warning and keeps the primary benchmark.
125
+ streaming-benchmark --provider-request-id attaches provider/Pi telemetry delta counts, byte stats, gap stats, parse errors, first-text latency, and provider-to-transport preservation ratios from pibo debug telemetry.
126
+ streaming-benchmark --provider-session-id, --provider-turn-id, or --provider-selected-session discovers the latest provider request from telemetry session/turn metadata after the benchmark window before attaching provider metrics.
127
+ streaming-benchmark --assert exits non-zero when fixture/debug/DOM/provider preservation gates fail.
128
+ streaming-benchmark --expect-regression marks a required regression substring for controlled negative benchmarks; unexpected or missing expected regressions still fail with --assert.
129
+ streaming-benchmark --negative-profile batch expands to the backend batch reasoning/text fixture with required controlled regression assertions.
130
+ streaming-benchmark --negative-profile overlay-drop preserves SSE/EventSource input but drops live-overlay text/reasoning enqueue for a controlled pipeline-preservation failure.
131
+ `);
132
+ }
133
+ function printReportHelp() {
134
+ console.log(`pibo debug web report - render saved debug artifacts
135
+
136
+ Usage:
137
+ pibo debug web report streaming-benchmark --from artifact.json [--compact] [--output report.md] [--json-output report.json] [--json] [--artifact]
138
+
139
+ Reports:
140
+ streaming-benchmark Summarize saved pibo debug web scenario streaming-benchmark JSON as Markdown.
141
+ --compact Render reviewer-friendly Markdown tables instead of the detailed line report.
142
+ --output Write the Markdown report to a specific file path.
143
+ --json-output Write the normalized JSON report payload and compact rows to a specific file path.
144
+
145
+ Next:
146
+ pibo debug web scenario streaming-benchmark --backend-fixture --assert --artifact
147
+ `);
148
+ }
149
+ async function runTargets(options) {
150
+ const targets = await listBrowserUseCdpTargets({ cdpUrl: options.cdpUrl, probe: true });
151
+ if (options.json) {
152
+ console.log(JSON.stringify({ targets }, null, 2));
153
+ return;
154
+ }
155
+ console.log(formatBrowserUseTargets(targets));
156
+ if (targets.length === 0) {
157
+ console.log("\nNext: eval \"$(pibo tools env browser-use)\" or pass --cdp-url http://127.0.0.1:<port>");
158
+ }
159
+ }
160
+ async function runAttachChat(options) {
161
+ const targets = await listBrowserUseCdpTargets({ cdpUrl: options.cdpUrl, probe: true });
162
+ const target = resolveTargetFromList(targets, options.target) ?? selectBestChatTarget(targets);
163
+ if (!target) {
164
+ throw new Error("No authenticated Chat Web target with a composer textarea was found. Next: pibo tools browser-use targets or acquire a Browser Use lease.");
165
+ }
166
+ if (options.json) {
167
+ console.log(JSON.stringify({ target }, null, 2));
168
+ return;
169
+ }
170
+ console.log(`target\t${target.id}`);
171
+ console.log(`url\t${target.url}`);
172
+ console.log(`auth\t${target.auth}`);
173
+ console.log(`composer\t${target.composer ? "yes" : "no"}`);
174
+ console.log(`ws\t${target.webSocketDebuggerUrl ?? ""}`);
175
+ console.log("\nNext:");
176
+ console.log(` pibo debug web snapshot --target ${shellQuote(target.id)} --preset session-list`);
177
+ console.log(` pibo debug web watch --target ${shellQuote(target.id)} --preset chat-shell --duration 5000`);
178
+ }
179
+ async function runSnapshot(options) {
180
+ if (options.positionals[0] === "--help" || options.positionals[0] === "-h") {
181
+ printSnapshotHelp();
182
+ return;
183
+ }
184
+ const scope = resolveScope(options);
185
+ const { client, target } = await connectTarget(options);
186
+ try {
187
+ const snapshot = await captureSnapshot(client, scope, options);
188
+ if (options.json) {
189
+ console.log(JSON.stringify({ target: compactTarget(target), snapshot }, null, 2));
190
+ }
191
+ else {
192
+ console.log(limitStdout(formatSnapshot(snapshot, target)));
193
+ }
194
+ await writeLastSnapshot(snapshot);
195
+ if (options.artifact) {
196
+ const artifact = await writeArtifact("snapshot", snapshot);
197
+ if (!options.json)
198
+ console.log(`Artifact: ${artifact}`);
199
+ }
200
+ }
201
+ finally {
202
+ client.close();
203
+ }
204
+ }
205
+ async function runDiff(options) {
206
+ if (options.positionals[0] === "--help" || options.positionals[0] === "-h") {
207
+ console.log(`pibo debug web diff - compare scoped render snapshots
208
+
209
+ Usage:
210
+ pibo debug web diff --scope <selector> [--from artifact.json]
211
+ pibo debug web diff --preset session-list
212
+
213
+ Default --from is the last snapshot captured by pibo debug web snapshot.
214
+ `);
215
+ return;
216
+ }
217
+ const scope = resolveScope(options);
218
+ const baseline = await readBaselineSnapshot(options.from);
219
+ const { client, target } = await connectTarget(options);
220
+ try {
221
+ const current = await captureSnapshot(client, scope, options);
222
+ if (baseline.scope !== current.scope) {
223
+ if (options.json)
224
+ console.log(JSON.stringify({ target: compactTarget(target), baseline, current, error: "scope_mismatch" }, null, 2));
225
+ else
226
+ console.log(`Scope mismatch: baseline=${baseline.scope} current=${current.scope}\nTake a new baseline with: pibo debug web snapshot --scope ${shellQuote(current.scope)}`);
227
+ await writeLastSnapshot(current);
228
+ return;
229
+ }
230
+ const diff = diffSnapshots(baseline, current);
231
+ if (options.json)
232
+ console.log(JSON.stringify({ target: compactTarget(target), baseline, current, diff }, null, 2));
233
+ else
234
+ console.log(limitStdout(formatSnapshotDiff(diff, baseline, current, target)));
235
+ await writeLastSnapshot(current);
236
+ if (options.artifact) {
237
+ const artifact = await writeArtifact("diff", { baseline, current, diff });
238
+ if (!options.json)
239
+ console.log(`Artifact: ${artifact}`);
240
+ }
241
+ }
242
+ finally {
243
+ client.close();
244
+ }
245
+ }
246
+ async function runWatch(options) {
247
+ if (options.positionals[0] === "--help" || options.positionals[0] === "-h") {
248
+ printWatchHelp();
249
+ return;
250
+ }
251
+ if (options.act || options.manual) {
252
+ throw new Error("Action flags are only supported by scenarios. Next: pibo debug web scenario new-session --act");
253
+ }
254
+ if (options.positionals.length) {
255
+ throw new Error(`Unexpected pibo debug web watch argument "${options.positionals[0]}". Run pibo debug web watch --help.`);
256
+ }
257
+ const scope = resolveScope(options);
258
+ const durationMs = parseDuration(options.duration);
259
+ const { client, target } = await connectTarget(options);
260
+ try {
261
+ const watch = await runBrowserWatch(client, scope, durationMs, options);
262
+ if (options.json)
263
+ console.log(JSON.stringify({ target: compactTarget(target), watch }, null, 2));
264
+ else
265
+ console.log(limitStdout(formatWatch(watch, target)));
266
+ await writeLastSnapshot(watch.after ?? watch.before);
267
+ const artifact = await writeArtifact("watch", watch);
268
+ if (options.artifact && !options.json)
269
+ console.log(`Artifact: ${artifact}`);
270
+ }
271
+ finally {
272
+ client.close();
273
+ }
274
+ }
275
+ async function runScenario(options) {
276
+ const scenario = options.positionals[0];
277
+ if (!scenario || scenario === "--help" || scenario === "-h") {
278
+ printScenarioHelp();
279
+ return;
280
+ }
281
+ if (options.positionals.length > 1) {
282
+ throw new Error(`Unexpected pibo debug web scenario argument "${options.positionals[1]}". Run pibo debug web scenario --help.`);
283
+ }
284
+ if (options.act && options.manual)
285
+ throw new Error("Use either --manual or --act, not both.");
286
+ if (scenario !== "new-session" && scenario !== "streaming-benchmark")
287
+ throw new Error(`Unknown pibo debug web scenario "${scenario}". Run pibo debug web scenario --help.`);
288
+ if (scenario === "streaming-benchmark" && (options.act || options.manual))
289
+ throw new Error("streaming-benchmark does not support --act or --manual. Start or observe the stream separately, then run the scenario.");
290
+ const negativeProfile = scenario === "streaming-benchmark" ? parseNegativeProfile(options.negativeProfile) : undefined;
291
+ const streamingOptions = negativeProfile ? applyNegativeStreamingProfile(options, negativeProfile) : options;
292
+ if (scenario === "streaming-benchmark" && streamingOptions.fixture && streamingOptions.backendFixture)
293
+ throw new Error("Use either --fixture or --backend-fixture, not both.");
294
+ if (scenario === "streaming-benchmark" && streamingOptions.fixtureProfile && !streamingOptions.fixture && !streamingOptions.backendFixture)
295
+ throw new Error("--fixture-profile requires --fixture or --backend-fixture.");
296
+ if (scenario === "streaming-benchmark" && streamingOptions.fixtureMix && !streamingOptions.fixture && !streamingOptions.backendFixture)
297
+ throw new Error("--fixture-mix requires --fixture or --backend-fixture.");
298
+ if (scenario === "streaming-benchmark" && streamingOptions.fixturePreludeMessages && !streamingOptions.backendFixture)
299
+ throw new Error("--fixture-prelude-messages requires --backend-fixture.");
300
+ if (scenario === "streaming-benchmark" && streamingOptions.simulateReconnect && !streamingOptions.backendFixture)
301
+ throw new Error("--simulate-reconnect requires --backend-fixture.");
302
+ if (scenario === "streaming-benchmark" && streamingOptions.simulateTraceCatchup && !streamingOptions.backendFixture)
303
+ throw new Error("--simulate-trace-catchup requires --backend-fixture.");
304
+ if (scenario === "streaming-benchmark" && streamingOptions.simulateOverlayDrop && !streamingOptions.backendFixture)
305
+ throw new Error("overlay-drop simulation requires --backend-fixture.");
306
+ if (scenario === "streaming-benchmark" && streamingOptions.simulateReconnect && streamingOptions.simulateTraceCatchup)
307
+ throw new Error("Use either --simulate-reconnect or --simulate-trace-catchup, not both.");
308
+ if (scenario === "streaming-benchmark" && [streamingOptions.simulateReconnect, streamingOptions.simulateTraceCatchup, streamingOptions.simulateOverlayDrop].filter(Boolean).length > 1)
309
+ throw new Error("Use only one streaming simulation mode.");
310
+ const providerTelemetryModes = [streamingOptions.providerRequestId ? "--provider-request-id" : undefined, streamingOptions.providerSessionId ? "--provider-session-id" : undefined, streamingOptions.providerTurnId ? "--provider-turn-id" : undefined, streamingOptions.providerSelectedSession ? "--provider-selected-session" : undefined].filter(Boolean);
311
+ if (scenario === "streaming-benchmark" && providerTelemetryModes.length > 1)
312
+ throw new Error(`Use only one provider telemetry source flag: ${providerTelemetryModes.join(", ")}.`);
313
+ const hostedCompareModes = [streamingOptions.compareUrl ? "--compare-url" : undefined, streamingOptions.compareHosted ? "--compare-hosted" : undefined, streamingOptions.compareHostedIfConfigured ? "--compare-hosted-if-configured" : undefined].filter(Boolean);
314
+ if (scenario === "streaming-benchmark" && hostedCompareModes.length > 1)
315
+ throw new Error(`Use only one compare target flag: ${hostedCompareModes.join(", ")}.`);
316
+ if (scenario === "streaming-benchmark" && streamingOptions.compareUrl && !streamingOptions.backendFixture)
317
+ throw new Error("--compare-url requires --backend-fixture so the benchmark can replay a deterministic stream at both URLs.");
318
+ if (scenario === "streaming-benchmark" && streamingOptions.compareHosted && !streamingOptions.backendFixture)
319
+ throw new Error("--compare-hosted requires --backend-fixture so the benchmark can replay a deterministic stream at both URLs.");
320
+ if (scenario === "streaming-benchmark" && streamingOptions.compareHostedIfConfigured && !streamingOptions.backendFixture)
321
+ throw new Error("--compare-hosted-if-configured requires --backend-fixture so the benchmark can replay a deterministic stream at both URLs.");
322
+ const hostedCompareUrl = scenario === "streaming-benchmark" && (streamingOptions.compareHosted || streamingOptions.compareHostedIfConfigured) ? await resolveStreamingBenchmarkHostedCompareUrl({ optional: streamingOptions.compareHostedIfConfigured }) : undefined;
323
+ const hostedCompareWarning = scenario === "streaming-benchmark" && streamingOptions.compareHostedIfConfigured && !hostedCompareUrl ? "--compare-hosted-if-configured skipped: PIBO_DEV_PUBLIC_URL or PIBO_DEV_BASE_URL is not configured" : undefined;
324
+ const fixtureProfile = parseFixtureProfile(streamingOptions.fixtureProfile);
325
+ const fixtureMix = parseFixtureMix(streamingOptions.fixtureMix);
326
+ const fixturePreludeMessages = parseFixturePreludeMessages(streamingOptions.fixturePreludeMessages);
327
+ const durationMs = parseDuration(streamingOptions.duration);
328
+ const runs = parseRuns(streamingOptions.runs);
329
+ const { client, target } = await connectTarget({ ...options, preset: "app" });
330
+ try {
331
+ if (scenario === "streaming-benchmark") {
332
+ const baseline = streamingOptions.from ? await readStreamingBenchmarkRuns(streamingOptions.from) : undefined;
333
+ const providerTelemetryRequested = providerTelemetryModes.length > 0;
334
+ const runOptions = { startFixture: streamingOptions.fixture, startBackendFixture: streamingOptions.backendFixture, fixtureProfile, fixtureMix, fixturePreludeMessages, simulateReconnect: streamingOptions.simulateReconnect, simulateTraceCatchup: streamingOptions.simulateTraceCatchup, simulateOverlayDrop: streamingOptions.simulateOverlayDrop, negativeProfile };
335
+ const primaryUrl = await currentBrowserUrl(client);
336
+ const rawBenchmarks = await runStreamingBenchmarkSeries(client, runs, durationMs, runOptions);
337
+ const primaryProviderTelemetry = providerTelemetryRequested ? await collectStreamingProviderTelemetryForOptions(streamingOptions, client) : undefined;
338
+ const benchmarks = attachStreamingProviderTelemetryToBenchmarks(rawBenchmarks, primaryProviderTelemetry);
339
+ let benchmark = runs === 1
340
+ ? benchmarks[0]
341
+ : summarizeStreamingBenchmarkGroup(benchmarks, baseline);
342
+ const rawCompareUrl = streamingOptions.compareUrl ?? hostedCompareUrl;
343
+ if (!rawCompareUrl && hostedCompareWarning)
344
+ benchmark.warnings.push(hostedCompareWarning);
345
+ if (rawCompareUrl) {
346
+ const compareUrl = resolveStreamingBenchmarkCompareUrl(rawCompareUrl, primaryUrl);
347
+ await navigateStreamingBenchmarkTarget(client, compareUrl);
348
+ const rawCompareRuns = await runStreamingBenchmarkSeries(client, runs, durationMs, runOptions);
349
+ const compareProviderTelemetry = providerTelemetryRequested ? await collectStreamingProviderTelemetryForOptions(streamingOptions, client) : undefined;
350
+ const compareRuns = attachStreamingProviderTelemetryToBenchmarks(rawCompareRuns, compareProviderTelemetry);
351
+ const primaryGroup = summarizeStreamingBenchmarkGroup(benchmarks, baseline);
352
+ const compareGroup = summarizeStreamingBenchmarkGroup(compareRuns, benchmarks);
353
+ benchmark = summarizeStreamingBenchmarkUrlComparison(primaryUrl, compareUrl, primaryGroup, compareGroup);
354
+ }
355
+ const assertion = applyExpectedStreamingRegressions(benchmark, streamingOptions.expectedRegressionPatterns);
356
+ if (streamingOptions.json)
357
+ console.log(JSON.stringify({ target: compactTarget(target), scenario, benchmark }, null, 2));
358
+ else
359
+ console.log(limitStdout(formatStreamingBenchmarkResult(benchmark, target)));
360
+ const artifact = await writeArtifact(`scenario-${scenario}`, benchmark);
361
+ if (!streamingOptions.json)
362
+ console.log(`Artifact: ${artifact}`);
363
+ if (streamingOptions.assertHealthy && !assertion.passed)
364
+ throw new Error(formatStreamingBenchmarkAssertionError(assertion));
365
+ return;
366
+ }
367
+ const watch = await runBrowserWatch(client, presetScope("app"), durationMs, {
368
+ ...options,
369
+ act: options.act,
370
+ manual: !options.act,
371
+ }, options.act ? "new-session" : undefined);
372
+ if (options.json)
373
+ console.log(JSON.stringify({ target: compactTarget(target), scenario, watch }, null, 2));
374
+ else
375
+ console.log(limitStdout(formatWatch(watch, target, `scenario ${scenario}`)));
376
+ const artifact = await writeArtifact(`scenario-${scenario}`, watch);
377
+ if (!options.json)
378
+ console.log(`Artifact: ${artifact}`);
379
+ }
380
+ finally {
381
+ client.close();
382
+ }
383
+ }
384
+ async function runReport(options) {
385
+ const report = options.positionals[0];
386
+ if (!report || report === "--help" || report === "-h") {
387
+ printReportHelp();
388
+ return;
389
+ }
390
+ if (options.positionals.length > 1) {
391
+ throw new Error(`Unexpected pibo debug web report argument "${options.positionals[1]}". Run pibo debug web report --help.`);
392
+ }
393
+ if (report !== "streaming-benchmark") {
394
+ throw new Error(`Unknown pibo debug web report "${report}". Run pibo debug web report --help.`);
395
+ }
396
+ if (!options.from)
397
+ throw new Error("pibo debug web report streaming-benchmark requires --from artifact.json");
398
+ const benchmark = await readStreamingBenchmarkArtifact(options.from);
399
+ const target = streamingBenchmarkReportTarget(benchmark);
400
+ const markdown = options.compact ? formatStreamingBenchmarkCompactReport(benchmark, target) : formatStreamingBenchmarkResult(benchmark, target);
401
+ const format = options.compact ? "compact" : "detailed";
402
+ const output = options.output ? await writeReportOutput(options.output, markdown) : undefined;
403
+ const artifact = options.artifact ? await writeTextArtifact(options.compact ? "report-streaming-benchmark-compact" : "report-streaming-benchmark", "md", markdown) : undefined;
404
+ const jsonOutput = options.jsonOutput ? path.resolve(options.jsonOutput) : undefined;
405
+ const rows = streamingBenchmarkReportRows(benchmark, options.compact);
406
+ const jsonPayload = { report, source: options.from, format, target, output, artifact, jsonOutput, markdown, rows, benchmark };
407
+ if (options.jsonOutput)
408
+ await writeReportOutput(options.jsonOutput, JSON.stringify(jsonPayload, null, 2));
409
+ if (options.json)
410
+ console.log(JSON.stringify(jsonPayload, null, 2));
411
+ else {
412
+ if (output)
413
+ console.log(`Wrote report: ${output}`);
414
+ else
415
+ console.log(markdown);
416
+ if (artifact)
417
+ console.log(`Artifact: ${artifact}`);
418
+ if (jsonOutput)
419
+ console.log(`Wrote report JSON: ${jsonOutput}`);
420
+ }
421
+ }
422
+ async function connectTarget(options) {
423
+ const envWs = process.env.PIBO_CDP_TARGET_WS;
424
+ if (isWebSocketUrl(options.target)) {
425
+ const client = new CdpClient(options.target);
426
+ await client.connect();
427
+ return { client, target: { id: "direct", url: "", title: "direct", webSocketDebuggerUrl: options.target } };
428
+ }
429
+ if (!options.target && envWs) {
430
+ const client = new CdpClient(envWs);
431
+ await client.connect();
432
+ return { client, target: { id: process.env.PIBO_CDP_TARGET_ID ?? "env", url: process.env.PIBO_CHAT_URL ?? "", title: "env", webSocketDebuggerUrl: envWs } };
433
+ }
434
+ const cdpUrl = options.cdpUrl ?? process.env.PIBO_CDP_URL;
435
+ const targets = await listBrowserUseCdpTargets({ cdpUrl, probe: !options.target });
436
+ const target = resolveTargetFromList(targets, options.target) ?? selectBestChatTarget(targets) ?? targets.find((item) => item.webSocketDebuggerUrl);
437
+ if (!target?.webSocketDebuggerUrl) {
438
+ throw new Error("No attachable CDP target found. Next: pibo debug web targets or pass --cdp-url/--target.");
439
+ }
440
+ const client = new CdpClient(target.webSocketDebuggerUrl);
441
+ await client.connect();
442
+ return { client, target };
443
+ }
444
+ function resolveTargetFromList(targets, target) {
445
+ if (!target)
446
+ return undefined;
447
+ return targets.find((item) => item.id === target || item.url === target || item.title === target || item.webSocketDebuggerUrl === target);
448
+ }
449
+ async function captureSnapshot(client, scope, options) {
450
+ const expression = buildSnapshotExpression({
451
+ scope,
452
+ maxNodes: DEFAULT_NODE_LIMIT,
453
+ maxDepth: DEFAULT_DEPTH_LIMIT,
454
+ textLimit: DEFAULT_TEXT_LIMIT,
455
+ includeText: options.includeText,
456
+ includeLayout: options.includeLayout,
457
+ });
458
+ return client.evaluate(expression, 10_000);
459
+ }
460
+ async function runBrowserWatch(client, scope, durationMs, options, action) {
461
+ const expression = buildWatchExpression({
462
+ scope,
463
+ durationMs,
464
+ maxNodes: DEFAULT_NODE_LIMIT,
465
+ maxDepth: DEFAULT_DEPTH_LIMIT,
466
+ maxEvents: DEFAULT_EVENT_LIMIT,
467
+ textLimit: DEFAULT_TEXT_LIMIT,
468
+ includeText: options.includeText,
469
+ includeLayout: options.includeLayout,
470
+ action,
471
+ });
472
+ return client.evaluate(expression, durationMs + 10_000);
473
+ }
474
+ async function runStreamingBenchmarkSeries(client, runs, durationMs, options) {
475
+ if (options.startFixture)
476
+ await navigateStreamingBenchmarkFixture(client, options.fixtureProfile ?? "steady", options.fixtureMix ?? "text");
477
+ if (options.startBackendFixture)
478
+ await prepareStreamingBenchmarkEventSourceProbe(client);
479
+ const benchmarks = [];
480
+ for (let run = 0; run < runs; run++)
481
+ benchmarks.push(await runStreamingBenchmark(client, durationMs, options));
482
+ return benchmarks;
483
+ }
484
+ async function runStreamingBenchmark(client, durationMs, options = {}) {
485
+ await client.send("Page.bringToFront").catch(() => undefined);
486
+ const benchmarkTimeoutMs = durationMs + (options.startBackendFixture ? 20_000 : 10_000);
487
+ const benchmark = await client.evaluate(buildStreamingBenchmarkExpression(durationMs, options), benchmarkTimeoutMs);
488
+ const withProvider = { ...benchmark, provider: options.providerTelemetry };
489
+ const scored = { ...withProvider, score: scoreStreamingBenchmark(withProvider), providerPreservation: summarizeStreamingProviderPreservation(withProvider) };
490
+ const withLivePipeline = { ...scored, livePipeline: summarizeStreamingLivePipeline(scored) };
491
+ const withCadence = { ...withLivePipeline, cadence: summarizeStreamingCadence(withLivePipeline), negativeProfile: options.negativeProfile };
492
+ return { ...withCadence, regressions: [...withCadence.regressions, ...evaluateStreamingLivePipelineRegressions(withCadence), ...evaluateStreamingProviderRegressions(withCadence)] };
493
+ }
494
+ async function currentBrowserUrl(client) {
495
+ const state = await client.evaluate(`(() => ({ href: location.href }))()`, 5_000);
496
+ return state.href;
497
+ }
498
+ async function collectStreamingProviderTelemetryForOptions(options, client) {
499
+ if (options.providerRequestId)
500
+ return collectStreamingProviderTelemetry(options.providerRequestId);
501
+ if (options.providerSessionId)
502
+ return collectStreamingProviderTelemetryFromSession(options.providerSessionId);
503
+ if (options.providerTurnId)
504
+ return collectStreamingProviderTelemetryFromTurn(options.providerTurnId);
505
+ if (options.providerSelectedSession)
506
+ return collectStreamingProviderTelemetryFromSelectedBrowserSession(client);
507
+ return undefined;
508
+ }
509
+ async function prepareStreamingBenchmarkEventSourceProbe(client, targetUrl) {
510
+ await client.send("Page.enable").catch(() => undefined);
511
+ await client.send("Page.addScriptToEvaluateOnNewDocument", { source: streamingBenchmarkEventSourceProbeScript() }, 5_000);
512
+ if (targetUrl)
513
+ await navigateStreamingBenchmarkTarget(client, targetUrl);
514
+ const state = await client.evaluate(`(() => {
515
+ try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
516
+ return { href: location.href };
517
+ })()`, 5_000);
518
+ const url = new URL(state.href);
519
+ if (url.protocol !== "http:" && url.protocol !== "https:")
520
+ throw new Error("stream simulation requires an HTTP Chat Web target");
521
+ url.searchParams.set("debugStreaming", "1");
522
+ await navigateStreamingBenchmarkTarget(client, url.toString());
523
+ await client.send("Page.bringToFront").catch(() => undefined);
524
+ await client.evaluate("new Promise((resolve) => { if (document.readyState === 'complete') resolve(true); else addEventListener('load', () => resolve(true), { once: true }); })", 5_000);
525
+ await client.evaluate("new Promise((resolve) => setTimeout(resolve, 800))", 2_000);
526
+ }
527
+ async function navigateStreamingBenchmarkTarget(client, url) {
528
+ try {
529
+ await client.send("Page.navigate", { url }, 5_000);
530
+ return;
531
+ }
532
+ catch (error) {
533
+ const message = error instanceof Error ? error.message : String(error);
534
+ if (!message.includes("Timed out waiting for CDP method Page.navigate"))
535
+ throw error;
536
+ }
537
+ await client.evaluate(`(() => { if (location.href !== ${JSON.stringify(url)}) location.assign(${JSON.stringify(url)}); return true; })()`, 5_000).catch(() => undefined);
538
+ }
539
+ async function navigateStreamingBenchmarkFixture(client, fixtureProfile, fixtureMix) {
540
+ const url = `data:text/html;charset=utf-8,${encodeURIComponent(streamingBenchmarkFixtureHtml(fixtureProfile, fixtureMix))}`;
541
+ await client.send("Page.enable").catch(() => undefined);
542
+ await client.send("Page.navigate", { url }, 5_000);
543
+ await client.send("Page.bringToFront").catch(() => undefined);
544
+ await client.evaluate("new Promise((resolve) => { if (document.readyState === 'complete') resolve(true); else addEventListener('load', () => resolve(true), { once: true }); })", 5_000);
545
+ }
546
+ async function enableStreamingDebugForCurrentApp(client) {
547
+ const state = await client.evaluate(`(() => {
548
+ try { localStorage.setItem('pibo.chat.debugStreaming', '1'); } catch {}
549
+ return { href: location.href, hasReset: typeof window.__piboStreamingDebugReset === 'function' };
550
+ })()`, 5_000);
551
+ if (state.hasReset)
552
+ return;
553
+ const url = new URL(state.href);
554
+ if (url.protocol !== "http:" && url.protocol !== "https:")
555
+ return;
556
+ url.searchParams.set("debugStreaming", "1");
557
+ await client.send("Page.enable").catch(() => undefined);
558
+ await client.send("Page.navigate", { url: url.toString() }, 5_000);
559
+ await client.send("Page.bringToFront").catch(() => undefined);
560
+ await client.evaluate("new Promise((resolve) => { if (document.readyState === 'complete') resolve(true); else addEventListener('load', () => resolve(true), { once: true }); })", 5_000);
561
+ await client.evaluate("new Promise((resolve) => setTimeout(resolve, 500))", 2_000);
562
+ }
563
+ function isWebSocketUrl(value) {
564
+ return Boolean(value && /^wss?:\/\//.test(value));
565
+ }
566
+ function jsonShort(value) {
567
+ if (value === undefined)
568
+ return "undefined";
569
+ const text = typeof value === "string" ? value : JSON.stringify(value);
570
+ return text.length > 90 ? `${text.slice(0, 89)}…` : text;
571
+ }
572
+ function shellQuote(value) {
573
+ return `'${value.replace(/'/g, `'\\''`)}'`;
574
+ }
@@ -0,0 +1,83 @@
1
+ import { execSync } from "node:child_process";
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join, relative } from "node:path";
5
+ const BACKUP_DIR = join(homedir(), ".pibo", "stable");
6
+ const BACKUP_META_PATH = join(BACKUP_DIR, ".backup-meta.json");
7
+ function getGitCommit(sourcePath) {
8
+ try {
9
+ return execSync("git rev-parse HEAD", { cwd: sourcePath, encoding: "utf-8" }).trim();
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ function isExcludedPath(source, srcRoot) {
16
+ const rel = relative(srcRoot, source);
17
+ return rel === "node_modules" || rel.startsWith("node_modules/") || rel === ".git" || rel.startsWith(".git/");
18
+ }
19
+ export function installBackup(sourcePath) {
20
+ const src = sourcePath ?? process.cwd();
21
+ if (!existsSync(join(src, "package.json"))) {
22
+ throw new Error(`No package.json found at ${src}`);
23
+ }
24
+ if (existsSync(BACKUP_DIR)) {
25
+ rmSync(BACKUP_DIR, { recursive: true, force: true });
26
+ }
27
+ mkdirSync(BACKUP_DIR, { recursive: true });
28
+ cpSync(src, BACKUP_DIR, {
29
+ recursive: true,
30
+ filter: (source) => !isExcludedPath(source, src),
31
+ });
32
+ // Symlink .pibo in the backup dir so the fallback process finds config,
33
+ // sessions, auth DB and user skills in the same location as the main gateway.
34
+ const backupDotPibo = join(BACKUP_DIR, ".pibo");
35
+ const realDotPibo = join(homedir(), ".pibo");
36
+ try {
37
+ if (existsSync(backupDotPibo)) {
38
+ const stat = lstatSync(backupDotPibo);
39
+ if (!stat.isSymbolicLink()) {
40
+ rmSync(backupDotPibo, { recursive: true, force: true });
41
+ symlinkSync(realDotPibo, backupDotPibo, "dir");
42
+ }
43
+ }
44
+ else {
45
+ symlinkSync(realDotPibo, backupDotPibo, "dir");
46
+ }
47
+ }
48
+ catch {
49
+ // ignore if symlink already exists or fails
50
+ }
51
+ execSync("npm install --include=dev", { cwd: BACKUP_DIR, stdio: "inherit" });
52
+ execSync("npm run build", { cwd: BACKUP_DIR, stdio: "inherit" });
53
+ const meta = {
54
+ commit: getGitCommit(src),
55
+ installedAt: new Date().toISOString(),
56
+ sourcePath: src,
57
+ };
58
+ writeFileSync(BACKUP_META_PATH, JSON.stringify(meta, null, 2));
59
+ console.log(`Backup installed at ${BACKUP_DIR}`);
60
+ console.log(` Commit: ${meta.commit ?? "unknown"}`);
61
+ console.log(` Installed at: ${meta.installedAt}`);
62
+ }
63
+ export function updateBackup() {
64
+ const currentStatus = getBackupStatus();
65
+ const sourcePath = currentStatus?.sourcePath ?? process.cwd();
66
+ installBackup(sourcePath);
67
+ }
68
+ export function getBackupStatus() {
69
+ if (!existsSync(BACKUP_META_PATH))
70
+ return null;
71
+ try {
72
+ return JSON.parse(readFileSync(BACKUP_META_PATH, "utf-8"));
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ export function removeBackup() {
79
+ if (existsSync(BACKUP_DIR)) {
80
+ rmSync(BACKUP_DIR, { recursive: true, force: true });
81
+ }
82
+ console.log("Backup removed.");
83
+ }