@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
@@ -1,8 +1,12 @@
1
1
  import { createHash } from "node:crypto";
2
- import { existsSync, readFileSync } from "node:fs";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
3
5
  import { parseSessionEntries, SessionManager } from "@mariozechner/pi-coding-agent";
4
- import { childTraceOrder, compareTraceOrder, eventTraceOrder, transcriptTraceOrder } from "../../shared/trace-order.js";
6
+ import { buildTraceViewFromEvents } from "../../shared/trace-engine.js";
5
7
  import { isChatWebSessionArchived } from "./session-metadata.js";
8
+ import { workflowSessionKindFromMetadata } from "../../sessions/workflow-session-kind.js";
9
+ export { compareTraceNodes, sortTraceNodes, nestTraceNodes, flattenTraceNodes, mapTraceNodesById, buildTraceViewFromEvents, traceNodesFromEntries, } from "../../shared/trace-engine.js";
6
10
  export async function loadPiSessionMetadata(session, cwd = process.cwd()) {
7
11
  const piSession = await findPiSession(session, cwd);
8
12
  return metadataFromPiSession(piSession);
@@ -10,25 +14,40 @@ export async function loadPiSessionMetadata(session, cwd = process.cwd()) {
10
14
  function metadataFromPiSession(piSession) {
11
15
  if (!piSession)
12
16
  return {};
17
+ let sessionSize;
18
+ let sessionMtimeMs;
19
+ try {
20
+ const stats = statSync(piSession.path);
21
+ sessionSize = stats.size;
22
+ sessionMtimeMs = stats.mtimeMs;
23
+ }
24
+ catch {
25
+ // The session list can contain a file that was removed before trace rendering.
26
+ }
13
27
  return {
14
28
  sessionPath: piSession.path,
29
+ sessionSize,
30
+ sessionMtimeMs,
15
31
  name: piSession.name,
16
32
  firstMessage: piSession.firstMessage,
17
33
  modified: piSession.modified,
18
34
  };
19
35
  }
20
- export async function buildSessionNodes(sessions, indexItems, cwd = process.cwd(), unreadCounts = new Map()) {
36
+ export async function buildSessionNodes(sessions, indexItems, cwd = process.cwd(), unreadCounts = new Map(), options = {}) {
21
37
  const indexByKey = new Map(indexItems.map((item) => [item.piboSessionId, item]));
22
38
  const nodes = new Map();
23
39
  const piSessionsByCwd = new Map();
24
40
  for (const session of sessions) {
25
- const sessionCwd = session.workspace ?? cwd;
26
- let piSessions = piSessionsByCwd.get(sessionCwd);
27
- if (!piSessions) {
28
- piSessions = listPiSessions(sessionCwd);
29
- piSessionsByCwd.set(sessionCwd, piSessions);
41
+ let metadata = {};
42
+ if (!session.title && !options.skipPiMetadataFallback) {
43
+ const sessionCwd = session.workspace ?? cwd;
44
+ let piSessions = piSessionsByCwd.get(sessionCwd);
45
+ if (!piSessions) {
46
+ piSessions = listPiSessions(sessionCwd);
47
+ piSessionsByCwd.set(sessionCwd, piSessions);
48
+ }
49
+ metadata = metadataFromPiSession((await piSessions).find((piSession) => piSession.id === session.piSessionId));
30
50
  }
31
- const metadata = metadataFromPiSession((await piSessions).find((piSession) => piSession.id === session.piSessionId));
32
51
  const indexed = indexByKey.get(session.id);
33
52
  nodes.set(session.id, {
34
53
  piboSessionId: session.id,
@@ -36,12 +55,14 @@ export async function buildSessionNodes(sessions, indexItems, cwd = process.cwd(
36
55
  parentId: session.parentId,
37
56
  originId: session.originId,
38
57
  profile: session.profile,
58
+ activeModel: session.activeModel,
39
59
  subagentName: stringValue(session.metadata?.subagentName),
60
+ workflowSessionKind: workflowSessionKindFromMetadata(session.metadata),
40
61
  title: createSessionTitle(session, metadata),
41
62
  subtitle: session.id,
42
63
  archived: isChatWebSessionArchived(session),
43
- status: indexed?.status ?? "idle",
44
- lastActivityAt: indexed?.lastActivityAt ?? metadata.modified ?? session.updatedAt,
64
+ status: sessionNodeStatus(indexed?.status),
65
+ lastActivityAt: indexed?.lastActivityAt ?? indexed?.createdAt ?? session.createdAt,
45
66
  unreadCount: unreadCounts.get(session.id) || undefined,
46
67
  derivedSessions: [],
47
68
  children: [],
@@ -67,6 +88,7 @@ export async function buildSessionNodes(sessions, indexItems, cwd = process.cwd(
67
88
  piboSessionId: node.piboSessionId,
68
89
  profile: node.profile,
69
90
  subagentName: node.subagentName,
91
+ workflowSessionKind: node.workflowSessionKind,
70
92
  title: node.title,
71
93
  status: node.status,
72
94
  lastActivityAt: node.lastActivityAt,
@@ -82,88 +104,37 @@ export async function buildSessionNodes(sessions, indexItems, cwd = process.cwd(
82
104
  sortNodes(roots);
83
105
  return roots;
84
106
  }
107
+ function sessionNodeStatus(indexedStatus) {
108
+ return indexedStatus ?? "idle";
109
+ }
85
110
  export async function buildTraceView(input) {
86
- const metadata = await loadPiSessionMetadata(input.session, input.session.workspace ?? input.cwd);
111
+ const metadata = input.metadata ?? (await loadPiSessionMetadata(input.session, input.session.workspace ?? input.cwd));
87
112
  const allEntries = metadata.sessionPath ? readEntries(metadata.sessionPath) : [];
88
113
  const sessionStatus = input.status ?? "idle";
89
- const openTranscriptEventIds = findOpenTranscriptEventIds(input.events, sessionStatus);
90
- const entries = projectTranscriptEntries(allEntries, sessionStatus, openTranscriptEventIds);
91
- const nodes = traceNodesFromEntries(input.session.id, entries);
92
- const byId = mapTraceNodesById(nodes);
93
- const childByParent = mapChildren(input.sessions);
94
- const linkedChildByToolCallId = mapSubagentSessionLinks(input.events);
95
- const hasPersistedTranscript = entries.some((entry) => entry.type === "message");
96
- for (const storedEvent of input.events) {
97
- if (hasPersistedTranscript &&
98
- isTranscriptEchoEvent(storedEvent.payload) &&
99
- !shouldKeepTranscriptEchoEvent(storedEvent.payload, openTranscriptEventIds)) {
100
- continue;
101
- }
102
- if (hasPersistedTranscript && isStaleToolCallEchoEvent(storedEvent.payload, sessionStatus)) {
103
- continue;
104
- }
105
- if (storedEvent.payload.type === "assistant_delta") {
106
- mergeAssistantDeltaEvent(nodes, byId, storedEvent.payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence);
107
- continue;
108
- }
109
- if (storedEvent.payload.type === "thinking_delta") {
110
- mergeThinkingDeltaEvent(nodes, byId, storedEvent.payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence);
111
- continue;
112
- }
113
- const node = traceNodeFromEvent(input.session.id, storedEvent.payload, childByParent, linkedChildByToolCallId, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence);
114
- if (!node)
115
- continue;
116
- if (node.type === "agent.turn" && node.eventId) {
117
- const existingTurn = [...byId.values()].find((candidate) => candidate.type === "agent.turn" && candidate.eventId === node.eventId);
118
- if (existingTurn) {
119
- existingTurn.status = node.status;
120
- existingTurn.completedAt = node.completedAt ?? existingTurn.completedAt;
121
- continue;
122
- }
123
- }
124
- if (node.type === "assistant.message") {
125
- const existing = byId.get(node.id);
126
- if (existing) {
127
- mergeAssistantMessageEvent(existing, node);
128
- closeParentTurnForFinalAssistant(byId, existing);
129
- continue;
130
- }
131
- closeParentTurnForFinalAssistant(byId, node);
132
- }
133
- if (node.type === "model.reasoning") {
134
- const existing = byId.get(node.id);
135
- if (existing) {
136
- mergeReasoningEvent(existing, node);
137
- continue;
138
- }
139
- }
140
- if (node.toolCallId) {
141
- const existing = [...byId.values()].find((candidate) => candidate.toolCallId === node.toolCallId &&
142
- (candidate.type === "tool.call" || candidate.type === "agent.delegation"));
143
- if (existing) {
144
- if (isRunStartToolNode(existing) && node.type === "agent.delegation") {
145
- attachAsyncAgentRunNode(existing, input.session.id, storedEvent.createdAt, node);
146
- continue;
147
- }
148
- mergeToolEvent(existing, node);
149
- attachAsyncAgentRunNode(existing, input.session.id, storedEvent.createdAt);
150
- continue;
151
- }
152
- }
153
- if (node.eventId && byId.has(node.id))
154
- continue;
155
- attachAsyncAgentRunNode(node, input.session.id, storedEvent.createdAt);
156
- nodes.push(node);
157
- for (const indexed of flattenTraceNodes([node]))
158
- byId.set(indexed.id, indexed);
159
- }
160
- const nestedNodes = nestTraceNodes(nodes);
161
- reconcileAsyncAgentRunStatuses(nestedNodes);
162
- sortTraceNodes(nestedNodes);
114
+ const view = buildTraceViewFromEvents({
115
+ session: {
116
+ id: input.session.id,
117
+ piSessionId: input.session.piSessionId,
118
+ title: createSessionTitle(input.session, metadata),
119
+ },
120
+ events: input.events,
121
+ transcriptEntries: allEntries,
122
+ sessions: input.sessions.map((s) => ({
123
+ id: s.id,
124
+ parentId: s.parentId ?? null,
125
+ originId: s.originId ?? null,
126
+ updatedAt: s.updatedAt,
127
+ title: s.title ?? null,
128
+ metadata: s.metadata,
129
+ })),
130
+ status: sessionStatus,
131
+ latestStreamId: input.latestStreamId,
132
+ includeRawEvents: input.includeRawEvents,
133
+ rawEventsLimit: input.rawEventsLimit,
134
+ });
135
+ annotateForkableUserMessageNodes(view.nodes, allEntries);
163
136
  return {
164
- piboSessionId: input.session.id,
165
- piSessionId: input.session.piSessionId,
166
- title: createSessionTitle(input.session, metadata),
137
+ ...view,
167
138
  version: createTraceViewVersion({
168
139
  session: input.session,
169
140
  sessions: input.sessions,
@@ -172,9 +143,6 @@ export async function buildTraceView(input) {
172
143
  metadata,
173
144
  latestStreamId: input.latestStreamId,
174
145
  }),
175
- latestStreamId: input.latestStreamId,
176
- nodes: nestedNodes,
177
- rawEvents: input.includeRawEvents === false ? [] : input.events.slice(-(input.rawEventsLimit ?? input.events.length)),
178
146
  };
179
147
  }
180
148
  export function createTraceViewVersion(input) {
@@ -198,6 +166,9 @@ export function createTraceViewVersion(input) {
198
166
  updatedAt: input.session.updatedAt,
199
167
  },
200
168
  metadata: {
169
+ sessionPath: input.metadata?.sessionPath ?? null,
170
+ sessionSize: input.metadata?.sessionSize ?? null,
171
+ sessionMtimeMs: input.metadata?.sessionMtimeMs ?? null,
201
172
  name: input.metadata?.name ?? null,
202
173
  firstMessage: input.metadata?.firstMessage ?? null,
203
174
  modified: input.metadata?.modified ?? null,
@@ -212,9 +183,14 @@ export function createTraceViewVersion(input) {
212
183
  }))
213
184
  .digest("hex");
214
185
  }
186
+ const PI_SESSION_LIST_CACHE_TTL_MS = 5_000;
187
+ const piSessionListCache = new Map();
215
188
  export async function listPiSessions(cwd = process.cwd()) {
216
- const sessions = await SessionManager.list(cwd);
217
- return sessions.map((session) => ({
189
+ const now = Date.now();
190
+ const cached = piSessionListCache.get(cwd);
191
+ if (cached && cached.expiresAt > now)
192
+ return cached.promise;
193
+ const promise = SessionManager.list(cwd).then((sessions) => sessions.map((session) => ({
218
194
  path: session.path,
219
195
  id: session.id,
220
196
  cwd: session.cwd,
@@ -224,7 +200,13 @@ export async function listPiSessions(cwd = process.cwd()) {
224
200
  modified: session.modified.toISOString(),
225
201
  messageCount: session.messageCount,
226
202
  firstMessage: session.firstMessage,
227
- }));
203
+ })));
204
+ piSessionListCache.set(cwd, { expiresAt: now + PI_SESSION_LIST_CACHE_TTL_MS, promise });
205
+ promise.catch(() => {
206
+ if (piSessionListCache.get(cwd)?.promise === promise)
207
+ piSessionListCache.delete(cwd);
208
+ });
209
+ return promise;
228
210
  }
229
211
  function createSessionTitle(session, metadata) {
230
212
  const candidate = session.title || metadata.name || metadata.firstMessage || session.id;
@@ -237,946 +219,140 @@ function truncateTitle(title, maxLength = 56) {
237
219
  return `${normalized.slice(0, maxLength - 1)}…`;
238
220
  }
239
221
  async function findPiSession(piboSession, cwd) {
240
- const sessions = await listPiSessions(cwd);
241
- return sessions.find((session) => session.id === piboSession.piSessionId);
242
- }
243
- function readEntries(path) {
244
- if (!existsSync(path))
245
- return [];
246
- const content = readFileSync(path, "utf8");
247
- return parseSessionEntries(content).filter((entry) => entry.type !== "session");
222
+ return (findPiSessionDirect(piboSession.piSessionId, cwd) ??
223
+ (await listPiSessions(cwd)).find((session) => session.id === piboSession.piSessionId));
248
224
  }
249
- function projectTranscriptEntries(entries, sessionStatus, openTranscriptEventIds) {
250
- if (sessionStatus !== "running" || openTranscriptEventIds.size === 0)
251
- return entries;
252
- let lastUserMessageIndex = -1;
253
- for (let index = entries.length - 1; index >= 0; index -= 1) {
254
- const entry = entries[index];
255
- if (entry.type === "message" && messageRole(entry) === "user") {
256
- lastUserMessageIndex = index;
257
- break;
258
- }
259
- }
260
- return lastUserMessageIndex === -1 ? entries : entries.slice(0, lastUserMessageIndex);
261
- }
262
- function messageRole(entry) {
263
- return entry.message.role;
264
- }
265
- function messageContent(entry) {
266
- return entry.message.content;
267
- }
268
- function messageParts(entry) {
269
- const content = messageContent(entry);
270
- if (typeof content === "string")
271
- return [{ type: "text", text: content }];
272
- return Array.isArray(content) ? content : [];
273
- }
274
- export function traceNodesFromEntries(piboSessionId, entries) {
275
- const nodes = [];
276
- for (let index = 0; index < entries.length; index += 1) {
277
- const entry = entries[index];
278
- if (entry.type === "message") {
279
- const role = messageRole(entry);
280
- if (role === "user") {
281
- nodes.push(createUserMessageNode(piboSessionId, entry, messageContent(entry), index));
282
- }
283
- else if (role === "assistant" || role === "toolResult") {
284
- const turn = collectAssistantTurn(entries, index);
285
- nodes.push(...createAssistantTurnNodes(piboSessionId, turn.entries));
286
- index = turn.nextIndex - 1;
287
- }
288
- }
289
- else if (entry.type === "session_info" && entry.name) {
290
- nodes.push({
291
- id: `entry:${entry.id}`,
292
- entryId: entry.id,
293
- piboSessionId,
294
- type: "execution.command",
295
- title: "Session Info",
296
- status: "done",
297
- startedAt: entry.timestamp,
298
- output: { name: entry.name },
299
- source: "transcript",
300
- stableKey: `entry:${entry.id}`,
301
- orderKey: transcriptTraceOrder(index, 0, "execution.command"),
302
- children: [],
303
- });
304
- }
305
- }
306
- reconcileAsyncAgentRunStatuses(nodes);
307
- sortTraceNodes(nodes);
308
- return nodes;
309
- }
310
- function collectAssistantTurn(entries, startIndex) {
311
- const turnEntries = [];
312
- let index = startIndex;
313
- while (index < entries.length) {
314
- const entry = entries[index];
315
- if (entry.type !== "message")
316
- break;
317
- const role = messageRole(entry);
318
- if (role !== "assistant" && role !== "toolResult")
319
- break;
320
- turnEntries.push({ entry, index });
321
- index += 1;
322
- }
323
- return { entries: turnEntries, nextIndex: index };
324
- }
325
- function createUserMessageNode(piboSessionId, entry, content, entryIndex) {
326
- const text = extractText(content);
327
- const notification = parseRunNotificationText(text);
328
- if (notification) {
329
- return createRunNotificationNode({
330
- id: `entry:${entry.id}`,
331
- entryId: entry.id,
332
- piboSessionId,
333
- startedAt: entry.timestamp,
334
- orderKey: transcriptTraceOrder(entryIndex, 0, "yielded.run"),
335
- source: "transcript",
336
- stableKey: `entry:${entry.id}`,
337
- notification,
338
- });
339
- }
340
- return {
341
- id: `entry:${entry.id}`,
342
- entryId: entry.id,
343
- piboSessionId,
344
- type: "user.message",
345
- title: "User Message",
346
- status: "done",
347
- startedAt: entry.timestamp,
348
- summary: text,
349
- output: text,
350
- source: "transcript",
351
- stableKey: `entry:${entry.id}`,
352
- orderKey: transcriptTraceOrder(entryIndex, 0, "user.message"),
353
- children: [],
354
- };
355
- }
356
- function createAssistantTurnNodes(piboSessionId, entries) {
357
- const firstAssistant = entries.find(({ entry }) => messageRole(entry) === "assistant");
358
- if (!firstAssistant)
359
- return [];
360
- const orderedNodes = [];
361
- const toolsByCallId = new Map();
362
- for (const { entry, index: entryIndex } of entries) {
363
- if (messageRole(entry) === "toolResult") {
364
- mergePersistedToolResult(toolsByCallId, orderedNodes, entry, piboSessionId, entryIndex);
365
- continue;
366
- }
367
- const responseStatus = messageStatus(entry.message);
368
- const responseError = messageError(entry.message);
369
- let responseNode;
370
- for (const [index, part] of messageParts(entry).entries()) {
371
- const typed = part;
372
- if (typed.type === "thinking" && typeof typed.thinking === "string" && hasVisibleText(typed.thinking)) {
373
- orderedNodes.push(createReasoningNode(piboSessionId, entry, entryIndex, index, typed.thinking));
374
- }
375
- else if (typed.type === "text" && typeof typed.text === "string" && typed.text !== "") {
376
- if (!responseNode) {
377
- responseNode = createAssistantMessageNode({
378
- id: `entry:${entry.id}:response`,
379
- piboSessionId,
380
- entry,
381
- entryIndex,
382
- contentPartIndex: index,
383
- status: responseStatus,
384
- text: typed.text,
385
- error: responseError,
386
- children: [],
387
- startedAt: entry.timestamp,
388
- completedAt: entry.timestamp,
389
- });
390
- orderedNodes.push(responseNode);
391
- }
392
- else {
393
- responseNode.summary = `${typeof responseNode.summary === "string" ? responseNode.summary : ""}${typed.text}`;
394
- responseNode.output = `${typeof responseNode.output === "string" ? responseNode.output : ""}${typed.text}`;
395
- responseNode.completedAt = entry.timestamp;
396
- }
397
- }
398
- else if (typed.type === "toolCall" && typeof typed.id === "string" && typeof typed.name === "string") {
399
- const toolNode = createToolCallNode(piboSessionId, entry, entryIndex, index, typed);
400
- orderedNodes.push(toolNode);
401
- toolsByCallId.set(typed.id, toolNode);
402
- }
403
- }
404
- if (responseNode) {
405
- responseNode.status = responseStatus;
406
- responseNode.error = responseError;
407
- }
408
- }
409
- return orderedNodes;
410
- }
411
- function createReasoningNode(piboSessionId, entry, entryIndex, index, thinking) {
412
- return {
413
- id: `entry:${entry.id}:thinking:${index}`,
414
- entryId: entry.id,
415
- piboSessionId,
416
- type: "model.reasoning",
417
- title: "Thinking",
418
- status: "done",
419
- startedAt: entry.timestamp,
420
- summary: thinking,
421
- output: thinking,
422
- source: "transcript",
423
- stableKey: `entry:${entry.id}:thinking:${index}`,
424
- orderKey: transcriptTraceOrder(entryIndex, index, "model.reasoning"),
425
- children: [],
426
- };
427
- }
428
- function createToolCallNode(piboSessionId, entry, entryIndex, contentPartIndex, part) {
429
- const name = typeof part.name === "string" ? part.name : "Tool Call";
430
- const toolCallId = typeof part.id === "string" ? part.id : undefined;
431
- return {
432
- id: `entry:${entry.id}:tool:${String(part.id)}`,
433
- entryId: entry.id,
434
- piboSessionId,
435
- toolCallId,
436
- type: isSubagentToolName(name) ? "agent.delegation" : "tool.call",
437
- title: name,
438
- status: "done",
439
- startedAt: entry.timestamp,
440
- input: part.arguments ?? {},
441
- source: "transcript",
442
- stableKey: toolCallId ? `tool:${toolCallId}` : `entry:${entry.id}:tool:${contentPartIndex}`,
443
- orderKey: transcriptTraceOrder(entryIndex, contentPartIndex, isSubagentToolName(name) ? "agent.delegation" : "tool.call"),
444
- children: [],
445
- };
446
- }
447
- function mergePersistedToolResult(toolsByCallId, childNodes, entry, piboSessionId, entryIndex) {
448
- const message = entry.message;
449
- const toolCallId = typeof message.toolCallId === "string" ? message.toolCallId : undefined;
450
- if (!toolCallId)
451
- return;
452
- let toolNode = toolsByCallId.get(toolCallId);
453
- if (!toolNode) {
454
- toolNode = createMissingToolResultNode(piboSessionId, entry, entryIndex, toolCallId);
455
- childNodes.push(toolNode);
456
- toolsByCallId.set(toolCallId, toolNode);
457
- }
458
- toolNode.status = message.isError === true ? "error" : "done";
459
- toolNode.completedAt = entry.timestamp;
460
- toolNode.output = toolResultOutput(message);
461
- toolNode.error = message.isError === true ? stringifyPreview(toolNode.output) : undefined;
462
- attachAsyncAgentRunNode(toolNode, piboSessionId, entry.timestamp);
463
- }
464
- function createMissingToolResultNode(piboSessionId, entry, entryIndex, toolCallId) {
465
- const message = entry.message;
466
- return {
467
- id: `entry:${entry.id}:tool-result:${toolCallId}`,
468
- entryId: entry.id,
469
- piboSessionId,
470
- toolCallId,
471
- type: "tool.result",
472
- title: typeof message.toolName === "string" ? message.toolName : "Tool Result",
473
- status: "done",
474
- startedAt: entry.timestamp,
475
- source: "transcript",
476
- stableKey: `tool:${toolCallId}`,
477
- orderKey: transcriptTraceOrder(entryIndex, 0, "tool.result"),
478
- children: [],
479
- };
480
- }
481
- function toolResultOutput(message) {
482
- if (message.details === undefined)
483
- return { content: message.content };
484
- return { content: message.content, details: message.details };
485
- }
486
- function createAssistantMessageNode(input) {
487
- return {
488
- id: input.id,
489
- entryId: input.entry.id,
490
- piboSessionId: input.piboSessionId,
491
- type: "assistant.message",
492
- title: "Agent Message",
493
- status: input.status,
494
- startedAt: input.startedAt ?? input.entry.timestamp,
495
- completedAt: input.completedAt,
496
- summary: input.text,
497
- output: input.text,
498
- error: input.error,
499
- source: "transcript",
500
- stableKey: `entry:${input.entry.id}:response:${input.contentPartIndex}`,
501
- orderKey: transcriptTraceOrder(input.entryIndex, input.contentPartIndex, "assistant.message"),
502
- children: input.children ?? [],
503
- };
504
- }
505
- function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByToolCallId, sessionStatus, createdAt, eventSequence) {
506
- const eventId = "eventId" in event && typeof event.eventId === "string" ? event.eventId : undefined;
507
- const id = `event:${event.type}:${eventId ?? cryptoSafeId(event)}`;
508
- const turnParentId = eventId ? messageTurnNodeId(eventId) : undefined;
509
- const base = {
510
- id,
511
- piboSessionId,
512
- eventId,
513
- startedAt: createdAt,
514
- source: "event-log",
515
- stableKey: eventStableKey(event),
516
- orderKey: eventTraceNodeOrder(eventSequence, event.type),
517
- children: [],
518
- };
519
- switch (event.type) {
520
- case "message_queued": {
521
- const notification = parseRunNotificationText(event.text);
522
- if (event.source === "service" && notification) {
523
- return createRunNotificationNode({
524
- id,
525
- piboSessionId,
526
- eventId,
527
- startedAt: createdAt,
528
- source: "event-log",
529
- stableKey: eventId ? `run-notification:${eventId}` : id,
530
- orderKey: eventTraceNodeOrder(eventSequence, event.type),
531
- notification,
532
- });
533
- }
534
- return {
535
- ...base,
536
- type: "user.message",
537
- title: "User Message",
538
- status: "done",
539
- summary: event.text,
540
- output: event.text,
541
- };
542
- }
543
- case "message_started":
544
- case "message_finished":
545
- if (event.source === "service")
546
- return undefined;
547
- return {
548
- ...base,
549
- id: eventId ? messageTurnNodeId(eventId) : id,
550
- type: "agent.turn",
551
- title: "Agent Turn",
552
- status: event.type === "message_finished" || sessionStatus !== "running" ? "done" : "running",
553
- completedAt: event.type === "message_finished" ? createdAt : undefined,
554
- summary: event.type === "message_started" ? event.text : undefined,
555
- input: event.type === "message_started" ? { text: event.text, source: event.source } : undefined,
556
- stableKey: eventId ? `turn:${eventId}` : base.stableKey,
557
- };
558
- case "thinking_finished": {
559
- if (!hasVisibleText(event.text))
560
- return undefined;
561
- const thinkingId = thinkingEventNodeId(event);
562
- return {
563
- ...base,
564
- id: thinkingId ? thinkingNodeId(thinkingId) : id,
565
- parentId: turnParentId,
566
- type: "model.reasoning",
567
- title: "Thinking",
568
- status: "done",
569
- summary: event.text,
570
- output: event.text,
571
- stableKey: thinkingId ? `reasoning:${thinkingId}` : base.stableKey,
572
- };
573
- }
574
- case "assistant_message": {
575
- const assistantId = assistantEventNodeId(event);
576
- return {
577
- ...base,
578
- id: assistantId ? assistantMessageNodeId(assistantId) : id,
579
- parentId: turnParentId,
580
- type: "assistant.message",
581
- title: "Agent Message",
582
- status: "done",
583
- summary: event.text,
584
- output: event.text,
585
- stableKey: assistantId ? `assistant:${assistantId}` : base.stableKey,
586
- };
587
- }
588
- case "tool_call":
589
- case "tool_execution_started":
590
- case "tool_execution_updated":
591
- case "tool_execution_finished": {
592
- const subagentTool = isSubagentToolName(event.toolName);
593
- const linkedPiboSessionId = linkedChildByToolCallId.get(event.toolCallId) ??
594
- (subagentTool ? findLikelyChildSession(piboSessionId, event.toolName, event, childByParent) : undefined);
595
- return {
596
- ...base,
597
- id: `tool:${event.toolCallId}`,
598
- parentId: turnParentId,
599
- toolCallId: event.toolCallId,
600
- type: subagentTool ? "agent.delegation" : "tool.call",
601
- title: event.toolName,
602
- status: event.type === "tool_execution_finished"
603
- ? event.isError
604
- ? "error"
605
- : "done"
606
- : sessionStatus === "running" &&
607
- (event.type === "tool_execution_started" || event.type === "tool_execution_updated")
608
- ? "running"
609
- : "done",
610
- completedAt: event.type === "tool_execution_finished" ? createdAt : undefined,
611
- input: "args" in event ? event.args : undefined,
612
- output: event.type === "tool_execution_finished"
613
- ? event.result
614
- : event.type === "tool_execution_updated"
615
- ? event.partialResult
616
- : undefined,
617
- error: event.type === "tool_execution_finished" && event.isError ? stringifyPreview(event.result) : undefined,
618
- linkedPiboSessionId,
619
- stableKey: `tool:${event.toolCallId}`,
620
- children: [],
621
- };
622
- }
623
- case "subagent_session":
624
- return {
625
- ...base,
626
- id: event.toolCallId ? `tool:${event.toolCallId}` : id,
627
- eventId,
628
- toolCallId: event.toolCallId,
629
- type: "agent.delegation",
630
- title: event.toolName,
631
- status: sessionStatus === "running" ? "running" : "done",
632
- summary: event.subagentName,
633
- input: { subagentName: event.subagentName, threadKey: event.threadKey },
634
- linkedPiboSessionId: event.childPiboSessionId,
635
- stableKey: event.toolCallId ? `tool:${event.toolCallId}` : `subagent:${event.childPiboSessionId}`,
636
- children: [],
637
- };
638
- case "execution_result":
639
- if (isInternalSessionOperation(event.action))
640
- return undefined;
641
- return {
642
- ...base,
643
- type: "execution.command",
644
- title: event.action,
645
- status: "done",
646
- input: { action: event.action },
647
- output: event.result,
648
- };
649
- case "session_error":
650
- return {
651
- ...base,
652
- type: "error",
653
- title: "Error",
654
- status: "error",
655
- error: event.error,
656
- output: event.error,
657
- };
658
- default:
225
+ function findPiSessionDirect(piSessionId, cwd) {
226
+ const sessionDir = defaultPiSessionDir(cwd);
227
+ if (!existsSync(sessionDir))
228
+ return undefined;
229
+ try {
230
+ const file = readdirSync(sessionDir).find((candidate) => candidate.endsWith(`_${piSessionId}.jsonl`));
231
+ if (!file)
659
232
  return undefined;
660
- }
661
- }
662
- function mergeAssistantDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence) {
663
- if (event.text.length === 0)
664
- return;
665
- const assistantId = assistantEventNodeId(event);
666
- const id = assistantId ? assistantMessageNodeId(assistantId) : `event:assistant_delta:${cryptoSafeId(event)}`;
667
- const existing = byId.get(id);
668
- if (existing) {
669
- const text = `${typeof existing.output === "string" ? existing.output : ""}${event.text}`;
670
- existing.status = sessionStatus === "running" ? "running" : "done";
671
- existing.summary = text;
672
- existing.output = text;
673
- return;
674
- }
675
- const node = {
676
- id,
677
- parentId: event.eventId ? messageTurnNodeId(event.eventId) : undefined,
678
- piboSessionId: event.piboSessionId,
679
- eventId: event.eventId,
680
- type: "assistant.message",
681
- title: "Agent Message",
682
- status: sessionStatus === "running" ? "running" : "done",
683
- startedAt: createdAt,
684
- summary: event.text,
685
- output: event.text,
686
- source: "event-log",
687
- stableKey: assistantId ? `assistant:${assistantId}` : id,
688
- orderKey: eventTraceNodeOrder(eventSequence, event.type),
689
- children: [],
690
- };
691
- nodes.push(node);
692
- byId.set(node.id, node);
693
- }
694
- function mergeAssistantMessageEvent(target, update) {
695
- target.status = update.status;
696
- target.summary = update.summary ?? target.summary;
697
- target.output = update.output ?? target.output;
698
- target.error = update.error ?? target.error;
699
- target.completedAt = update.completedAt ?? target.completedAt;
700
- }
701
- function mergeThinkingDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence) {
702
- if (event.text.length === 0)
703
- return;
704
- const thinkingId = thinkingEventNodeId(event);
705
- const id = thinkingId ? thinkingNodeId(thinkingId) : `event:thinking_delta:${cryptoSafeId(event)}`;
706
- const existing = byId.get(id);
707
- if (existing) {
708
- const text = `${typeof existing.output === "string" ? existing.output : ""}${event.text}`;
709
- existing.status = sessionStatus === "running" ? "running" : "done";
710
- existing.summary = text;
711
- existing.output = text;
712
- return;
713
- }
714
- const node = {
715
- id,
716
- parentId: event.eventId ? messageTurnNodeId(event.eventId) : undefined,
717
- piboSessionId: event.piboSessionId,
718
- eventId: event.eventId,
719
- type: "model.reasoning",
720
- title: "Thinking",
721
- status: sessionStatus === "running" ? "running" : "done",
722
- startedAt: createdAt,
723
- summary: event.text,
724
- output: event.text,
725
- source: "event-log",
726
- stableKey: thinkingId ? `reasoning:${thinkingId}` : id,
727
- orderKey: eventTraceNodeOrder(eventSequence, event.type),
728
- children: [],
729
- };
730
- nodes.push(node);
731
- byId.set(node.id, node);
732
- }
733
- function mergeReasoningEvent(target, update) {
734
- target.status = update.status;
735
- target.summary = update.summary ?? target.summary;
736
- target.output = update.output ?? target.output;
737
- target.completedAt = update.completedAt ?? target.completedAt;
738
- }
739
- function closeParentTurnForFinalAssistant(byId, assistant) {
740
- if (!assistant.parentId || assistant.status !== "done")
741
- return;
742
- const parent = byId.get(assistant.parentId);
743
- if (!parent || parent.type !== "agent.turn")
744
- return;
745
- parent.status = "done";
746
- parent.completedAt = assistant.completedAt ?? assistant.startedAt ?? parent.completedAt;
747
- }
748
- function isInternalSessionOperation(action) {
749
- return action === "session.fork" || action === "session.clone" || action === "session.switch";
750
- }
751
- function isTranscriptEchoEvent(event) {
752
- return (event.type === "message_queued" ||
753
- event.type === "message_started" ||
754
- event.type === "message_finished" ||
755
- event.type === "assistant_delta" ||
756
- event.type === "assistant_message" ||
757
- event.type === "thinking_started" ||
758
- event.type === "thinking_delta" ||
759
- event.type === "thinking_finished");
760
- }
761
- function shouldKeepTranscriptEchoEvent(event, openTranscriptEventIds) {
762
- const eventId = "eventId" in event && typeof event.eventId === "string" ? event.eventId : undefined;
763
- return Boolean(eventId && openTranscriptEventIds.has(eventId));
764
- }
765
- function isStaleToolCallEchoEvent(event, sessionStatus) {
766
- return sessionStatus !== "running" && event.type === "tool_call";
767
- }
768
- function findOpenTranscriptEventIds(events, sessionStatus) {
769
- if (sessionStatus !== "running")
770
- return new Set();
771
- const open = new Set();
772
- for (const storedEvent of events) {
773
- const event = storedEvent.payload;
774
- const eventId = "eventId" in event && typeof event.eventId === "string" ? event.eventId : undefined;
775
- if (!eventId)
776
- continue;
777
- if (isOpenTranscriptEvent(event)) {
778
- open.add(eventId);
779
- }
780
- else if (event.type === "message_finished" || event.type === "session_error") {
781
- open.delete(eventId);
233
+ const sessionPath = join(sessionDir, file);
234
+ const stats = statSync(sessionPath);
235
+ const entries = parseSessionEntries(readFileSync(sessionPath, "utf8"));
236
+ const header = entries.find((entry) => entry.type === "session");
237
+ if (header?.id !== piSessionId)
238
+ return undefined;
239
+ let name;
240
+ let firstMessage = "";
241
+ let messageCount = 0;
242
+ for (const entry of entries) {
243
+ if (entry.type === "session_info")
244
+ name = stringValue(entry.name)?.trim() || undefined;
245
+ if (entry.type !== "message")
246
+ continue;
247
+ messageCount++;
248
+ if (firstMessage || messageRole(entry) !== "user")
249
+ continue;
250
+ firstMessage = extractMessageText(messageContent(entry));
782
251
  }
252
+ return {
253
+ path: sessionPath,
254
+ id: piSessionId,
255
+ cwd: stringValue(header.cwd) ?? cwd,
256
+ name,
257
+ parentSessionPath: stringValue(header.parentSession),
258
+ created: stringValue(header.timestamp) ?? stats.birthtime.toISOString(),
259
+ modified: sessionModifiedIso(entries.filter((entry) => entry.type !== "session"), stringValue(header.timestamp), stats.mtime),
260
+ messageCount,
261
+ firstMessage: firstMessage || "(no messages)",
262
+ };
783
263
  }
784
- return open;
785
- }
786
- function isOpenTranscriptEvent(event) {
787
- return (event.type === "message_queued" ||
788
- event.type === "message_started" ||
789
- event.type === "assistant_delta" ||
790
- event.type === "assistant_message" ||
791
- event.type === "thinking_started" ||
792
- event.type === "thinking_delta" ||
793
- event.type === "thinking_finished");
794
- }
795
- function eventTraceNodeOrder(eventSequence, type) {
796
- return eventTraceOrder(eventSequence, eventNodeKind(type));
797
- }
798
- function eventNodeKind(type) {
799
- switch (type) {
800
- case "message_queued":
801
- return "user.message";
802
- case "message_started":
803
- case "message_finished":
804
- return "agent.turn";
805
- case "thinking_started":
806
- case "thinking_delta":
807
- case "thinking_finished":
808
- return "model.reasoning";
809
- case "tool_call":
810
- case "tool_execution_started":
811
- case "tool_execution_updated":
812
- case "tool_execution_finished":
813
- case "subagent_session":
814
- return "tool.call";
815
- case "assistant_delta":
816
- case "assistant_message":
817
- return "assistant.message";
818
- case "execution_result":
819
- return "execution.command";
820
- case "session_error":
821
- return "error";
822
- default:
823
- return "execution.command";
824
- }
825
- }
826
- function eventStableKey(event) {
827
- const eventId = "eventId" in event && typeof event.eventId === "string" ? event.eventId : undefined;
828
- if (event.type === "tool_call" || event.type === "tool_execution_started" || event.type === "tool_execution_updated" || event.type === "tool_execution_finished") {
829
- return `tool:${event.toolCallId}`;
830
- }
831
- if (event.type === "subagent_session" && event.toolCallId)
832
- return `tool:${event.toolCallId}`;
833
- if (eventId && (event.type === "message_started" || event.type === "message_finished"))
834
- return `turn:${eventId}`;
835
- if (event.type === "thinking_started" || event.type === "thinking_delta" || event.type === "thinking_finished") {
836
- const thinkingId = thinkingEventNodeId(event);
837
- if (thinkingId)
838
- return `reasoning:${thinkingId}`;
839
- }
840
- if (event.type === "assistant_delta" || event.type === "assistant_message") {
841
- const assistantId = assistantEventNodeId(event);
842
- if (assistantId)
843
- return `assistant:${assistantId}`;
844
- }
845
- return `event:${event.type}:${eventId ?? cryptoSafeId(event)}`;
846
- }
847
- function messageTurnNodeId(eventId) {
848
- return `event:message:${eventId}`;
849
- }
850
- function assistantMessageNodeId(eventId) {
851
- return `event:assistant:${eventId}`;
852
- }
853
- function assistantEventNodeId(event) {
854
- if (!event.eventId)
855
- return undefined;
856
- const partIndex = typeof event.assistantIndex === "number" ? event.assistantIndex : event.contentIndex;
857
- return typeof partIndex === "number" ? `${event.eventId}:assistant:${partIndex}` : event.eventId;
858
- }
859
- function thinkingNodeId(eventId) {
860
- return `event:thinking:${eventId}`;
861
- }
862
- function thinkingEventNodeId(event) {
863
- if (!event.eventId)
264
+ catch {
864
265
  return undefined;
865
- const partIndex = typeof event.thinkingIndex === "number" ? event.thinkingIndex : event.contentIndex;
866
- return typeof partIndex === "number" ? `${event.eventId}:thinking:${partIndex}` : event.eventId;
867
- }
868
- function mapTraceNodesById(nodes) {
869
- const byId = new Map();
870
- for (const node of flattenTraceNodes(nodes))
871
- byId.set(node.id, node);
872
- return byId;
873
- }
874
- function sortTraceNodes(nodes) {
875
- nodes.sort(compareTraceNodes);
876
- for (const node of nodes)
877
- sortTraceNodes(node.children);
878
- }
879
- function compareTraceNodes(left, right) {
880
- const byOrder = compareTraceOrder(left.orderKey, right.orderKey);
881
- if (byOrder !== 0)
882
- return byOrder;
883
- return (left.startedAt ?? "").localeCompare(right.startedAt ?? "") || left.id.localeCompare(right.id);
266
+ }
884
267
  }
885
- function flattenTraceNodes(nodes) {
886
- return nodes.flatMap((node) => [node, ...flattenTraceNodes(node.children)]);
268
+ function defaultPiSessionDir(cwd) {
269
+ const agentDir = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
270
+ const safePath = `--${cwd.replace(/^[\\/]/, "").replace(/[\\/:]/g, "-")}--`;
271
+ return join(agentDir, "sessions", safePath);
887
272
  }
888
- function nestTraceNodes(nodes) {
889
- const byId = new Map();
890
- for (const node of nodes) {
891
- byId.set(node.id, { ...node, children: [...node.children] });
892
- }
893
- const nestedChildIds = new Set();
894
- for (const node of byId.values()) {
895
- if (!node.parentId)
273
+ function sessionModifiedIso(entries, headerTimestamp, statsMtime) {
274
+ let lastActivityTime;
275
+ for (const entry of entries) {
276
+ if (entry.type !== "message")
896
277
  continue;
897
- const parent = byId.get(node.parentId);
898
- if (!parent)
278
+ const timestamp = entry.message.timestamp;
279
+ if (typeof timestamp === "number") {
280
+ lastActivityTime = Math.max(lastActivityTime ?? 0, timestamp);
899
281
  continue;
900
- parent.children.push(node);
901
- nestedChildIds.add(node.id);
282
+ }
283
+ const entryTime = new Date(entry.timestamp).getTime();
284
+ if (!Number.isNaN(entryTime))
285
+ lastActivityTime = Math.max(lastActivityTime ?? 0, entryTime);
902
286
  }
903
- const roots = [...byId.values()].filter((node) => !nestedChildIds.has(node.id));
904
- sortTraceNodes(roots);
905
- return roots;
287
+ if (lastActivityTime)
288
+ return new Date(lastActivityTime).toISOString();
289
+ const headerTime = headerTimestamp ? new Date(headerTimestamp).getTime() : NaN;
290
+ return !Number.isNaN(headerTime) ? new Date(headerTime).toISOString() : statsMtime.toISOString();
906
291
  }
907
- function mergeToolEvent(target, update) {
908
- target.status = update.status;
909
- target.summary = update.summary ?? target.summary;
910
- target.input = update.input ?? target.input;
911
- target.output = update.output ?? target.output;
912
- target.error = update.error ?? target.error;
913
- target.completedAt = update.completedAt ?? target.completedAt;
914
- target.linkedPiboSessionId = update.linkedPiboSessionId ?? target.linkedPiboSessionId;
292
+ function readEntries(path) {
293
+ if (!existsSync(path))
294
+ return [];
295
+ const content = readFileSync(path, "utf8");
296
+ return parseSessionEntries(content).filter((entry) => entry.type !== "session");
915
297
  }
916
- function attachAsyncAgentRunNode(parent, piboSessionId, startedAt, delegation) {
917
- const node = createAsyncAgentRunNode(parent, piboSessionId, startedAt, delegation);
918
- if (!node)
919
- return;
920
- const existing = parent.children.find((child) => child.id === node.id);
921
- if (existing) {
922
- mergeToolEvent(existing, node);
923
- existing.runId = node.runId ?? existing.runId;
298
+ function annotateForkableUserMessageNodes(nodes, entries) {
299
+ const candidates = userMessageForkCandidates(entries);
300
+ if (!candidates.length)
924
301
  return;
925
- }
926
- parent.children.push(node);
927
- }
928
- function reconcileAsyncAgentRunStatuses(nodes) {
929
- const runSnapshots = new Map();
930
- for (const node of flattenTraceNodes(nodes)) {
931
- const snapshot = extractRunSnapshot(node.output);
932
- if (!snapshot)
933
- continue;
934
- const runId = stringValue(snapshot.runId);
935
- if (!runId)
936
- continue;
937
- runSnapshots.set(runId, {
938
- snapshot,
939
- completedAt: stringValue(snapshot.completedAt) ?? stringValue(snapshot.updatedAt) ?? node.completedAt,
940
- });
941
- }
942
- for (const node of flattenTraceNodes(nodes)) {
943
- if (node.type !== "agent.async" || !node.runId)
944
- continue;
945
- const latest = runSnapshots.get(node.runId);
946
- if (!latest)
302
+ const used = new Set();
303
+ for (const node of flattenTraceNodesForForkAnnotation(nodes)) {
304
+ if (node.type !== "user.message" || node.entryId)
947
305
  continue;
948
- const status = stringValue(latest.snapshot.status);
949
- if (status !== "completed" && status !== "cancelled" && status !== "failed")
306
+ const text = stringValue(node.output) ?? stringValue(node.summary) ?? "";
307
+ const candidate = candidates.find((item) => !used.has(item.entryId) && item.text === text);
308
+ if (!candidate)
950
309
  continue;
951
- node.status = status === "failed" ? "error" : "done";
952
- node.completedAt = latest.completedAt ?? node.completedAt;
953
- node.output = latest.snapshot;
954
- if (status === "failed")
955
- node.error = stringValue(latest.snapshot.summary) ?? node.error;
310
+ node.entryId = candidate.entryId;
311
+ used.add(candidate.entryId);
956
312
  }
957
313
  }
958
- function createAsyncAgentRunNode(parent, piboSessionId, startedAt, delegation) {
959
- if (!isRunStartToolNode(parent))
960
- return undefined;
961
- const run = extractRunSnapshot(parent.output);
962
- const input = isRecord(parent.input) ? parent.input : {};
963
- const toolName = stringValue(run?.toolName) ?? stringValue(input.toolName) ?? delegation?.title;
964
- if (!toolName || !isSubagentToolName(toolName))
965
- return undefined;
966
- const subagentName = stringValue(delegation?.summary) ?? subagentNameFromToolName(toolName);
967
- const runId = stringValue(run?.runId);
968
- const runStatus = stringValue(run?.status);
969
- const delegatedArguments = input.arguments;
970
- const completionPolicy = stringValue(run?.completionPolicy) ?? stringValue(input.completionPolicy);
971
- return {
972
- id: `${parent.id}:async-agent`,
973
- parentId: parent.id,
974
- piboSessionId,
975
- eventId: parent.eventId,
976
- toolCallId: parent.toolCallId,
977
- runId,
978
- type: "agent.async",
979
- title: subagentName,
980
- status: asyncAgentStatus(parent, runStatus),
981
- startedAt: delegation?.startedAt ?? startedAt ?? parent.startedAt,
982
- completedAt: runStatus === "completed" || runStatus === "cancelled" ? parent.completedAt : undefined,
983
- summary: `Started by ${parent.title}`,
984
- input: {
985
- startedBy: parent.title,
986
- startToolCallId: parent.toolCallId,
987
- toolName,
988
- subagentName,
989
- runId,
990
- completionPolicy,
991
- arguments: delegatedArguments,
992
- threadKey: isRecord(delegation?.input) ? delegation.input.threadKey : undefined,
993
- },
994
- output: run,
995
- error: parent.error,
996
- linkedPiboSessionId: delegation?.linkedPiboSessionId ?? parent.linkedPiboSessionId,
997
- source: parent.source,
998
- stableKey: runId ? `async-agent:${runId}` : `${parent.stableKey ?? parent.id}:async-agent`,
999
- orderKey: childTraceOrder(parent.orderKey, "agent.async"),
1000
- children: [],
314
+ function flattenTraceNodesForForkAnnotation(nodes) {
315
+ const flattened = [];
316
+ const visit = (items) => {
317
+ for (const item of items) {
318
+ flattened.push(item);
319
+ visit(item.children);
320
+ }
1001
321
  };
322
+ visit(nodes);
323
+ return flattened;
1002
324
  }
1003
- function isRunStartToolNode(node) {
1004
- return node.type === "tool.call" && node.title === "pibo_run_start";
1005
- }
1006
- function extractRunSnapshot(value) {
1007
- if (!isRecord(value))
1008
- return undefined;
1009
- if (isRunSnapshot(value))
1010
- return value;
1011
- if (isRecord(value.details) && isRunSnapshot(value.details))
1012
- return value.details;
1013
- return undefined;
1014
- }
1015
- function isRunSnapshot(value) {
1016
- return typeof value.runId === "string" && typeof value.toolName === "string";
1017
- }
1018
- function stringValue(value) {
1019
- return typeof value === "string" ? value : undefined;
1020
- }
1021
- function subagentNameFromToolName(toolName) {
1022
- return toolName.slice("pibo_subagent_".length);
1023
- }
1024
- function asyncAgentStatus(parent, runStatus) {
1025
- if (parent.status === "error" || runStatus === "failed")
1026
- return "error";
1027
- if (runStatus === "completed" || runStatus === "cancelled")
1028
- return "done";
1029
- return "running";
1030
- }
1031
- function mapChildren(sessions) {
1032
- const result = new Map();
1033
- for (const session of sessions) {
1034
- if (!session.parentId)
325
+ function userMessageForkCandidates(entries) {
326
+ const candidates = [];
327
+ for (const entry of entries) {
328
+ if (entry.type !== "message" || messageRole(entry) !== "user")
1035
329
  continue;
1036
- const children = result.get(session.parentId) ?? [];
1037
- children.push(session);
1038
- result.set(session.parentId, children);
330
+ const text = extractMessageText(messageContent(entry));
331
+ if (text)
332
+ candidates.push({ entryId: entry.id, text });
1039
333
  }
1040
- return result;
334
+ return candidates;
1041
335
  }
1042
- function mapSubagentSessionLinks(events) {
1043
- const result = new Map();
1044
- for (const storedEvent of events) {
1045
- const event = storedEvent.payload;
1046
- if (event.type !== "subagent_session" || !event.toolCallId)
1047
- continue;
1048
- result.set(event.toolCallId, event.childPiboSessionId);
1049
- }
1050
- return result;
1051
- }
1052
- function findLikelyChildSession(piboSessionId, toolName, event, childByParent) {
1053
- if (!isSubagentToolName(toolName))
1054
- return undefined;
1055
- const candidates = childByParent.get(piboSessionId)?.filter((session) => session.metadata?.subagentToolName === toolName) ?? [];
1056
- const threadKey = toolEventThreadKey(event);
1057
- if (threadKey) {
1058
- return candidates.find((session) => session.metadata?.threadKey === threadKey)?.id;
1059
- }
1060
- return candidates.length === 1 ? candidates[0].id : undefined;
1061
- }
1062
- function isSubagentToolName(name) {
1063
- return name.startsWith("pibo_subagent_");
1064
- }
1065
- function toolEventThreadKey(event) {
1066
- const args = "args" in event && event.args && typeof event.args === "object" && !Array.isArray(event.args) ? event.args : undefined;
1067
- const threadKey = args && "threadKey" in args ? args.threadKey : undefined;
1068
- return typeof threadKey === "string" && threadKey.trim() ? threadKey.trim() : undefined;
1069
- }
1070
- function messageStatus(message) {
1071
- if (message && typeof message === "object") {
1072
- const stopReason = message.stopReason;
1073
- const errorMessage = message.errorMessage;
1074
- if (stopReason === "error" || typeof errorMessage === "string")
1075
- return "error";
1076
- }
1077
- return "done";
1078
- }
1079
- function messageError(message) {
1080
- if (!message || typeof message !== "object")
1081
- return undefined;
1082
- const errorMessage = message.errorMessage;
1083
- return typeof errorMessage === "string" ? errorMessage : undefined;
336
+ function messageRole(entry) {
337
+ return entry.type === "message" ? entry.message.role : undefined;
1084
338
  }
1085
- function hasVisibleText(value) {
1086
- return typeof value === "string" && value.trim().length > 0;
339
+ function messageContent(entry) {
340
+ return entry.type === "message" ? entry.message.content : undefined;
1087
341
  }
1088
- function extractText(content) {
342
+ function extractMessageText(content) {
1089
343
  if (typeof content === "string")
1090
344
  return content;
1091
345
  if (!Array.isArray(content))
1092
346
  return "";
1093
347
  return content
1094
348
  .map((part) => {
349
+ if (!part || typeof part !== "object")
350
+ return "";
1095
351
  const typed = part;
1096
- if (typed.type === "text" && typeof typed.text === "string")
1097
- return typed.text;
1098
- return "";
352
+ return typed.type === "text" && typeof typed.text === "string" ? typed.text : "";
1099
353
  })
1100
354
  .join("");
1101
355
  }
1102
- function stringifyPreview(value) {
1103
- if (typeof value === "string")
1104
- return value;
1105
- try {
1106
- return JSON.stringify(value);
1107
- }
1108
- catch {
1109
- return String(value);
1110
- }
1111
- }
1112
- function parseRunNotificationText(text) {
1113
- const trimmed = text.trim();
1114
- const start = "<pibo_run_notification>";
1115
- const end = "</pibo_run_notification>";
1116
- if (!trimmed.startsWith(start) || !trimmed.endsWith(end))
1117
- return undefined;
1118
- const jsonText = trimmed.slice(start.length, trimmed.length - end.length).trim();
1119
- try {
1120
- const parsed = JSON.parse(jsonText);
1121
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
1122
- return undefined;
1123
- return parsed;
1124
- }
1125
- catch {
1126
- return undefined;
1127
- }
1128
- }
1129
- function createRunNotificationNode(input) {
1130
- const runs = runNotificationRuns(input.notification);
1131
- const singleRun = runs.length === 1 ? runs[0] : undefined;
1132
- const failedCount = countRunGroup(input.notification.failed);
1133
- const runningCount = countRunGroup(input.notification.running);
1134
- return {
1135
- id: input.id,
1136
- entryId: input.entryId,
1137
- piboSessionId: input.piboSessionId,
1138
- eventId: input.eventId,
1139
- runId: typeof singleRun?.runId === "string" ? singleRun.runId : undefined,
1140
- type: "yielded.run",
1141
- title: "Run Notification",
1142
- status: failedCount > 0 ? "error" : runningCount > 0 ? "running" : "done",
1143
- startedAt: input.startedAt,
1144
- summary: runNotificationSummary(input.notification),
1145
- output: input.notification,
1146
- source: input.source,
1147
- stableKey: input.stableKey ?? input.id,
1148
- orderKey: input.orderKey,
1149
- children: [],
1150
- };
1151
- }
1152
- function runNotificationRuns(notification) {
1153
- return [
1154
- ...runGroup(notification.completed),
1155
- ...runGroup(notification.failed),
1156
- ...runGroup(notification.cancelled),
1157
- ...runGroup(notification.running),
1158
- ];
1159
- }
1160
- function runGroup(value) {
1161
- return Array.isArray(value) ? value.filter(isRecord) : [];
1162
- }
1163
- function countRunGroup(value) {
1164
- return Array.isArray(value) ? value.length : 0;
1165
- }
1166
- function runNotificationSummary(notification) {
1167
- const parts = [
1168
- [countRunGroup(notification.completed), "completed"],
1169
- [countRunGroup(notification.failed), "failed"],
1170
- [countRunGroup(notification.cancelled), "cancelled"],
1171
- [countRunGroup(notification.running), "running"],
1172
- ]
1173
- .filter(([count]) => Number(count) > 0)
1174
- .map(([count, label]) => `${count} ${label}`);
1175
- return parts.length ? parts.join(", ") : "No yielded run updates";
1176
- }
1177
- function isRecord(value) {
1178
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1179
- }
1180
- function cryptoSafeId(value) {
1181
- return Buffer.from(JSON.stringify(value)).toString("base64url").slice(0, 48);
356
+ function stringValue(value) {
357
+ return typeof value === "string" ? value : undefined;
1182
358
  }