@stigmer/react 0.3.4 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/billing/AutoRechargeCard.d.ts +38 -0
  2. package/billing/AutoRechargeCard.d.ts.map +1 -0
  3. package/billing/AutoRechargeCard.js +90 -0
  4. package/billing/AutoRechargeCard.js.map +1 -0
  5. package/billing/BillingSection.d.ts +32 -0
  6. package/billing/BillingSection.d.ts.map +1 -0
  7. package/billing/BillingSection.js +81 -0
  8. package/billing/BillingSection.js.map +1 -0
  9. package/billing/CreditBalanceCard.d.ts +25 -0
  10. package/billing/CreditBalanceCard.d.ts.map +1 -0
  11. package/billing/CreditBalanceCard.js +28 -0
  12. package/billing/CreditBalanceCard.js.map +1 -0
  13. package/billing/CreditLedgerTable.d.ts +22 -0
  14. package/billing/CreditLedgerTable.d.ts.map +1 -0
  15. package/billing/CreditLedgerTable.js +75 -0
  16. package/billing/CreditLedgerTable.js.map +1 -0
  17. package/billing/CreditPackGrid.d.ts +31 -0
  18. package/billing/CreditPackGrid.d.ts.map +1 -0
  19. package/billing/CreditPackGrid.js +35 -0
  20. package/billing/CreditPackGrid.js.map +1 -0
  21. package/billing/LowBalanceBanner.d.ts +26 -0
  22. package/billing/LowBalanceBanner.d.ts.map +1 -0
  23. package/billing/LowBalanceBanner.js +33 -0
  24. package/billing/LowBalanceBanner.js.map +1 -0
  25. package/billing/PaymentMethodCard.d.ts +35 -0
  26. package/billing/PaymentMethodCard.d.ts.map +1 -0
  27. package/billing/PaymentMethodCard.js +48 -0
  28. package/billing/PaymentMethodCard.js.map +1 -0
  29. package/billing/credit-packs.d.ts +25 -0
  30. package/billing/credit-packs.d.ts.map +1 -0
  31. package/billing/credit-packs.js +39 -0
  32. package/billing/credit-packs.js.map +1 -0
  33. package/billing/format.d.ts +39 -0
  34. package/billing/format.d.ts.map +1 -0
  35. package/billing/format.js +90 -0
  36. package/billing/format.js.map +1 -0
  37. package/billing/index.d.ts +32 -0
  38. package/billing/index.d.ts.map +1 -0
  39. package/billing/index.js +21 -0
  40. package/billing/index.js.map +1 -0
  41. package/billing/useBillingAccount.d.ts +40 -0
  42. package/billing/useBillingAccount.d.ts.map +1 -0
  43. package/billing/useBillingAccount.js +35 -0
  44. package/billing/useBillingAccount.js.map +1 -0
  45. package/billing/useBillingUsageReport.d.ts +42 -0
  46. package/billing/useBillingUsageReport.d.ts.map +1 -0
  47. package/billing/useBillingUsageReport.js +43 -0
  48. package/billing/useBillingUsageReport.js.map +1 -0
  49. package/billing/useCreateBillingPortalSession.d.ts +35 -0
  50. package/billing/useCreateBillingPortalSession.d.ts.map +1 -0
  51. package/billing/useCreateBillingPortalSession.js +50 -0
  52. package/billing/useCreateBillingPortalSession.js.map +1 -0
  53. package/billing/useCreateCheckoutSession.d.ts +54 -0
  54. package/billing/useCreateCheckoutSession.d.ts.map +1 -0
  55. package/billing/useCreateCheckoutSession.js +58 -0
  56. package/billing/useCreateCheckoutSession.js.map +1 -0
  57. package/billing/useCreditLedger.d.ts +48 -0
  58. package/billing/useCreditLedger.d.ts.map +1 -0
  59. package/billing/useCreditLedger.js +39 -0
  60. package/billing/useCreditLedger.js.map +1 -0
  61. package/billing/useCustomerModelPricing.d.ts +41 -0
  62. package/billing/useCustomerModelPricing.d.ts.map +1 -0
  63. package/billing/useCustomerModelPricing.js +37 -0
  64. package/billing/useCustomerModelPricing.js.map +1 -0
  65. package/billing/useSetAutoRechargeConfig.d.ts +50 -0
  66. package/billing/useSetAutoRechargeConfig.d.ts.map +1 -0
  67. package/billing/useSetAutoRechargeConfig.js +53 -0
  68. package/billing/useSetAutoRechargeConfig.js.map +1 -0
  69. package/composer/ComposerToolbar.js +1 -1
  70. package/composer/ComposerToolbar.js.map +1 -1
  71. package/composer/SessionComposer.d.ts +1 -1
  72. package/composer/SessionComposer.d.ts.map +1 -1
  73. package/composer/SessionComposer.js +19 -4
  74. package/composer/SessionComposer.js.map +1 -1
  75. package/composer/__tests__/SessionComposer-memo.test.d.ts +2 -0
  76. package/composer/__tests__/SessionComposer-memo.test.d.ts.map +1 -0
  77. package/composer/__tests__/SessionComposer-memo.test.js +23 -0
  78. package/composer/__tests__/SessionComposer-memo.test.js.map +1 -0
  79. package/execution/ApprovalCard.d.ts +5 -1
  80. package/execution/ApprovalCard.d.ts.map +1 -1
  81. package/execution/ApprovalCard.js +7 -3
  82. package/execution/ApprovalCard.js.map +1 -1
  83. package/execution/ExecutionPhaseBadge.d.ts +1 -1
  84. package/execution/ExecutionPhaseBadge.d.ts.map +1 -1
  85. package/execution/ExecutionPhaseBadge.js +3 -2
  86. package/execution/ExecutionPhaseBadge.js.map +1 -1
  87. package/execution/MessageEntry.d.ts +7 -3
  88. package/execution/MessageEntry.d.ts.map +1 -1
  89. package/execution/MessageEntry.js +19 -8
  90. package/execution/MessageEntry.js.map +1 -1
  91. package/execution/MessageThread.d.ts +84 -3
  92. package/execution/MessageThread.d.ts.map +1 -1
  93. package/execution/MessageThread.js +113 -65
  94. package/execution/MessageThread.js.map +1 -1
  95. package/execution/SetupProgress.d.ts +1 -1
  96. package/execution/SetupProgress.d.ts.map +1 -1
  97. package/execution/SetupProgress.js +3 -3
  98. package/execution/SetupProgress.js.map +1 -1
  99. package/execution/SubAgentSection.d.ts +5 -1
  100. package/execution/SubAgentSection.d.ts.map +1 -1
  101. package/execution/SubAgentSection.js +13 -7
  102. package/execution/SubAgentSection.js.map +1 -1
  103. package/execution/ThreadSkeleton.d.ts +22 -0
  104. package/execution/ThreadSkeleton.d.ts.map +1 -0
  105. package/execution/ThreadSkeleton.js +26 -0
  106. package/execution/ThreadSkeleton.js.map +1 -0
  107. package/execution/ToolCallGroup.d.ts +16 -1
  108. package/execution/ToolCallGroup.d.ts.map +1 -1
  109. package/execution/ToolCallGroup.js +31 -3
  110. package/execution/ToolCallGroup.js.map +1 -1
  111. package/execution/UsageWidget.d.ts +1 -1
  112. package/execution/__tests__/message-entry.test.d.ts +2 -0
  113. package/execution/__tests__/message-entry.test.d.ts.map +1 -0
  114. package/execution/__tests__/message-entry.test.js +178 -0
  115. package/execution/__tests__/message-entry.test.js.map +1 -0
  116. package/execution/__tests__/thread-keys.test.d.ts +2 -0
  117. package/execution/__tests__/thread-keys.test.d.ts.map +1 -0
  118. package/execution/__tests__/thread-keys.test.js +289 -0
  119. package/execution/__tests__/thread-keys.test.js.map +1 -0
  120. package/execution/__tests__/thread-memoization.test.d.ts +2 -0
  121. package/execution/__tests__/thread-memoization.test.d.ts.map +1 -0
  122. package/execution/__tests__/thread-memoization.test.js +262 -0
  123. package/execution/__tests__/thread-memoization.test.js.map +1 -0
  124. package/execution/__tests__/thread-skeleton.test.d.ts +2 -0
  125. package/execution/__tests__/thread-skeleton.test.d.ts.map +1 -0
  126. package/execution/__tests__/thread-skeleton.test.js +35 -0
  127. package/execution/__tests__/thread-skeleton.test.js.map +1 -0
  128. package/execution/__tests__/useExecutionStream.test.js +73 -10
  129. package/execution/__tests__/useExecutionStream.test.js.map +1 -1
  130. package/execution/__tests__/useSessionVariables-stability.test.d.ts +2 -0
  131. package/execution/__tests__/useSessionVariables-stability.test.d.ts.map +1 -0
  132. package/execution/__tests__/useSessionVariables-stability.test.js +69 -0
  133. package/execution/__tests__/useSessionVariables-stability.test.js.map +1 -0
  134. package/execution/__tests__/virtualized-thread.test.d.ts +2 -0
  135. package/execution/__tests__/virtualized-thread.test.d.ts.map +1 -0
  136. package/execution/__tests__/virtualized-thread.test.js +274 -0
  137. package/execution/__tests__/virtualized-thread.test.js.map +1 -0
  138. package/execution/index.d.ts +2 -0
  139. package/execution/index.d.ts.map +1 -1
  140. package/execution/index.js +1 -0
  141. package/execution/index.js.map +1 -1
  142. package/execution/useExecutionStream.d.ts +35 -10
  143. package/execution/useExecutionStream.d.ts.map +1 -1
  144. package/execution/useExecutionStream.js +79 -40
  145. package/execution/useExecutionStream.js.map +1 -1
  146. package/execution/useSessionVariables.d.ts.map +1 -1
  147. package/execution/useSessionVariables.js +4 -3
  148. package/execution/useSessionVariables.js.map +1 -1
  149. package/github/useGitHubConnection.d.ts.map +1 -1
  150. package/github/useGitHubConnection.js +5 -4
  151. package/github/useGitHubConnection.js.map +1 -1
  152. package/identity-account/index.d.ts +2 -0
  153. package/identity-account/index.d.ts.map +1 -0
  154. package/identity-account/index.js +2 -0
  155. package/identity-account/index.js.map +1 -0
  156. package/identity-account/useIdentityAccountGate.d.ts +81 -0
  157. package/identity-account/useIdentityAccountGate.d.ts.map +1 -0
  158. package/identity-account/useIdentityAccountGate.js +100 -0
  159. package/identity-account/useIdentityAccountGate.js.map +1 -0
  160. package/index.d.ts +10 -4
  161. package/index.d.ts.map +1 -1
  162. package/index.js +8 -2
  163. package/index.js.map +1 -1
  164. package/internal/FetchCacheProvider.d.ts +44 -0
  165. package/internal/FetchCacheProvider.d.ts.map +1 -0
  166. package/internal/FetchCacheProvider.js +61 -0
  167. package/internal/FetchCacheProvider.js.map +1 -0
  168. package/internal/JumpToLatestButton.d.ts +14 -0
  169. package/internal/JumpToLatestButton.d.ts.map +1 -0
  170. package/internal/JumpToLatestButton.js +19 -0
  171. package/internal/JumpToLatestButton.js.map +1 -0
  172. package/internal/ThreadItemWrapper.d.ts +20 -0
  173. package/internal/ThreadItemWrapper.d.ts.map +1 -0
  174. package/internal/ThreadItemWrapper.js +44 -0
  175. package/internal/ThreadItemWrapper.js.map +1 -0
  176. package/internal/VirtualizedThread.d.ts +25 -0
  177. package/internal/VirtualizedThread.d.ts.map +1 -0
  178. package/internal/VirtualizedThread.js +58 -0
  179. package/internal/VirtualizedThread.js.map +1 -0
  180. package/internal/__tests__/fetch-cache.test.d.ts +2 -0
  181. package/internal/__tests__/fetch-cache.test.d.ts.map +1 -0
  182. package/internal/__tests__/fetch-cache.test.js +182 -0
  183. package/internal/__tests__/fetch-cache.test.js.map +1 -0
  184. package/internal/__tests__/stream-controller.test.d.ts +2 -0
  185. package/internal/__tests__/stream-controller.test.d.ts.map +1 -0
  186. package/internal/__tests__/stream-controller.test.js +294 -0
  187. package/internal/__tests__/stream-controller.test.js.map +1 -0
  188. package/internal/__tests__/thread-animation.test.d.ts +2 -0
  189. package/internal/__tests__/thread-animation.test.d.ts.map +1 -0
  190. package/internal/__tests__/thread-animation.test.js +79 -0
  191. package/internal/__tests__/thread-animation.test.js.map +1 -0
  192. package/internal/__tests__/useAutoScroll.test.d.ts +2 -0
  193. package/internal/__tests__/useAutoScroll.test.d.ts.map +1 -0
  194. package/internal/__tests__/useAutoScroll.test.js +188 -0
  195. package/internal/__tests__/useAutoScroll.test.js.map +1 -0
  196. package/internal/__tests__/useFetch-cache.test.d.ts +2 -0
  197. package/internal/__tests__/useFetch-cache.test.d.ts.map +1 -0
  198. package/internal/__tests__/useFetch-cache.test.js +137 -0
  199. package/internal/__tests__/useFetch-cache.test.js.map +1 -0
  200. package/internal/dev/__tests__/use-key-stability.test.d.ts +2 -0
  201. package/internal/dev/__tests__/use-key-stability.test.d.ts.map +1 -0
  202. package/internal/dev/__tests__/use-key-stability.test.js +72 -0
  203. package/internal/dev/__tests__/use-key-stability.test.js.map +1 -0
  204. package/internal/dev/__tests__/use-render-tracer.test.d.ts +2 -0
  205. package/internal/dev/__tests__/use-render-tracer.test.d.ts.map +1 -0
  206. package/internal/dev/__tests__/use-render-tracer.test.js +55 -0
  207. package/internal/dev/__tests__/use-render-tracer.test.js.map +1 -0
  208. package/internal/dev/dom-counter.d.ts +14 -0
  209. package/internal/dev/dom-counter.d.ts.map +1 -0
  210. package/internal/dev/dom-counter.js +39 -0
  211. package/internal/dev/dom-counter.js.map +1 -0
  212. package/internal/dev/index.d.ts +6 -0
  213. package/internal/dev/index.d.ts.map +1 -0
  214. package/internal/dev/index.js +6 -0
  215. package/internal/dev/index.js.map +1 -0
  216. package/internal/dev/profiler-wrapper.d.ts +16 -0
  217. package/internal/dev/profiler-wrapper.d.ts.map +1 -0
  218. package/internal/dev/profiler-wrapper.js +31 -0
  219. package/internal/dev/profiler-wrapper.js.map +1 -0
  220. package/internal/dev/use-key-stability.d.ts +22 -0
  221. package/internal/dev/use-key-stability.d.ts.map +1 -0
  222. package/internal/dev/use-key-stability.js +67 -0
  223. package/internal/dev/use-key-stability.js.map +1 -0
  224. package/internal/dev/use-render-tracer.d.ts +13 -0
  225. package/internal/dev/use-render-tracer.d.ts.map +1 -0
  226. package/internal/dev/use-render-tracer.js +57 -0
  227. package/internal/dev/use-render-tracer.js.map +1 -0
  228. package/internal/dev/use-stream-rate.d.ts +23 -0
  229. package/internal/dev/use-stream-rate.d.ts.map +1 -0
  230. package/internal/dev/use-stream-rate.js +94 -0
  231. package/internal/dev/use-stream-rate.js.map +1 -0
  232. package/internal/fetch-cache.d.ts +72 -0
  233. package/internal/fetch-cache.d.ts.map +1 -0
  234. package/internal/fetch-cache.js +118 -0
  235. package/internal/fetch-cache.js.map +1 -0
  236. package/internal/store/__tests__/conversation-store.test.d.ts +2 -0
  237. package/internal/store/__tests__/conversation-store.test.d.ts.map +1 -0
  238. package/internal/store/__tests__/conversation-store.test.js +200 -0
  239. package/internal/store/__tests__/conversation-store.test.js.map +1 -0
  240. package/internal/store/__tests__/structural-share.test.d.ts +2 -0
  241. package/internal/store/__tests__/structural-share.test.d.ts.map +1 -0
  242. package/internal/store/__tests__/structural-share.test.js +368 -0
  243. package/internal/store/__tests__/structural-share.test.js.map +1 -0
  244. package/internal/store/conversation-store.d.ts +62 -0
  245. package/internal/store/conversation-store.d.ts.map +1 -0
  246. package/internal/store/conversation-store.js +95 -0
  247. package/internal/store/conversation-store.js.map +1 -0
  248. package/internal/store/index.d.ts +31 -0
  249. package/internal/store/index.d.ts.map +1 -0
  250. package/internal/store/index.js +54 -0
  251. package/internal/store/index.js.map +1 -0
  252. package/internal/store/structural-share.d.ts +13 -0
  253. package/internal/store/structural-share.d.ts.map +1 -0
  254. package/internal/store/structural-share.js +240 -0
  255. package/internal/store/structural-share.js.map +1 -0
  256. package/internal/stream-controller.d.ts +85 -0
  257. package/internal/stream-controller.d.ts.map +1 -0
  258. package/internal/stream-controller.js +146 -0
  259. package/internal/stream-controller.js.map +1 -0
  260. package/internal/useAutoScroll.d.ts +32 -0
  261. package/internal/useAutoScroll.d.ts.map +1 -0
  262. package/internal/useAutoScroll.js +97 -0
  263. package/internal/useAutoScroll.js.map +1 -0
  264. package/internal/useFetch.d.ts +14 -0
  265. package/internal/useFetch.d.ts.map +1 -1
  266. package/internal/useFetch.js +32 -2
  267. package/internal/useFetch.js.map +1 -1
  268. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  269. package/mcp-server/McpServerDetailView.js +3 -3
  270. package/mcp-server/McpServerDetailView.js.map +1 -1
  271. package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
  272. package/mcp-server/useMcpServerOAuthConnect.js +37 -9
  273. package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
  274. package/package.json +7 -5
  275. package/session/__tests__/useNewSessionFlow.test.js +16 -0
  276. package/session/__tests__/useNewSessionFlow.test.js.map +1 -1
  277. package/session/__tests__/usePersistedModel.test.d.ts +2 -0
  278. package/session/__tests__/usePersistedModel.test.d.ts.map +1 -0
  279. package/session/__tests__/usePersistedModel.test.js +82 -0
  280. package/session/__tests__/usePersistedModel.test.js.map +1 -0
  281. package/session/__tests__/useSession.test.d.ts +2 -0
  282. package/session/__tests__/useSession.test.d.ts.map +1 -0
  283. package/session/__tests__/useSession.test.js +130 -0
  284. package/session/__tests__/useSession.test.js.map +1 -0
  285. package/session/useNewSessionFlow.d.ts.map +1 -1
  286. package/session/useNewSessionFlow.js +12 -6
  287. package/session/useNewSessionFlow.js.map +1 -1
  288. package/session/usePersistedModel.d.ts +3 -0
  289. package/session/usePersistedModel.d.ts.map +1 -1
  290. package/session/usePersistedModel.js +27 -2
  291. package/session/usePersistedModel.js.map +1 -1
  292. package/session/useSession.d.ts.map +1 -1
  293. package/session/useSession.js +1 -1
  294. package/session/useSession.js.map +1 -1
  295. package/session/useSessionConversation.d.ts.map +1 -1
  296. package/session/useSessionConversation.js +9 -1
  297. package/session/useSessionConversation.js.map +1 -1
  298. package/session/useSessionExecutions.d.ts.map +1 -1
  299. package/session/useSessionExecutions.js +1 -1
  300. package/session/useSessionExecutions.js.map +1 -1
  301. package/session/useSessionPageFlow.js +1 -1
  302. package/session/useSessionPageFlow.js.map +1 -1
  303. package/session/useSessionUsage.d.ts +24 -40
  304. package/session/useSessionUsage.d.ts.map +1 -1
  305. package/session/useSessionUsage.js +64 -97
  306. package/session/useSessionUsage.js.map +1 -1
  307. package/settings/BillingSection.d.ts +3 -0
  308. package/settings/BillingSection.d.ts.map +1 -0
  309. package/settings/BillingSection.js +3 -0
  310. package/settings/BillingSection.js.map +1 -0
  311. package/settings/index.d.ts +2 -0
  312. package/settings/index.d.ts.map +1 -1
  313. package/settings/index.js +1 -0
  314. package/settings/index.js.map +1 -1
  315. package/settings/settings-nav.js +1 -1
  316. package/settings/settings-nav.js.map +1 -1
  317. package/src/billing/AutoRechargeCard.tsx +274 -0
  318. package/src/billing/BillingSection.tsx +255 -0
  319. package/src/billing/CreditBalanceCard.tsx +81 -0
  320. package/src/billing/CreditLedgerTable.tsx +281 -0
  321. package/src/billing/CreditPackGrid.tsx +132 -0
  322. package/src/billing/LowBalanceBanner.tsx +67 -0
  323. package/src/billing/PaymentMethodCard.tsx +133 -0
  324. package/src/billing/credit-packs.ts +54 -0
  325. package/src/billing/format.ts +97 -0
  326. package/src/billing/index.ts +51 -0
  327. package/src/billing/useBillingAccount.ts +64 -0
  328. package/src/billing/useBillingUsageReport.ts +73 -0
  329. package/src/billing/useCreateBillingPortalSession.ts +76 -0
  330. package/src/billing/useCreateCheckoutSession.ts +101 -0
  331. package/src/billing/useCreditLedger.ts +79 -0
  332. package/src/billing/useCustomerModelPricing.ts +67 -0
  333. package/src/billing/useSetAutoRechargeConfig.ts +90 -0
  334. package/src/composer/ComposerToolbar.tsx +1 -1
  335. package/src/composer/SessionComposer.tsx +22 -4
  336. package/src/composer/__tests__/SessionComposer-memo.test.ts +26 -0
  337. package/src/execution/ApprovalCard.tsx +7 -3
  338. package/src/execution/ExecutionPhaseBadge.tsx +3 -2
  339. package/src/execution/MessageEntry.tsx +27 -16
  340. package/src/execution/MessageThread.tsx +308 -131
  341. package/src/execution/SetupProgress.tsx +3 -3
  342. package/src/execution/SubAgentSection.tsx +14 -6
  343. package/src/execution/ThreadSkeleton.tsx +73 -0
  344. package/src/execution/ToolCallGroup.tsx +36 -3
  345. package/src/execution/UsageWidget.tsx +1 -1
  346. package/src/execution/__tests__/message-entry.test.tsx +236 -0
  347. package/src/execution/__tests__/thread-keys.test.ts +409 -0
  348. package/src/execution/__tests__/thread-memoization.test.ts +320 -0
  349. package/src/execution/__tests__/thread-skeleton.test.tsx +44 -0
  350. package/src/execution/__tests__/useExecutionStream.test.tsx +109 -12
  351. package/src/execution/__tests__/useSessionVariables-stability.test.ts +95 -0
  352. package/src/execution/__tests__/virtualized-thread.test.tsx +401 -0
  353. package/src/execution/index.ts +3 -0
  354. package/src/execution/useExecutionStream.ts +123 -48
  355. package/src/execution/useSessionVariables.ts +17 -12
  356. package/src/github/useGitHubConnection.ts +18 -13
  357. package/src/identity-account/index.ts +5 -0
  358. package/src/identity-account/useIdentityAccountGate.ts +163 -0
  359. package/src/index.ts +73 -0
  360. package/src/internal/FetchCacheProvider.tsx +74 -0
  361. package/src/internal/JumpToLatestButton.tsx +61 -0
  362. package/src/internal/ThreadItemWrapper.tsx +65 -0
  363. package/src/internal/VirtualizedThread.tsx +162 -0
  364. package/src/internal/__tests__/fetch-cache.test.ts +230 -0
  365. package/src/internal/__tests__/stream-controller.test.ts +395 -0
  366. package/src/internal/__tests__/thread-animation.test.tsx +121 -0
  367. package/src/internal/__tests__/useAutoScroll.test.tsx +261 -0
  368. package/src/internal/__tests__/useFetch-cache.test.ts +214 -0
  369. package/src/internal/dev/__tests__/use-key-stability.test.ts +124 -0
  370. package/src/internal/dev/__tests__/use-render-tracer.test.ts +78 -0
  371. package/src/internal/dev/dom-counter.ts +47 -0
  372. package/src/internal/dev/index.ts +5 -0
  373. package/src/internal/dev/profiler-wrapper.tsx +52 -0
  374. package/src/internal/dev/use-key-stability.ts +86 -0
  375. package/src/internal/dev/use-render-tracer.ts +70 -0
  376. package/src/internal/dev/use-stream-rate.ts +138 -0
  377. package/src/internal/fetch-cache.ts +155 -0
  378. package/src/internal/store/__tests__/conversation-store.test.ts +257 -0
  379. package/src/internal/store/__tests__/structural-share.test.ts +454 -0
  380. package/src/internal/store/conversation-store.ts +128 -0
  381. package/src/internal/store/index.ts +68 -0
  382. package/src/internal/store/structural-share.ts +318 -0
  383. package/src/internal/stream-controller.ts +201 -0
  384. package/src/internal/useAutoScroll.ts +121 -0
  385. package/src/internal/useFetch.ts +51 -2
  386. package/src/mcp-server/McpServerDetailView.tsx +15 -0
  387. package/src/mcp-server/useMcpServerOAuthConnect.ts +37 -9
  388. package/src/session/__tests__/useNewSessionFlow.test.tsx +22 -0
  389. package/src/session/__tests__/usePersistedModel.test.tsx +117 -0
  390. package/src/session/__tests__/useSession.test.tsx +187 -0
  391. package/src/session/useNewSessionFlow.ts +12 -6
  392. package/src/session/usePersistedModel.ts +28 -2
  393. package/src/session/useSession.ts +1 -0
  394. package/src/session/useSessionConversation.ts +11 -2
  395. package/src/session/useSessionExecutions.ts +1 -0
  396. package/src/session/useSessionPageFlow.ts +1 -1
  397. package/src/session/useSessionUsage.ts +102 -123
  398. package/src/settings/BillingSection.tsx +4 -0
  399. package/src/settings/index.ts +2 -0
  400. package/src/settings/settings-nav.ts +1 -1
  401. package/src/styles.css +31 -0
  402. package/src/usage/AgentBreakdownList.tsx +147 -0
  403. package/src/usage/CreditRunwayIndicator.tsx +71 -0
  404. package/src/usage/ExportButton.tsx +115 -0
  405. package/src/usage/HarnessSplitCard.tsx +103 -0
  406. package/src/usage/OrgUsagePanel.tsx +109 -45
  407. package/src/usage/index.ts +15 -0
  408. package/src/usage/useExportCSV.ts +115 -0
  409. package/src/usage/useOrgUsageReport.ts +2 -1
  410. package/src/workspace/__tests__/useWorkspaceEntries-stability.test.ts +76 -0
  411. package/src/workspace/useWorkspaceEntries.ts +16 -11
  412. package/styles.css +1 -1
  413. package/usage/AgentBreakdownList.d.ts +21 -0
  414. package/usage/AgentBreakdownList.d.ts.map +1 -0
  415. package/usage/AgentBreakdownList.js +44 -0
  416. package/usage/AgentBreakdownList.js.map +1 -0
  417. package/usage/CreditRunwayIndicator.d.ts +21 -0
  418. package/usage/CreditRunwayIndicator.d.ts.map +1 -0
  419. package/usage/CreditRunwayIndicator.js +38 -0
  420. package/usage/CreditRunwayIndicator.js.map +1 -0
  421. package/usage/ExportButton.d.ts +20 -0
  422. package/usage/ExportButton.d.ts.map +1 -0
  423. package/usage/ExportButton.js +36 -0
  424. package/usage/ExportButton.js.map +1 -0
  425. package/usage/HarnessSplitCard.d.ts +17 -0
  426. package/usage/HarnessSplitCard.d.ts.map +1 -0
  427. package/usage/HarnessSplitCard.js +38 -0
  428. package/usage/HarnessSplitCard.js.map +1 -0
  429. package/usage/OrgUsagePanel.d.ts.map +1 -1
  430. package/usage/OrgUsagePanel.js +30 -22
  431. package/usage/OrgUsagePanel.js.map +1 -1
  432. package/usage/index.d.ts +10 -0
  433. package/usage/index.d.ts.map +1 -1
  434. package/usage/index.js +5 -0
  435. package/usage/index.js.map +1 -1
  436. package/usage/useExportCSV.d.ts +23 -0
  437. package/usage/useExportCSV.d.ts.map +1 -0
  438. package/usage/useExportCSV.js +81 -0
  439. package/usage/useExportCSV.js.map +1 -0
  440. package/usage/useOrgUsageReport.d.ts +2 -1
  441. package/usage/useOrgUsageReport.d.ts.map +1 -1
  442. package/usage/useOrgUsageReport.js +2 -1
  443. package/usage/useOrgUsageReport.js.map +1 -1
  444. package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts +2 -0
  445. package/workspace/__tests__/useWorkspaceEntries-stability.test.d.ts.map +1 -0
  446. package/workspace/__tests__/useWorkspaceEntries-stability.test.js +57 -0
  447. package/workspace/__tests__/useWorkspaceEntries-stability.test.js.map +1 -0
  448. package/workspace/useWorkspaceEntries.d.ts.map +1 -1
  449. package/workspace/useWorkspaceEntries.js +5 -4
  450. package/workspace/useWorkspaceEntries.js.map +1 -1
