@ashlr/hub 3.11.5 → 3.13.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 (408) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +29 -16
  3. package/dist/authority-surface.json +91 -45
  4. package/dist/build-identity.json +2 -2
  5. package/dist/cli/authority.d.ts +145 -33
  6. package/dist/cli/authority.js +1196 -313
  7. package/dist/cli/authority.js.map +1 -1
  8. package/dist/cli/cloud.js +12 -3
  9. package/dist/cli/cloud.js.map +1 -1
  10. package/dist/core/authority/protected-paths.js +11 -0
  11. package/dist/core/authority/protected-paths.js.map +1 -1
  12. package/dist/core/authority/resident.d.ts +101 -0
  13. package/dist/core/authority/resident.js +246 -0
  14. package/dist/core/authority/resident.js.map +1 -0
  15. package/dist/core/authority/trust-roots.js +7 -1
  16. package/dist/core/authority/trust-roots.js.map +1 -1
  17. package/dist/core/authority/types.d.ts +43 -0
  18. package/dist/core/authority/types.js +6 -0
  19. package/dist/core/authority/types.js.map +1 -1
  20. package/dist/core/cloud/budget.js +11 -1
  21. package/dist/core/cloud/budget.js.map +1 -1
  22. package/dist/core/cloud/cloud-api.d.ts +25 -2
  23. package/dist/core/cloud/cloud-api.js +139 -5
  24. package/dist/core/cloud/cloud-api.js.map +1 -1
  25. package/dist/core/cloud/pr-actions.d.ts +93 -0
  26. package/dist/core/cloud/pr-actions.js +436 -0
  27. package/dist/core/cloud/pr-actions.js.map +1 -0
  28. package/dist/core/cloud/pr-preview.d.ts +128 -0
  29. package/dist/core/cloud/pr-preview.js +228 -0
  30. package/dist/core/cloud/pr-preview.js.map +1 -0
  31. package/dist/core/cloud/store.d.ts +2 -0
  32. package/dist/core/cloud/store.js +28 -0
  33. package/dist/core/cloud/store.js.map +1 -1
  34. package/dist/core/cloud/timeline-api.d.ts +24 -0
  35. package/dist/core/cloud/timeline-api.js +46 -0
  36. package/dist/core/cloud/timeline-api.js.map +1 -0
  37. package/dist/core/cloud/timeline-types.d.ts +62 -0
  38. package/dist/core/cloud/timeline-types.js +36 -0
  39. package/dist/core/cloud/timeline-types.js.map +1 -0
  40. package/dist/core/cloud/timeline.d.ts +102 -0
  41. package/dist/core/cloud/timeline.js +919 -0
  42. package/dist/core/cloud/timeline.js.map +1 -0
  43. package/dist/core/cloud/tracker.js +67 -0
  44. package/dist/core/cloud/tracker.js.map +1 -1
  45. package/dist/core/cloud/types.d.ts +38 -0
  46. package/dist/core/cloud/types.js +1 -1
  47. package/dist/core/cloud/types.js.map +1 -1
  48. package/dist/core/daemon/service-install-authority.d.ts +10 -2
  49. package/dist/core/daemon/service-install-authority.js +14 -5
  50. package/dist/core/daemon/service-install-authority.js.map +1 -1
  51. package/dist/core/daemon/service.d.ts +15 -0
  52. package/dist/core/daemon/service.js +26 -0
  53. package/dist/core/daemon/service.js.map +1 -1
  54. package/dist/core/fleet/cloud-intake.d.ts +95 -0
  55. package/dist/core/fleet/cloud-intake.js +557 -0
  56. package/dist/core/fleet/cloud-intake.js.map +1 -0
  57. package/dist/core/fleet/dispatch-router.d.ts +13 -0
  58. package/dist/core/fleet/dispatch-router.js +32 -8
  59. package/dist/core/fleet/dispatch-router.js.map +1 -1
  60. package/dist/core/fleet/fleet-merge-state.d.ts +10 -0
  61. package/dist/core/fleet/fleet-merge-state.js.map +1 -1
  62. package/dist/core/fleet/host-merge.d.ts +5 -0
  63. package/dist/core/fleet/host-merge.js +11 -0
  64. package/dist/core/fleet/host-merge.js.map +1 -1
  65. package/dist/core/fleet/merge-gates.d.ts +8 -0
  66. package/dist/core/fleet/merge-gates.js +25 -5
  67. package/dist/core/fleet/merge-gates.js.map +1 -1
  68. package/dist/core/fleet/standing-merge-pass.js +30 -0
  69. package/dist/core/fleet/standing-merge-pass.js.map +1 -1
  70. package/dist/core/fleet/tick-hooks-live.d.ts +9 -0
  71. package/dist/core/fleet/tick-hooks-live.js +44 -5
  72. package/dist/core/fleet/tick-hooks-live.js.map +1 -1
  73. package/dist/core/fleet/verify-check-run.d.ts +90 -0
  74. package/dist/core/fleet/verify-check-run.js +274 -0
  75. package/dist/core/fleet/verify-check-run.js.map +1 -0
  76. package/dist/core/routing/budget-api.d.ts +11 -0
  77. package/dist/core/routing/budget-api.js +64 -8
  78. package/dist/core/routing/budget-api.js.map +1 -1
  79. package/dist/core/routing/budget-store.d.ts +22 -1
  80. package/dist/core/routing/budget-store.js +22 -8
  81. package/dist/core/routing/budget-store.js.map +1 -1
  82. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  83. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +8 -2
  84. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +7 -1
  85. package/dist/core/verse/account-health.js +9 -3
  86. package/dist/core/verse/account-health.js.map +1 -1
  87. package/dist/core/verse/activity-api.d.ts +5 -1
  88. package/dist/core/verse/activity-api.js +62 -14
  89. package/dist/core/verse/activity-api.js.map +1 -1
  90. package/dist/core/verse/authority-api.d.ts +9 -1
  91. package/dist/core/verse/authority-api.js +82 -2
  92. package/dist/core/verse/authority-api.js.map +1 -1
  93. package/dist/core/verse/seat-readiness.d.ts +25 -0
  94. package/dist/core/verse/seat-readiness.js +43 -6
  95. package/dist/core/verse/seat-readiness.js.map +1 -1
  96. package/dist/core/verse/verse-api.d.ts +3 -1
  97. package/dist/core/verse/verse-api.js +6 -0
  98. package/dist/core/verse/verse-api.js.map +1 -1
  99. package/dist/core/web/public/next/assets/{ActionMenu-DffwPklw.js → ActionMenu-Dwjk6rUQ.js} +2 -2
  100. package/dist/core/web/public/next/assets/{ActionMenu-DffwPklw.js.map → ActionMenu-Dwjk6rUQ.js.map} +1 -1
  101. package/dist/core/web/public/next/assets/Advanced-cVYTAsfB.js +2 -0
  102. package/dist/core/web/public/next/assets/{Advanced-CxzE6ekM.js.map → Advanced-cVYTAsfB.js.map} +1 -1
  103. package/dist/core/web/public/next/assets/App-IsaWDsdF.js +7 -0
  104. package/dist/core/web/public/next/assets/{App-DFlp-vdv.js.map → App-IsaWDsdF.js.map} +1 -1
  105. package/dist/core/web/public/next/assets/AppsSection-DDqeSrty.js +2 -0
  106. package/dist/core/web/public/next/assets/{AppsSection-Ct2O605-.js.map → AppsSection-DDqeSrty.js.map} +1 -1
  107. package/dist/core/web/public/next/assets/{AreaTrend-o-GLl2Is.js → AreaTrend-C32rUaxm.js} +2 -2
  108. package/dist/core/web/public/next/assets/{AreaTrend-o-GLl2Is.js.map → AreaTrend-C32rUaxm.js.map} +1 -1
  109. package/dist/core/web/public/next/assets/AutonomyOffState-CmSSTHVe.css +1 -0
  110. package/dist/core/web/public/next/assets/AutonomyOffState-CpFYS3tQ.js +3 -0
  111. package/dist/core/web/public/next/assets/AutonomyOffState-CpFYS3tQ.js.map +1 -0
  112. package/dist/core/web/public/next/assets/AutonomySection-Dwn8UtOy.js +2 -0
  113. package/dist/core/web/public/next/assets/{AutonomySection-BTg7yVa1.js.map → AutonomySection-Dwn8UtOy.js.map} +1 -1
  114. package/dist/core/web/public/next/assets/{BranchBar-BjPFtGsj.js → BranchBar-ISZ7xUCj.js} +2 -2
  115. package/dist/core/web/public/next/assets/{BranchBar-BjPFtGsj.js.map → BranchBar-ISZ7xUCj.js.map} +1 -1
  116. package/dist/core/web/public/next/assets/BudgetControl-BARVp-En.js +2 -0
  117. package/dist/core/web/public/next/assets/BudgetControl-BARVp-En.js.map +1 -0
  118. package/dist/core/web/public/next/assets/{Button-OjVJSrFq.js → Button-DtE0rlWD.js} +2 -2
  119. package/dist/core/web/public/next/assets/{Button-OjVJSrFq.js.map → Button-DtE0rlWD.js.map} +1 -1
  120. package/dist/core/web/public/next/assets/{CapacityStrip-Bx4c3dxD.js → CapacityStrip-DKbKA_Aa.js} +2 -2
  121. package/dist/core/web/public/next/assets/{CapacityStrip-Bx4c3dxD.js.map → CapacityStrip-DKbKA_Aa.js.map} +1 -1
  122. package/dist/core/web/public/next/assets/{ChartFrame-B_w2Siqg.js → ChartFrame-DK_BDXCt.js} +2 -2
  123. package/dist/core/web/public/next/assets/{ChartFrame-B_w2Siqg.js.map → ChartFrame-DK_BDXCt.js.map} +1 -1
  124. package/dist/core/web/public/next/assets/ChatSection-C9myY4ei.js +3 -0
  125. package/dist/core/web/public/next/assets/ChatSection-C9myY4ei.js.map +1 -0
  126. package/dist/core/web/public/next/assets/{CloudBudgetForm-5Gf4iAok.js → CloudBudgetForm-CvjK4Oh6.js} +2 -2
  127. package/dist/core/web/public/next/assets/{CloudBudgetForm-5Gf4iAok.js.map → CloudBudgetForm-CvjK4Oh6.js.map} +1 -1
  128. package/dist/core/web/public/next/assets/{CommandPalette-iTpk6I8r.js → CommandPalette-DzPsth0u.js} +2 -2
  129. package/dist/core/web/public/next/assets/{CommandPalette-iTpk6I8r.js.map → CommandPalette-DzPsth0u.js.map} +1 -1
  130. package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js +3 -0
  131. package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js.map +1 -0
  132. package/dist/core/web/public/next/assets/{ConfirmDialog-_S9iE-cJ.js → ConfirmDialog-CLUhzaBj.js} +2 -2
  133. package/dist/core/web/public/next/assets/{ConfirmDialog-_S9iE-cJ.js.map → ConfirmDialog-CLUhzaBj.js.map} +1 -1
  134. package/dist/core/web/public/next/assets/{DeleteChatDialog-KUYUygiA.js → DeleteChatDialog-C_eDhV8b.js} +2 -2
  135. package/dist/core/web/public/next/assets/{DeleteChatDialog-KUYUygiA.js.map → DeleteChatDialog-C_eDhV8b.js.map} +1 -1
  136. package/dist/core/web/public/next/assets/{Dialog-BuIaG6HF.js → Dialog-BRd_B9OE.js} +2 -2
  137. package/dist/core/web/public/next/assets/{Dialog-BuIaG6HF.js.map → Dialog-BRd_B9OE.js.map} +1 -1
  138. package/dist/core/web/public/next/assets/{DiffPane-De4IQt82.js → DiffPane-Cpr9soB2.js} +2 -2
  139. package/dist/core/web/public/next/assets/{DiffPane-De4IQt82.js.map → DiffPane-Cpr9soB2.js.map} +1 -1
  140. package/dist/core/web/public/next/assets/{DiffViewer-B75t6Ile.js → DiffViewer-CNwd0W3Q.js} +2 -2
  141. package/dist/core/web/public/next/assets/{DiffViewer-B75t6Ile.js.map → DiffViewer-CNwd0W3Q.js.map} +1 -1
  142. package/dist/core/web/public/next/assets/DockHost-BcEq2qaS.js +2 -0
  143. package/dist/core/web/public/next/assets/{DockHost-BPqyhtCP.js.map → DockHost-BcEq2qaS.js.map} +1 -1
  144. package/dist/core/web/public/next/assets/{EmptyState-DXkT4vhW.js → EmptyState-DsN1H6MC.js} +2 -2
  145. package/dist/core/web/public/next/assets/{EmptyState-DXkT4vhW.js.map → EmptyState-DsN1H6MC.js.map} +1 -1
  146. package/dist/core/web/public/next/assets/{Epistemic-CfqFe_aP.js → Epistemic-fycQTBRO.js} +2 -2
  147. package/dist/core/web/public/next/assets/{Epistemic-CfqFe_aP.js.map → Epistemic-fycQTBRO.js.map} +1 -1
  148. package/dist/core/web/public/next/assets/EvidenceTimeline-PBDAiSuG.css +1 -0
  149. package/dist/core/web/public/next/assets/EvidenceTimeline-sCCAdnBK.js +2 -0
  150. package/dist/core/web/public/next/assets/EvidenceTimeline-sCCAdnBK.js.map +1 -0
  151. package/dist/core/web/public/next/assets/{FleetSection-B7f-XBiX.js → FleetSection-BG8iGraG.js} +3 -3
  152. package/dist/core/web/public/next/assets/{FleetSection-B7f-XBiX.js.map → FleetSection-BG8iGraG.js.map} +1 -1
  153. package/dist/core/web/public/next/assets/{Funnel-pXYySwXQ.js → Funnel-B88_wpA4.js} +2 -2
  154. package/dist/core/web/public/next/assets/{Funnel-pXYySwXQ.js.map → Funnel-B88_wpA4.js.map} +1 -1
  155. package/dist/core/web/public/next/assets/{GearTray-gj6lT7ba.js → GearTray-CpDt0xwj.js} +2 -2
  156. package/dist/core/web/public/next/assets/{GearTray-gj6lT7ba.js.map → GearTray-CpDt0xwj.js.map} +1 -1
  157. package/dist/core/web/public/next/assets/{GrowthSection-D8e9m9Wy.js → GrowthSection-BvZezOsX.js} +2 -2
  158. package/dist/core/web/public/next/assets/{GrowthSection-D8e9m9Wy.js.map → GrowthSection-BvZezOsX.js.map} +1 -1
  159. package/dist/core/web/public/next/assets/{HandoffDialog-VfKxKhxF.js → HandoffDialog-B1G6gQyk.js} +2 -2
  160. package/dist/core/web/public/next/assets/{HandoffDialog-VfKxKhxF.js.map → HandoffDialog-B1G6gQyk.js.map} +1 -1
  161. package/dist/core/web/public/next/assets/{Input-u1YR_Ogl.js → Input-CI0yBHmn.js} +2 -2
  162. package/dist/core/web/public/next/assets/{Input-u1YR_Ogl.js.map → Input-CI0yBHmn.js.map} +1 -1
  163. package/dist/core/web/public/next/assets/{LeaderCard-BDELBrnx.js → LeaderCard-BxxiEg4e.js} +2 -2
  164. package/dist/core/web/public/next/assets/{LeaderCard-BDELBrnx.js.map → LeaderCard-BxxiEg4e.js.map} +1 -1
  165. package/dist/core/web/public/next/assets/{MatrixHeatmap-NKLF2srR.js → MatrixHeatmap-iPFEU2Tv.js} +2 -2
  166. package/dist/core/web/public/next/assets/{MatrixHeatmap-NKLF2srR.js.map → MatrixHeatmap-iPFEU2Tv.js.map} +1 -1
  167. package/dist/core/web/public/next/assets/McpSection-nuXer4K-.js +2 -0
  168. package/dist/core/web/public/next/assets/{McpSection-D1tDvlRa.js.map → McpSection-nuXer4K-.js.map} +1 -1
  169. package/dist/core/web/public/next/assets/{MessageMarkdown-DlfLEJxu.js → MessageMarkdown-BCe4TsXk.js} +3 -3
  170. package/dist/core/web/public/next/assets/{MessageMarkdown-DlfLEJxu.js.map → MessageMarkdown-BCe4TsXk.js.map} +1 -1
  171. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-BYZzI115.js → MessageMarkdownRenderer-DL3LU5kL.js} +2 -2
  172. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-BYZzI115.js.map → MessageMarkdownRenderer-DL3LU5kL.js.map} +1 -1
  173. package/dist/core/web/public/next/assets/{Meter-BSVhU43Q.js → Meter-b69LM0mU.js} +2 -2
  174. package/dist/core/web/public/next/assets/{Meter-BSVhU43Q.js.map → Meter-b69LM0mU.js.map} +1 -1
  175. package/dist/core/web/public/next/assets/{MindSection-lqV2e_Sq.js → MindSection-Dc5v5rH3.js} +2 -2
  176. package/dist/core/web/public/next/assets/{MindSection-lqV2e_Sq.js.map → MindSection-Dc5v5rH3.js.map} +1 -1
  177. package/dist/core/web/public/next/assets/{MutationTokenDialog-CLGP72g6.js → MutationTokenDialog-Bm34BNVV.js} +2 -2
  178. package/dist/core/web/public/next/assets/{MutationTokenDialog-CLGP72g6.js.map → MutationTokenDialog-Bm34BNVV.js.map} +1 -1
  179. package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js +3 -0
  180. package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js.map +1 -0
  181. package/dist/core/web/public/next/assets/NeedsYouList-CH6Mq-E_.css +1 -0
  182. package/dist/core/web/public/next/assets/NeedsYouList-D5Kk549g.js +2 -0
  183. package/dist/core/web/public/next/assets/{NeedsYouList-eBOlJr0b.js.map → NeedsYouList-D5Kk549g.js.map} +1 -1
  184. package/dist/core/web/public/next/assets/{NewChatDialog-DoYTH26M.js → NewChatDialog-BqFTWgHU.js} +2 -2
  185. package/dist/core/web/public/next/assets/{NewChatDialog-DoYTH26M.js.map → NewChatDialog-BqFTWgHU.js.map} +1 -1
  186. package/dist/core/web/public/next/assets/OnboardingFlow-DcDsguAM.js +3 -0
  187. package/dist/core/web/public/next/assets/OnboardingFlow-DcDsguAM.js.map +1 -0
  188. package/dist/core/web/public/next/assets/OnboardingGate-BZafM1Vf.js +3 -0
  189. package/dist/core/web/public/next/assets/{OnboardingGate-DrDEVBqw.js.map → OnboardingGate-BZafM1Vf.js.map} +1 -1
  190. package/dist/core/web/public/next/assets/{PreviewPane-ULN673zm.js → PreviewPane-zT3gK9TD.js} +2 -2
  191. package/dist/core/web/public/next/assets/{PreviewPane-ULN673zm.js.map → PreviewPane-zT3gK9TD.js.map} +1 -1
  192. package/dist/core/web/public/next/assets/{ProviderLogo-8WaUjTlN.js → ProviderLogo-AwHn2sKm.js} +2 -2
  193. package/dist/core/web/public/next/assets/{ProviderLogo-8WaUjTlN.js.map → ProviderLogo-AwHn2sKm.js.map} +1 -1
  194. package/dist/core/web/public/next/assets/{RailStatus-Ckw9nvYU.js → RailStatus-xHrovWvI.js} +2 -2
  195. package/dist/core/web/public/next/assets/{RailStatus-Ckw9nvYU.js.map → RailStatus-xHrovWvI.js.map} +1 -1
  196. package/dist/core/web/public/next/assets/{RefreshIndicator-DGubF4vR.js → RefreshIndicator-SEFZlMB2.js} +2 -2
  197. package/dist/core/web/public/next/assets/{RefreshIndicator-DGubF4vR.js.map → RefreshIndicator-SEFZlMB2.js.map} +1 -1
  198. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BahEaY4d.js → ResourcePoolConsoleApp-CAxPQ4sZ.js} +3 -3
  199. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BahEaY4d.js.map → ResourcePoolConsoleApp-CAxPQ4sZ.js.map} +1 -1
  200. package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js +3 -0
  201. package/dist/core/web/public/next/assets/{ResourcesChrome-C2ZrA7la.js.map → ResourcesChrome-BnhnEdJe.js.map} +1 -1
  202. package/dist/core/web/public/next/assets/{ResourcesDrawer-BC93fzwQ.js → ResourcesDrawer-BAFGodny.js} +2 -2
  203. package/dist/core/web/public/next/assets/{ResourcesDrawer-BC93fzwQ.js.map → ResourcesDrawer-BAFGodny.js.map} +1 -1
  204. package/dist/core/web/public/next/assets/{RouteErrorBoundary-BvhHNpE_.js → RouteErrorBoundary-C8WGiixc.js} +2 -2
  205. package/dist/core/web/public/next/assets/{RouteErrorBoundary-BvhHNpE_.js.map → RouteErrorBoundary-C8WGiixc.js.map} +1 -1
  206. package/dist/core/web/public/next/assets/{RunInCloudAction-Dywfnw0C.js → RunInCloudAction-1-IPLYhf.js} +2 -2
  207. package/dist/core/web/public/next/assets/{RunInCloudAction-Dywfnw0C.js.map → RunInCloudAction-1-IPLYhf.js.map} +1 -1
  208. package/dist/core/web/public/next/assets/{SeatSelector-CH7hTgwy.js → SeatSelector-DpwNiX8F.js} +2 -2
  209. package/dist/core/web/public/next/assets/{SeatSelector-CH7hTgwy.js.map → SeatSelector-DpwNiX8F.js.map} +1 -1
  210. package/dist/core/web/public/next/assets/{Segmented-Wynbg0F5.js → Segmented-Wt1ATod9.js} +2 -2
  211. package/dist/core/web/public/next/assets/{Segmented-Wynbg0F5.js.map → Segmented-Wt1ATod9.js.map} +1 -1
  212. package/dist/core/web/public/next/assets/{Select-DMyLCkId.js → Select-By-V9lMc.js} +2 -2
  213. package/dist/core/web/public/next/assets/{Select-DMyLCkId.js.map → Select-By-V9lMc.js.map} +1 -1
  214. package/dist/core/web/public/next/assets/{SessionGate-8RtQFWeZ.js → SessionGate-WROS02tK.js} +2 -2
  215. package/dist/core/web/public/next/assets/{SessionGate-8RtQFWeZ.js.map → SessionGate-WROS02tK.js.map} +1 -1
  216. package/dist/core/web/public/next/assets/{SessionInsightChip-zBJbKv2L.js → SessionInsightChip-DNUcruwp.js} +2 -2
  217. package/dist/core/web/public/next/assets/{SessionInsightChip-zBJbKv2L.js.map → SessionInsightChip-DNUcruwp.js.map} +1 -1
  218. package/dist/core/web/public/next/assets/{SessionSearch-DfJIcxxM.js → SessionSearch-UHtt7a8f.js} +2 -2
  219. package/dist/core/web/public/next/assets/{SessionSearch-DfJIcxxM.js.map → SessionSearch-UHtt7a8f.js.map} +1 -1
  220. package/dist/core/web/public/next/assets/{SettingsSection-Da9RYyH5.js → SettingsSection-Bf74l0Gj.js} +2 -2
  221. package/dist/core/web/public/next/assets/{SettingsSection-Da9RYyH5.js.map → SettingsSection-Bf74l0Gj.js.map} +1 -1
  222. package/dist/core/web/public/next/assets/SetupChecklist-BhZpFLsj.css +1 -0
  223. package/dist/core/web/public/next/assets/SetupChecklist-CzpEcfOl.js +2 -0
  224. package/dist/core/web/public/next/assets/SetupChecklist-CzpEcfOl.js.map +1 -0
  225. package/dist/core/web/public/next/assets/{Sheet-DhXyIDmq.js → Sheet-HkBOBMTT.js} +2 -2
  226. package/dist/core/web/public/next/assets/{Sheet-DhXyIDmq.js.map → Sheet-HkBOBMTT.js.map} +1 -1
  227. package/dist/core/web/public/next/assets/{ShortcutsOverlay-Bi5f-wUw.js → ShortcutsOverlay-DiigiT8H.js} +2 -2
  228. package/dist/core/web/public/next/assets/{ShortcutsOverlay-Bi5f-wUw.js.map → ShortcutsOverlay-DiigiT8H.js.map} +1 -1
  229. package/dist/core/web/public/next/assets/Sidebar-C9YtBYVZ.js +3 -0
  230. package/dist/core/web/public/next/assets/Sidebar-C9YtBYVZ.js.map +1 -0
  231. package/dist/core/web/public/next/assets/{Slider-Bd9YFWEV.js → Slider-DaEDws-b.js} +2 -2
  232. package/dist/core/web/public/next/assets/{Slider-Bd9YFWEV.js.map → Slider-DaEDws-b.js.map} +1 -1
  233. package/dist/core/web/public/next/assets/{StatTile-DScTd3c-.js → StatTile-CTX41O6y.js} +2 -2
  234. package/dist/core/web/public/next/assets/{StatTile-DScTd3c-.js.map → StatTile-CTX41O6y.js.map} +1 -1
  235. package/dist/core/web/public/next/assets/{StatusBadge-DQ1UtQAJ.js → StatusBadge-CXG3iNL4.js} +2 -2
  236. package/dist/core/web/public/next/assets/{StatusBadge-DQ1UtQAJ.js.map → StatusBadge-CXG3iNL4.js.map} +1 -1
  237. package/dist/core/web/public/next/assets/{StepBand-BB3IJxhr.js → StepBand-jJTqYIdX.js} +2 -2
  238. package/dist/core/web/public/next/assets/{StepBand-BB3IJxhr.js.map → StepBand-jJTqYIdX.js.map} +1 -1
  239. package/dist/core/web/public/next/assets/{Surface-DWMtQe3Q.js → Surface-5bNA08tK.js} +2 -2
  240. package/dist/core/web/public/next/assets/{Surface-DWMtQe3Q.js.map → Surface-5bNA08tK.js.map} +1 -1
  241. package/dist/core/web/public/next/assets/{Swimlane-DcENqtdp.js → Swimlane-LrslsGxw.js} +2 -2
  242. package/dist/core/web/public/next/assets/{Swimlane-DcENqtdp.js.map → Swimlane-LrslsGxw.js.map} +1 -1
  243. package/dist/core/web/public/next/assets/{Switch-CenChEYf.js → Switch-BmCzfFnu.js} +2 -2
  244. package/dist/core/web/public/next/assets/{Switch-CenChEYf.js.map → Switch-BmCzfFnu.js.map} +1 -1
  245. package/dist/core/web/public/next/assets/{Tag-D4k5E3u0.js → Tag-WSUIaMVy.js} +2 -2
  246. package/dist/core/web/public/next/assets/{Tag-D4k5E3u0.js.map → Tag-WSUIaMVy.js.map} +1 -1
  247. package/dist/core/web/public/next/assets/{TerminalPane-DCQTukcE.js → TerminalPane-BVFgYX6K.js} +5 -5
  248. package/dist/core/web/public/next/assets/{TerminalPane-DCQTukcE.js.map → TerminalPane-BVFgYX6K.js.map} +1 -1
  249. package/dist/core/web/public/next/assets/{UniverseConsoleApp-DsuWT0pi.js → UniverseConsoleApp-BpphLqoz.js} +2 -2
  250. package/dist/core/web/public/next/assets/{UniverseConsoleApp-DsuWT0pi.js.map → UniverseConsoleApp-BpphLqoz.js.map} +1 -1
  251. package/dist/core/web/public/next/assets/{UniverseView-DyI5ApsA.js → UniverseView-DbpbSMwO.js} +4 -4
  252. package/dist/core/web/public/next/assets/{UniverseView-DyI5ApsA.js.map → UniverseView-DbpbSMwO.js.map} +1 -1
  253. package/dist/core/web/public/next/assets/{UsageSection-Imr28nwK.js → UsageSection-CUlaKtws.js} +3 -3
  254. package/dist/core/web/public/next/assets/{UsageSection-Imr28nwK.js.map → UsageSection-CUlaKtws.js.map} +1 -1
  255. package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js +3 -0
  256. package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js.map +1 -0
  257. package/dist/core/web/public/next/assets/{Workspace-CpxBO98E.js → Workspace-RXy0pqp6.js} +5 -5
  258. package/dist/core/web/public/next/assets/{Workspace-CpxBO98E.js.map → Workspace-RXy0pqp6.js.map} +1 -1
  259. package/dist/core/web/public/next/assets/{actions-DE8NoWV_.js → actions-BZTidCXZ.js} +2 -2
  260. package/dist/core/web/public/next/assets/{actions-DE8NoWV_.js.map → actions-BZTidCXZ.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/{apps-model-CFGCUu9p.js → apps-model-CHO133qt.js} +2 -2
  262. package/dist/core/web/public/next/assets/{apps-model-CFGCUu9p.js.map → apps-model-CHO133qt.js.map} +1 -1
  263. package/dist/core/web/public/next/assets/{authority-model-CmnfJzmM.js → authority-model-8NeAEwAF.js} +2 -2
  264. package/dist/core/web/public/next/assets/{authority-model-CmnfJzmM.js.map → authority-model-8NeAEwAF.js.map} +1 -1
  265. package/dist/core/web/public/next/assets/{budget-queries-DjrPRFwl.js → budget-queries-DFF-3ICg.js} +2 -2
  266. package/dist/core/web/public/next/assets/{budget-queries-DjrPRFwl.js.map → budget-queries-DFF-3ICg.js.map} +1 -1
  267. package/dist/core/web/public/next/assets/{capacity-strip-model-C7cdQnuK.js → capacity-strip-model-5ViUgUlP.js} +2 -2
  268. package/dist/core/web/public/next/assets/{capacity-strip-model-C7cdQnuK.js.map → capacity-strip-model-5ViUgUlP.js.map} +1 -1
  269. package/dist/core/web/public/next/assets/{charts-DUD_jprE.js → charts-CzxWrZn7.js} +2 -2
  270. package/dist/core/web/public/next/assets/{charts-DUD_jprE.js.map → charts-CzxWrZn7.js.map} +1 -1
  271. package/dist/core/web/public/next/assets/cloud-model-CfRydq8N.js +2 -0
  272. package/dist/core/web/public/next/assets/{cloud-model-DoxBMDvx.js.map → cloud-model-CfRydq8N.js.map} +1 -1
  273. package/dist/core/web/public/next/assets/{cloud-queries-CTGvO-k-.js → cloud-queries-DmptbjS8.js} +2 -2
  274. package/dist/core/web/public/next/assets/{cloud-queries-CTGvO-k-.js.map → cloud-queries-DmptbjS8.js.map} +1 -1
  275. package/dist/core/web/public/next/assets/{command-catalog-CmrHNFzh.js → command-catalog-ffCAijVY.js} +2 -2
  276. package/dist/core/web/public/next/assets/{command-catalog-CmrHNFzh.js.map → command-catalog-ffCAijVY.js.map} +1 -1
  277. package/dist/core/web/public/next/assets/{context-model-2Owp2jYF.js → context-model-Bb15chFt.js} +2 -2
  278. package/dist/core/web/public/next/assets/{context-model-2Owp2jYF.js.map → context-model-Bb15chFt.js.map} +1 -1
  279. package/dist/core/web/public/next/assets/{context-model-9xywbXxX.js → context-model-CDeyP0cA.js} +2 -2
  280. package/dist/core/web/public/next/assets/{context-model-9xywbXxX.js.map → context-model-CDeyP0cA.js.map} +1 -1
  281. package/dist/core/web/public/next/assets/{context-queries-wvcRnV-I.js → context-queries-_9bFWb9v.js} +2 -2
  282. package/dist/core/web/public/next/assets/{context-queries-wvcRnV-I.js.map → context-queries-_9bFWb9v.js.map} +1 -1
  283. package/dist/core/web/public/next/assets/{control-queries-DB6Kh7UN.js → control-queries-CXtmZZH6.js} +2 -2
  284. package/dist/core/web/public/next/assets/{control-queries-DB6Kh7UN.js.map → control-queries-CXtmZZH6.js.map} +1 -1
  285. package/dist/core/web/public/next/assets/copy-setup-BIp0iaiZ.js +2 -0
  286. package/dist/core/web/public/next/assets/copy-setup-BIp0iaiZ.js.map +1 -0
  287. package/dist/core/web/public/next/assets/{dock-icons-BBUGl4tE.js → dock-icons-Cc43W7r4.js} +2 -2
  288. package/dist/core/web/public/next/assets/{dock-icons-BBUGl4tE.js.map → dock-icons-Cc43W7r4.js.map} +1 -1
  289. package/dist/core/web/public/next/assets/{fleet-model-BRfRWkZl.js → fleet-model-DOK8ZtEt.js} +2 -2
  290. package/dist/core/web/public/next/assets/{fleet-model-BRfRWkZl.js.map → fleet-model-DOK8ZtEt.js.map} +1 -1
  291. package/dist/core/web/public/next/assets/{fleet-queries-tU6UEXN2.js → fleet-queries-BeEAqD6y.js} +2 -2
  292. package/dist/core/web/public/next/assets/{fleet-queries-tU6UEXN2.js.map → fleet-queries-BeEAqD6y.js.map} +1 -1
  293. package/dist/core/web/public/next/assets/{focus-trap-BGOceFvj.js → focus-trap-ChZ5EFfM.js} +2 -2
  294. package/dist/core/web/public/next/assets/{focus-trap-BGOceFvj.js.map → focus-trap-ChZ5EFfM.js.map} +1 -1
  295. package/dist/core/web/public/next/assets/format-BmH2yWL6.js +2 -0
  296. package/dist/core/web/public/next/assets/format-BmH2yWL6.js.map +1 -0
  297. package/dist/core/web/public/next/assets/{git-model-53iRLInY.js → git-model-BFwAVbxF.js} +2 -2
  298. package/dist/core/web/public/next/assets/{git-model-53iRLInY.js.map → git-model-BFwAVbxF.js.map} +1 -1
  299. package/dist/core/web/public/next/assets/global-y_exIyAP.js +2 -0
  300. package/dist/core/web/public/next/assets/{global-CXHHMz9o.js.map → global-y_exIyAP.js.map} +1 -1
  301. package/dist/core/web/public/next/assets/{guarded-runners-B8zFVBVZ.js → guarded-runners-Cd4POBtI.js} +2 -2
  302. package/dist/core/web/public/next/assets/{guarded-runners-B8zFVBVZ.js.map → guarded-runners-Cd4POBtI.js.map} +1 -1
  303. package/dist/core/web/public/next/assets/{icons-D4s-jlxX.js → icons-CygCEFWs.js} +2 -2
  304. package/dist/core/web/public/next/assets/{icons-D4s-jlxX.js.map → icons-CygCEFWs.js.map} +1 -1
  305. package/dist/core/web/public/next/assets/{index-BG177cPN.js → index-CyK31YRm.js} +3 -3
  306. package/dist/core/web/public/next/assets/{index-BG177cPN.js.map → index-CyK31YRm.js.map} +1 -1
  307. package/dist/core/web/public/next/assets/{live-model-CEf01wrW.js → live-model-D7hilYFk.js} +2 -2
  308. package/dist/core/web/public/next/assets/live-model-D7hilYFk.js.map +1 -0
  309. package/dist/core/web/public/next/assets/{mind.module-D_xk6HIQ.js → mind.module-B15k0Y9q.js} +2 -2
  310. package/dist/core/web/public/next/assets/{mind.module-D_xk6HIQ.js.map → mind.module-B15k0Y9q.js.map} +1 -1
  311. package/dist/core/web/public/next/assets/mutations-CWlxEMEm.js +2 -0
  312. package/dist/core/web/public/next/assets/{mutations-CbTSofVH.js.map → mutations-CWlxEMEm.js.map} +1 -1
  313. package/dist/core/web/public/next/assets/{nav-CmZcbPFJ.js → nav-mimleI0R.js} +2 -2
  314. package/dist/core/web/public/next/assets/{nav-CmZcbPFJ.js.map → nav-mimleI0R.js.map} +1 -1
  315. package/dist/core/web/public/next/assets/{overnight-queries-CR0b_j-V.js → overnight-queries-DJ4mZKSj.js} +2 -2
  316. package/dist/core/web/public/next/assets/{overnight-queries-CR0b_j-V.js.map → overnight-queries-DJ4mZKSj.js.map} +1 -1
  317. package/dist/core/web/public/next/assets/primitives-DMijqcu0.js +1 -0
  318. package/dist/core/web/public/next/assets/{queries-rvRsAGW2.js → queries-Bw1McHTj.js} +2 -2
  319. package/dist/core/web/public/next/assets/{queries-rvRsAGW2.js.map → queries-Bw1McHTj.js.map} +1 -1
  320. package/dist/core/web/public/next/assets/{reasoning-pref-DMPQkujg.js → reasoning-pref-KkhI_5-j.js} +2 -2
  321. package/dist/core/web/public/next/assets/{reasoning-pref-DMPQkujg.js.map → reasoning-pref-KkhI_5-j.js.map} +1 -1
  322. package/dist/core/web/public/next/assets/{reveal-anchor-BKk2wZZZ.js → reveal-anchor-CCCx_kfT.js} +2 -2
  323. package/dist/core/web/public/next/assets/{reveal-anchor-BKk2wZZZ.js.map → reveal-anchor-CCCx_kfT.js.map} +1 -1
  324. package/dist/core/web/public/next/assets/{seat-subscription-CLn2ReSZ.js → seat-subscription-BhUUz7VL.js} +2 -2
  325. package/dist/core/web/public/next/assets/{seat-subscription-CLn2ReSZ.js.map → seat-subscription-BhUUz7VL.js.map} +1 -1
  326. package/dist/core/web/public/next/assets/{sidebar-model-CjQLvdag.js → sidebar-model-Dcd437cf.js} +2 -2
  327. package/dist/core/web/public/next/assets/{sidebar-model-CjQLvdag.js.map → sidebar-model-Dcd437cf.js.map} +1 -1
  328. package/dist/core/web/public/next/assets/{slots-DRxNosZg.js → slots-BL_J5mmV.js} +3 -3
  329. package/dist/core/web/public/next/assets/{slots-DRxNosZg.js.map → slots-BL_J5mmV.js.map} +1 -1
  330. package/dist/core/web/public/next/assets/{surface-data-DshUC_TU.js → surface-data-C3UAQ4QX.js} +2 -2
  331. package/dist/core/web/public/next/assets/{surface-data-DshUC_TU.js.map → surface-data-C3UAQ4QX.js.map} +1 -1
  332. package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js +2 -0
  333. package/dist/core/web/public/next/assets/{surface-prefetch-DO8r4ttQ.js.map → surface-prefetch-BXKjPsV5.js.map} +1 -1
  334. package/dist/core/web/public/next/assets/{tasks-model-BKPFZAmZ.js → tasks-model-CzHvclVm.js} +2 -2
  335. package/dist/core/web/public/next/assets/{tasks-model-BKPFZAmZ.js.map → tasks-model-CzHvclVm.js.map} +1 -1
  336. package/dist/core/web/public/next/assets/{terminal-icons-DoeQkP3y.js → terminal-icons-BwgQTQP0.js} +2 -2
  337. package/dist/core/web/public/next/assets/{terminal-icons-DoeQkP3y.js.map → terminal-icons-BwgQTQP0.js.map} +1 -1
  338. package/dist/core/web/public/next/assets/types-IYKrYLku.js +2 -0
  339. package/dist/core/web/public/next/assets/types-IYKrYLku.js.map +1 -0
  340. package/dist/core/web/public/next/assets/{usage-queries-MnUeYzwp.js → usage-queries-pXxvy54x.js} +2 -2
  341. package/dist/core/web/public/next/assets/{usage-queries-MnUeYzwp.js.map → usage-queries-pXxvy54x.js.map} +1 -1
  342. package/dist/core/web/public/next/assets/{use-guarded-action-P12MfNwU.js → use-guarded-action-EgVWjM5c.js} +2 -2
  343. package/dist/core/web/public/next/assets/{use-guarded-action-P12MfNwU.js.map → use-guarded-action-EgVWjM5c.js.map} +1 -1
  344. package/dist/core/web/public/next/assets/{use-ticker-DIvAZ4Ey.js → use-ticker-BoqFxRFG.js} +2 -2
  345. package/dist/core/web/public/next/assets/{use-ticker-DIvAZ4Ey.js.map → use-ticker-BoqFxRFG.js.map} +1 -1
  346. package/dist/core/web/public/next/assets/{use-token-gate-DfEja7Wr.js → use-token-gate-DSNIIpI6.js} +2 -2
  347. package/dist/core/web/public/next/assets/{use-token-gate-DfEja7Wr.js.map → use-token-gate-DSNIIpI6.js.map} +1 -1
  348. package/dist/core/web/public/next/assets/{useOnboarding-CkOHadqC.js → useOnboarding-Bk0VnkxQ.js} +2 -2
  349. package/dist/core/web/public/next/assets/{useOnboarding-CkOHadqC.js.map → useOnboarding-Bk0VnkxQ.js.map} +1 -1
  350. package/dist/core/web/public/next/assets/{useSeatsRefresh-BDlbDlIU.js → useSeatsRefresh-q7Id9RcW.js} +2 -2
  351. package/dist/core/web/public/next/assets/{useSeatsRefresh-BDlbDlIU.js.map → useSeatsRefresh-q7Id9RcW.js.map} +1 -1
  352. package/dist/core/web/public/next/assets/{useVerseTranscript-BGtA55k2.js → useVerseTranscript-CqH51rt9.js} +2 -2
  353. package/dist/core/web/public/next/assets/{useVerseTranscript-BGtA55k2.js.map → useVerseTranscript-CqH51rt9.js.map} +1 -1
  354. package/dist/core/web/public/next/assets/{verse-icons-wOet9JZy.js → verse-icons-DsG1dOQx.js} +2 -2
  355. package/dist/core/web/public/next/assets/{verse-icons-wOet9JZy.js.map → verse-icons-DsG1dOQx.js.map} +1 -1
  356. package/dist/core/web/public/next/assets/{verse-model-CSzzdyu2.js → verse-model-JTuvRBVK.js} +2 -2
  357. package/dist/core/web/public/next/assets/{verse-model-CSzzdyu2.js.map → verse-model-JTuvRBVK.js.map} +1 -1
  358. package/dist/core/web/public/next/assets/{warmup-CecO_Nk0.js → warmup-Bv1RumVq.js} +3 -3
  359. package/dist/core/web/public/next/assets/{warmup-CecO_Nk0.js.map → warmup-Bv1RumVq.js.map} +1 -1
  360. package/dist/core/web/public/next/assets/why-seat-model-Cau8qG6O.js +2 -0
  361. package/dist/core/web/public/next/assets/why-seat-model-Cau8qG6O.js.map +1 -0
  362. package/dist/core/web/public/next/assets/{workspace-model-BdIVybKr.js → workspace-model-D-SLfads.js} +2 -2
  363. package/dist/core/web/public/next/assets/{workspace-model-BdIVybKr.js.map → workspace-model-D-SLfads.js.map} +1 -1
  364. package/dist/core/web/public/next/index.html +1 -1
  365. package/dist/release-dependency-inventory.json +1 -1
  366. package/docs/AUTONOMY-GAP.md +1 -1
  367. package/package.json +1 -1
  368. package/dist/core/web/public/next/assets/Advanced-CxzE6ekM.js +0 -2
  369. package/dist/core/web/public/next/assets/App-DFlp-vdv.js +0 -7
  370. package/dist/core/web/public/next/assets/AppsSection-Ct2O605-.js +0 -2
  371. package/dist/core/web/public/next/assets/AutonomyOffState-CXhXpsim.js +0 -2
  372. package/dist/core/web/public/next/assets/AutonomyOffState-CXhXpsim.js.map +0 -1
  373. package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +0 -1
  374. package/dist/core/web/public/next/assets/AutonomySection-BTg7yVa1.js +0 -2
  375. package/dist/core/web/public/next/assets/BudgetControl-ng6swoZp.js +0 -2
  376. package/dist/core/web/public/next/assets/BudgetControl-ng6swoZp.js.map +0 -1
  377. package/dist/core/web/public/next/assets/ChatSection-Bisj9R6E.js +0 -3
  378. package/dist/core/web/public/next/assets/ChatSection-Bisj9R6E.js.map +0 -1
  379. package/dist/core/web/public/next/assets/CommandSection-D8ZihzvE.js +0 -2
  380. package/dist/core/web/public/next/assets/CommandSection-D8ZihzvE.js.map +0 -1
  381. package/dist/core/web/public/next/assets/DockHost-BPqyhtCP.js +0 -2
  382. package/dist/core/web/public/next/assets/McpSection-D1tDvlRa.js +0 -2
  383. package/dist/core/web/public/next/assets/NeedsYouDrawer-D992XTOn.js +0 -2
  384. package/dist/core/web/public/next/assets/NeedsYouDrawer-D992XTOn.js.map +0 -1
  385. package/dist/core/web/public/next/assets/NeedsYouList-CruOt4JT.css +0 -1
  386. package/dist/core/web/public/next/assets/NeedsYouList-eBOlJr0b.js +0 -2
  387. package/dist/core/web/public/next/assets/OnboardingFlow-D3yfITK1.js +0 -2
  388. package/dist/core/web/public/next/assets/OnboardingFlow-D3yfITK1.js.map +0 -1
  389. package/dist/core/web/public/next/assets/OnboardingGate-DrDEVBqw.js +0 -3
  390. package/dist/core/web/public/next/assets/ResourcesChrome-C2ZrA7la.js +0 -3
  391. package/dist/core/web/public/next/assets/Sidebar-BuO3sViG.js +0 -3
  392. package/dist/core/web/public/next/assets/Sidebar-BuO3sViG.js.map +0 -1
  393. package/dist/core/web/public/next/assets/VerseConsoleApp-DeuBEvAO.js +0 -3
  394. package/dist/core/web/public/next/assets/VerseConsoleApp-DeuBEvAO.js.map +0 -1
  395. package/dist/core/web/public/next/assets/cloud-model-DoxBMDvx.js +0 -2
  396. package/dist/core/web/public/next/assets/copy-setup-CJQhFl-4.js +0 -2
  397. package/dist/core/web/public/next/assets/copy-setup-CJQhFl-4.js.map +0 -1
  398. package/dist/core/web/public/next/assets/format-DEAaVF6X.js +0 -2
  399. package/dist/core/web/public/next/assets/format-DEAaVF6X.js.map +0 -1
  400. package/dist/core/web/public/next/assets/global-CXHHMz9o.js +0 -2
  401. package/dist/core/web/public/next/assets/live-model-CEf01wrW.js.map +0 -1
  402. package/dist/core/web/public/next/assets/mutations-CbTSofVH.js +0 -2
  403. package/dist/core/web/public/next/assets/primitives-DNI-uJBd.js +0 -1
  404. package/dist/core/web/public/next/assets/surface-prefetch-DO8r4ttQ.js +0 -2
  405. package/dist/core/web/public/next/assets/types-D5XOdyw8.js +0 -2
  406. package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +0 -1
  407. package/dist/core/web/public/next/assets/why-seat-model-D68ZA7G8.js +0 -2
  408. package/dist/core/web/public/next/assets/why-seat-model-D68ZA7G8.js.map +0 -1
@@ -0,0 +1,919 @@
1
+ /**
2
+ * Cloud task evidence timeline (3.13) — READ-ONLY.
3
+ *
4
+ * Joins what is already stored about one cloud task into the ordered chain
5
+ * docs/VERSE-COMPETITIVE-ACCEPTANCE.md asks for (objective → worker → diff →
6
+ * checks that actually ran → PR → merge → release → health → cost). Nothing
7
+ * here writes, fetches, or talks to GitHub; every source is local:
8
+ *
9
+ * cloud task record store.ts (prompt, origin, backlog item, seat,
10
+ * session URL, PR + delivery pin, report, estimate)
11
+ * fleet merge record fleet/fleet-merge-state.ts (diff binding, checks
12
+ * memo, gate memos, landing) — matched by repo + PR
13
+ * number, the task branch, or the task id
14
+ * authority ledger gate:result / merge:landed / post-merge:result
15
+ * rows (hash-chained; a broken chain is 'unknown')
16
+ * post-merge watch fleet/post-merge-watch.ts verdicts
17
+ * evidence pack autonomy/evidence-pack.ts (the producing model)
18
+ * local git the fleet mirror, else an enrolled checkout whose
19
+ * origin is the task's repo: the merge commit (when
20
+ * no landing recorded it) and `git tag --contains`
21
+ *
22
+ * EPISTEMICS (the reason this file exists): the session's report is a CLAIM
23
+ * and is always `verified: false`; the cost is an ESTIMATE fixed at launch
24
+ * and is always `verified: false`; the model and account are 'unknown'
25
+ * unless a record names them. Nothing is inferred from the report.
26
+ *
27
+ * BOUNDED: every source has its own time budget and an unreadable or slow
28
+ * source degrades its steps to 'unknown' — the route always answers. Git
29
+ * answers and the merge-record index are cached; a whole timeline is cached
30
+ * briefly per task revision so a re-opened panel costs nothing.
31
+ */
32
+ import { existsSync, statSync } from 'node:fs';
33
+ import { join } from 'node:path';
34
+ import { readLedger } from '../authority/ledger.js';
35
+ import { readAutonomyEvidencePack } from '../autonomy/evidence-pack.js';
36
+ import { listFleetMergeStateKeys, readFleetMergeState } from '../fleet/fleet-merge-state.js';
37
+ import { GATE_ORDER } from '../fleet/fleet-types.js';
38
+ import { mirrorPathFor } from '../fleet/mirrors.js';
39
+ import { listPostMergeWatches } from '../fleet/post-merge-watch.js';
40
+ import { scrubSecrets } from '../util/scrub.js';
41
+ import { defaultGitRunner } from '../verse/git-ops.js';
42
+ import { discoverProjects } from '../verse/projects.js';
43
+ import { readCloudTask } from './store.js';
44
+ import { CLOUD_TIMELINE_SCHEMA_VERSION, } from './timeline-types.js';
45
+ import { CLOUD_BALANCE_URL, CLOUD_TASK_ID_PATTERN } from './types.js';
46
+ // ---------------------------------------------------------------------------
47
+ // Text helpers
48
+ // ---------------------------------------------------------------------------
49
+ function clip(text, max) {
50
+ // eslint-disable-next-line no-control-regex
51
+ const flat = scrubSecrets(text).replace(/[\u0000-\u001f\u007f\u2028\u2029]+/g, ' ').replace(/\s+/g, ' ').trim();
52
+ return flat.length <= max ? flat : `${flat.slice(0, max - 1).trimEnd()}…`;
53
+ }
54
+ const short = (sha) => sha.slice(0, 7);
55
+ function isoOrNull(value) {
56
+ if (typeof value !== 'string')
57
+ return null;
58
+ const ms = Date.parse(value);
59
+ return Number.isFinite(ms) ? new Date(ms).toISOString() : null;
60
+ }
61
+ function httpsLink(href, host, label) {
62
+ if (typeof href !== 'string' || href.length > 2_048)
63
+ return undefined;
64
+ try {
65
+ const url = new URL(href);
66
+ return url.protocol === 'https:' && url.hostname === host ? { href: url.toString(), label } : undefined;
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ }
72
+ function commitLink(repo, sha) {
73
+ return httpsLink(`https://github.com/${repo}/commit/${sha}`, 'github.com', `Commit ${short(sha)}`);
74
+ }
75
+ function tagLink(repo, tag) {
76
+ return httpsLink(`https://github.com/${repo}/releases/tag/${encodeURIComponent(tag)}`, 'github.com', tag);
77
+ }
78
+ const ORIGIN_WORD = {
79
+ chat: 'a chat’s “Run in cloud”',
80
+ operator: 'New cloud task',
81
+ leader: 'the Leader',
82
+ 'self-improve': 'self-improvement',
83
+ cli: 'the ashlr CLI',
84
+ };
85
+ function prNumberOf(task) {
86
+ return task.pr?.number ?? task.deliveryPin?.number ?? null;
87
+ }
88
+ const sameRepo = (a, b) => a.toLowerCase() === b.toLowerCase();
89
+ function step(kind, fields) {
90
+ const out = { kind, at: fields.at, title: fields.title, detail: fields.detail, source: fields.source, verified: fields.verified, reached: fields.reached };
91
+ if (fields.link)
92
+ out.link = fields.link;
93
+ return out;
94
+ }
95
+ function objectiveStep(task) {
96
+ const parts = [`From ${ORIGIN_WORD[task.origin]}, requested by ${task.requestedBy}.`];
97
+ if (task.backlogItemId)
98
+ parts.push(`Backlog item ${clip(task.backlogItemId, 80)}.`);
99
+ parts.push(`${task.repo} from ${clip(task.baseBranch, 120)}.`);
100
+ const prompt = clip(task.prompt, 600);
101
+ if (prompt)
102
+ parts.push(`Task: ${prompt}`);
103
+ return step('objective', {
104
+ at: isoOrNull(task.createdAt),
105
+ title: clip(task.title, 120) || 'Untitled cloud task',
106
+ detail: parts.join(' '),
107
+ source: 'cloud task record',
108
+ verified: true,
109
+ reached: true,
110
+ });
111
+ }
112
+ function launchStep(task) {
113
+ const session = httpsLink(task.sessionUrl, 'claude.ai', 'Open session');
114
+ if (task.state === 'failed') {
115
+ return step('launch', {
116
+ at: isoOrNull(task.launchedAt) ?? isoOrNull(task.updatedAt),
117
+ title: 'Launch failed',
118
+ detail: clip(task.stateReason ?? `The cloud session was not started (${task.failure ?? 'unknown'}).`, 400),
119
+ source: 'cloud task record',
120
+ verified: true,
121
+ reached: true,
122
+ });
123
+ }
124
+ if (task.sessionId || session) {
125
+ return step('launch', {
126
+ at: isoOrNull(task.launchedAt),
127
+ title: `Cloud session started on seat ${clip(task.seat, 40)}`,
128
+ detail: `Branch ${task.branch}.`,
129
+ source: 'cloud task record (CLI output at launch)',
130
+ verified: true,
131
+ reached: true,
132
+ ...(session ? { link: session } : {}),
133
+ });
134
+ }
135
+ return step('launch', {
136
+ at: null,
137
+ title: task.state === 'queued' ? 'Waiting for a launch slot' : task.state === 'launching' ? 'Launching' : 'No session recorded',
138
+ detail: task.state === 'queued' || task.state === 'launching' ? '' : 'The task record has no session id.',
139
+ source: 'cloud task record',
140
+ verified: task.state === 'queued' || task.state === 'launching' ? true : 'unknown',
141
+ reached: false,
142
+ });
143
+ }
144
+ function workerStep(task, model) {
145
+ const launched = task.sessionId !== null || task.sessionUrl !== null;
146
+ const modelText = model ? `Model: ${clip(model, 80)} (evidence pack).` : 'Model: unknown — not recorded.';
147
+ return step('worker', {
148
+ at: isoOrNull(task.launchedAt),
149
+ title: `Claude Code cloud session · seat ${clip(task.seat, 40)}`,
150
+ detail: `${modelText} Account: unknown — the claude.ai account behind the seat is not recorded with the task.`,
151
+ source: model ? 'evidence pack' : 'not recorded',
152
+ verified: model ? true : 'unknown',
153
+ reached: launched,
154
+ });
155
+ }
156
+ function reportStep(task) {
157
+ const report = task.report;
158
+ if (!report) {
159
+ const hasPr = task.pr !== null;
160
+ return step('report', {
161
+ at: null,
162
+ title: hasPr ? 'No session report' : 'No session report yet',
163
+ detail: hasPr ? 'The pull request carries no ashlr-cloud-report block.' : '',
164
+ source: 'pull request body',
165
+ verified: 'unknown',
166
+ reached: hasPr,
167
+ });
168
+ }
169
+ const parts = [clip(report.summary, 500)];
170
+ if (report.testsRun.length > 0)
171
+ parts.push(`Tests it says it ran: ${clip(report.testsRun.slice(0, 8).join('; '), 300)}.`);
172
+ else
173
+ parts.push('It names no tests.');
174
+ if (report.risks.length > 0)
175
+ parts.push(`Risks it names: ${clip(report.risks.slice(0, 5).join('; '), 300)}.`);
176
+ return step('report', {
177
+ at: null,
178
+ title: `Session reports “${report.status}” (unverified)`,
179
+ detail: parts.filter(Boolean).join(' '),
180
+ source: 'session report (a claim, not evidence)',
181
+ verified: false,
182
+ reached: true,
183
+ });
184
+ }
185
+ function prStep(task, merge) {
186
+ const openedAt = merge.state === 'ok' ? isoOrNull(merge.record.pr?.openedAt) : null;
187
+ if (task.pr) {
188
+ const link = httpsLink(task.pr.url, 'github.com', `PR #${task.pr.number}`);
189
+ const pinned = task.deliveryPin ? task.deliveryPin.number === task.pr.number : null;
190
+ const stateWord = task.pr.state === 'open' ? (task.pr.draft ? 'open (draft)' : 'open') : task.pr.state;
191
+ return step('pr', {
192
+ at: openedAt,
193
+ title: `PR #${task.pr.number} ${stateWord}`,
194
+ detail: `${clip(task.pr.title, 200)}. Repository, branch and base checked against the task by the tracker${pinned === false ? '; it differs from the PR first pinned for this task' : ''}.`,
195
+ source: 'GitHub, read by the cloud tracker',
196
+ verified: pinned === false ? 'unknown' : true,
197
+ reached: true,
198
+ ...(link ? { link } : {}),
199
+ });
200
+ }
201
+ if (task.deliveryPin) {
202
+ const link = httpsLink(task.deliveryPin.url, 'github.com', `PR #${task.deliveryPin.number}`);
203
+ return step('pr', {
204
+ at: openedAt,
205
+ title: `PR #${task.deliveryPin.number} (not currently verified)`,
206
+ detail: 'This PR was verified for the task earlier; the latest GitHub lookup could not confirm it.',
207
+ source: 'cloud task delivery pin',
208
+ verified: 'unknown',
209
+ reached: true,
210
+ ...(link ? { link } : {}),
211
+ });
212
+ }
213
+ return step('pr', {
214
+ at: null,
215
+ title: 'No pull request yet',
216
+ detail: task.state === 'expired' ? 'No PR appeared within the watch window; the session link still works.' : '',
217
+ source: 'GitHub, read by the cloud tracker',
218
+ verified: 'unknown',
219
+ reached: false,
220
+ });
221
+ }
222
+ function diffStep(task, merge) {
223
+ const record = merge.state === 'ok' ? merge.record : null;
224
+ const landing = record?.landing ?? null;
225
+ const files = landing?.files ?? record?.files ?? null;
226
+ const added = landing?.linesAdded ?? record?.linesAdded ?? null;
227
+ const deleted = landing?.linesDeleted ?? record?.linesDeleted ?? null;
228
+ if (files !== null && added !== null && deleted !== null) {
229
+ const risk = landing?.risk ?? record?.risk ?? null;
230
+ const tree = record?.treeSha ? ` Tree ${short(record.treeSha)} verified on base ${record.baseSha ? short(record.baseSha) : 'unknown'}.` : '';
231
+ return step('diff', {
232
+ at: null,
233
+ title: `${files} ${files === 1 ? 'file' : 'files'}, +${added} −${deleted}`,
234
+ detail: `${risk ? `Risk ${risk}.` : ''}${tree}`.trim(),
235
+ source: 'fleet merge record',
236
+ verified: true,
237
+ reached: true,
238
+ });
239
+ }
240
+ const claimed = task.report?.filesChanged;
241
+ if (typeof claimed === 'number') {
242
+ return step('diff', {
243
+ at: null,
244
+ title: `${claimed} ${claimed === 1 ? 'file' : 'files'} changed (claimed)`,
245
+ detail: 'Only the session report gives a size; no merge record measured the diff.',
246
+ source: 'session report (a claim, not evidence)',
247
+ verified: false,
248
+ reached: true,
249
+ });
250
+ }
251
+ return step('diff', {
252
+ at: null,
253
+ title: 'Diff not measured',
254
+ detail: merge.state === 'unknown' ? `The fleet merge record could not be read: ${clip(merge.reason, 200)}` : 'No merge record measured this PR’s diff.',
255
+ source: 'fleet merge record',
256
+ verified: 'unknown',
257
+ reached: task.pr !== null,
258
+ });
259
+ }
260
+ function checksStep(task, merge) {
261
+ const checks = merge.state === 'ok' ? merge.record.pr?.checks ?? null : null;
262
+ if (checks) {
263
+ const title = checks.state === 'green' ? 'Required checks passed'
264
+ : checks.state === 'red' ? 'Required checks failed'
265
+ : checks.state === 'pending' ? 'Required checks running'
266
+ : 'No required checks on this repo';
267
+ return step('checks', {
268
+ at: isoOrNull(checks.at),
269
+ title,
270
+ detail: clip(checks.detail, 300),
271
+ source: 'fleet merge record (GitHub required checks)',
272
+ verified: true,
273
+ reached: true,
274
+ });
275
+ }
276
+ const claimed = task.report?.testsRun.length ?? 0;
277
+ return step('checks', {
278
+ at: null,
279
+ title: 'No check run recorded',
280
+ detail: claimed > 0
281
+ ? `Verse recorded no check run for this PR. The ${claimed} ${claimed === 1 ? 'test' : 'tests'} in the session report are its own claim.`
282
+ : 'Verse recorded no check run for this PR.',
283
+ source: merge.state === 'unknown' ? 'fleet merge record (unreadable)' : 'fleet merge record',
284
+ verified: 'unknown',
285
+ reached: task.pr !== null,
286
+ });
287
+ }
288
+ function gatesStep(task, merge, ledger) {
289
+ if (ledger.state === 'ok' && ledger.gates.length > 0) {
290
+ const latest = new Map();
291
+ for (const row of ledger.gates)
292
+ latest.set(row.gate, row); // oldest first ⇒ last wins
293
+ const ordered = GATE_ORDER.map((g) => latest.get(g)).filter((r) => r !== undefined);
294
+ const stop = ordered.find((r) => r.verdict !== 'pass') ?? null;
295
+ const summary = ordered.map((r) => `${r.gate} ${r.verdict}`).join(' · ');
296
+ const at = ordered.reduce((max, r) => (max === null || r.rowAt > max ? r.rowAt : max), null);
297
+ return step('gates', {
298
+ at: isoOrNull(at),
299
+ title: stop ? `Merge gates: ${stop.gate} ${stop.verdict}` : `Merge gates passed (${ordered.length})`,
300
+ detail: `${summary}.${stop ? ` ${clip(stop.reason, 300)}` : ''}`,
301
+ source: 'authority ledger (hash-chained)',
302
+ verified: true,
303
+ reached: true,
304
+ });
305
+ }
306
+ const memos = merge.state === 'ok' ? merge.record.gates : null;
307
+ const memoRows = memos ? GATE_ORDER.map((g) => (memos[g] ? { gate: g, ...memos[g] } : null)).filter((m) => m !== null) : [];
308
+ if (memoRows.length > 0) {
309
+ const stop = memoRows.find((m) => m.verdict !== 'pass') ?? null;
310
+ const at = memoRows.reduce((max, m) => (max === null || m.at > max ? m.at : max), null);
311
+ return step('gates', {
312
+ at: isoOrNull(at),
313
+ title: stop ? `Merge gates: ${stop.gate} ${stop.verdict}` : `Merge gates passed (${memoRows.length})`,
314
+ detail: `${memoRows.map((m) => `${m.gate} ${m.verdict}`).join(' · ')}.${ledger.state === 'unknown' ? ` The ledger rows could not be read: ${clip(ledger.reason, 200)}` : ''}`,
315
+ source: 'fleet merge record (gate memos)',
316
+ verified: true,
317
+ reached: true,
318
+ });
319
+ }
320
+ return step('gates', {
321
+ at: null,
322
+ title: 'No merge-gate evaluation recorded',
323
+ detail: ledger.state === 'unknown'
324
+ ? `The authority ledger could not be read: ${clip(ledger.reason, 200)}`
325
+ : 'Neither the ledger nor a merge record shows the gates judging this PR; it is merged by the gates or by Mason.',
326
+ source: ledger.state === 'unknown' ? 'authority ledger (unreadable)' : 'authority ledger',
327
+ verified: 'unknown',
328
+ reached: task.pr !== null,
329
+ });
330
+ }
331
+ function landingOf(sources) {
332
+ if (sources.merge.state === 'ok' && sources.merge.record.landing)
333
+ return sources.merge.record.landing;
334
+ return sources.ledger.state === 'ok' ? sources.ledger.landing : null;
335
+ }
336
+ function mergeStep(sources) {
337
+ const { task, mergeCommit } = sources;
338
+ const landing = landingOf(sources);
339
+ if (landing) {
340
+ return step('merge', {
341
+ at: isoOrNull(landing.landedAt),
342
+ title: `Merged as ${short(landing.mergeSha)}`,
343
+ detail: `Landed on ${clip(landing.baseBranch, 80)} by the fleet host merge (grant ${clip(landing.grantId, 40)}), pinned to head ${short(landing.headSha)}.`,
344
+ source: 'fleet landing record',
345
+ verified: true,
346
+ reached: true,
347
+ ...(commitLink(task.repo, landing.mergeSha) ? { link: commitLink(task.repo, landing.mergeSha) } : {}),
348
+ });
349
+ }
350
+ if (task.state === 'merged' || task.pr?.state === 'merged') {
351
+ const found = mergeCommit?.basis === 'git' ? mergeCommit.sha : null;
352
+ return step('merge', {
353
+ at: null,
354
+ title: found ? `Merged as ${short(found)}` : 'Merged on GitHub',
355
+ detail: found
356
+ ? 'GitHub reports the PR merged; the commit was found in local git by its merge message (no fleet landing recorded it).'
357
+ : 'GitHub reports the PR merged. No landing record or local commit names the merge commit.',
358
+ source: found ? 'GitHub (cloud tracker) + local git' : 'GitHub, read by the cloud tracker',
359
+ verified: true,
360
+ reached: true,
361
+ ...(found && commitLink(task.repo, found) ? { link: commitLink(task.repo, found) } : {}),
362
+ });
363
+ }
364
+ if (task.state === 'pr-open' && task.supersededBy) {
365
+ // 3.13: the cloud PR was closed in favour of the fleet App PR (fleet/cloud-intake.ts).
366
+ return step('merge', {
367
+ at: null,
368
+ title: `Superseded by fleet PR #${task.supersededBy.number}`,
369
+ detail: 'The fleet rebuilt this change through the standing merge gates; it lands from that PR, never from the cloud PR.',
370
+ source: 'cloud task record',
371
+ verified: true,
372
+ reached: false,
373
+ });
374
+ }
375
+ if (task.state === 'closed' || task.pr?.state === 'closed') {
376
+ return step('merge', {
377
+ at: null,
378
+ title: 'Closed without merging',
379
+ detail: clip(task.stateReason ?? '', 300),
380
+ source: 'cloud task record',
381
+ verified: true,
382
+ reached: true,
383
+ });
384
+ }
385
+ return step('merge', {
386
+ at: null,
387
+ title: 'Not merged',
388
+ detail: task.state === 'pr-open' ? 'The PR is open; nothing merges on its own.' : '',
389
+ source: 'cloud task record',
390
+ verified: task.state === 'pr-open' ? true : 'unknown',
391
+ reached: false,
392
+ });
393
+ }
394
+ function releaseStep(sources) {
395
+ const { task, mergeCommit, release } = sources;
396
+ if (!mergeCommit || !release) {
397
+ return step('release', {
398
+ at: null,
399
+ title: 'Release unknown',
400
+ detail: task.state === 'merged' ? 'Without a merge commit there is nothing to look for in the release tags.' : 'Not merged, so not released.',
401
+ source: 'local git tags',
402
+ verified: 'unknown',
403
+ reached: false,
404
+ });
405
+ }
406
+ switch (release.state) {
407
+ case 'contained':
408
+ return step('release', {
409
+ at: null,
410
+ title: `In the latest release, ${release.latestTag}`,
411
+ detail: release.firstTag && release.firstTag !== release.latestTag ? `First released in ${release.firstTag}.` : `${short(mergeCommit.sha)} is contained in ${release.latestTag}.`,
412
+ source: 'local git tags (git tag --contains)',
413
+ verified: true,
414
+ reached: true,
415
+ ...(tagLink(task.repo, release.latestTag) ? { link: tagLink(task.repo, release.latestTag) } : {}),
416
+ });
417
+ case 'not-contained':
418
+ return step('release', {
419
+ at: null,
420
+ title: `Not in the latest release (${release.latestTag}) yet`,
421
+ detail: `${short(mergeCommit.sha)} is not contained in ${release.latestTag}.`,
422
+ source: 'local git tags (git tag --contains)',
423
+ verified: true,
424
+ reached: false,
425
+ ...(tagLink(task.repo, release.latestTag) ? { link: tagLink(task.repo, release.latestTag) } : {}),
426
+ });
427
+ case 'no-tags':
428
+ return step('release', {
429
+ at: null,
430
+ title: 'No release tags',
431
+ detail: 'The local checkout has no release-looking tags.',
432
+ source: 'local git tags',
433
+ verified: 'unknown',
434
+ reached: false,
435
+ });
436
+ default:
437
+ return step('release', {
438
+ at: null,
439
+ title: 'Release unknown',
440
+ detail: clip(release.reason, 300),
441
+ source: 'local git tags',
442
+ verified: 'unknown',
443
+ reached: false,
444
+ });
445
+ }
446
+ }
447
+ function healthStep(sources) {
448
+ const { watch, ledger, task } = sources;
449
+ const view = watch.state === 'ok' ? watch.view : null;
450
+ if (view) {
451
+ if (view.verdict) {
452
+ return step('health', {
453
+ at: isoOrNull(view.checkedAt),
454
+ title: view.verdict === 'green' ? 'Healthy after merge' : 'Red after merge',
455
+ detail: `CI ${view.ci ?? 'unknown'}, suite ${view.suite}.${view.detail ? ` ${clip(view.detail, 300)}` : ''}`,
456
+ source: 'post-merge watch',
457
+ verified: true,
458
+ reached: true,
459
+ });
460
+ }
461
+ return step('health', {
462
+ at: isoOrNull(view.checkedAt),
463
+ title: view.phase === 'reverting' ? 'Reverting after a red watch' : 'Post-merge watch in progress',
464
+ detail: `Watching until ${isoOrNull(view.watchUntil) ?? 'unknown'}. CI ${view.ci ?? 'unknown'}, suite ${view.suite}.`,
465
+ source: 'post-merge watch',
466
+ verified: true,
467
+ reached: true,
468
+ });
469
+ }
470
+ const row = ledger.state === 'ok' ? ledger.postMerge : null;
471
+ if (row) {
472
+ return step('health', {
473
+ at: isoOrNull(row.checkedAt),
474
+ title: row.verdict === 'green' ? 'Healthy after merge' : 'Red after merge',
475
+ detail: `CI ${row.ci}, suite ${row.suite}. ${clip(row.detail, 300)}`,
476
+ source: 'authority ledger (post-merge result)',
477
+ verified: true,
478
+ reached: true,
479
+ });
480
+ }
481
+ const merged = task.state === 'merged' || landingOf(sources) !== null;
482
+ return step('health', {
483
+ at: null,
484
+ title: merged ? 'No post-merge watch recorded' : 'Health unknown',
485
+ detail: watch.state === 'unknown'
486
+ ? `The post-merge watch store could not be read: ${clip(watch.reason, 200)}`
487
+ : landingOf(sources) !== null
488
+ ? 'The fleet landed this merge, but no post-merge verdict is recorded yet.'
489
+ : merged ? 'Only fleet landings are watched after merge; this merge was not.' : 'Not merged, so nothing to watch.',
490
+ source: 'post-merge watch',
491
+ verified: 'unknown',
492
+ reached: false,
493
+ });
494
+ }
495
+ function costStep(task) {
496
+ const amount = Number.isInteger(task.estimatedCostUsd) ? String(task.estimatedCostUsd) : task.estimatedCostUsd.toFixed(2);
497
+ return step('cost', {
498
+ at: isoOrNull(task.launchedAt) ?? isoOrNull(task.createdAt),
499
+ title: `$${amount} estimated`,
500
+ detail: 'Fixed at launch from the per-session estimate. Claude does not expose the credit balance, so the real spend is only on claude.ai.',
501
+ source: 'cloud budget estimate',
502
+ verified: false,
503
+ reached: true,
504
+ link: { href: CLOUD_BALANCE_URL, label: 'Check usage on claude.ai' },
505
+ });
506
+ }
507
+ /** PURE: the ordered evidence chain for one task from already-gathered sources. */
508
+ export function buildCloudTimeline(sources, now = new Date()) {
509
+ const { task } = sources;
510
+ const steps = [
511
+ objectiveStep(task),
512
+ launchStep(task),
513
+ workerStep(task, sources.model),
514
+ reportStep(task),
515
+ prStep(task, sources.merge),
516
+ diffStep(task, sources.merge),
517
+ checksStep(task, sources.merge),
518
+ gatesStep(task, sources.merge, sources.ledger),
519
+ mergeStep(sources),
520
+ releaseStep(sources),
521
+ healthStep(sources),
522
+ costStep(task),
523
+ ];
524
+ return {
525
+ v: CLOUD_TIMELINE_SCHEMA_VERSION,
526
+ generatedAt: now.toISOString(),
527
+ taskId: task.id,
528
+ repo: task.repo,
529
+ title: clip(task.title, 120) || 'Untitled cloud task',
530
+ state: task.state,
531
+ steps,
532
+ };
533
+ }
534
+ // ---------------------------------------------------------------------------
535
+ // Gathering — bounded, cached, every failure degrades to 'unknown'
536
+ // ---------------------------------------------------------------------------
537
+ const LEDGER_BUDGET_MS = 2_500;
538
+ const GIT_TIMEOUT_MS = 2_500;
539
+ /** Everything git-shaped for one timeline together (finding a checkout, the merge commit, the tags). */
540
+ const GIT_TOTAL_BUDGET_MS = 5_000;
541
+ const GIT_MAX_STDOUT = 256 * 1024;
542
+ const MERGE_INDEX_TTL_MS = 30_000;
543
+ const MERGE_SCAN_MAX = 1_024;
544
+ const GIT_CACHE_TTL_MS = 5 * 60_000;
545
+ const CHECKOUT_CACHE_TTL_MS = 5 * 60_000;
546
+ const TIMELINE_CACHE_TTL_MS = 15_000;
547
+ const CACHE_MAX_ENTRIES = 256;
548
+ const MAX_PROJECTS_PROBED = 40;
549
+ const SHA_RE = /^[0-9a-f]{40}$/;
550
+ /** A release-looking tag: `v3.12.0`, `3.12.0`, `v3.12.0-rc.1`. */
551
+ const RELEASE_TAG_RE = /^v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
552
+ class TimedOut extends Error {
553
+ }
554
+ async function withBudget(ms, work) {
555
+ let timer;
556
+ try {
557
+ return await Promise.race([
558
+ work(),
559
+ new Promise((_resolve, reject) => {
560
+ timer = setTimeout(() => reject(new TimedOut(`took longer than ${ms} ms`)), ms);
561
+ timer.unref?.();
562
+ }),
563
+ ]);
564
+ }
565
+ finally {
566
+ if (timer)
567
+ clearTimeout(timer);
568
+ }
569
+ }
570
+ function reasonOf(error) {
571
+ if (error instanceof TimedOut)
572
+ return `the read ${error.message}`;
573
+ return error instanceof Error ? error.message : String(error);
574
+ }
575
+ /** A tiny TTL map that never grows past CACHE_MAX_ENTRIES (oldest insert evicted). */
576
+ class TtlCache {
577
+ ttlMs;
578
+ map = new Map();
579
+ constructor(ttlMs) {
580
+ this.ttlMs = ttlMs;
581
+ }
582
+ get(key, now) {
583
+ const hit = this.map.get(key);
584
+ if (!hit)
585
+ return undefined;
586
+ if (now - hit.at >= this.ttlMs) {
587
+ this.map.delete(key);
588
+ return undefined;
589
+ }
590
+ return hit.value;
591
+ }
592
+ set(key, value, now) {
593
+ this.map.delete(key);
594
+ this.map.set(key, { at: now, value });
595
+ while (this.map.size > CACHE_MAX_ENTRIES) {
596
+ const oldest = this.map.keys().next().value;
597
+ if (oldest === undefined)
598
+ break;
599
+ this.map.delete(oldest);
600
+ }
601
+ }
602
+ clear() {
603
+ this.map.clear();
604
+ }
605
+ }
606
+ const mergeIndexCache = new TtlCache(MERGE_INDEX_TTL_MS);
607
+ const gitCache = new TtlCache(GIT_CACHE_TTL_MS);
608
+ const checkoutCache = new TtlCache(CHECKOUT_CACHE_TTL_MS);
609
+ const timelineCache = new TtlCache(TIMELINE_CACHE_TTL_MS);
610
+ const inFlight = new Map();
611
+ /** Test hook: drop every cache (the merge index, git answers, checkouts, whole timelines). */
612
+ export function clearCloudTimelineCaches() {
613
+ mergeIndexCache.clear();
614
+ gitCache.clear();
615
+ checkoutCache.clear();
616
+ timelineCache.clear();
617
+ inFlight.clear();
618
+ }
619
+ function mergeIndex(deps, now) {
620
+ const cached = mergeIndexCache.get('all', now);
621
+ if (cached !== undefined)
622
+ return cached;
623
+ const keys = deps.listMergeKeys();
624
+ if (keys === null) {
625
+ mergeIndexCache.set('all', null, now);
626
+ return null;
627
+ }
628
+ const entries = [];
629
+ for (const key of keys.slice(0, MERGE_SCAN_MAX)) {
630
+ const read = deps.readMergeRecord(key);
631
+ if (read.state !== 'ok')
632
+ continue;
633
+ const r = read.record;
634
+ entries.push({
635
+ key,
636
+ repo: r.repo,
637
+ prNumber: r.pr?.number ?? null,
638
+ landingPrNumber: r.landing?.prNumber ?? null,
639
+ branch: r.pr?.branch ?? null,
640
+ proposalId: r.proposalId,
641
+ });
642
+ }
643
+ const index = { entries, complete: keys.length <= MERGE_SCAN_MAX };
644
+ mergeIndexCache.set('all', index, now);
645
+ return index;
646
+ }
647
+ function findMergeRecord(task, deps, now) {
648
+ try {
649
+ const index = mergeIndex(deps, now);
650
+ if (!index)
651
+ return { state: 'unknown', reason: 'the fleet merge records could not be listed' };
652
+ const pr = prNumberOf(task);
653
+ const hit = index.entries.find((e) => sameRepo(e.repo, task.repo) && ((pr !== null && (e.prNumber === pr || e.landingPrNumber === pr))
654
+ || e.branch === task.branch
655
+ || e.proposalId === task.id));
656
+ if (!hit)
657
+ return index.complete ? { state: 'missing' } : { state: 'unknown', reason: `more than ${MERGE_SCAN_MAX} merge records; not all were searched` };
658
+ const read = deps.readMergeRecord(hit.key);
659
+ if (read.state === 'ok')
660
+ return { state: 'ok', record: read.record };
661
+ if (read.state === 'missing')
662
+ return { state: 'missing' };
663
+ return { state: 'unknown', reason: read.reason };
664
+ }
665
+ catch (error) {
666
+ return { state: 'unknown', reason: reasonOf(error) };
667
+ }
668
+ }
669
+ async function gatherLedger(task, merge, read, budgetMs) {
670
+ try {
671
+ const result = await withBudget(budgetMs, () => read({
672
+ kinds: ['gate:result', 'merge:landed', 'post-merge:result'],
673
+ sinceAt: task.createdAt,
674
+ }));
675
+ if (result.chain === 'broken') {
676
+ return { state: 'unknown', reason: `the ledger chain is broken${result.brokenAtSeq !== null ? ` at entry ${result.brokenAtSeq}` : ''}, so its rows are not trusted` };
677
+ }
678
+ const proposals = new Set([task.id]);
679
+ if (merge.state === 'ok' && merge.record.proposalId)
680
+ proposals.add(merge.record.proposalId);
681
+ const pr = prNumberOf(task);
682
+ const gates = [];
683
+ let landing = null;
684
+ let postMerge = null;
685
+ for (const entry of result.entries) {
686
+ if (entry.kind === 'gate:result') {
687
+ if (sameRepo(entry.data.repo, task.repo) && proposals.has(entry.data.proposalId))
688
+ gates.push({ ...entry.data, rowAt: entry.at });
689
+ }
690
+ else if (entry.kind === 'merge:landed') {
691
+ if (pr !== null && sameRepo(entry.data.repo, task.repo) && entry.data.prNumber === pr)
692
+ landing = entry.data;
693
+ }
694
+ }
695
+ if (landing) {
696
+ for (const entry of result.entries) {
697
+ if (entry.kind === 'post-merge:result' && (entry.data.landingId === landing.id || entry.data.mergeSha === landing.mergeSha))
698
+ postMerge = entry.data;
699
+ }
700
+ }
701
+ return { state: 'ok', chain: result.chain, gates, landing, postMerge };
702
+ }
703
+ catch (error) {
704
+ return { state: 'unknown', reason: reasonOf(error) };
705
+ }
706
+ }
707
+ function gatherWatch(task, landing, mergeSha, list) {
708
+ try {
709
+ const pr = prNumberOf(task);
710
+ const views = list().filter((v) => sameRepo(v.repo, task.repo) && v.kind === 'merge');
711
+ const view = views.find((v) => (landing && v.landingId === landing.id) || (mergeSha !== null && v.mergeSha === mergeSha))
712
+ ?? (pr !== null ? views.find((v) => v.prNumber === pr) : undefined)
713
+ ?? null;
714
+ return { state: 'ok', view };
715
+ }
716
+ catch (error) {
717
+ return { state: 'unknown', reason: reasonOf(error) };
718
+ }
719
+ }
720
+ async function gitLines(git, cwd, args) {
721
+ // `core.fsmonitor=false`: a read must never start a repo-configured helper.
722
+ const result = await git('git', ['-c', 'core.fsmonitor=false', ...args], { cwd, timeoutMs: GIT_TIMEOUT_MS, maxStdoutBytes: GIT_MAX_STDOUT });
723
+ if (result.missing)
724
+ return { ok: false, reason: 'git is not installed' };
725
+ if (result.timedOut)
726
+ return { ok: false, reason: 'git took too long' };
727
+ if (result.truncated)
728
+ return { ok: false, reason: 'git answered more than expected' };
729
+ if (result.code !== 0)
730
+ return { ok: false, reason: clip(result.stderr, 200) || `git exited ${result.code}` };
731
+ return { ok: true, lines: result.stdout.split('\n').map((l) => l.trim()).filter(Boolean) };
732
+ }
733
+ /** The merge commit by its message in local git: the task branch in a merge commit, else a squash subject ending `(#N)`. */
734
+ async function findMergeCommitInGit(git, cwd, task, pr) {
735
+ const merged = await gitLines(git, cwd, [
736
+ 'log', '--all', '-n', '1', '--format=%H', '--fixed-strings', '--all-match',
737
+ `--grep=Merge pull request #${pr} from `, `--grep=${task.branch}`,
738
+ ]);
739
+ if (merged.ok && merged.lines[0] && SHA_RE.test(merged.lines[0]))
740
+ return merged.lines[0];
741
+ const squash = await gitLines(git, cwd, ['log', '--all', '-n', '5', '--format=%H%x09%s', '--fixed-strings', `--grep=(#${pr})`]);
742
+ if (!squash.ok)
743
+ return null;
744
+ for (const line of squash.lines) {
745
+ const tab = line.indexOf('\t');
746
+ const sha = line.slice(0, tab);
747
+ const subject = line.slice(tab + 1);
748
+ if (SHA_RE.test(sha) && subject.endsWith(`(#${pr})`) && !/^revert\b/i.test(subject))
749
+ return sha;
750
+ }
751
+ return null;
752
+ }
753
+ async function releaseFor(git, cwd, sha) {
754
+ const tags = await gitLines(git, cwd, ['tag', '--list', '--sort=-v:refname']);
755
+ if (!tags.ok)
756
+ return { state: 'unknown', reason: `The release tags could not be read: ${tags.reason}.` };
757
+ const latest = tags.lines.find((t) => RELEASE_TAG_RE.test(t)) ?? null;
758
+ if (!latest)
759
+ return { state: 'no-tags' };
760
+ const containing = await gitLines(git, cwd, ['tag', '--contains', sha, '--sort=v:refname']);
761
+ if (!containing.ok)
762
+ return { state: 'unknown', reason: `Commit ${short(sha)} is not in the local checkout (it may need a fetch).` };
763
+ const released = containing.lines.filter((t) => RELEASE_TAG_RE.test(t));
764
+ if (!released.includes(latest))
765
+ return { state: 'not-contained', latestTag: latest };
766
+ return { state: 'contained', latestTag: latest, firstTag: released[0] ?? null };
767
+ }
768
+ function isGitDir(path) {
769
+ try {
770
+ return existsSync(join(path, '.git')) && statSync(path).isDirectory();
771
+ }
772
+ catch {
773
+ return false;
774
+ }
775
+ }
776
+ /** `owner/name` of a GitHub remote URL (https, ssh, scp-style), lowercased; null otherwise. */
777
+ export function githubNameFromRemote(url) {
778
+ const match = /^(?:https:\/\/github\.com\/|ssh:\/\/git@github\.com\/|git@github\.com:)([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?\/?$/.exec(url.trim());
779
+ return match ? `${match[1]}/${match[2]}`.toLowerCase() : null;
780
+ }
781
+ /** Production checkout finder: the fleet mirror, else an enrolled project whose origin is `repo`. */
782
+ export function defaultCheckoutFor(git) {
783
+ return async (repo) => {
784
+ try {
785
+ const mirror = mirrorPathFor(repo);
786
+ if (isGitDir(mirror))
787
+ return mirror;
788
+ }
789
+ catch { /* not a valid owner/name — fall through */ }
790
+ const want = repo.toLowerCase();
791
+ for (const project of discoverProjects().filter((p) => p.enrolled).slice(0, MAX_PROJECTS_PROBED)) {
792
+ if (!isGitDir(project.path))
793
+ continue;
794
+ const origin = await gitLines(git, project.path, ['remote', 'get-url', 'origin']);
795
+ if (origin.ok && origin.lines[0] && githubNameFromRemote(origin.lines[0]) === want)
796
+ return project.path;
797
+ }
798
+ return null;
799
+ };
800
+ }
801
+ async function gatherGit(task, landing, deps, now) {
802
+ const merged = landing !== null || task.state === 'merged' || task.pr?.state === 'merged';
803
+ if (!merged)
804
+ return { mergeCommit: null, release: null };
805
+ let checkout = checkoutCache.get(task.repo.toLowerCase(), now);
806
+ try {
807
+ if (checkout === undefined) {
808
+ checkout = await deps.checkoutFor(task.repo);
809
+ checkoutCache.set(task.repo.toLowerCase(), checkout, now);
810
+ }
811
+ }
812
+ catch {
813
+ checkout = null;
814
+ }
815
+ let mergeCommit = landing && SHA_RE.test(landing.mergeSha) ? { sha: landing.mergeSha, basis: 'landing' } : null;
816
+ if (!checkout) {
817
+ return { mergeCommit, release: mergeCommit ? { state: 'unknown', reason: `No local mirror or checkout of ${task.repo} to read release tags from.` } : null };
818
+ }
819
+ const pr = prNumberOf(task);
820
+ if (!mergeCommit && pr !== null) {
821
+ const key = `merge\0${checkout}\0${task.id}\0${pr}`;
822
+ let sha = gitCache.get(key, now);
823
+ if (sha === undefined) {
824
+ sha = await findMergeCommitInGit(deps.git, checkout, task, pr).catch(() => null);
825
+ // Only a hit is cached: a miss may just mean the checkout has not fetched the merge yet.
826
+ if (sha)
827
+ gitCache.set(key, sha, now);
828
+ }
829
+ if (sha)
830
+ mergeCommit = { sha, basis: 'git' };
831
+ }
832
+ if (!mergeCommit)
833
+ return { mergeCommit: null, release: null };
834
+ const releaseKey = `release\0${checkout}\0${mergeCommit.sha}`;
835
+ let release = gitCache.get(releaseKey, now);
836
+ if (release === undefined) {
837
+ release = await releaseFor(deps.git, checkout, mergeCommit.sha).catch((error) => ({ state: 'unknown', reason: reasonOf(error) }));
838
+ // Only settled answers are cached; an unknown is retried next time.
839
+ if (release.state !== 'unknown')
840
+ gitCache.set(releaseKey, release, now);
841
+ }
842
+ return { mergeCommit, release };
843
+ }
844
+ function evidenceModel(proposalId) {
845
+ const pack = readAutonomyEvidencePack(proposalId);
846
+ const model = pack?.producer.engineModel;
847
+ return typeof model === 'string' && model.trim() ? model : null;
848
+ }
849
+ /** Gather every source for one task. Never throws; a failing source becomes 'unknown'. */
850
+ export async function gatherTimelineSources(task, deps = {}) {
851
+ const now = (deps.now ?? (() => new Date()))().getTime();
852
+ const git = deps.git ?? defaultGitRunner;
853
+ const merge = findMergeRecord(task, {
854
+ listMergeKeys: deps.listMergeKeys ?? listFleetMergeStateKeys,
855
+ readMergeRecord: deps.readMergeRecord ?? readFleetMergeState,
856
+ }, now);
857
+ const ledger = await gatherLedger(task, merge, deps.readLedger ?? readLedger, deps.ledgerBudgetMs ?? LEDGER_BUDGET_MS);
858
+ const landing = merge.state === 'ok' && merge.record.landing ? merge.record.landing : ledger.state === 'ok' ? ledger.landing : null;
859
+ const recorded = landing && SHA_RE.test(landing.mergeSha) ? { sha: landing.mergeSha, basis: 'landing' } : null;
860
+ const { mergeCommit, release } = await withBudget(deps.gitBudgetMs ?? GIT_TOTAL_BUDGET_MS, () => gatherGit(task, landing, { git, checkoutFor: deps.checkoutFor ?? defaultCheckoutFor(git) }, now)).catch((error) => ({
861
+ mergeCommit: recorded,
862
+ release: recorded ? { state: 'unknown', reason: `Local git ${error instanceof TimedOut ? error.message : 'failed'}.` } : null,
863
+ }));
864
+ const watch = gatherWatch(task, landing, mergeCommit?.sha ?? null, deps.listWatches ?? listPostMergeWatches);
865
+ let model = null;
866
+ const proposalId = merge.state === 'ok' ? merge.record.proposalId : null;
867
+ if (proposalId) {
868
+ try {
869
+ model = (deps.readEvidenceModel ?? evidenceModel)(proposalId);
870
+ }
871
+ catch {
872
+ model = null;
873
+ }
874
+ }
875
+ return { task, merge, ledger, watch, model, mergeCommit, release };
876
+ }
877
+ let routeDeps = null;
878
+ /** Test hook: the sources the HTTP route reads (null restores production). Clears every cache. */
879
+ export function setCloudTimelineDepsForTest(deps) {
880
+ routeDeps = deps;
881
+ clearCloudTimelineCaches();
882
+ }
883
+ /** What timeline-api.ts passes to cloudTaskTimeline (production: real stores and git). */
884
+ export function timelineDepsForRoute() {
885
+ return routeDeps ?? {};
886
+ }
887
+ /**
888
+ * The timeline for task `id`, or null when there is no such task. Cached per
889
+ * task revision (`updatedAt`) for a few seconds, and concurrent requests for
890
+ * one task share a single gather.
891
+ */
892
+ export async function cloudTaskTimeline(id, deps = {}) {
893
+ if (!CLOUD_TASK_ID_PATTERN.test(id))
894
+ return null;
895
+ const clock = deps.now ?? (() => new Date());
896
+ const task = (deps.readTask ?? readCloudTask)(id);
897
+ if (!task)
898
+ return null;
899
+ const key = `${task.id}\0${task.updatedAt}`;
900
+ const cached = timelineCache.get(key, clock().getTime());
901
+ if (cached)
902
+ return cached;
903
+ const pending = inFlight.get(key);
904
+ if (pending)
905
+ return pending;
906
+ const work = (async () => {
907
+ try {
908
+ const timeline = buildCloudTimeline(await gatherTimelineSources(task, deps), clock());
909
+ timelineCache.set(key, timeline, clock().getTime());
910
+ return timeline;
911
+ }
912
+ finally {
913
+ inFlight.delete(key);
914
+ }
915
+ })();
916
+ inFlight.set(key, work);
917
+ return work;
918
+ }
919
+ //# sourceMappingURL=timeline.js.map