@pasko70/pibo 1.0.5 → 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 (429) hide show
  1. package/README.md +106 -250
  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 +42 -5
  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 +47 -0
  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 +3168 -1811
  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-CI0Xj2Cp.js → dist-B4lw9z4F.js} +1 -1
  54. package/dist/apps/chat-ui/assets/{dist-aMr2VYOu.js → dist-BbTaHWON.js} +1 -1
  55. package/dist/apps/chat-ui/assets/{dist-u2OzzOTm.js → dist-BcT_c1EJ.js} +1 -1
  56. package/dist/apps/chat-ui/assets/{dist-Di1ScJ22.js → dist-CGINd7XU.js} +1 -1
  57. package/dist/apps/chat-ui/assets/{dist-wiRpAHIv.js → dist-CrBzZkUp.js} +1 -1
  58. package/dist/apps/chat-ui/assets/{dist-CaNOvqMY.js → dist-CyyISotB.js} +1 -1
  59. package/dist/apps/chat-ui/assets/{dist-zgYUl2B-.js → dist-DFbnFNpX.js} +1 -1
  60. package/dist/apps/chat-ui/assets/{dist-CNlhGq5i.js → dist-DGLWQLX8.js} +1 -1
  61. package/dist/apps/chat-ui/assets/{dist-BGxHKHPX.js → dist-DfcIkFSN.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dist-DrM-H3e1.js → dist-sKDHTwaT.js} +1 -1
  63. package/dist/apps/chat-ui/assets/{dist-DpmEro5R.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 +174 -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 +252 -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 +66 -2
  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 +214 -0
  373. package/dist/user-skills/manager.js +35 -0
  374. package/dist/user-skills/store.js +267 -0
  375. package/dist/user-skills/types.js +1 -0
  376. package/dist/web/auth.js +5 -1
  377. package/dist/web/channel.js +86 -0
  378. package/dist/web/http.js +79 -14
  379. package/dist/web-annotations/api.js +348 -0
  380. package/dist/web-annotations/attachments.js +201 -0
  381. package/dist/web-annotations/cdp.js +1107 -0
  382. package/dist/web-annotations/index.js +7 -0
  383. package/dist/web-annotations/store.js +407 -0
  384. package/dist/web-annotations/tools.js +350 -0
  385. package/dist/web-annotations/types.js +34 -0
  386. package/dist/web-annotations/validation.js +288 -0
  387. package/docs/README.md +23 -0
  388. package/docs/ops/install-developer-host.md +112 -0
  389. package/docs/ops/install-user-host.md +76 -0
  390. package/docs/ops/upgrade-user-to-developer-host.md +69 -0
  391. package/package.json +24 -10
  392. package/{.codex/skills → skills/builtin}/pi-agent-harness/SKILL.md +24 -24
  393. package/skills/builtin/pibo-docker-system/SKILL.md +170 -0
  394. package/skills/builtin/pibo-spec-writing/SKILL.md +330 -0
  395. package/skills/builtin/prd/SKILL.md +143 -0
  396. package/skills/builtin/ralph-loop/SKILL.md +359 -0
  397. package/skills/builtin/ralph-prd-json/SKILL.md +123 -0
  398. package/skills/builtin/skill-creator/LICENSE.txt +202 -0
  399. package/skills/builtin/skill-creator/SKILL.md +513 -0
  400. package/skills/builtin/skill-creator/agents/analyzer.md +274 -0
  401. package/skills/builtin/skill-creator/agents/comparator.md +202 -0
  402. package/skills/builtin/skill-creator/agents/grader.md +223 -0
  403. package/skills/builtin/skill-creator/assets/eval_review.html +146 -0
  404. package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -0
  405. package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -0
  406. package/skills/builtin/skill-creator/references/schemas.md +430 -0
  407. package/skills/builtin/skill-creator/scripts/__init__.py +0 -0
  408. package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -0
  409. package/skills/builtin/skill-creator/scripts/generate_report.py +326 -0
  410. package/skills/builtin/skill-creator/scripts/improve_description.py +247 -0
  411. package/skills/builtin/skill-creator/scripts/package_skill.py +136 -0
  412. package/skills/builtin/skill-creator/scripts/quick_validate.py +103 -0
  413. package/skills/builtin/skill-creator/scripts/run_eval.py +310 -0
  414. package/skills/builtin/skill-creator/scripts/run_loop.py +328 -0
  415. package/skills/builtin/skill-creator/scripts/utils.py +47 -0
  416. package/skills/builtin/web-annotations/SKILL.md +93 -0
  417. package/dist/apps/chat-ui/assets/index-B_E935fP.js +0 -151
  418. package/dist/apps/chat-ui/assets/index-Dk-opWl3.css +0 -1
  419. package/dist/env.js +0 -32
  420. package/dist/plugins/core-tools.js +0 -94
  421. package/dist/plugins/example.js +0 -67
  422. package/dist/plugins/remote-agent.js +0 -9
  423. package/dist/remote/channel.js +0 -176
  424. package/dist/remote/client.js +0 -92
  425. package/dist/remote/examples/tui-controller.js +0 -263
  426. package/dist/remote/protocol.js +0 -55
  427. package/dist/remote/session-client.js +0 -189
  428. package/dist/sessions/bindings.js +0 -41
  429. /package/{.codex/skills → skills/builtin}/pi-agent-harness/agents/openai.yaml +0 -0
@@ -0,0 +1,8 @@
1
+ import { PiboRalphService } from './service.js';
2
+ import { createDefaultPiboRalphStore } from './store.js';
3
+ let currentRalphService;
4
+ export function getPiboRalphService() { return currentRalphService; }
5
+ export function createPiboRalphChannel(options = {}) {
6
+ return { name: 'pibo.ralph', kind: 'custom', description: 'Runs continuous Ralph Pibo agent jobs.', auth: { mode: 'trusted-local' }, start(context) { if (currentRalphService)
7
+ return; currentRalphService = new PiboRalphService({ ...options, context, store: createDefaultPiboRalphStore({ path: options.ralphStorePath }) }); currentRalphService.start(); }, stop() { currentRalphService?.stop(); currentRalphService = undefined; } };
8
+ }
@@ -0,0 +1,152 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { Command } from 'commander';
3
+ import { createDefaultPiboRalphStore } from './store.js';
4
+ import { createBuiltInRalphStopConditions } from './stopping.js';
5
+ import { getRalphJobTemplate, listRalphJobTemplates } from './templates.js';
6
+ function printDiscovery() {
7
+ console.log(`pibo ralph
8
+
9
+ Manage continuous Ralph Pibo agent jobs.
10
+
11
+ Commands:
12
+ status Show Ralph status
13
+ list List Ralph jobs
14
+ add Create a Ralph job
15
+ edit Update a Ralph job
16
+ conditions List registered built-in stop conditions
17
+ templates List built-in Ralph job templates
18
+ policy Show, set, or clear a job stop policy
19
+ start Start a Ralph job now
20
+ stop Stop after the current session finishes
21
+ cancel Abort the current session and stop
22
+ remove Delete a Ralph job
23
+ runs List Ralph runs
24
+
25
+ Next: pibo ralph add --help`);
26
+ }
27
+ function targetFromOptions(options) { if (options.room)
28
+ return { kind: 'room', roomId: options.room }; if (options.defaultChat)
29
+ return { kind: 'default-chat' }; throw new Error('Choose a target: --room <room-id> or --default-chat'); }
30
+ function maybeTargetFromOptions(options) { if (options.room || options.defaultChat)
31
+ return targetFromOptions(options); return undefined; }
32
+ function printJson(value) { console.log(JSON.stringify(value, null, 2)); }
33
+ function maxIterations(value) { if (value === undefined)
34
+ return undefined; const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1)
35
+ throw new Error('--max-iterations must be a positive integer'); return parsed; }
36
+ function templatePatch(id) {
37
+ if (!id)
38
+ return {};
39
+ const template = getRalphJobTemplate(id);
40
+ if (!template)
41
+ throw new Error(`Unknown Ralph template: ${id}`);
42
+ return { name: template.job.name, description: template.job.description, prompt: template.job.prompt, maxIterations: template.job.maxIterations ?? null, stopPolicy: template.job.stopPolicy ?? null };
43
+ }
44
+ function compactResourceText(value, max = 80) { return value.length <= max ? value : `${value.slice(0, max - 1)}…`; }
45
+ function shellToken(value) { return /^[A-Za-z0-9._:@/-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`; }
46
+ export function formatRalphResourceSummary(resources) {
47
+ if (!resources)
48
+ return '-';
49
+ const parts = [
50
+ resources.workerId ? `worker=${resources.workerId}` : undefined,
51
+ resources.cleanupState ? `state=${resources.cleanupState}` : undefined,
52
+ resources.browserLeaseIds?.length ? `leases=${resources.browserLeaseIds.length}` : undefined,
53
+ resources.retainedUntil ? `retainedUntil=${resources.retainedUntil}` : undefined,
54
+ resources.dirtyReason ? `dirty=${compactResourceText(resources.dirtyReason)}` : undefined,
55
+ ].filter((part) => !!part);
56
+ if (resources.cleanupState === 'dirty')
57
+ parts.push(`next=${resources.workerId ? `pibo tools browser-use pool reap --worker-id ${shellToken(resources.workerId)} --json` : 'pibo compute reap --dry-run'}`);
58
+ else if (resources.cleanupState === 'retained')
59
+ parts.push('next=pibo compute reap --dry-run --include-dev');
60
+ return parts.length ? parts.join(';') : '-';
61
+ }
62
+ function formatRalphJobLine(job) { return `${job.id}\t${job.enabled ? 'running' : 'stopped'}\t${job.state.runningAt ? 'active' : '-'}\tresources=${formatRalphResourceSummary(job.resources)}\t${job.name}`; }
63
+ function formatRalphRunLine(run) { return `${run.id}\t${run.jobId}\t${run.status}\t${run.piboSessionId ?? '-'}\t${run.completedAt ?? '-'}\tresources=${formatRalphResourceSummary(run.resources)}`; }
64
+ export async function runRalphCli(argv = process.argv) {
65
+ const program = new Command();
66
+ program.name('pibo ralph').description('Manage continuous Ralph Pibo jobs').helpOption('-h, --help');
67
+ program.option('--store <path>', 'Ralph store path');
68
+ program.command('status').description('Show Ralph store status').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const status = store.status(); if (options.json)
69
+ printJson(status);
70
+ else {
71
+ console.log(`jobs\t${status.jobs}`);
72
+ console.log(`running\t${status.running}`);
73
+ } store.close(); });
74
+ program.command('list').description('List Ralph jobs').option('--all', 'Include stopped jobs').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const jobs = store.listJobs({ includeDisabled: options.all }); if (options.json)
75
+ printJson(jobs);
76
+ else
77
+ for (const job of jobs)
78
+ console.log(formatRalphJobLine(job)); store.close(); });
79
+ program.command('add').description('Create a Ralph job').option('--template <id>', 'Built-in job template id').option('--prompt <text>', 'Task prompt').option('--name <name>', 'Job name').option('--description <text>', 'Job description').option('--profile <profile>', 'Agent profile', 'default').option('--room <room-id>', 'Target room id').option('--default-chat', 'Target the shared default chat').option('--max-iterations <n>', 'Stop after n completed run attempts')
80
+ .option('--start', 'Start immediately').option('--json', 'Print JSON').action((options) => { const base = templatePatch(options.template); const prompt = options.prompt ?? base.prompt; if (typeof prompt !== 'string' || !prompt.trim())
81
+ throw new Error('Choose --template <id> or provide --prompt <text>'); const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.createJob({ name: options.name ?? base.name, description: options.description ?? base.description, enabled: options.start === true, target: targetFromOptions(options), profile: options.profile, prompt, maxIterations: options.maxIterations !== undefined ? maxIterations(options.maxIterations) : typeof base.maxIterations === 'number' ? base.maxIterations : undefined, stopPolicy: base.stopPolicy ?? undefined }); if (options.json)
82
+ printJson(job);
83
+ else
84
+ console.log(`${job.id}\t${job.enabled ? 'running' : 'stopped'}\t${job.name}`); store.close(); });
85
+ program.command('edit').argument('<id>', 'Ralph job id').description('Update a Ralph job').option('--template <id>', 'Apply a built-in job template before explicit overrides').option('--prompt <text>', 'Task prompt').option('--name <name>', 'Job name').option('--description <text>', 'Job description').option('--profile <profile>', 'Agent profile').option('--room <room-id>', 'Target room id').option('--default-chat', 'Target the shared default chat').option('--max-iterations <n>', 'Stop after n completed run attempts').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const patch = { ...templatePatch(options.template) }; if (options.name !== undefined)
86
+ patch.name = options.name; if (options.description !== undefined)
87
+ patch.description = options.description; if (options.profile !== undefined)
88
+ patch.profile = options.profile; if (options.prompt !== undefined)
89
+ patch.prompt = options.prompt; if (options.maxIterations !== undefined)
90
+ patch.maxIterations = maxIterations(options.maxIterations); const target = maybeTargetFromOptions(options); if (target)
91
+ patch.target = target; if (Object.keys(patch).length === 0)
92
+ throw new Error('No Ralph job update fields provided'); const job = store.updateJob(id, patch); if (!job)
93
+ throw new Error('Ralph job not found'); if (options.json)
94
+ printJson(job);
95
+ else
96
+ console.log(`${job.id}\tupdated\t${job.name}`); store.close(); });
97
+ program.command('conditions').description('List built-in Ralph stop-condition types').option('--json', 'Print JSON').action((options) => { const conditions = createBuiltInRalphStopConditions().map((condition) => ({ type: condition.type, name: condition.name, description: condition.description, phases: condition.phases, defaultOptions: condition.defaultOptions, optionsSchema: condition.optionsSchema })); if (options.json)
98
+ printJson(conditions);
99
+ else
100
+ for (const condition of conditions)
101
+ console.log(`${condition.type} ${condition.phases.join(',')} ${condition.name}`); });
102
+ program.command('templates').description('List built-in Ralph job templates').option('--json', 'Print JSON').action((options) => { const templates = listRalphJobTemplates(); if (options.json)
103
+ printJson(templates);
104
+ else
105
+ for (const template of templates)
106
+ console.log(`${template.id}\t${template.category}\t${template.name}\t${template.description}`); });
107
+ const policy = program.command('policy').description('Manage a Ralph job stop policy');
108
+ policy.command('show').argument('<id>').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.getJob(id); if (!job)
109
+ throw new Error('Ralph job not found'); const value = job.stopPolicy ?? null; if (options.json)
110
+ printJson(value);
111
+ else
112
+ console.log(value ? JSON.stringify(value, null, 2) : 'default'); store.close(); });
113
+ policy.command('set').argument('<id>').requiredOption('--file <path>', 'JSON stop policy file').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const stopPolicy = JSON.parse(readFileSync(options.file, 'utf8')); const job = store.updateJob(id, { stopPolicy }); if (!job)
114
+ throw new Error('Ralph job not found'); if (options.json)
115
+ printJson(job);
116
+ else
117
+ console.log(`${job.id} policy-updated ${job.name}`); store.close(); });
118
+ policy.command('clear').argument('<id>').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.updateJob(id, { stopPolicy: null }); if (!job)
119
+ throw new Error('Ralph job not found'); if (options.json)
120
+ printJson(job);
121
+ else
122
+ console.log(`${job.id} policy-cleared ${job.name}`); store.close(); });
123
+ program.command('start').argument('<id>').description('Mark a Ralph job running; the gateway service starts the next session').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.updateJob(id, { enabled: true }); if (!job)
124
+ throw new Error('Ralph job not found'); if (options.json)
125
+ printJson(job);
126
+ else
127
+ console.log(`${job.id}\trunning\t${job.name}`); store.close(); });
128
+ program.command('stop').argument('<id>').description('Stop after the current session finishes').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.requestStop(id); if (!job)
129
+ throw new Error('Ralph job not found'); if (options.json)
130
+ printJson(job);
131
+ else
132
+ console.log(`${job.id}\tstopping\t${job.name}`); store.close(); });
133
+ program.command('cancel').argument('<id>').description('Abort the current session and stop').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const job = store.requestCancel(id); if (!job)
134
+ throw new Error('Ralph job not found'); if (options.json)
135
+ printJson(job);
136
+ else
137
+ console.log(`${job.id}\tcancel-requested\t${job.name}`); store.close(); });
138
+ program.command('remove').argument('<id>').description('Delete a Ralph job').option('--json', 'Print JSON').action((id, options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const removed = store.removeJob(id); if (options.json)
139
+ printJson({ removed });
140
+ else
141
+ console.log(removed ? 'removed' : 'not found'); store.close(); });
142
+ program.command('runs').description('List Ralph runs').option('--job <id>', 'Filter by job').option('--json', 'Print JSON').action((options) => { const store = createDefaultPiboRalphStore({ path: program.opts().store }); const runs = store.listRuns({ jobId: options.job }); if (options.json)
143
+ printJson(runs);
144
+ else
145
+ for (const run of runs)
146
+ console.log(formatRalphRunLine(run)); store.close(); });
147
+ if (argv.length <= 2 || argv.includes('--help') || argv.includes('-h')) {
148
+ printDiscovery();
149
+ return;
150
+ }
151
+ await program.parseAsync(argv);
152
+ }
@@ -0,0 +1,14 @@
1
+ import { definePiboPlugin } from '../plugins/registry.js';
2
+ import { createPiboRalphChannel } from './channel.js';
3
+ import { createBuiltInRalphStopConditions } from './stopping.js';
4
+ export function createPiboRalphPlugin(options = {}) {
5
+ return definePiboPlugin({
6
+ id: 'pibo.ralph',
7
+ name: 'Pibo Ralph',
8
+ register(api) {
9
+ for (const condition of createBuiltInRalphStopConditions())
10
+ api.registerRalphStopCondition(condition);
11
+ api.registerChannel(createPiboRalphChannel(options));
12
+ },
13
+ });
14
+ }
@@ -0,0 +1,271 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { getDefaultPiboWorkspace } from '../core/workspace.js';
5
+ import { PiboDataStore } from '../data/pibo-store.js';
6
+ import { ChatRoomService } from '../apps/chat/data/room-service.js';
7
+ import { isPiboRoomArchived } from '../apps/chat/types/rooms.js';
8
+ import { browserPoolPaths, releaseBrowserPoolLease } from '../tools/browser-pool.js';
9
+ import { createDefaultPiboRalphStore } from './store.js';
10
+ import { createBuiltInRalphStopConditions, evaluateRalphStopPolicy } from './stopping.js';
11
+ const CHAT_WEB_CHANNEL = 'pibo.chat-web';
12
+ function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
13
+ function buildRalphPrompt(job) { return ['You are running a continuous Pibo Ralph job.', `Job: ${job.name}`, `Target: ${job.target.kind}`, '', 'Complete the task below. Return the result in this session. When this session finishes, Ralph may start a fresh session with the same task unless a configured stop condition is satisfied.', 'Important: if this job uses a promise-complete stop condition, do not quote, negate, explain, or mention its literal completion marker unless the task is fully complete and you intend to stop the job.', '', 'Task:', job.prompt].join('\n'); }
14
+ function isJsonObject(value) { return !!value && typeof value === 'object' && !Array.isArray(value); }
15
+ function mergeRunResources(jobResources, runResources) {
16
+ if (!jobResources && !runResources)
17
+ return undefined;
18
+ const browserLeaseIds = [...new Set([...(jobResources?.browserLeaseIds ?? []), ...(runResources?.browserLeaseIds ?? [])])];
19
+ return {
20
+ ...(jobResources ?? {}),
21
+ ...(runResources ?? {}),
22
+ ...(browserLeaseIds.length ? { browserLeaseIds } : {}),
23
+ };
24
+ }
25
+ function clearDirtyReason(resources) {
26
+ const clean = { ...resources };
27
+ delete clean.dirtyReason;
28
+ return clean;
29
+ }
30
+ export class PiboRalphService {
31
+ options;
32
+ store;
33
+ dataStore;
34
+ roomService;
35
+ intervalMs;
36
+ maxConcurrentRuns;
37
+ runTimeoutMs;
38
+ timer;
39
+ activeRuns = 0;
40
+ stopped = true;
41
+ cancelledRuns = new Set();
42
+ unsubscribeProductEvents;
43
+ constructor(options) {
44
+ this.options = options;
45
+ this.store = options.store ?? createDefaultPiboRalphStore();
46
+ this.dataStore = new PiboDataStore(options.dataStorePath, { payloadRootDir: options.dataPayloadRootDir });
47
+ this.roomService = new ChatRoomService(this.dataStore);
48
+ this.intervalMs = options.intervalMs ?? 5_000;
49
+ this.maxConcurrentRuns = Math.max(1, options.maxConcurrentRuns ?? 2);
50
+ this.runTimeoutMs = options.runTimeoutMs ?? 30 * 60_000;
51
+ }
52
+ start() { if (!this.stopped)
53
+ return; this.stopped = false; this.store.recoverInterruptedRuns(); this.unsubscribeProductEvents = this.options.context.subscribeProductEvents?.((event) => this.handleProductEvent(event)); this.arm(250); }
54
+ stop() { this.stopped = true; if (this.timer)
55
+ clearTimeout(this.timer); this.timer = undefined; this.unsubscribeProductEvents?.(); this.unsubscribeProductEvents = undefined; this.dataStore.close(); this.store.close(); }
56
+ status() { return { enabled: !this.stopped, ...this.store.status() }; }
57
+ async startJob(id) { const job = this.store.updateJob(id, { enabled: true }); if (!job)
58
+ return undefined; const reserved = await this.reserveAfterBeforeRunEvaluation(job); if (!reserved)
59
+ return undefined; void this.executeReserved(reserved.job, reserved.run).finally(() => this.armSoon()); return reserved.run; }
60
+ stopJob(id) { const job = this.store.requestStop(id); this.armSoon(); return job; }
61
+ async cancelJob(id) {
62
+ const job = this.store.requestCancel(id);
63
+ if (!job)
64
+ return undefined;
65
+ await this.abortJobIfRunning(job);
66
+ this.armSoon();
67
+ return this.store.getJob(id);
68
+ }
69
+ arm(delayMs) { if (this.stopped)
70
+ return; if (this.timer)
71
+ clearTimeout(this.timer); this.timer = setTimeout(() => void this.tick(), delayMs ?? this.intervalMs); }
72
+ armSoon() { this.arm(250); }
73
+ async tick() { if (this.stopped)
74
+ return; try {
75
+ await this.abortCancelRequestedJobs();
76
+ const capacity = this.maxConcurrentRuns - this.activeRuns;
77
+ if (capacity > 0) {
78
+ const jobs = this.store.listJobs({ includeDisabled: false }).filter((job) => !job.state.runningAt).slice(0, capacity);
79
+ for (const job of jobs) {
80
+ const reserved = await this.reserveAfterBeforeRunEvaluation(job);
81
+ if (reserved)
82
+ void this.executeReserved(reserved.job, reserved.run).finally(() => this.armSoon());
83
+ }
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.error('[ralph] scheduler tick failed', error);
88
+ }
89
+ finally {
90
+ this.arm();
91
+ } }
92
+ async reserveAfterBeforeRunEvaluation(job) {
93
+ const fresh = this.store.getJob(job.id) ?? job;
94
+ if (!fresh.enabled || fresh.state.runningAt)
95
+ return undefined;
96
+ const { evaluation, conditionStates } = await this.evaluateStopPolicy(fresh, 'before-run');
97
+ if (evaluation.finalAction !== 'continue') {
98
+ this.store.applyStopEvaluation({ jobId: fresh.id, evaluation, conditionStates, disable: true });
99
+ return undefined;
100
+ }
101
+ this.store.applyStopEvaluation({ jobId: fresh.id, evaluation, conditionStates, disable: false });
102
+ return this.store.reserveRun(fresh.id);
103
+ }
104
+ async abortCancelRequestedJobs() { for (const job of this.store.listJobs({ includeDisabled: true })) {
105
+ if (job.state.cancelRequestedAt)
106
+ await this.abortJobIfRunning(job);
107
+ } }
108
+ async abortJobIfRunning(job) {
109
+ if (!job.state.runningAt || !job.state.lastRunId)
110
+ return;
111
+ const sessionId = job.state.lastPiboSessionId;
112
+ if (!sessionId) {
113
+ this.markRunResourcesDirty(job, 'Cancel requested but active session is unavailable; browser lease may still exist');
114
+ return;
115
+ }
116
+ this.cancelledRuns.add(job.state.lastRunId);
117
+ try {
118
+ await this.options.context.emit({ type: 'execution', piboSessionId: sessionId, action: 'abort', id: `ralph_cancel_${randomUUID()}` });
119
+ }
120
+ catch (error) {
121
+ this.cancelledRuns.delete(job.state.lastRunId);
122
+ this.markRunResourcesDirty(job, `Cancel requested but abort failed: ${errorMessage(error)}`);
123
+ }
124
+ }
125
+ async executeReserved(job, run) {
126
+ this.activeRuns += 1;
127
+ try {
128
+ const result = await this.executeJob(job, run);
129
+ const cancelled = this.cancelledRuns.delete(run.id);
130
+ const outcome = { status: cancelled ? 'cancelled' : 'ok', piboSessionId: result.piboSessionId, finalAnswer: result.finalAnswer };
131
+ const { evaluation, conditionStates } = await this.evaluateStopPolicy(this.store.getJob(job.id) ?? job, 'after-run', run, outcome);
132
+ this.store.completeRun({ jobId: job.id, runId: run.id, status: outcome.status, piboSessionId: result.piboSessionId, reason: cancelled ? 'cancelled' : evaluation.reason, stopAfterRun: evaluation.finalAction !== 'continue', stopEvaluation: evaluation, conditionStates });
133
+ await this.cleanupRunResources(job, run);
134
+ }
135
+ catch (error) {
136
+ const cancelled = this.cancelledRuns.delete(run.id);
137
+ const outcome = { status: cancelled ? 'cancelled' : 'error', error: cancelled ? undefined : errorMessage(error) };
138
+ const { evaluation, conditionStates } = await this.evaluateStopPolicy(this.store.getJob(job.id) ?? job, 'after-run', run, outcome);
139
+ this.store.completeRun({ jobId: job.id, runId: run.id, status: outcome.status, error: outcome.error, reason: cancelled ? 'cancelled' : evaluation.reason, stopAfterRun: evaluation.finalAction !== 'continue', stopEvaluation: evaluation, conditionStates });
140
+ await this.cleanupRunResources(job, run);
141
+ if (!cancelled)
142
+ console.error(`[ralph] job ${job.id} failed`, error);
143
+ }
144
+ finally {
145
+ this.activeRuns -= 1;
146
+ }
147
+ }
148
+ markRunResourcesDirty(job, dirtyReason) {
149
+ const latestJob = this.store.getJob(job.id) ?? job;
150
+ const runId = latestJob.state.lastRunId ?? job.state.lastRunId;
151
+ const latestRun = runId ? this.store.listRuns({ jobId: latestJob.id, limit: 100 }).find((candidate) => candidate.id === runId) : undefined;
152
+ const resources = mergeRunResources(latestJob.resources, latestRun?.resources);
153
+ if (!resources || (!resources.workerId && (resources.browserLeaseIds ?? []).length === 0))
154
+ return;
155
+ const nextResources = { ...resources, cleanupState: 'dirty', dirtyReason, updatedAt: new Date().toISOString() };
156
+ try {
157
+ if (latestRun)
158
+ this.store.updateRunResources({ jobId: latestJob.id, runId: latestRun.id, resources: nextResources });
159
+ this.store.updateJobResources(latestJob.id, nextResources);
160
+ }
161
+ catch (error) {
162
+ console.error(`[ralph] failed to mark resource cleanup dirty for job ${latestJob.id}`, error);
163
+ }
164
+ }
165
+ async cleanupRunResources(job, run) {
166
+ const latestJob = this.store.getJob(job.id) ?? job;
167
+ const latestRun = this.store.listRuns({ jobId: job.id, limit: 100 }).find((candidate) => candidate.id === run.id) ?? run;
168
+ const resources = mergeRunResources(latestJob.resources, latestRun.resources);
169
+ const leaseIds = resources?.browserLeaseIds ?? [];
170
+ if (!resources || leaseIds.length === 0)
171
+ return;
172
+ const workerId = resources.workerId || process.env.PIBO_BROWSER_POOL_WORKER_ID || process.env.PIBO_COMPUTE_WORKER_ID || process.env.HOSTNAME || 'local';
173
+ const poolId = this.options.resourceCleanup?.browserPoolId || process.env.PIBO_BROWSER_POOL_ID || 'default';
174
+ const rootDir = this.options.resourceCleanup?.browserPoolRootDir || process.env.PIBO_BROWSER_POOL_ROOT || join(process.env.BROWSER_USE_HOME || join(homedir(), '.browser-use'), 'pibo-browser-pool');
175
+ const identity = { workerId, poolId };
176
+ const paths = browserPoolPaths(rootDir, identity);
177
+ const release = this.options.resourceCleanup?.releaseBrowserPoolLease ?? releaseBrowserPoolLease;
178
+ let dirtyReason;
179
+ for (const leaseId of leaseIds) {
180
+ try {
181
+ const result = await release(paths, identity, { leaseId, lockOptions: { holder: `ralph:${run.id}` } });
182
+ if (result.cleanupStatus === 'failed' || result.state.state === 'dirty' || (!result.released && !!result.state.activeLeaseId))
183
+ dirtyReason = result.lastError || `Browser lease ${leaseId} cleanup failed`;
184
+ }
185
+ catch (error) {
186
+ dirtyReason = `Browser lease ${leaseId} cleanup failed: ${errorMessage(error)}`;
187
+ }
188
+ if (dirtyReason)
189
+ break;
190
+ }
191
+ const updatedAt = new Date().toISOString();
192
+ const nextResources = dirtyReason
193
+ ? { ...resources, workerId, cleanupState: 'dirty', dirtyReason, updatedAt }
194
+ : clearDirtyReason({ ...resources, workerId, cleanupState: 'released', updatedAt });
195
+ try {
196
+ this.store.updateRunResources({ jobId: job.id, runId: run.id, resources: nextResources });
197
+ this.store.updateJobResources(job.id, nextResources);
198
+ }
199
+ catch (error) {
200
+ console.error(`[ralph] failed to record resource cleanup for run ${run.id}`, error);
201
+ }
202
+ }
203
+ async evaluateStopPolicy(job, phase, run, outcome) {
204
+ return await evaluateRalphStopPolicy({ job, phase, definitions: this.getStopConditionDefinitions(), facts: this.store.createFactReader(job), run, outcome });
205
+ }
206
+ getStopConditionDefinitions() { return this.options.context.getRalphStopConditionDefinitions?.() ?? createBuiltInRalphStopConditions(); }
207
+ handleProductEvent(event) {
208
+ if (event.type !== 'pibo.ralph.fact' && event.type !== 'ralph.fact')
209
+ return;
210
+ const payload = event.payload;
211
+ if (!isJsonObject(payload.payload))
212
+ return;
213
+ if (typeof payload.jobId !== 'string' || typeof payload.type !== 'string')
214
+ return;
215
+ const source = payload.source === 'pi-extension' || payload.source === 'tool' || payload.source === 'plugin' || payload.source === 'pibo' ? payload.source : 'plugin';
216
+ try {
217
+ this.store.appendRunFact({ jobId: payload.jobId, runId: typeof payload.runId === 'string' ? payload.runId : undefined, piboSessionId: typeof payload.piboSessionId === 'string' ? payload.piboSessionId : undefined, type: payload.type, source: source, payload: payload.payload });
218
+ }
219
+ catch (error) {
220
+ console.error('[ralph] failed to append run fact', error);
221
+ }
222
+ }
223
+ async executeJob(job, run) {
224
+ const target = this.resolveTarget(job);
225
+ const session = this.options.context.createSession({
226
+ channel: CHAT_WEB_CHANNEL,
227
+ kind: 'ralph',
228
+ profile: job.profile,
229
+ workspace: target.workspace ?? getDefaultPiboWorkspace(),
230
+ title: job.name,
231
+ activeModel: job.modelOverride ? { ...job.modelOverride } : undefined,
232
+ metadata: {
233
+ ...(target.metadata ?? {}),
234
+ chatRoomId: target.roomId,
235
+ ralphJobId: job.id,
236
+ ralphRunId: run.id,
237
+ ralphTargetKind: job.target.kind,
238
+ ...(job.thinkingLevel ? { initialThinkingLevel: job.thinkingLevel } : {}),
239
+ ...(job.fastMode !== undefined ? { initialFastMode: job.fastMode } : {}),
240
+ },
241
+ });
242
+ this.store.attachRunSession(job.id, run.id, session.id);
243
+ const finalAnswer = await this.emitMessageAndWait(session.id, buildRalphPrompt(job), { isCancelled: () => this.cancelledRuns.has(run.id) });
244
+ return { piboSessionId: session.id, finalAnswer };
245
+ }
246
+ resolveTarget(job) { if (job.target.kind === 'room') {
247
+ const room = this.roomService.getRoom(job.target.roomId);
248
+ if (!room)
249
+ throw new Error('Target room no longer exists');
250
+ if (isPiboRoomArchived(room))
251
+ throw new Error('Target room is archived');
252
+ return { roomId: room.id, workspace: room.workspace ?? getDefaultPiboWorkspace() };
253
+ } const room = this.roomService.ensureDefaultRoom({ name: 'Shared Chat' }); return { roomId: room.id, workspace: room.workspace ?? getDefaultPiboWorkspace() }; }
254
+ async emitMessageAndWait(piboSessionId, text, options = {}) {
255
+ const eventId = `ralph_msg_${randomUUID()}`;
256
+ return await new Promise((resolve, reject) => { let settled = false; let deltaAnswer = ''; let finalAnswer = ''; let lastSessionError; let unsubscribe; const timeout = setTimeout(() => finish(new Error(lastSessionError ? `Ralph run timed out after session error: ${lastSessionError}` : 'Ralph run timed out')), this.runTimeoutMs); const finish = (error) => { if (settled)
257
+ return; settled = true; clearTimeout(timeout); unsubscribe?.(); if (error)
258
+ reject(error);
259
+ else
260
+ resolve(finalAnswer || deltaAnswer); }; unsubscribe = this.options.context.subscribe((event) => { if (event.piboSessionId !== piboSessionId)
261
+ return; if ('eventId' in event && event.eventId !== eventId)
262
+ return; if (event.type === 'assistant_delta')
263
+ deltaAnswer += event.text; if (event.type === 'assistant_message')
264
+ finalAnswer = event.text; if (event.type === 'message_finished')
265
+ finish(); if (event.type === 'session_error') {
266
+ lastSessionError = event.error;
267
+ if (options.isCancelled?.())
268
+ finish(new Error(event.error));
269
+ } }); this.options.context.emit({ type: 'message', piboSessionId, id: eventId, source: 'service', text }).catch((error) => finish(error instanceof Error ? error : new Error(String(error)))); });
270
+ }
271
+ }
@@ -0,0 +1,151 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export const PROMISE_COMPLETE_STOP_TOKEN = '<promise>COMPLETE</promise>';
3
+ export const MAX_ITERATIONS_STOP_CONDITION = 'pibo.ralph.max-iterations';
4
+ export const PROMISE_COMPLETE_STOP_CONDITION = 'pibo.ralph.promise-complete';
5
+ export const FACT_COUNT_STOP_CONDITION = 'pibo.ralph.fact-count';
6
+ function hasPromiseCompleteMarker(finalAnswer) { return finalAnswer.split(/\r?\n/).some((line) => line.trim() === PROMISE_COMPLETE_STOP_TOKEN); }
7
+ function isObject(value) { return !!value && typeof value === 'object' && !Array.isArray(value); }
8
+ function stringOption(options, key) { const value = options?.[key]; return typeof value === 'string' && value.trim() ? value.trim() : undefined; }
9
+ function numberOption(options, key) { const value = options?.[key]; return typeof value === 'number' && Number.isFinite(value) ? value : undefined; }
10
+ function boolOption(options, key) { const value = options?.[key]; return typeof value === 'boolean' ? value : undefined; }
11
+ export function getDefaultRalphStopPolicy(job) {
12
+ const conditions = [];
13
+ if (job.maxIterations !== undefined)
14
+ conditions.push({ id: 'max-iterations', type: MAX_ITERATIONS_STOP_CONDITION });
15
+ conditions.push({ id: 'promise-complete', type: PROMISE_COMPLETE_STOP_CONDITION });
16
+ return { mode: 'any', conditions };
17
+ }
18
+ export function getEffectiveRalphStopPolicy(job) {
19
+ return job.stopPolicy ?? getDefaultRalphStopPolicy(job);
20
+ }
21
+ export function createBuiltInRalphStopConditions() {
22
+ return [
23
+ {
24
+ type: MAX_ITERATIONS_STOP_CONDITION,
25
+ name: 'Max iterations',
26
+ description: 'Stops a Ralph job after its configured number of completed run attempts, regardless of outcome.',
27
+ phases: ['before-run', 'after-run'],
28
+ evaluate(context) {
29
+ const maxIterations = context.job.maxIterations;
30
+ if (maxIterations === undefined)
31
+ return { action: 'continue' };
32
+ const current = context.job.state.completedIterations ?? 0;
33
+ const completed = context.phase === 'after-run' && context.outcome ? current + 1 : current;
34
+ if (completed >= maxIterations)
35
+ return { action: 'stop-after-run', reason: 'max-iterations', details: { maxIterations, completedIterations: completed } };
36
+ return { action: 'continue', details: { maxIterations, completedIterations: completed } };
37
+ },
38
+ },
39
+ {
40
+ type: PROMISE_COMPLETE_STOP_CONDITION,
41
+ name: 'Promise complete token',
42
+ description: 'Stops after a successful run whose final answer contains the promise-complete marker on its own line.',
43
+ phases: ['after-run'],
44
+ evaluate(context) {
45
+ const finalAnswer = context.outcome?.finalAnswer ?? '';
46
+ if (context.outcome?.status === 'ok' && hasPromiseCompleteMarker(finalAnswer))
47
+ return { action: 'stop-after-run', reason: 'promise-complete', details: { token: PROMISE_COMPLETE_STOP_TOKEN } };
48
+ return { action: 'continue' };
49
+ },
50
+ },
51
+ {
52
+ type: FACT_COUNT_STOP_CONDITION,
53
+ name: 'Run fact count',
54
+ description: 'Stops when the current run or job history contains at least a configured number of matching Ralph run facts.',
55
+ phases: ['after-run'],
56
+ defaultOptions: { factType: 'example.fact', threshold: 1, currentRunOnly: true },
57
+ optionsSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ factType: { type: 'string', description: 'Fact type to count.' },
61
+ threshold: { type: 'number', description: 'Stop after at least this many facts.' },
62
+ currentRunOnly: { type: 'boolean', description: 'Only count facts for the current run.' },
63
+ reason: { type: 'string', description: 'Optional stop reason.' },
64
+ },
65
+ },
66
+ evaluate(context) {
67
+ const factType = stringOption(context.instance.options, 'factType');
68
+ if (!factType)
69
+ return { action: 'continue', details: { missingOption: 'factType' } };
70
+ const threshold = Math.max(1, Math.floor(numberOption(context.instance.options, 'threshold') ?? 1));
71
+ const currentRunOnly = boolOption(context.instance.options, 'currentRunOnly') ?? true;
72
+ const runId = currentRunOnly ? context.run?.id : undefined;
73
+ const count = context.facts.count({ type: factType, runId });
74
+ if (count >= threshold)
75
+ return { action: 'stop-after-run', reason: stringOption(context.instance.options, 'reason') ?? `fact:${factType}`, details: { factType, threshold, count, currentRunOnly } };
76
+ return { action: 'continue', details: { factType, threshold, count, currentRunOnly } };
77
+ },
78
+ },
79
+ ];
80
+ }
81
+ function severity(action) {
82
+ if (action === 'cancel-current-run')
83
+ return 2;
84
+ if (action === 'stop-after-run')
85
+ return 1;
86
+ return 0;
87
+ }
88
+ function highest(left, right) { return severity(right) > severity(left) ? right : left; }
89
+ function sanitizeDecision(value) {
90
+ if (!isObject(value))
91
+ throw new Error('condition returned a non-object decision');
92
+ if (value.action !== 'continue' && value.action !== 'stop-after-run' && value.action !== 'cancel-current-run')
93
+ throw new Error('condition returned an invalid action');
94
+ return { action: value.action, reason: typeof value.reason === 'string' ? value.reason : undefined, details: isObject(value.details) ? value.details : undefined, nextState: isObject(value.nextState) ? value.nextState : undefined };
95
+ }
96
+ async function withTimeout(promise, timeoutMs, signal) {
97
+ if (!timeoutMs || timeoutMs <= 0)
98
+ return await promise;
99
+ return await new Promise((resolve, reject) => {
100
+ const timeout = setTimeout(() => reject(new Error(`condition timed out after ${timeoutMs}ms`)), timeoutMs);
101
+ if (signal)
102
+ signal.addEventListener('abort', () => reject(new Error('condition aborted')), { once: true });
103
+ promise.then((value) => { clearTimeout(timeout); resolve(value); }, (error) => { clearTimeout(timeout); reject(error); });
104
+ });
105
+ }
106
+ export async function evaluateRalphStopPolicy(input) {
107
+ const now = (input.now ?? new Date()).toISOString();
108
+ const policy = getEffectiveRalphStopPolicy(input.job);
109
+ const definitions = new Map(input.definitions.map((definition) => [definition.type, definition]));
110
+ const decisions = [];
111
+ const conditionStates = { ...(input.job.state.conditionStates ?? {}) };
112
+ let finalAction = 'continue';
113
+ for (const instance of policy.conditions) {
114
+ const base = { id: instance.id, type: instance.type, phase: input.phase };
115
+ if (instance.enabled === false) {
116
+ decisions.push({ ...base, action: 'continue', skipped: true, reason: 'disabled' });
117
+ continue;
118
+ }
119
+ const definition = definitions.get(instance.type);
120
+ if (!definition) {
121
+ decisions.push({ ...base, action: 'continue', skipped: true, error: `Unknown Ralph stop condition type: ${instance.type}` });
122
+ continue;
123
+ }
124
+ if (!definition.phases.includes(input.phase)) {
125
+ decisions.push({ ...base, action: 'continue', skipped: true, reason: 'unsupported-phase' });
126
+ continue;
127
+ }
128
+ try {
129
+ const state = conditionStates[instance.id] ?? {};
130
+ const decision = sanitizeDecision(await withTimeout(Promise.resolve(definition.evaluate({ phase: input.phase, job: input.job, policy, instance, state, now, run: input.run, outcome: input.outcome, facts: input.facts, signal: input.signal })), instance.timeoutMs ?? definition.timeoutMs, input.signal));
131
+ if (decision.nextState)
132
+ conditionStates[instance.id] = decision.nextState;
133
+ decisions.push({ ...base, action: decision.action, reason: decision.reason, details: decision.details });
134
+ }
135
+ catch (error) {
136
+ const failClosed = instance.failClosed ?? definition.failClosedDefault ?? false;
137
+ const action = failClosed ? 'stop-after-run' : 'continue';
138
+ decisions.push({ ...base, action, reason: failClosed ? 'condition-error-fail-closed' : 'condition-error', error: error instanceof Error ? error.message : String(error) });
139
+ }
140
+ }
141
+ const active = decisions.filter((decision) => !decision.skipped);
142
+ if (policy.mode === 'all' && active.length > 0) {
143
+ const allStop = active.every((decision) => severity(decision.action) >= severity('stop-after-run'));
144
+ finalAction = allStop ? active.reduce((action, decision) => highest(action, decision.action), 'stop-after-run') : 'continue';
145
+ }
146
+ else {
147
+ finalAction = active.reduce((action, decision) => highest(action, decision.action), 'continue');
148
+ }
149
+ const contributing = finalAction === 'continue' ? active.find((decision) => decision.error || decision.reason) : active.find((decision) => decision.action === finalAction) ?? active.find((decision) => severity(decision.action) > 0);
150
+ return { evaluation: { id: `rse_${randomUUID()}`, phase: input.phase, at: now, mode: policy.mode, finalAction, reason: contributing?.reason ?? (contributing?.error ? 'condition-error' : undefined), decisions }, conditionStates };
151
+ }