@@ -17,6 +17,7 @@ import type {
17
17
  } from "@stigmer/sdk";
18
18
  import { isTerminalPhase } from "../execution/execution-phases";
19
19
  import { useStigmer } from "../hooks";
20
+ import { useConversationStoreRef } from "../internal/store";
20
21
  import { useCreateAgentExecution } from "../execution/useCreateAgentExecution";
21
22
  import { useExecutionStream } from "../execution/useExecutionStream";
22
23
  import { useSubmitApproval } from "../execution/useSubmitApproval";
@@ -248,7 +249,14 @@ export function useSessionConversation(
248
249
 
249
250
  const activeExecutionId = pendingExecutionId ?? listActiveId;
250
251
 
251
- const stream = useExecutionStream(activeExecutionId);
252
+ // The conversation store is shared between useExecutionStream (which
253
+ // ingests snapshots with structural sharing + rAF coalescing) and the
254
+ // rendering tree. This eliminates the duplicate structuralShare that
255
+ // was previously done in this hook.
256
+ const conversationStore = useConversationStoreRef();
257
+ const stream = useExecutionStream(activeExecutionId, {
258
+ store: conversationStore,
259
+ });
252
260
 
253
261
  // Clear pendingExecutionId once the execution appears in the fetched list
254
262
  useEffect(() => {
@@ -291,7 +299,8 @@ export function useSessionConversation(
291
299
  );
292
300
  }, [executions, activeExecutionId]);
293
301
 
294
- const activeStreamExecution = stream.execution ?? fetchedActiveExecution;
302
+ const activeStreamExecution =
303
+ stream.execution ?? fetchedActiveExecution;
295
304
 
296
305
  const activePhase = useMemo<ExecutionPhase | null>(() => {
297
306
  if (!activeExecutionId) return null;
@@ -73,6 +73,7 @@ export function useSessionExecutions(
73
73
  : null,
74
74
  [sessionId, stigmer],
75
75
  [] as AgentExecution[],
76
+ { cacheKey: sessionId ? `session-executions:${sessionId}` : undefined },
76
77
  );
77
78
 
78
79
  return { executions, isLoading, isRefetching, error, refetch };
@@ -253,7 +253,7 @@ export function useSessionPageFlow(
253
253
 
254
254
  sessionVariables.clear();
255
255
  },
256
- [conv, modelId, workspace, mcpServerUsages, skillRefs, sessionVariables, resolution, agentRef, sessionInstanceId, stigmer],
256
+ [conv.sendFollowUp, modelId, workspace, mcpServerUsages, skillRefs, sessionVariables.clear, resolution, agentRef, sessionInstanceId, stigmer],
257
257
  );
258
258
 
259
259
  // -------------------------------------------------------------------------
@@ -1,27 +1,33 @@
1
1
  "use client";
2
2
 
3
3
  import { useMemo } from "react";
4
+ import { create } from "@bufbuild/protobuf";
4
5
  import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
5
- import { MessageType } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
6
- import type { LlmCallMetrics } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/usage_pb";
6
+ import {
7
+ GetSessionUsageReportInputSchema,
8
+ type GetSessionUsageReportOutput,
9
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
10
+ import type { ModelUsage } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/usage_pb";
11
+ import { useStigmer } from "../hooks";
12
+ import { useFetch } from "../internal/useFetch";
7
13
 
8
14
  /**
9
- * Per-model cost breakdown computed from per-message {@link LlmCallMetrics}.
15
+ * Per-model cost breakdown.
10
16
  */
11
17
  export interface ModelCostEntry {
12
- /** Model identifier (e.g., `"claude-3-5-sonnet-20241022"`). */
18
+ /** Model identifier (e.g. "claude-sonnet-4-20250514"). */
13
19
  readonly model: string;
14
- /** Provider that served the model (e.g., `"anthropic"`). */
20
+ /** Provider name (e.g. "anthropic", "openai"). */
15
21
  readonly provider: string;
16
- /** Estimated cost in USD for all calls to this model. */
22
+ /** Estimated cost in USD for this model's usage. */
17
23
  readonly estimatedCostUsd: number;
18
- /** Total non-cached input tokens across all calls to this model. */
24
+ /** Total input tokens consumed by this model. */
19
25
  readonly inputTokens: number;
20
- /** Total output tokens across all calls to this model. */
26
+ /** Total output tokens generated by this model. */
21
27
  readonly outputTokens: number;
22
- /** Total cache creation tokens across all calls to this model. */
28
+ /** Tokens used to create cache entries. */
23
29
  readonly cacheCreationTokens: number;
24
- /** Total cache read tokens across all calls to this model. */
30
+ /** Tokens served from cache. */
25
31
  readonly cacheReadTokens: number;
26
32
  /** Number of LLM calls made to this model. */
27
33
  readonly callCount: number;
@@ -29,140 +35,113 @@ export interface ModelCostEntry {
29
35
 
30
36
  /** Return value of {@link useSessionUsage}. */
31
37
  export interface UseSessionUsageReturn {
32
- /** Total estimated cost across all executions in the session. */
38
+ /** Aggregate estimated cost in USD across all models. */
33
39
  readonly totalCostUsd: number;
34
- /** Total tokens (all types) across all executions. */
40
+ /** Total tokens (input + output) across all models. */
35
41
  readonly totalTokens: number;
36
- /** Total input tokens (non-cached) across all executions. */
42
+ /** Total input tokens across all models. */
37
43
  readonly inputTokens: number;
38
- /** Total output tokens across all executions. */
44
+ /** Total output tokens across all models. */
39
45
  readonly outputTokens: number;
40
- /** Total cache read tokens across all executions. */
46
+ /** Total tokens served from cache across all models. */
41
47
  readonly cacheReadTokens: number;
42
- /** Total cache creation tokens across all executions. */
48
+ /** Total tokens used to create cache entries across all models. */
43
49
  readonly cacheCreationTokens: number;
44
- /** Total number of LLM calls across all executions. */
50
+ /** Total number of LLM calls in this session. */
45
51
  readonly llmCallCount: number;
46
- /** Per-model breakdown, sorted by cost descending. */
52
+ /** Per-model cost and token breakdown. */
47
53
  readonly modelBreakdown: readonly ModelCostEntry[];
48
- /** Primary model (first model encountered). */
54
+ /** Model with the highest usage in this session. */
49
55
  readonly primaryModel: string;
50
- /** Primary provider (first provider encountered). */
56
+ /** Provider of the primary model. */
51
57
  readonly primaryProvider: string;
52
- /** `true` when at least one execution has cost data. */
58
+ /** `true` when usage data is available. */
53
59
  readonly hasUsage: boolean;
54
60
  }
55
61
 
62
+ const EMPTY: UseSessionUsageReturn = {
63
+ totalCostUsd: 0,
64
+ totalTokens: 0,
65
+ inputTokens: 0,
66
+ outputTokens: 0,
67
+ cacheReadTokens: 0,
68
+ cacheCreationTokens: 0,
69
+ llmCallCount: 0,
70
+ modelBreakdown: [],
71
+ primaryModel: "",
72
+ primaryProvider: "",
73
+ hasUsage: false,
74
+ };
75
+
76
+ function microsToUsd(micros: bigint): number {
77
+ return Number(micros) / 1_000_000;
78
+ }
79
+
80
+ function mapModelUsage(m: ModelUsage): ModelCostEntry {
81
+ return {
82
+ model: m.model,
83
+ provider: m.provider,
84
+ estimatedCostUsd: microsToUsd(m.billableCostMicros),
85
+ inputTokens: Number(m.inputTokens),
86
+ outputTokens: Number(m.outputTokens),
87
+ cacheCreationTokens: Number(m.cacheCreationInputTokens),
88
+ cacheReadTokens: Number(m.cacheReadInputTokens),
89
+ callCount: m.callCount,
90
+ };
91
+ }
92
+
93
+ function mapReport(report: GetSessionUsageReportOutput): UseSessionUsageReturn {
94
+ const agg = report.totalUsage;
95
+ if (!agg) return EMPTY;
96
+
97
+ return {
98
+ totalCostUsd: microsToUsd(agg.billableCostMicros),
99
+ totalTokens: Number(agg.totalTokens),
100
+ inputTokens: Number(agg.inputTokens),
101
+ outputTokens: Number(agg.outputTokens),
102
+ cacheReadTokens: Number(agg.cacheReadInputTokens),
103
+ cacheCreationTokens: Number(agg.cacheCreationInputTokens),
104
+ llmCallCount: agg.llmCallCount,
105
+ modelBreakdown: report.modelBreakdown.map(mapModelUsage),
106
+ primaryModel: agg.primaryModel,
107
+ primaryProvider: agg.primaryProvider,
108
+ hasUsage: true,
109
+ };
110
+ }
111
+
56
112
  /**
57
- * Pure derivation hook that aggregates usage data across all executions
58
- * in a session from per-message {@link LlmCallMetrics}.
113
+ * Usage hook for session-level cost and token aggregation.
59
114
  *
60
- * Follows the same pattern as {@link useSessionArtifacts} and
61
- * {@link useSessionWriteBacks}: `useMemo`-based derivation, no side
62
- * effects, no data fetching. Takes the same `executions` array input.
115
+ * Calls `getSessionUsageReport` to fetch real usage data from the
116
+ * billing domain. Returns zeros while loading or when no session is
117
+ * available.
63
118
  *
64
- * Per-message `llm_metrics` on `AgentMessage` (type == MESSAGE_AI) is
65
- * the single source of truth for cost data. This hook walks all messages
66
- * (main agent + sub-agents) across all executions and sums the fields.
67
- *
68
- * @param executions - All executions for a session, in chronological
69
- * order. Pass both completed and active-stream executions.
70
- *
71
- * @example
72
- * ```tsx
73
- * const conv = useSessionConversation(sessionId, org);
74
- * const allExecutions = [
75
- * ...conv.completedExecutions,
76
- * ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
77
- * ];
78
- * const { totalCostUsd, totalTokens, hasUsage } = useSessionUsage(allExecutions);
79
- * ```
119
+ * @param executions - All executions for a session (used to derive session ID).
80
120
  */
81
121
  export function useSessionUsage(
82
122
  executions: readonly AgentExecution[],
83
123
  ): UseSessionUsageReturn {
84
- return useMemo(() => {
85
- let totalCostUsd = 0;
86
- let totalTokens = 0;
87
- let inputTokens = 0;
88
- let outputTokens = 0;
89
- let cacheReadTokens = 0;
90
- let cacheCreationTokens = 0;
91
- let llmCallCount = 0;
92
- let primaryModel = "";
93
- let primaryProvider = "";
94
- const modelMap = new Map<string, ModelCostEntry>();
95
-
96
- const processMessage = (msg: { type: MessageType; llmMetrics?: LlmCallMetrics }) => {
97
- const m = msg.llmMetrics;
98
- if (!m) return;
124
+ const stigmer = useStigmer();
99
125
 
100
- totalCostUsd += m.estimatedCostUsd;
101
- totalTokens += m.totalTokens;
102
- inputTokens += m.inputTokens;
103
- outputTokens += m.outputTokens;
104
- cacheReadTokens += m.cacheReadTokens;
105
- cacheCreationTokens += m.cacheCreationTokens;
106
- llmCallCount++;
126
+ const sessionId = useMemo(
127
+ () => executions[0]?.spec?.sessionId ?? null,
128
+ [executions],
129
+ );
107
130
 
108
- if (!primaryModel && m.model) {
109
- primaryModel = m.model;
110
- primaryProvider = m.provider;
111
- }
131
+ const { data: report } = useFetch(
132
+ sessionId
133
+ ? () =>
134
+ stigmer.agentExecution.getSessionUsageReport(
135
+ create(GetSessionUsageReportInputSchema, { sessionId }),
136
+ )
137
+ : null,
138
+ [sessionId, stigmer],
139
+ null as GetSessionUsageReportOutput | null,
140
+ { cacheKey: sessionId ? `session-usage:${sessionId}` : undefined },
141
+ );
112
142
 
113
- const key = `${m.model}\0${m.provider}`;
114
- const existing = modelMap.get(key);
115
- if (existing) {
116
- modelMap.set(key, {
117
- ...existing,
118
- estimatedCostUsd: existing.estimatedCostUsd + m.estimatedCostUsd,
119
- inputTokens: existing.inputTokens + m.inputTokens,
120
- outputTokens: existing.outputTokens + m.outputTokens,
121
- cacheCreationTokens: existing.cacheCreationTokens + m.cacheCreationTokens,
122
- cacheReadTokens: existing.cacheReadTokens + m.cacheReadTokens,
123
- callCount: existing.callCount + 1,
124
- });
125
- } else {
126
- modelMap.set(key, {
127
- model: m.model,
128
- provider: m.provider,
129
- estimatedCostUsd: m.estimatedCostUsd,
130
- inputTokens: m.inputTokens,
131
- outputTokens: m.outputTokens,
132
- cacheCreationTokens: m.cacheCreationTokens,
133
- cacheReadTokens: m.cacheReadTokens,
134
- callCount: 1,
135
- });
136
- }
137
- };
138
-
139
- for (const execution of executions) {
140
- for (const msg of execution.status?.messages ?? []) {
141
- processMessage(msg);
142
- }
143
- for (const sub of execution.status?.subAgentExecutions ?? []) {
144
- for (const msg of sub.messages) {
145
- processMessage(msg);
146
- }
147
- }
148
- }
149
-
150
- const modelBreakdown = Array.from(modelMap.values()).sort(
151
- (a, b) => b.estimatedCostUsd - a.estimatedCostUsd,
152
- );
153
-
154
- return {
155
- totalCostUsd,
156
- totalTokens,
157
- inputTokens,
158
- outputTokens,
159
- cacheReadTokens,
160
- cacheCreationTokens,
161
- llmCallCount,
162
- modelBreakdown,
163
- primaryModel,
164
- primaryProvider,
165
- hasUsage: llmCallCount > 0,
166
- };
167
- }, [executions]);
143
+ return useMemo(() => {
144
+ if (!report) return EMPTY;
145
+ return mapReport(report);
146
+ }, [report]);
168
147
  }
@@ -0,0 +1,4 @@
1
+ "use client";
2
+
3
+ export { BillingSection } from "../billing/BillingSection";
4
+ export type { BillingSectionProps } from "../billing/BillingSection";
@@ -2,6 +2,8 @@ export { SETTINGS_NAV_GROUPS } from "./settings-nav";
2
2
  export type { SettingsNavItem, SettingsNavGroup } from "./settings-nav";
3
3
 
4
4
  export { ApiKeysSection } from "./ApiKeysSection";
5
+ export { BillingSection } from "./BillingSection";
6
+ export type { BillingSectionProps } from "./BillingSection";
5
7
  export { MembersSection } from "./MembersSection";
6
8
  export { OrgProfileSection } from "./OrgProfileSection";
7
9
  export { EnvironmentsSection } from "./EnvironmentsSection";
@@ -69,7 +69,7 @@ export const SETTINGS_NAV_GROUPS: readonly SettingsNavGroup[] = [
69
69
  },
70
70
  {
71
71
  label: "Billing & Usage",
72
- description: "Subscription management and usage metrics.",
72
+ description: "Credit management and usage metrics.",
73
73
  items: [
74
74
  { href: "/settings/billing", label: "Billing", icon: CreditCard },
75
75
  { href: "/settings/usage", label: "Usage", icon: BarChart3 },
package/src/styles.css CHANGED
@@ -1,4 +1,5 @@
1
1
  @source "./**/*.{ts,tsx}";
2
+ @source "../node_modules/streamdown/dist/*.js";
2
3
 
3
4
  @layer stgm;
4
5
 
@@ -82,6 +83,8 @@
82
83
 
83
84
  @layer stgm {
84
85
  .stgm {
86
+ --stgm-motion-duration: 150ms;
87
+ --stgm-motion-easing: var(--stgm-transition-timing, ease-out);
85
88
  line-height: 1.5;
86
89
  -webkit-font-smoothing: antialiased;
87
90
  -moz-osx-font-smoothing: grayscale;
@@ -95,4 +98,32 @@
95
98
  border-style: solid;
96
99
  border-color: var(--stgm-border, currentColor);
97
100
  }
101
+
102
+ @keyframes stgm-fade-in-up {
103
+ from {
104
+ opacity: 0;
105
+ transform: translateY(6px);
106
+ }
107
+ }
108
+
109
+ .stgm-thread-item-enter {
110
+ animation: stgm-fade-in-up var(--stgm-motion-duration) var(--stgm-motion-easing) both;
111
+ }
112
+ }
113
+
114
+ @layer stgm {
115
+ @media (prefers-reduced-motion: reduce) {
116
+ .stgm {
117
+ --stgm-motion-duration: 0ms;
118
+ --stgm-transition-duration: 0ms;
119
+ }
120
+
121
+ .stgm *,
122
+ .stgm *::before,
123
+ .stgm *::after {
124
+ animation-duration: 0.01ms !important;
125
+ animation-iteration-count: 1 !important;
126
+ transition-duration: 0.01ms !important;
127
+ }
128
+ }
98
129
  }
@@ -0,0 +1,147 @@
1
+ "use client";
2
+
3
+ import { cn } from "@stigmer/theme";
4
+ import type { AgentUsageSummary } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
5
+ import { formatCost } from "../execution/UsageWidget";
6
+
7
+ /** Props for {@link AgentBreakdownList}. */
8
+ export interface AgentBreakdownListProps {
9
+ /** Top agents by cost, ordered by billable cost descending. */
10
+ readonly agents: readonly AgentUsageSummary[];
11
+ /** Total billable cost for the org (used to compute percentages). */
12
+ readonly totalBillableCostMicros: bigint;
13
+ /** Optional href builder for agent links. Receives the agent ID. */
14
+ readonly agentHref?: (agentId: string) => string;
15
+ /** Additional CSS class names. */
16
+ readonly className?: string;
17
+ }
18
+
19
+ /**
20
+ * Renders a ranked list of agents by cost with proportional cost bars.
21
+ *
22
+ * Each row shows the agent name, execution count, token usage,
23
+ * billable cost, and a visual bar representing cost as a percentage
24
+ * of the organization total.
25
+ */
26
+ export function AgentBreakdownList({
27
+ agents,
28
+ totalBillableCostMicros,
29
+ agentHref,
30
+ className,
31
+ }: AgentBreakdownListProps) {
32
+ if (agents.length === 0) return null;
33
+
34
+ const totalCost = Number(totalBillableCostMicros);
35
+ const maxCost =
36
+ agents.length > 0 ? Number(agents[0].billableCostMicros) : 0;
37
+
38
+ return (
39
+ <div className={className}>
40
+ <h3 className="mb-2 text-xs font-semibold text-foreground">
41
+ Top Agents by Cost
42
+ </h3>
43
+ <div
44
+ className="rounded-lg border border-border bg-card"
45
+ role="table"
46
+ aria-label="Agent cost breakdown"
47
+ >
48
+ <div
49
+ role="row"
50
+ className="grid grid-cols-[1fr_auto_auto_auto] gap-x-4 border-b border-border px-3.5 py-2 text-[0.65rem] font-medium uppercase tracking-wider text-muted-foreground"
51
+ >
52
+ <span role="columnheader">Agent</span>
53
+ <span role="columnheader" className="text-right">
54
+ Runs
55
+ </span>
56
+ <span role="columnheader" className="text-right">
57
+ Tokens
58
+ </span>
59
+ <span role="columnheader" className="text-right">
60
+ Cost
61
+ </span>
62
+ </div>
63
+ {agents.map((agent) => {
64
+ const cost = Number(agent.billableCostMicros);
65
+ const pct = totalCost > 0 ? (cost / totalCost) * 100 : 0;
66
+ const barWidth =
67
+ maxCost > 0 ? (cost / maxCost) * 100 : 0;
68
+
69
+ const NameTag = agentHref ? "a" : "span";
70
+ const nameProps = agentHref
71
+ ? { href: agentHref(agent.agentId) }
72
+ : {};
73
+
74
+ return (
75
+ <div
76
+ key={agent.agentId}
77
+ className="border-b border-border-muted px-3.5 py-2 last:border-b-0"
78
+ >
79
+ <div
80
+ role="row"
81
+ className="grid grid-cols-[1fr_auto_auto_auto] gap-x-4"
82
+ >
83
+ <div role="cell" className="min-w-0">
84
+ <NameTag
85
+ {...nameProps}
86
+ className={cn(
87
+ "block truncate text-xs font-medium",
88
+ agentHref
89
+ ? "text-primary hover:underline"
90
+ : "text-foreground",
91
+ )}
92
+ >
93
+ {agent.agentName || agent.agentId}
94
+ </NameTag>
95
+ </div>
96
+ <span
97
+ role="cell"
98
+ className="self-center text-right text-xs tabular-nums text-muted-foreground"
99
+ >
100
+ {agent.executionCount}
101
+ </span>
102
+ <span
103
+ role="cell"
104
+ className="self-center text-right text-xs tabular-nums text-muted-foreground"
105
+ >
106
+ {formatCompactTokens(Number(agent.totalTokens))}
107
+ </span>
108
+ <span
109
+ role="cell"
110
+ className="self-center text-right text-xs tabular-nums text-foreground"
111
+ >
112
+ {formatCost(cost / 1_000_000)}
113
+ <span className="ml-1.5 text-[0.6rem] text-muted-foreground">
114
+ {pct.toFixed(0)}%
115
+ </span>
116
+ </span>
117
+ </div>
118
+ {/* Proportional cost bar */}
119
+ <div className="mt-1.5 h-1 w-full rounded-full bg-muted">
120
+ <div
121
+ className="h-full rounded-full bg-chart-2 transition-all"
122
+ style={{ width: `${barWidth}%` }}
123
+ />
124
+ </div>
125
+ </div>
126
+ );
127
+ })}
128
+ </div>
129
+ </div>
130
+ );
131
+ }
132
+
133
+ function formatCompactTokens(n: number): string {
134
+ if (n >= 1_000_000) {
135
+ const v = n / 1_000_000;
136
+ return v >= 100 ? `${Math.round(v)}M` : `${trimZero(v.toFixed(1))}M`;
137
+ }
138
+ if (n >= 1_000) {
139
+ const v = n / 1_000;
140
+ return v >= 100 ? `${Math.round(v)}K` : `${trimZero(v.toFixed(1))}K`;
141
+ }
142
+ return String(n);
143
+ }
144
+
145
+ function trimZero(s: string): string {
146
+ return s.endsWith(".0") ? s.slice(0, -2) : s;
147
+ }
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import { cn } from "@stigmer/theme";
4
+ import { useBillingAccount } from "../billing/useBillingAccount";
5
+ import { useOrg } from "../organization/OrgProvider";
6
+ import { useDeploymentMode } from "../deployment-mode";
7
+
8
+ /** Props for {@link CreditRunwayIndicator}. */
9
+ export interface CreditRunwayIndicatorProps {
10
+ /** Total billable cost in micro-USD for the report period. */
11
+ readonly totalBillableCostMicros: bigint;
12
+ /** Number of calendar days the report covers. */
13
+ readonly daysInRange: number;
14
+ /** Additional CSS class names. */
15
+ readonly className?: string;
16
+ }
17
+
18
+ /**
19
+ * Displays projected credit runway: "~N days at this rate".
20
+ *
21
+ * Computes runway by dividing available balance by the daily spend rate
22
+ * derived from the usage report. Color-coded by urgency:
23
+ * green (>14d), amber (7-14d), red (<7d).
24
+ *
25
+ * Requires `useBillingAccount` — renders nothing in local mode or if
26
+ * billing data is unavailable.
27
+ */
28
+ export function CreditRunwayIndicator({
29
+ totalBillableCostMicros,
30
+ daysInRange,
31
+ className,
32
+ }: CreditRunwayIndicatorProps) {
33
+ const mode = useDeploymentMode();
34
+ const { activeOrg } = useOrg();
35
+ const orgId = activeOrg?.metadata?.id ?? "";
36
+ const { account } = useBillingAccount(mode === "cloud" ? orgId : "");
37
+
38
+ if (!account?.balance || daysInRange <= 0) return null;
39
+
40
+ const totalCost = Number(totalBillableCostMicros);
41
+ if (totalCost <= 0) return null;
42
+
43
+ const dailyRate = totalCost / daysInRange;
44
+ const availableMicros = Number(account.balance.availableMicros);
45
+ const runwayDays = Math.floor(availableMicros / dailyRate);
46
+
47
+ if (runwayDays < 0) return null;
48
+
49
+ const label =
50
+ runwayDays === 0
51
+ ? "Less than 1 day remaining"
52
+ : `~${runwayDays} day${runwayDays === 1 ? "" : "s"} at this rate`;
53
+
54
+ const urgency: "healthy" | "warning" | "critical" =
55
+ runwayDays > 14 ? "healthy" : runwayDays >= 7 ? "warning" : "critical";
56
+
57
+ return (
58
+ <span
59
+ className={cn(
60
+ "text-xs tabular-nums",
61
+ urgency === "healthy" && "text-emerald-600 dark:text-emerald-400",
62
+ urgency === "warning" && "text-amber-600 dark:text-amber-400",
63
+ urgency === "critical" && "text-red-600 dark:text-red-400",
64
+ className,
65
+ )}
66
+ aria-label={`Credit runway: ${label}`}
67
+ >
68
+ {label}
69
+ </span>
70
+ );
71
+ }