specrails-desktop 2.58.1 → 2.59.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 (438) hide show
  1. package/README.md +2 -5
  2. package/client/dist/assets/{ActivityFeedPage-BQGppIR0.js → ActivityFeedPage-vAY9C71W.js} +1 -1
  3. package/client/dist/assets/AgentBrowserCapture-CpwjGXQm.js +1 -0
  4. package/client/dist/assets/AgentModeAnalyticsPane-BHeoJVxQ.js +2 -0
  5. package/client/dist/assets/AgentModeCodePane-B0Nf3YkN.js +2 -0
  6. package/client/dist/assets/{AgentModeJobsPane-DR_06oqH.js → AgentModeJobsPane-CpbIItY_.js} +1 -1
  7. package/client/dist/assets/{AgentsPage-BKIKjm_1.js → AgentsPage-BVJAFXn3.js} +3 -3
  8. package/client/dist/assets/{AnalyticsPage-069npRVo.js → AnalyticsPage-DDWees-K.js} +1 -1
  9. package/client/dist/assets/CodePage-CzV5tkvS.js +3 -0
  10. package/client/dist/assets/{DesktopAnalyticsPage-qtWAPM47.js → DesktopAnalyticsPage-DfRHNK7i.js} +1 -1
  11. package/client/dist/assets/DocsDialog-BxduBYbh.js +11 -0
  12. package/client/dist/assets/DocsPage-DOVeRJn_.js +11 -0
  13. package/client/dist/assets/{ExportDropdown-BcMpvV89.js → ExportDropdown-BnKVV8UK.js} +1 -1
  14. package/client/dist/assets/InteractiveJobComposer-Da9dvM-0.js +19 -0
  15. package/client/dist/assets/JobDetailModal-DhwKbZGe.js +1 -0
  16. package/client/dist/assets/JobDetailPage-MtPE-E_1.js +1 -0
  17. package/client/dist/assets/JobsPage-0vdlbNik.js +1 -0
  18. package/client/dist/assets/LoopBuilderPage-DCUHozXh.js +1 -0
  19. package/client/dist/assets/{LoopPreviewModal-je5pSCf-.js → LoopPreviewModal-Df-S8NGf.js} +1 -1
  20. package/client/dist/assets/LoopWindowSurface-sdb7QbSo.js +1 -0
  21. package/client/dist/assets/LoopsPage-CDfCC9Px.js +2 -0
  22. package/client/dist/assets/MinimizedChatsContext-DKlPf54Y.js +1 -0
  23. package/client/dist/assets/PluginsPage-iL0G3rQQ.js +2 -0
  24. package/client/dist/assets/ProjectSettingsDialog-DOkjT7xv.js +1 -0
  25. package/client/dist/assets/{RepositoryDeliveries-BiwJuS8r.js → RepositoryDeliveries-CJVpOUpZ.js} +1 -1
  26. package/client/dist/assets/RepositoryScopeSelector-BeM-2gIZ.js +2 -0
  27. package/client/dist/assets/ReviewPacketPage-EBCim2w_.js +4 -0
  28. package/client/dist/assets/TemplatePreviewModal-1-92UGwN.js +1 -0
  29. package/client/dist/assets/TicketDetailModalContext-CkVXuHxU.js +16 -0
  30. package/client/dist/assets/{Trans-D3AfDylf.js → Trans-CzhPjnjB.js} +1 -1
  31. package/client/dist/assets/agent--8QAfoXL.js +1 -0
  32. package/client/dist/assets/agent-3HxXkIWX.js +1 -0
  33. package/client/dist/assets/agent-BjttZLIl.js +1 -0
  34. package/client/dist/assets/agent-CpFCz32T.js +1 -0
  35. package/client/dist/assets/agent-DVnw6ybO.js +1 -0
  36. package/client/dist/assets/agent-Z5s_GTP0.js +1 -0
  37. package/client/dist/assets/agent-hv57-zyG.js +1 -0
  38. package/client/dist/assets/agent-xGrZ_aN1.js +1 -0
  39. package/client/dist/assets/{agentRuntime-DGz_IqKW.js → agentRuntime-15Pkk6we.js} +1 -1
  40. package/client/dist/assets/agentRuntime-Bpx3yWHK.js +1 -0
  41. package/client/dist/assets/{agentRuntime-Bg9tbmqm.js → agentRuntime-C78n13To.js} +1 -1
  42. package/client/dist/assets/{agentRuntime-D-GJVGkj.js → agentRuntime-CCI7XF4c.js} +1 -1
  43. package/client/dist/assets/{agentRuntime-D2__CVI_.js → agentRuntime-CKDHe2-a.js} +1 -1
  44. package/client/dist/assets/{agentRuntime-D35dGVOP.js → agentRuntime-Ddqvp2bP.js} +1 -1
  45. package/client/dist/assets/{agentRuntime-hInH9Fzj.js → agentRuntime-TXPQowKJ.js} +1 -1
  46. package/client/dist/assets/{agentRuntime-O1liDt6G.js → agentRuntime-hqZRy08E.js} +1 -1
  47. package/client/dist/assets/{builder-DGETbtZj.js → builder-B9gorTnT.js} +1 -1
  48. package/client/dist/assets/{builder-DyQperXU.js → builder-Bvw5s3Mi.js} +1 -1
  49. package/client/dist/assets/{builder-C1neIYGR.js → builder-CL5l4dU3.js} +1 -1
  50. package/client/dist/assets/{builder-DXEJUlC0.js → builder-CVDTVrQX.js} +1 -1
  51. package/client/dist/assets/{builder-CzW5ovyI.js → builder-CpS9liE9.js} +1 -1
  52. package/client/dist/assets/{builder-CvnFm0im.js → builder-DNctIL9Q.js} +1 -1
  53. package/client/dist/assets/{builder-D06L7iPy.js → builder-De2NxX6o.js} +1 -1
  54. package/client/dist/assets/{builder-C0FyvM83.js → builder-DeYT7Y-m.js} +1 -1
  55. package/client/dist/assets/{button-Ccc9Dc-D.js → button-D1xExSTF.js} +1 -1
  56. package/client/dist/assets/{common-DmsclwjP.js → common-Bdi0qN4S.js} +1 -1
  57. package/client/dist/assets/{common-C4Yvvhp6.js → common-Bhb9zN1P.js} +1 -1
  58. package/client/dist/assets/{common-od8WThlf.js → common-BykKlZg1.js} +1 -1
  59. package/client/dist/assets/{common-C0BOdeNi.js → common-CvnNNSJA.js} +1 -1
  60. package/client/dist/assets/{common-BCK7c9Pv.js → common-D5zk_mqq.js} +1 -1
  61. package/client/dist/assets/{common-DpLWwgI1.js → common-DQNO_al5.js} +1 -1
  62. package/client/dist/assets/{common-OCvl3c8t.js → common-Dax30Vmp.js} +1 -1
  63. package/client/dist/assets/{common-c0aujEZC.js → common-DkllpVSb.js} +1 -1
  64. package/client/dist/assets/{dialog-xXB2q5HJ.js → dialog-CMgps2MY.js} +1 -1
  65. package/client/dist/assets/external-link-D6XxC_Cu.js +1 -0
  66. package/client/dist/assets/file-text-BcLCfcWZ.js +1 -0
  67. package/client/dist/assets/{formatDistanceToNow-aBss1Nai.js → formatDistanceToNow-DlQaXc7c.js} +1 -1
  68. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-DOGj1Mfz.js → getTimezoneOffsetInMilliseconds-DxUFGcVq.js} +1 -1
  69. package/client/dist/assets/index-Bfunvi6w.css +2 -0
  70. package/client/dist/assets/index-Czov72g7.js +83 -0
  71. package/client/dist/assets/integrations-BkpRUbvp.js +1 -0
  72. package/client/dist/assets/integrations-Bo8qbJf4.js +1 -0
  73. package/client/dist/assets/integrations-CmSrKzZb.js +1 -0
  74. package/client/dist/assets/integrations-DGtq26Rr.js +1 -0
  75. package/client/dist/assets/integrations-De38GFnQ.js +1 -0
  76. package/client/dist/assets/integrations-Dw6zdtb-.js +1 -0
  77. package/client/dist/assets/integrations-Dwl9KQp0.js +1 -0
  78. package/client/dist/assets/integrations-Refg_d2I.js +1 -0
  79. package/client/dist/assets/jira-api-CbJvbRYx.js +1 -0
  80. package/client/dist/assets/{jobs-KG4Sn12X.js → jobs-1G3wodhl.js} +1 -1
  81. package/client/dist/assets/{jobs-6_-r75yC.js → jobs-B4pu8TdF.js} +1 -1
  82. package/client/dist/assets/{jobs-pPv4KWjb.js → jobs-BD47Ov11.js} +1 -1
  83. package/client/dist/assets/{jobs-B1yqyId5.js → jobs-BLOoVRRl.js} +1 -1
  84. package/client/dist/assets/{jobs-BKiK-ZWh.js → jobs-CSrRx5lD.js} +1 -1
  85. package/client/dist/assets/{jobs-BFuV7ttH.js → jobs-DZAbh1m2.js} +1 -1
  86. package/client/dist/assets/{jobs-DmKV7b7d.js → jobs-epP7gt8W.js} +1 -1
  87. package/client/dist/assets/{jobs-BKa8LuwA.js → jobs-tWjcDF_6.js} +1 -1
  88. package/client/dist/assets/loops--KWr0X-w.js +1 -0
  89. package/client/dist/assets/{loops-BO3V8244.js → loops-3IutojWt.js} +1 -1
  90. package/client/dist/assets/{loops-C-hZK8pf.js → loops-BAosWtXE.js} +1 -1
  91. package/client/dist/assets/{loops-eUnCfLjC.js → loops-BISDssL5.js} +1 -1
  92. package/client/dist/assets/{loops-Dv849ckF.js → loops-Cm55CXJ4.js} +1 -1
  93. package/client/dist/assets/{loops-CDOWZ0ci.js → loops-D7tL_Saw.js} +1 -1
  94. package/client/dist/assets/{loops-BJDY9FTh.js → loops-DHQtnfze.js} +1 -1
  95. package/client/dist/assets/{loops-Q9LIgGkq.js → loops-kIJJkaxf.js} +1 -1
  96. package/client/dist/assets/nav--u7iPYlS.js +1 -0
  97. package/client/dist/assets/nav-C5Jgfaby.js +1 -0
  98. package/client/dist/assets/nav-CAna_Wpt.js +1 -0
  99. package/client/dist/assets/nav-CCLqeyHo.js +1 -0
  100. package/client/dist/assets/nav-Cf3c90Jk.js +1 -0
  101. package/client/dist/assets/nav-DMYQaQjR.js +1 -0
  102. package/client/dist/assets/nav-Df_PkZ9F.js +1 -0
  103. package/client/dist/assets/nav-VyNGBJwj.js +1 -0
  104. package/client/dist/assets/{project-repositories-CSnfzUpg.js → project-repositories-BkBD3rxx.js} +1 -1
  105. package/client/dist/assets/provider-capabilities-lePfeT_Y.js +1 -0
  106. package/client/dist/assets/save-OsUqVn99.js +1 -0
  107. package/client/dist/assets/settings-B5Hy_Kol.js +1 -0
  108. package/client/dist/assets/settings-BBj_kZaD.js +1 -0
  109. package/client/dist/assets/settings-ByVE7jdZ.js +1 -0
  110. package/client/dist/assets/settings-COlH_P33.js +1 -0
  111. package/client/dist/assets/settings-D77mC_Lb.js +1 -0
  112. package/client/dist/assets/settings-DZKy7MqN.js +1 -0
  113. package/client/dist/assets/settings-Dbyd6gmj.js +1 -0
  114. package/client/dist/assets/settings-Dn-pXukr.js +1 -0
  115. package/client/dist/assets/setup-Be485n2u.js +1 -0
  116. package/client/dist/assets/setup-CKGUxKr-.js +1 -0
  117. package/client/dist/assets/setup-Ck1Uwd7_.js +1 -0
  118. package/client/dist/assets/setup-Cm774a6v.js +1 -0
  119. package/client/dist/assets/setup-DIqMQpxt.js +1 -0
  120. package/client/dist/assets/setup-DfCsoNFL.js +1 -0
  121. package/client/dist/assets/setup-DkeE8mP0.js +1 -0
  122. package/client/dist/assets/setup-xVntVaz1.js +1 -0
  123. package/client/dist/assets/{spending-HBSk-6jv.js → spending-CYotH-9N.js} +1 -1
  124. package/client/dist/assets/subscriptionUsage-BH73RO86.js +1 -0
  125. package/client/dist/assets/subscriptionUsage-BWTeWlHx.js +1 -0
  126. package/client/dist/assets/subscriptionUsage-CBh82zVa.js +1 -0
  127. package/client/dist/assets/subscriptionUsage-CHcQ7lLe.js +1 -0
  128. package/client/dist/assets/subscriptionUsage-CdlE5Mg1.js +1 -0
  129. package/client/dist/assets/subscriptionUsage-DUPBmSQi.js +1 -0
  130. package/client/dist/assets/subscriptionUsage-DrlwrJ17.js +1 -0
  131. package/client/dist/assets/subscriptionUsage-EFu0mIK3.js +1 -0
  132. package/client/dist/assets/tauri-shell-DE6LfGPw.js +2 -0
  133. package/client/dist/assets/{useDesktop-0unHDBJJ.js → useDesktop-DpxVGfUC.js} +1 -1
  134. package/client/dist/assets/{useRuntimeRuns-BN1rhyEm.js → useRuntimeRuns-CfGRbhr9.js} +1 -1
  135. package/client/dist/assets/useSharedWebSocket-C17TGqT8.js +2 -0
  136. package/client/dist/index.html +33 -32
  137. package/docs/README.md +1 -9
  138. package/docs/agent-live-steering.md +0 -6
  139. package/docs/agents/README.md +0 -2
  140. package/docs/agents/mcp.md +1 -14
  141. package/docs/cli.md +0 -13
  142. package/docs/codex.md +2 -75
  143. package/docs/creating-specs.md +0 -39
  144. package/docs/customizing.md +1 -15
  145. package/docs/getting-started.md +0 -23
  146. package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +0 -8
  147. package/docs/guide/de/agents/4-custom-agents-catalog.md +0 -15
  148. package/docs/guide/de/getting-started/1-what-is-specrails.md +0 -2
  149. package/docs/guide/de/getting-started/2-installing-and-first-run.md +0 -2
  150. package/docs/guide/de/getting-started/3-adding-your-first-project.md +0 -4
  151. package/docs/guide/de/getting-started/4-the-dashboard-tour.md +0 -5
  152. package/docs/guide/de/integrations/1-ai-providers.md +2 -50
  153. package/docs/guide/de/integrations/2-plugins.md +0 -8
  154. package/docs/guide/de/integrations/5-mcp-server.md +1 -14
  155. package/docs/guide/de/integrations/6-agent-chat.md +0 -11
  156. package/docs/guide/de/integrations/7-local-engines.md +0 -4
  157. package/docs/guide/de/pipeline/1-rails-and-jobs.md +0 -13
  158. package/docs/guide/de/pipeline/2-the-job-detail-view.md +0 -3
  159. package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +0 -20
  160. package/docs/guide/de/pipeline/5-the-loop-builder.md +0 -6
  161. package/docs/guide/de/specs/2-add-spec-quick-mode.md +0 -7
  162. package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +0 -10
  163. package/docs/guide/en/agents/4-custom-agents-catalog.md +0 -25
  164. package/docs/guide/en/getting-started/1-what-is-specrails.md +0 -2
  165. package/docs/guide/en/getting-started/2-installing-and-first-run.md +0 -2
  166. package/docs/guide/en/getting-started/3-adding-your-first-project.md +0 -4
  167. package/docs/guide/en/getting-started/4-the-dashboard-tour.md +0 -5
  168. package/docs/guide/en/insights/3-code-explorer.md +0 -5
  169. package/docs/guide/en/integrations/1-ai-providers.md +10 -99
  170. package/docs/guide/en/integrations/2-plugins.md +0 -8
  171. package/docs/guide/en/integrations/5-mcp-server.md +1 -1
  172. package/docs/guide/en/integrations/6-agent-chat.md +0 -17
  173. package/docs/guide/en/integrations/7-local-engines.md +0 -4
  174. package/docs/guide/en/pipeline/1-rails-and-jobs.md +2 -24
  175. package/docs/guide/en/pipeline/2-the-job-detail-view.md +0 -3
  176. package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +10 -65
  177. package/docs/guide/en/pipeline/5-the-loop-builder.md +0 -7
  178. package/docs/guide/en/specs/2-add-spec-quick-mode.md +0 -11
  179. package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +0 -8
  180. package/docs/guide/es/agents/4-custom-agents-catalog.md +0 -15
  181. package/docs/guide/es/getting-started/1-what-is-specrails.md +0 -2
  182. package/docs/guide/es/getting-started/2-installing-and-first-run.md +0 -2
  183. package/docs/guide/es/getting-started/3-adding-your-first-project.md +0 -4
  184. package/docs/guide/es/getting-started/4-the-dashboard-tour.md +0 -5
  185. package/docs/guide/es/integrations/1-ai-providers.md +10 -75
  186. package/docs/guide/es/integrations/2-plugins.md +0 -8
  187. package/docs/guide/es/integrations/5-mcp-server.md +1 -1
  188. package/docs/guide/es/integrations/6-agent-chat.md +0 -11
  189. package/docs/guide/es/integrations/7-local-engines.md +0 -4
  190. package/docs/guide/es/pipeline/1-rails-and-jobs.md +3 -13
  191. package/docs/guide/es/pipeline/2-the-job-detail-view.md +0 -3
  192. package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +10 -53
  193. package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -6
  194. package/docs/guide/es/specs/2-add-spec-quick-mode.md +0 -7
  195. package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +0 -8
  196. package/docs/guide/fr/agents/4-custom-agents-catalog.md +0 -15
  197. package/docs/guide/fr/getting-started/1-what-is-specrails.md +0 -2
  198. package/docs/guide/fr/getting-started/2-installing-and-first-run.md +0 -2
  199. package/docs/guide/fr/getting-started/3-adding-your-first-project.md +0 -4
  200. package/docs/guide/fr/getting-started/4-the-dashboard-tour.md +0 -5
  201. package/docs/guide/fr/integrations/1-ai-providers.md +2 -50
  202. package/docs/guide/fr/integrations/2-plugins.md +0 -8
  203. package/docs/guide/fr/integrations/5-mcp-server.md +1 -14
  204. package/docs/guide/fr/integrations/6-agent-chat.md +0 -11
  205. package/docs/guide/fr/integrations/7-local-engines.md +0 -4
  206. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +0 -13
  207. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +0 -3
  208. package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +0 -22
  209. package/docs/guide/fr/pipeline/5-the-loop-builder.md +0 -6
  210. package/docs/guide/fr/specs/2-add-spec-quick-mode.md +0 -7
  211. package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +0 -8
  212. package/docs/guide/it/agents/4-custom-agents-catalog.md +0 -15
  213. package/docs/guide/it/getting-started/1-what-is-specrails.md +0 -2
  214. package/docs/guide/it/getting-started/2-installing-and-first-run.md +0 -2
  215. package/docs/guide/it/getting-started/3-adding-your-first-project.md +0 -4
  216. package/docs/guide/it/getting-started/4-the-dashboard-tour.md +0 -5
  217. package/docs/guide/it/integrations/1-ai-providers.md +2 -48
  218. package/docs/guide/it/integrations/2-plugins.md +0 -8
  219. package/docs/guide/it/integrations/5-mcp-server.md +1 -14
  220. package/docs/guide/it/integrations/6-agent-chat.md +0 -11
  221. package/docs/guide/it/integrations/7-local-engines.md +0 -4
  222. package/docs/guide/it/pipeline/1-rails-and-jobs.md +2 -13
  223. package/docs/guide/it/pipeline/2-the-job-detail-view.md +0 -3
  224. package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +0 -20
  225. package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -6
  226. package/docs/guide/it/specs/2-add-spec-quick-mode.md +0 -7
  227. package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +0 -9
  228. package/docs/guide/ja/agents/4-custom-agents-catalog.md +0 -15
  229. package/docs/guide/ja/getting-started/1-what-is-specrails.md +0 -2
  230. package/docs/guide/ja/getting-started/2-installing-and-first-run.md +0 -2
  231. package/docs/guide/ja/getting-started/3-adding-your-first-project.md +0 -4
  232. package/docs/guide/ja/getting-started/4-the-dashboard-tour.md +0 -5
  233. package/docs/guide/ja/integrations/1-ai-providers.md +1 -69
  234. package/docs/guide/ja/integrations/2-plugins.md +0 -8
  235. package/docs/guide/ja/integrations/5-mcp-server.md +1 -14
  236. package/docs/guide/ja/integrations/6-agent-chat.md +0 -10
  237. package/docs/guide/ja/integrations/7-local-engines.md +0 -4
  238. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +0 -13
  239. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +0 -3
  240. package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +0 -21
  241. package/docs/guide/ja/pipeline/5-the-loop-builder.md +0 -6
  242. package/docs/guide/ja/specs/2-add-spec-quick-mode.md +0 -7
  243. package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +0 -8
  244. package/docs/guide/pt/agents/4-custom-agents-catalog.md +0 -15
  245. package/docs/guide/pt/getting-started/1-what-is-specrails.md +0 -2
  246. package/docs/guide/pt/getting-started/2-installing-and-first-run.md +0 -2
  247. package/docs/guide/pt/getting-started/3-adding-your-first-project.md +0 -4
  248. package/docs/guide/pt/getting-started/4-the-dashboard-tour.md +0 -5
  249. package/docs/guide/pt/integrations/1-ai-providers.md +2 -48
  250. package/docs/guide/pt/integrations/2-plugins.md +0 -8
  251. package/docs/guide/pt/integrations/5-mcp-server.md +1 -14
  252. package/docs/guide/pt/integrations/6-agent-chat.md +0 -10
  253. package/docs/guide/pt/integrations/7-local-engines.md +0 -4
  254. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +0 -13
  255. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +0 -2
  256. package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +0 -21
  257. package/docs/guide/pt/pipeline/5-the-loop-builder.md +0 -6
  258. package/docs/guide/pt/specs/2-add-spec-quick-mode.md +0 -7
  259. package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +0 -7
  260. package/docs/guide/zh/agents/4-custom-agents-catalog.md +0 -15
  261. package/docs/guide/zh/getting-started/1-what-is-specrails.md +0 -2
  262. package/docs/guide/zh/getting-started/2-installing-and-first-run.md +0 -2
  263. package/docs/guide/zh/getting-started/3-adding-your-first-project.md +0 -4
  264. package/docs/guide/zh/getting-started/4-the-dashboard-tour.md +0 -5
  265. package/docs/guide/zh/integrations/1-ai-providers.md +1 -67
  266. package/docs/guide/zh/integrations/2-plugins.md +0 -8
  267. package/docs/guide/zh/integrations/5-mcp-server.md +1 -14
  268. package/docs/guide/zh/integrations/6-agent-chat.md +0 -9
  269. package/docs/guide/zh/integrations/7-local-engines.md +0 -4
  270. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +0 -13
  271. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +0 -2
  272. package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +0 -20
  273. package/docs/guide/zh/pipeline/5-the-loop-builder.md +0 -6
  274. package/docs/guide/zh/specs/2-add-spec-quick-mode.md +0 -7
  275. package/docs/internals/adding-a-provider.md +7 -0
  276. package/docs/internals/api-reference.md +1 -0
  277. package/docs/internals/core-runtime-updates.md +9 -2
  278. package/docs/internals/desktop-owned-workflows.md +144 -0
  279. package/docs/internals/mission-rail-cards.md +15 -0
  280. package/docs/internals/operations-runbook.md +26 -0
  281. package/docs/internals/programmatic-agent-runtime.md +34 -28
  282. package/docs/internals/project-builder.md +34 -11
  283. package/docs/internals/safe-pr-review-flow.md +25 -7
  284. package/docs/internals/source-map.md +53 -3
  285. package/docs/internals/spec-addenda.md +11 -5
  286. package/docs/internals/visual-design-audit.md +5 -0
  287. package/docs/local-providers.md +8 -13
  288. package/docs/mcp.md +1 -17
  289. package/docs/platforms/macos.md +0 -40
  290. package/docs/platforms/windows-parity.md +1 -1
  291. package/docs/platforms/windows.md +0 -8
  292. package/docs/running-pipelines.md +1 -46
  293. package/docs/subscription-usage.md +19 -0
  294. package/docs/terminal.md +0 -2
  295. package/docs/tracking-cost.md +2 -33
  296. package/package.json +1 -1
  297. package/server/dist/core-execution.js +24 -15
  298. package/server/dist/core-update-manager.js +1 -1
  299. package/server/dist/db/migrations.js +9 -0
  300. package/server/dist/desktop-db.js +23 -10
  301. package/server/dist/desktop-router.js +8 -4
  302. package/server/dist/index.js +10 -5
  303. package/server/dist/mcp/guide.js +1 -0
  304. package/server/dist/mcp/tools/jobs.js +1 -1
  305. package/server/dist/mcp/tools/loops.js +2 -0
  306. package/server/dist/mcp/tools/meta.js +6 -7
  307. package/server/dist/mcp/tools/projects.js +31 -6
  308. package/server/dist/mcp/tools/rails.js +6 -3
  309. package/server/dist/mcp/tools/setup.js +10 -0
  310. package/server/dist/mcp/tools/specs.js +1 -1
  311. package/server/dist/modules/accounting/runtime/pricing.js +6 -1
  312. package/server/dist/modules/agent-runtime/runtime/agent-runtime-bridge.js +169 -17
  313. package/server/dist/modules/agent-runtime/runtime/agent-runtime-metrics.js +1 -1
  314. package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings-router.js +1 -1
  315. package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings.js +42 -0
  316. package/server/dist/modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js +10 -4
  317. package/server/dist/modules/builder/runtime/milestone-chain.js +76 -10
  318. package/server/dist/modules/delivery/runtime/delivery-evidence.js +3 -2
  319. package/server/dist/modules/delivery/runtime/multi-repo-execution.js +10 -5
  320. package/server/dist/modules/delivery/runtime/rail-isolated-launch.js +66 -30
  321. package/server/dist/modules/delivery/runtime/rail-launch-parser.js +8 -0
  322. package/server/dist/modules/delivery/runtime/rail-pr-store.js +3 -3
  323. package/server/dist/modules/delivery/runtime/rail-relaunch.js +154 -0
  324. package/server/dist/modules/delivery/runtime/rails-router.js +157 -36
  325. package/server/dist/modules/delivery/runtime/review-packet.js +1 -1
  326. package/server/dist/modules/execution/runtime/revision-seed.js +6 -2
  327. package/server/dist/modules/loops/runtime/loop-agent-defaults.json +6 -0
  328. package/server/dist/modules/loops/runtime/loop-agents.js +21 -0
  329. package/server/dist/modules/loops/runtime/loop-command-catalog.js +1 -1
  330. package/server/dist/modules/loops/runtime/loop-core-factory.js +19 -3
  331. package/server/dist/modules/loops/runtime/loop-definition-events.js +1 -1
  332. package/server/dist/modules/loops/runtime/loop-definition.js +79 -12
  333. package/server/dist/modules/loops/runtime/loop-effect.js +1 -1
  334. package/server/dist/modules/loops/runtime/loop-executors.js +24 -9
  335. package/server/dist/modules/loops/runtime/loop-factory.js +1 -1
  336. package/server/dist/modules/loops/runtime/loop-graph.js +5 -14
  337. package/server/dist/modules/loops/runtime/loop-implement-recipe.js +53 -0
  338. package/server/dist/modules/loops/runtime/loop-run-manager.js +30 -20
  339. package/server/dist/modules/loops/runtime/loop-templates.js +29 -5
  340. package/server/dist/modules/loops/runtime/loops-router.js +17 -0
  341. package/server/dist/modules/missions/runtime/agent-context-resolver.js +1 -1
  342. package/server/dist/modules/missions/runtime/agent-operator-prompt.js +17 -8
  343. package/server/dist/modules/specs/runtime/spec-models.js +4 -7
  344. package/server/dist/modules/subscription-usage/adapters/claude.js +123 -0
  345. package/server/dist/modules/subscription-usage/adapters/codex.js +164 -0
  346. package/server/dist/modules/subscription-usage/adapters/errors.js +15 -0
  347. package/server/dist/modules/subscription-usage/adapters/http.js +20 -0
  348. package/server/dist/modules/subscription-usage/adapters/local-auth.js +61 -0
  349. package/server/dist/modules/subscription-usage/application.js +12 -0
  350. package/server/dist/modules/subscription-usage/domain.js +104 -0
  351. package/server/dist/modules/subscription-usage/index.js +2 -0
  352. package/server/dist/modules/subscription-usage/ports.js +2 -0
  353. package/server/dist/modules/subscription-usage/runtime/composition.js +20 -0
  354. package/server/dist/modules/subscription-usage/runtime/usage-service.js +111 -0
  355. package/server/dist/project-registry.js +16 -1
  356. package/server/dist/project-repositories.js +51 -2
  357. package/server/dist/project-router-helpers.js +1 -1
  358. package/server/dist/project-router-loop-runs.js +4 -1
  359. package/server/dist/providers/claude-adapter.js +6 -4
  360. package/server/dist/providers/codex-adapter.js +4 -5
  361. package/server/dist/schemas/workflow-definition.schema.json +2 -0
  362. package/server/dist/worktree-manager.js +114 -6
  363. package/server/dist/worktree-overlay.js +4 -4
  364. package/client/dist/assets/AgentBrowserCapture-PI-cxyxi.js +0 -1
  365. package/client/dist/assets/AgentModeAnalyticsPane-mQsOqdXx.js +0 -2
  366. package/client/dist/assets/AgentModeCodePane-BL-vpmlY.js +0 -2
  367. package/client/dist/assets/CodePage-Alitorrv.js +0 -3
  368. package/client/dist/assets/DocsDialog-DwL6rgcT.js +0 -11
  369. package/client/dist/assets/DocsPage-BA1hiJZ-.js +0 -11
  370. package/client/dist/assets/InteractiveJobComposer-B3H1YHr6.js +0 -19
  371. package/client/dist/assets/JobDetailModal-XZQ9eAAy.js +0 -1
  372. package/client/dist/assets/JobDetailPage-B-SIaq_q.js +0 -1
  373. package/client/dist/assets/JobsPage-iQXAv2mx.js +0 -1
  374. package/client/dist/assets/LoopBuilderPage-B_gbFAHn.js +0 -1
  375. package/client/dist/assets/LoopsPage-BZwcY5cu.js +0 -2
  376. package/client/dist/assets/MinimizedChatsContext-CNx_0bZu.js +0 -1
  377. package/client/dist/assets/PluginsPage-DFocnoHX.js +0 -2
  378. package/client/dist/assets/ProjectSettingsDialog-Bh3S6EBB.js +0 -1
  379. package/client/dist/assets/RepositoryScopeSelector-C2mvWBQ6.js +0 -1
  380. package/client/dist/assets/ReviewPacketPage-CrAf-WDy.js +0 -4
  381. package/client/dist/assets/TemplatePreviewModal-C7DordpN.js +0 -1
  382. package/client/dist/assets/TicketDetailModalContext-B-DySpKL.js +0 -16
  383. package/client/dist/assets/agent-BaG10AN6.js +0 -1
  384. package/client/dist/assets/agent-CH4aJ884.js +0 -1
  385. package/client/dist/assets/agent-CLc9fA7v.js +0 -1
  386. package/client/dist/assets/agent-DHh9-AdL.js +0 -1
  387. package/client/dist/assets/agent-DkKnd6Wv.js +0 -1
  388. package/client/dist/assets/agent-aiVhqFW1.js +0 -1
  389. package/client/dist/assets/agent-dbznD3eO.js +0 -1
  390. package/client/dist/assets/agent-sMVFcPwL.js +0 -1
  391. package/client/dist/assets/agentRuntime-BeUb3g9g.js +0 -1
  392. package/client/dist/assets/file-text-CFT-xXKN.js +0 -1
  393. package/client/dist/assets/index-BS7KCWkV.css +0 -2
  394. package/client/dist/assets/index-C4Mv6tV6.js +0 -80
  395. package/client/dist/assets/integrations-CH0zy1Mw.js +0 -1
  396. package/client/dist/assets/integrations-CIAjhd7L.js +0 -1
  397. package/client/dist/assets/integrations-CZdwOe8A.js +0 -1
  398. package/client/dist/assets/integrations-Ct7omMld.js +0 -1
  399. package/client/dist/assets/integrations-D6MSxy3-.js +0 -1
  400. package/client/dist/assets/integrations-DbZa-Zyc.js +0 -1
  401. package/client/dist/assets/integrations-b8pH-vfl.js +0 -1
  402. package/client/dist/assets/integrations-mB-7zoyT.js +0 -1
  403. package/client/dist/assets/jira-api-BYbEPlkr.js +0 -1
  404. package/client/dist/assets/layers-eDMjG41I.js +0 -1
  405. package/client/dist/assets/loops-B4_D-nbg.js +0 -1
  406. package/client/dist/assets/nav-B-tpjyc2.js +0 -1
  407. package/client/dist/assets/nav-BJNXGg29.js +0 -1
  408. package/client/dist/assets/nav-BdhtRLP7.js +0 -1
  409. package/client/dist/assets/nav-ByYgyN5T.js +0 -1
  410. package/client/dist/assets/nav-DA0Mva2c.js +0 -1
  411. package/client/dist/assets/nav-DcJm_Jg_.js +0 -1
  412. package/client/dist/assets/nav-DhMPtAXc.js +0 -1
  413. package/client/dist/assets/nav-DhPb-Isc.js +0 -1
  414. package/client/dist/assets/provider-capabilities-Vi1ZGvAK.js +0 -1
  415. package/client/dist/assets/save-B6wGWwBR.js +0 -1
  416. package/client/dist/assets/settings-3o4Ntzi5.js +0 -1
  417. package/client/dist/assets/settings-B97jlkwD.js +0 -1
  418. package/client/dist/assets/settings-BTaT_bsS.js +0 -1
  419. package/client/dist/assets/settings-CT8w7WiC.js +0 -1
  420. package/client/dist/assets/settings-Cvr8_tvh.js +0 -1
  421. package/client/dist/assets/settings-Dn1qgAC8.js +0 -1
  422. package/client/dist/assets/settings-EShDdg4J.js +0 -1
  423. package/client/dist/assets/settings-tfLhQZRN.js +0 -1
  424. package/client/dist/assets/setup-CBMu3tqH.js +0 -1
  425. package/client/dist/assets/setup-CPh-e6J2.js +0 -1
  426. package/client/dist/assets/setup-CRKLp_ke.js +0 -1
  427. package/client/dist/assets/setup-Cy302v4J.js +0 -1
  428. package/client/dist/assets/setup-D681vTPf.js +0 -1
  429. package/client/dist/assets/setup-DYK0VBkE.js +0 -1
  430. package/client/dist/assets/setup-KAuiIiVs.js +0 -1
  431. package/client/dist/assets/setup-OGX-oCfI.js +0 -1
  432. package/client/dist/assets/useSharedWebSocket-BZMrX4jr.js +0 -2
  433. package/client/dist/assets/wrench-BfmNO9Vw.js +0 -1
  434. package/docs/agy-cli-provider-study.md +0 -257
  435. package/docs/gemini-cli-provider-study.md +0 -301
  436. package/docs/gemini-core-support-evaluation.md +0 -160
  437. package/docs/gemini.md +0 -257
  438. package/docs/kimi.md +0 -291
@@ -149,7 +149,7 @@ function formatProjectOverview(ref, index, deps) {
149
149
  lines.push('resolution: unresolved project');
150
150
  return lines.join('\n');
151
151
  }
152
- lines.push(`project.id: ${project.id}`, `project.name: ${safe(project.name, 180)}`, `project.slug: ${safe(project.slug, 120)}`, `project.path: ${project.path}`, `project.provider: ${safe(project.provider, 80)}`, `project.providers: ${(project.providers ?? [project.provider]).join(', ')}`, `project.runtime: ${context ? 'available' : 'unavailable; do not interpret this as a deleted project'}`, `project.repositories: ${JSON.stringify((0, project_repositories_1.getProjectRepositories)(project).map(repository => ({ id: repository.id, name: repository.name, path: repository.path, isPrimary: repository.isPrimary, kind: repository.kind, available: repository.available })))}`, 'repository.scope: One shared project backlog. Files and Git operations require repositoryId when more than one member exists; find/search can discover across members. Reading context does not grant implementation write access. Historical specs without repositoryIds target only the primary.');
152
+ lines.push(`project.id: ${project.id}`, `project.name: ${safe(project.name, 180)}`, `project.slug: ${safe(project.slug, 120)}`, `project.path: ${project.path}`, `project.provider: ${safe(project.provider, 80)}`, `project.providers: ${(project.providers ?? [project.provider]).join(', ')}`, `project.runtime: ${context ? 'available' : 'unavailable; do not interpret this as a deleted project'}`, `project.repositories: ${JSON.stringify((0, project_repositories_1.getProjectRepositories)(project).map(repository => ({ id: repository.id, name: repository.name, path: repository.path, workspacePaths: repository.workspacePaths ?? [repository.workspacePath ?? repository.path], isPrimary: repository.isPrimary, kind: repository.kind, available: repository.available })))}`, 'repository.scope: One shared project backlog. Files and Git operations require repositoryId when more than one member exists; find/search can discover across members. Reading context does not grant implementation write access. Historical specs without repositoryIds target only the primary.');
153
153
  try {
154
154
  const tickets = Object.values((0, ticket_store_1.readStore)(ticketFileFor(project)).tickets);
155
155
  const counts = tickets.reduce((acc, ticket) => {
@@ -628,6 +628,13 @@ summary later.
628
628
  N-1. When talking to the user ALWAYS use the 1-based label (tool results
629
629
  include \`railLabel\`, e.g. railIndex 3 → "Rail 4") or the rail's custom name;
630
630
  never quote the raw railIndex as the rail's name.
631
+ - Code workspace selection: discover \`workspacePaths\` in the project context. A
632
+ project folder can contain several code workspaces; tests must run in the
633
+ workspace being changed. Include \`workspaceSelection\` (repository ID → array
634
+ of registered workspace paths) in rail-launch cards and direct launch calls to
635
+ target a subset. Preserve \`repositoryIds\` for affected Git memberships. Do not
636
+ invent paths or substitute the parent folder. Omission uses every configured
637
+ workspace for each affected membership.
631
638
  - Configure then launch: \`specrails_rails(set_tickets, railIndex, ticketIds)\` →
632
639
  \`specrails_rails(launch, railIndex, mode, …)\`. Setting a profile and then
633
640
  switching the rail's engine to a provider without profile support
@@ -657,15 +664,15 @@ summary later.
657
664
  relaunch strategy even when \`main\` did not have that spec before the PR. If
658
665
  asked why a strategy was chosen, verify against active PR contents before
659
666
  answering.
660
- - **"Change something about work already delivered" = a Quick SDD continuation.** When
667
+ - **"Change something about work already delivered" = a delivery continuation.** When
661
668
  the user asks for a modification to a delivery that is awaiting their decision
662
669
  (any non-terminal card: \`on_review\`, \`pr_draft\`, \`pr_ready\`, \`no_changes\`,
663
670
  \`implementation_failed\`), call \`specrails_rails(launch)\` with
664
671
  \`revisionOfDeliveryId\` = that card's \`prDeliveryId\` and \`revisionNote\` = what
665
672
  they asked for, in their own words. Do NOT tell them to publish, discard or
666
- merge first, and do NOT relaunch the ordinary implement mode: a revision
667
- always uses Quick SDD: pass \`loopId:'factory:sdd-quick-openspec'\` alongside the delivery
668
- target. The server preserves the branch while running Quick SDD. The rail must still carry exactly that delivery's
673
+ merge first. Respect the user's explicit loop selection, including Implement:
674
+ pass that loopId alongside the delivery target. Without a preference, use
675
+ \`loopId:'factory:sdd-quick-openspec'\`. The server preserves the branch. The rail must still carry exactly that delivery's
669
676
  specs; a mismatch returns \`invalid_revision_target\`, which means re-check the
670
677
  rail's spec assignment rather than retrying blindly.
671
678
  - **"Resolve / fix the review comments on this PR" = a FOLLOW-UP launch, never a
@@ -706,9 +713,9 @@ summary later.
706
713
  \`dismiss_addendum\` withdraws it. Prefer an addendum + normal launch over a
707
714
  \`revisionNote\` when the change should stay attached to the spec for later
708
715
  runs; the two combine freely.
709
- **Addenda on an existing branch/open PR ALWAYS run Quick SDD**, never Revision.
710
- Use \`loopId:'factory:sdd-quick-openspec'\`; the server routes addenda there
711
- even if the rail stores a different loop. A same-spec pending delivery is
716
+ **Respect explicit loop selection for addenda**, including Implement.
717
+ Recommend Quick SDD when no preference was given; never silently replace
718
+ Implement with Quick SDD after agreeing to use Implement. A same-spec pending delivery is
712
719
  continued without requiring publish/discard first. Keep the exact ticket and
713
720
  repository scope; pass the delivery id when known. The runtime assigns a NEW
714
721
  run-specific OpenSpec change for the frozen addenda, so NEVER edit
@@ -889,6 +896,8 @@ never as a launch):
889
896
  \`null\` means "the rail's / project's default".
890
897
  - \`targetPrNumber\` / \`baseBranch\`: only when the user named an existing PR
891
898
  or a branch to stack on.
899
+ - \`repositoryIds\`: selected registered repository memberships, consistent with the specs.
900
+ - \`workspaceSelection\`: optional object mapping each selected repository id to a non-empty array of registered workspace paths. Discover paths from project context; never invent them. Omission uses every configured workspace. The card lets the user edit this choice before Play.
892
901
  - \`rationale\`: ONE sentence — why this grouping / engine.
893
902
 
894
903
  Prose around the block: say what you propose in one or two lines and stop —
@@ -916,7 +925,7 @@ investigate and fix. Read runtime_diagnose before recommending a retry.
916
925
  function buildOperatorInstructions() {
917
926
  return (0, feature_flags_1.isMissionRailCardsEnabled)() ? `${exports.OPERATOR_INSTRUCTIONS}\n${exports.RAIL_LAUNCH_CARD_SECTION}` : exports.OPERATOR_INSTRUCTIONS;
918
927
  }
919
- exports.RAIL_LAUNCH_CARD_SYSTEM_CLAUSE = ' When the user asks to assign, prepare or launch specs on a rail WITHOUT explicitly saying to launch now, do not call specrails_rails launch — emit one fenced rail-launch JSON block per rail (ticketIds, railIndex or newRail, mode, loopId, aiEngine, model, reasoningEffort, profileName, rationale) so the app renders an editable launch card the user plays; never propose a rail whose availability is not free. A message starting with "[Specrails run-failure briefing" is app-posted: answer in ≤ 6 lines with the failure and ONE recommended next action, and never resume, recover, relaunch or discard in that turn.';
928
+ exports.RAIL_LAUNCH_CARD_SYSTEM_CLAUSE = ' When the user asks to assign, prepare or launch specs on a rail WITHOUT explicitly saying to launch now, do not call specrails_rails launch — emit one fenced rail-launch JSON block per rail (ticketIds, railIndex or newRail, mode, loopId, aiEngine, model, reasoningEffort, profileName, repositoryIds, workspaceSelection, rationale) so the app renders an editable launch card the user plays; never propose a rail whose availability is not free. A message starting with "[Specrails run-failure briefing" is app-posted: answer in ≤ 6 lines with the failure and ONE recommended next action, and never resume, recover, relaunch or discard in that turn.';
920
929
  /** The per-turn system prompt (flag-aware). */
921
930
  function buildOperatorSystemPrompt() {
922
931
  return (0, feature_flags_1.isMissionRailCardsEnabled)() ? `${exports.OPERATOR_SYSTEM_PROMPT}${exports.RAIL_LAUNCH_CARD_SYSTEM_CLAUSE}` : exports.OPERATOR_SYSTEM_PROMPT;
@@ -6,20 +6,17 @@ exports.isValidModelForProvider = isValidModelForProvider;
6
6
  exports.getProviderDefault = getProviderDefault;
7
7
  const providers_1 = require("../../../providers");
8
8
  exports.CLAUDE_MODELS = [
9
- { value: 'sonnet', label: 'Claude Sonnet' },
10
- { value: 'fable', label: 'Claude Fable' },
9
+ { value: 'sonnet', label: 'Sonnet 5.5' },
10
+ { value: 'fable', label: 'Fable 5.1' },
11
11
  { value: 'opus', label: 'Claude Opus' },
12
12
  { value: 'haiku', label: 'Claude Haiku' },
13
13
  ];
14
14
  exports.CODEX_MODELS = [
15
+ { value: 'gpt-6.1-sol', label: 'GPT-6.1 Sol' },
15
16
  { value: 'gpt-6-astra', label: 'GPT-6 Astra' },
16
17
  { value: 'gpt-5.6-sol', label: 'GPT-5.6 Sol' },
17
18
  { value: 'gpt-5.6-terra', label: 'GPT-5.6 Terra' },
18
19
  { value: 'gpt-5.6-luna', label: 'GPT-5.6 Luna' },
19
- { value: 'gpt-5.5', label: 'GPT-5.5' },
20
- { value: 'gpt-5.4', label: 'GPT-5.4' },
21
- { value: 'gpt-5.4-mini', label: 'GPT-5.4 Mini' },
22
- { value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' },
23
20
  ];
24
21
  // Mirrors GEMINI_MODELS in server/providers/gemini-adapter.ts.
25
22
  exports.GEMINI_MODELS = [
@@ -43,7 +40,7 @@ const PROVIDER_MODELS = {
43
40
  };
44
41
  exports.PROVIDER_DEFAULT_MODEL = {
45
42
  claude: 'sonnet',
46
- codex: 'gpt-5.5',
43
+ codex: 'gpt-6.1-sol',
47
44
  gemini: 'gemini-3.5-flash',
48
45
  kimi: 'k3',
49
46
  };
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createClaudeReader = createClaudeReader;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_os_1 = require("node:os");
9
+ const promises_1 = require("node:fs/promises");
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const domain_1 = require("../domain");
12
+ const errors_1 = require("./errors");
13
+ const local_auth_1 = require("./local-auth");
14
+ function readKeychain(service, signal) {
15
+ return new Promise((resolve, reject) => {
16
+ let account;
17
+ try {
18
+ account = process.env.USER || process.env.USERNAME || (0, node_os_1.userInfo)().username;
19
+ }
20
+ catch {
21
+ account = 'claude-code-user';
22
+ }
23
+ if (!/^[a-zA-Z0-9._-]+$/.test(account))
24
+ account = 'claude-code-user';
25
+ (0, node_child_process_1.execFile)('/usr/bin/security', ['find-generic-password', '-s', service, '-a', account, '-w'], { timeout: 3000, maxBuffer: 1024 * 1024, signal }, (error, stdout) => {
26
+ if (!error)
27
+ resolve(stdout);
28
+ else if (error.code === 44)
29
+ resolve(null);
30
+ else
31
+ reject(new errors_1.UsageError('credentials-unreadable'));
32
+ });
33
+ });
34
+ }
35
+ function createClaudeReader(options = {}) {
36
+ const configured = options.configDir ?? process.env.CLAUDE_CONFIG_DIR;
37
+ const configDir = configured ?? node_path_1.default.join((0, node_os_1.homedir)(), '.claude');
38
+ async function credentials(signal) {
39
+ if (!node_path_1.default.isAbsolute(configDir))
40
+ throw new errors_1.UsageError('unsupported-platform');
41
+ let keychainFailure = false;
42
+ if ((options.platform ?? process.platform) === 'darwin') {
43
+ const aliases = configured ? [configDir] : [];
44
+ if (configured) {
45
+ try {
46
+ const canonical = await (0, promises_1.realpath)(configDir);
47
+ if (canonical !== configDir)
48
+ aliases.push(canonical);
49
+ }
50
+ catch { /* use the exact resolved context */ }
51
+ }
52
+ const services = configured ? aliases.map(dir => `Claude Code-credentials-${(0, local_auth_1.fingerprint)(dir.normalize('NFC')).slice(0, 8)}`) : ['Claude Code-credentials'];
53
+ for (const service of services) {
54
+ try {
55
+ const raw = await (options.keychain ?? readKeychain)(service, signal);
56
+ if (raw)
57
+ return raw;
58
+ }
59
+ catch {
60
+ keychainFailure = true;
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ const file = await (options.readFile ?? local_auth_1.readAuthFile)(node_path_1.default.join(configDir, '.credentials.json'));
66
+ if (file)
67
+ return file;
68
+ if (keychainFailure)
69
+ throw new errors_1.UsageError('credentials-unreadable');
70
+ return null;
71
+ }
72
+ return {
73
+ async context(signal) { return (0, local_auth_1.fingerprint)(`${configDir}:${await credentials(signal) ?? 'none'}`); },
74
+ async read(signal) {
75
+ const raw = await credentials(signal);
76
+ if (!raw)
77
+ return { availability: 'signed-out', windows: [], plan: null, source: null };
78
+ let data;
79
+ try {
80
+ data = (0, domain_1.record)(JSON.parse(raw));
81
+ }
82
+ catch {
83
+ throw new errors_1.UsageError('credentials-unreadable');
84
+ }
85
+ const oauth = (0, domain_1.record)(data.claudeAiOauth);
86
+ if (typeof oauth.accessToken !== 'string' || !oauth.accessToken)
87
+ return { availability: 'unsupported-auth', windows: [], plan: null, source: null };
88
+ async function query(route) {
89
+ const response = await (options.request ?? fetch)(`https://api.anthropic.com/api/oauth/${route}`, {
90
+ headers: { Authorization: `Bearer ${oauth.accessToken}`, 'anthropic-beta': 'oauth-2025-04-20', 'User-Agent': 'claude-code/2.1.0' },
91
+ signal: AbortSignal.any([signal, AbortSignal.timeout(10_000)]), redirect: 'error',
92
+ });
93
+ if (!response.ok) {
94
+ await response.body?.cancel().catch(() => { });
95
+ if (response.status === 401)
96
+ throw new errors_1.UsageError('signed-out');
97
+ if (response.status === 403)
98
+ throw new errors_1.UsageError('permission-denied');
99
+ if (response.status === 429) {
100
+ const header = response.headers.get('retry-after');
101
+ const seconds = header !== null && header.trim() !== '' ? Number(header) : NaN;
102
+ const date = header ? Date.parse(header) : NaN;
103
+ const retry = Number.isFinite(seconds) ? seconds * 1000 : Number.isFinite(date) ? date - Date.now() : 60_000;
104
+ throw new errors_1.UsageError('rate-limited', true, Math.max(30_000, Math.min(24 * 60 * 60_000, retry)));
105
+ }
106
+ throw new errors_1.UsageError('provider-error', response.status >= 500);
107
+ }
108
+ return (0, local_auth_1.limitedJson)(response);
109
+ }
110
+ const payload = await query('usage'), windows = (0, domain_1.normalizeClaude)(payload);
111
+ let plan = (0, domain_1.claudePlan)(oauth.subscriptionType) ?? (0, domain_1.claudePlan)(oauth.rateLimitTier);
112
+ const candidate = (0, domain_1.normalizeClaudeSpend)(payload, 'enterprise', (options.now ?? Date.now)());
113
+ if (!plan && candidate) {
114
+ const profile = (0, domain_1.record)(await query('profile')), organization = (0, domain_1.record)(profile.organization);
115
+ plan = (0, domain_1.claudePlan)(organization.organization_type) ?? (0, domain_1.claudePlan)(organization.rate_limit_tier);
116
+ }
117
+ const spend = plan === 'enterprise' ? candidate : null;
118
+ if (!windows.length && !spend)
119
+ throw new errors_1.UsageError('usage-unavailable');
120
+ return { availability: 'available', windows: spend ? [] : windows, spend, plan, source: 'oauth' };
121
+ },
122
+ };
123
+ }
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createCodexReader = createCodexReader;
7
+ const node_string_decoder_1 = require("node:string_decoder");
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const win_spawn_1 = require("../../../util/win-spawn");
11
+ const domain_1 = require("../domain");
12
+ const errors_1 = require("./errors");
13
+ const local_auth_1 = require("./local-auth");
14
+ async function stopProbe(child) {
15
+ if (child.exitCode !== null || child.signalCode !== null)
16
+ return;
17
+ await new Promise(resolve => {
18
+ const done = () => { clearTimeout(timer); child.off('close', done); resolve(); };
19
+ const timer = setTimeout(() => {
20
+ if (child.pid)
21
+ (0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL', () => done());
22
+ else {
23
+ child.kill('SIGKILL');
24
+ done();
25
+ }
26
+ }, 500);
27
+ child.once('close', done);
28
+ child.stdin?.end();
29
+ if (child.pid)
30
+ (0, win_spawn_1.treeKillSafe)(child.pid, 'SIGTERM');
31
+ else
32
+ child.kill('SIGTERM');
33
+ });
34
+ }
35
+ function createCodexReader(options = {}) {
36
+ const home = options.home ?? process.env.CODEX_HOME ?? node_path_1.default.join((0, node_os_1.homedir)(), '.codex');
37
+ return {
38
+ async context() {
39
+ if (!node_path_1.default.isAbsolute(home))
40
+ throw new errors_1.UsageError('unsupported-platform');
41
+ return (0, local_auth_1.fingerprint)(`${home}:${await (options.readFile ?? local_auth_1.readAuthFile)(node_path_1.default.join(home, 'auth.json')) ?? 'keychain-or-none'}`);
42
+ },
43
+ read(signal) {
44
+ if (signal.aborted)
45
+ return Promise.reject(new errors_1.UsageError('aborted'));
46
+ return new Promise((resolve, reject) => {
47
+ let child;
48
+ try {
49
+ child = options.spawn ? options.spawn() : (0, win_spawn_1.spawnCli)('codex', ['app-server', '--listen', 'stdio://'], {
50
+ cwd: (0, node_os_1.homedir)(), env: { ...process.env, CODEX_HOME: home }, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true,
51
+ });
52
+ }
53
+ catch {
54
+ reject(new errors_1.UsageError('unsupported-cli'));
55
+ return;
56
+ }
57
+ let buffer = '', finished = false, plan = null, identity;
58
+ const decoder = new node_string_decoder_1.StringDecoder('utf8');
59
+ const timer = setTimeout(() => finish(new errors_1.UsageError('probe-timeout', true)), options.timeoutMs ?? 25_000);
60
+ function cleanup() {
61
+ clearTimeout(timer);
62
+ signal.removeEventListener('abort', abort);
63
+ child.stdout?.off('data', data);
64
+ child.stderr?.off('data', drain);
65
+ child.off('error', failure);
66
+ child.off('close', closed);
67
+ child.stdin?.off('error', failure);
68
+ }
69
+ function finish(error, result) {
70
+ if (finished)
71
+ return;
72
+ finished = true;
73
+ cleanup();
74
+ // Continue draining without retaining provider diagnostics during termination.
75
+ child.stdout?.resume();
76
+ child.stderr?.resume();
77
+ void (options.stop ?? stopProbe)(child).then(() => error ? reject(error) : resolve(result), () => reject(new errors_1.UsageError('cleanup-failed', true)));
78
+ }
79
+ const abort = () => finish(new errors_1.UsageError('aborted'));
80
+ const failure = () => finish(new errors_1.UsageError('unsupported-cli'));
81
+ const closed = () => finish(new errors_1.UsageError('probe-exited', true));
82
+ const drain = () => { };
83
+ function send(id, method, params = {}) {
84
+ try {
85
+ child.stdin?.write(`${JSON.stringify({ id, method, params })}\n`);
86
+ }
87
+ catch {
88
+ failure();
89
+ }
90
+ }
91
+ function data(chunk) {
92
+ buffer += decoder.write(chunk);
93
+ if (Buffer.byteLength(buffer) > 1024 * 1024) {
94
+ finish(new errors_1.UsageError('invalid-response', true));
95
+ return;
96
+ }
97
+ let newline;
98
+ while (!finished && (newline = buffer.indexOf('\n')) >= 0) {
99
+ const line = buffer.slice(0, newline);
100
+ buffer = buffer.slice(newline + 1);
101
+ let message;
102
+ try {
103
+ message = (0, domain_1.record)(JSON.parse(line));
104
+ }
105
+ catch {
106
+ finish(new errors_1.UsageError('invalid-response', true));
107
+ return;
108
+ }
109
+ if (typeof message.id !== 'number')
110
+ continue;
111
+ if (message.error) {
112
+ const code = (0, domain_1.record)(message.error).code;
113
+ finish(new errors_1.UsageError(code === -32601 ? 'unsupported-cli' : 'provider-error', code !== -32601));
114
+ return;
115
+ }
116
+ if (message.id === 1) {
117
+ try {
118
+ child.stdin?.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`);
119
+ }
120
+ catch {
121
+ failure();
122
+ return;
123
+ }
124
+ send(2, 'account/read', { refreshToken: false });
125
+ }
126
+ else if (message.id === 2) {
127
+ const account = (0, domain_1.record)((0, domain_1.record)(message.result).account);
128
+ if (!Object.keys(account).length) {
129
+ finish(undefined, { availability: 'signed-out', windows: [], plan: null, source: null });
130
+ return;
131
+ }
132
+ if (account.type !== 'chatgpt') {
133
+ finish(undefined, { availability: 'unsupported-auth', windows: [], plan: null, source: null });
134
+ return;
135
+ }
136
+ plan = typeof account.planType === 'string' ? account.planType.slice(0, 80) : null;
137
+ // Never export an email; only an internal fingerprint for identity checks.
138
+ if (typeof account.email === 'string')
139
+ identity = (0, local_auth_1.fingerprint)(account.email);
140
+ send(3, 'account/rateLimits/read');
141
+ }
142
+ else if (message.id === 3) {
143
+ const payload = (0, domain_1.record)(message.result), windows = (0, domain_1.normalizeCodex)(payload);
144
+ if (typeof payload.accountId === 'string')
145
+ identity = (0, local_auth_1.fingerprint)(payload.accountId);
146
+ if (!windows.length) {
147
+ finish(new errors_1.UsageError('usage-unavailable'));
148
+ return;
149
+ }
150
+ finish(undefined, { availability: 'available', windows, plan, source: 'app-server', identity });
151
+ }
152
+ }
153
+ }
154
+ signal.addEventListener('abort', abort, { once: true });
155
+ child.on('error', failure);
156
+ child.on('close', closed);
157
+ child.stdin?.on('error', failure);
158
+ child.stdout?.on('data', data);
159
+ child.stderr?.on('data', drain);
160
+ send(1, 'initialize', { clientInfo: { name: 'specrails-subscription-usage', title: 'Specrails', version: '1.0.0' } });
161
+ });
162
+ },
163
+ };
164
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UsageError = void 0;
4
+ class UsageError extends Error {
5
+ code;
6
+ retryable;
7
+ retryMs;
8
+ constructor(code, retryable = false, retryMs) {
9
+ super(code);
10
+ this.code = code;
11
+ this.retryable = retryable;
12
+ this.retryMs = retryMs;
13
+ }
14
+ }
15
+ exports.UsageError = UsageError;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerUsageRoutes = registerUsageRoutes;
4
+ const domain_1 = require("../domain");
5
+ function registerUsageRoutes(router, service) {
6
+ router.get('/subscription-usage', (_req, res) => res.json(service.snapshot()));
7
+ router.post('/subscription-usage/refresh', (req, res) => {
8
+ const body = req.body ?? {};
9
+ if (typeof body !== 'object' || body === null || Array.isArray(body) || Object.keys(body).some(key => key !== 'providerId' && key !== 'automatic')) {
10
+ res.status(400).json({ error: 'Invalid usage refresh request' });
11
+ return;
12
+ }
13
+ const { providerId, automatic } = body;
14
+ if ((providerId !== undefined && !domain_1.USAGE_PROVIDERS.includes(providerId)) || (automatic !== undefined && typeof automatic !== 'boolean')) {
15
+ res.status(400).json({ error: 'Invalid usage refresh request' });
16
+ return;
17
+ }
18
+ res.status(202).json(service.refresh(providerId, automatic === true));
19
+ });
20
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fingerprint = void 0;
4
+ exports.readAuthFile = readAuthFile;
5
+ exports.limitedJson = limitedJson;
6
+ const promises_1 = require("node:fs/promises");
7
+ const node_crypto_1 = require("node:crypto");
8
+ const errors_1 = require("./errors");
9
+ const fingerprint = (value) => (0, node_crypto_1.createHash)('sha256').update(value).digest('hex');
10
+ exports.fingerprint = fingerprint;
11
+ /** Bounded read; never expose auth bytes or paths in errors. */
12
+ async function readAuthFile(file) {
13
+ let handle;
14
+ try {
15
+ handle = await (0, promises_1.open)(file, 'r');
16
+ const stat = await handle.stat();
17
+ if (!stat.isFile() || stat.size > 1024 * 1024)
18
+ throw new errors_1.UsageError('credentials-unreadable');
19
+ const buffer = Buffer.alloc(1024 * 1024 + 1);
20
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
21
+ if (bytesRead > 1024 * 1024)
22
+ throw new errors_1.UsageError('credentials-unreadable');
23
+ return buffer.toString('utf8', 0, bytesRead);
24
+ }
25
+ catch (error) {
26
+ if (error.code === 'ENOENT')
27
+ return null;
28
+ throw new errors_1.UsageError('credentials-unreadable');
29
+ }
30
+ finally {
31
+ await handle?.close();
32
+ }
33
+ }
34
+ async function limitedJson(response) {
35
+ const reader = response.body?.getReader();
36
+ if (!reader)
37
+ throw new errors_1.UsageError('invalid-response', true);
38
+ let size = 0;
39
+ const chunks = [];
40
+ try {
41
+ while (true) {
42
+ const { done, value } = await reader.read();
43
+ if (done)
44
+ break;
45
+ size += value.length;
46
+ if (size > 1024 * 1024)
47
+ throw new errors_1.UsageError('invalid-response', true);
48
+ chunks.push(value);
49
+ }
50
+ try {
51
+ return JSON.parse(Buffer.concat(chunks).toString('utf8'));
52
+ }
53
+ catch {
54
+ throw new errors_1.UsageError('invalid-response', true);
55
+ }
56
+ }
57
+ finally {
58
+ await reader.cancel().catch(() => { });
59
+ reader.releaseLock();
60
+ }
61
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withFreshness = withFreshness;
4
+ exports.backoff = backoff;
5
+ function withFreshness(row, now) {
6
+ if (!row.observedAt)
7
+ return { ...row, freshness: 'unknown' };
8
+ const expired = now - Date.parse(row.observedAt) >= 300_000 || row.windows.some(w => w.resetsAt && Date.parse(w.resetsAt) <= now)
9
+ || !!row.spend?.resetsAt && Date.parse(row.spend.resetsAt) <= now;
10
+ return { ...row, freshness: expired || row.refreshState === 'error' ? 'stale' : 'fresh' };
11
+ }
12
+ function backoff(failures) { return Math.min(300_000, 30_000 * 2 ** Math.min(4, Math.max(0, failures - 1))); }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.duration = exports.percentage = exports.record = exports.USAGE_PROVIDERS = void 0;
4
+ exports.timestamp = timestamp;
5
+ exports.windowLabel = windowLabel;
6
+ exports.normalizeClaude = normalizeClaude;
7
+ exports.claudePlan = claudePlan;
8
+ exports.hasClaudeWindows = hasClaudeWindows;
9
+ exports.normalizeClaudeSpend = normalizeClaudeSpend;
10
+ exports.normalizeCodex = normalizeCodex;
11
+ exports.initialUsage = initialUsage;
12
+ exports.USAGE_PROVIDERS = ['claude', 'codex'];
13
+ const record = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
14
+ exports.record = record;
15
+ const percentage = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 100 ? value : null;
16
+ exports.percentage = percentage;
17
+ const duration = (value) => typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : null;
18
+ exports.duration = duration;
19
+ function timestamp(value, seconds = false) {
20
+ const time = typeof value === 'number' && Number.isFinite(value) ? value * (seconds ? 1000 : 1) : typeof value === 'string' ? Date.parse(value) : NaN;
21
+ return Number.isFinite(time) && time > 0 && time <= 8.64e15 ? new Date(time).toISOString() : null;
22
+ }
23
+ function windowLabel(minutes) {
24
+ return minutes === 300 ? 'session' : minutes === 10080 ? 'weekly' : minutes === 43200 ? 'monthly' : 'window';
25
+ }
26
+ function normalizeClaude(payload) {
27
+ const data = (0, exports.record)(payload);
28
+ const windows = [];
29
+ for (const [key, raw] of Object.entries(data)) {
30
+ if (!/^(five_hour|seven_day(?:_[a-z0-9_]+)?|fable_(weekly|seven_day))$/.test(key) || raw === null)
31
+ continue;
32
+ const value = (0, exports.record)(raw);
33
+ if (!['utilization', 'used_percentage', 'resets_at'].some(field => Object.hasOwn(value, field)))
34
+ continue;
35
+ const minutes = key === 'five_hour' ? 300 : 10080;
36
+ const model = key.startsWith('seven_day_') ? key.slice(10) : key.startsWith('fable_') ? 'fable' : null;
37
+ windows.push({ id: key, label: windowLabel(minutes), scope: model ? 'model' : 'account', model,
38
+ usedPercent: (0, exports.percentage)(value.utilization ?? value.used_percentage), durationMinutes: minutes, resetsAt: timestamp(value.resets_at, typeof value.resets_at === 'number') });
39
+ }
40
+ if (Array.isArray(data.limits))
41
+ for (const raw of data.limits.slice(0, 32)) {
42
+ const value = (0, exports.record)(raw), model = (0, exports.record)((0, exports.record)(value.scope).model).display_name;
43
+ if (value.kind !== 'weekly_scoped' || typeof model !== 'string' || !model.trim())
44
+ continue;
45
+ const name = model.trim().slice(0, 80);
46
+ if (windows.some(w => w.model?.toLowerCase() === name.toLowerCase()))
47
+ continue;
48
+ windows.push({ id: `model:${name}`, label: 'weekly', scope: 'model', model: name,
49
+ usedPercent: (0, exports.percentage)(value.percent), durationMinutes: 10080, resetsAt: timestamp(value.resets_at, true) });
50
+ }
51
+ return windows;
52
+ }
53
+ function claudePlan(value) {
54
+ if (typeof value !== 'string')
55
+ return null;
56
+ const words = value.trim().toLowerCase().split(/[^a-z0-9]+/);
57
+ return ['enterprise', 'team', 'max', 'pro', 'ultra', 'free'].find(plan => words.includes(plan)) ?? null;
58
+ }
59
+ function hasClaudeWindows(windows) {
60
+ return windows.some(window => window.usedPercent !== null || window.resetsAt !== null);
61
+ }
62
+ function normalizeClaudeSpend(payload, plan, now) {
63
+ if (plan !== 'enterprise' || hasClaudeWindows(normalizeClaude(payload)))
64
+ return null;
65
+ const extra = (0, exports.record)((0, exports.record)(payload).extra_usage);
66
+ const amount = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;
67
+ const used = amount(extra.used_credits), limit = amount(extra.monthly_limit);
68
+ if (used === null && limit === null)
69
+ return null;
70
+ const currency = extra.currency == null ? 'USD' : typeof extra.currency === 'string' ? extra.currency.trim().toUpperCase() : '';
71
+ if (!/^[A-Z]{3}$/.test(currency))
72
+ return null;
73
+ // OAuth spend is in currency minor units, including fractional minor units.
74
+ const exponent = new Intl.NumberFormat('en', { style: 'currency', currency }).resolvedOptions().maximumFractionDigits ?? 2;
75
+ const divisor = 10 ** exponent;
76
+ const usedAmount = used === null ? null : used / divisor, limitAmount = limit === null ? null : limit / divisor;
77
+ const limitStatus = limit !== null ? 'limited' : extra.monthly_limit === null && extra.is_enabled === true ? 'unlimited' : 'unknown';
78
+ const ratio = used !== null && limit !== null && limit > 0 ? used / limit * 100 : null;
79
+ const usedPercent = limitStatus === 'limited' ? amount(extra.utilization) ?? (ratio !== null && Number.isFinite(ratio) ? ratio : null) : null;
80
+ const date = new Date(now);
81
+ return { kind: 'enterprise-on-demand', usedAmount, limitAmount, limitStatus, currency, usedPercent,
82
+ resetsAt: timestamp(extra.resets_at, typeof extra.resets_at === 'number') ?? new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1)).toISOString() };
83
+ }
84
+ function normalizeCodex(payload) {
85
+ const data = (0, exports.record)(payload), groups = (0, exports.record)(data.rateLimitsByLimitId);
86
+ const entries = Object.keys(groups).length ? Object.entries(groups) : [['codex', data.rateLimits]];
87
+ const windows = [];
88
+ for (const [group, raw] of entries.slice(0, 32)) {
89
+ const bucket = (0, exports.record)(raw);
90
+ for (const slot of ['primary', 'secondary']) {
91
+ if (!bucket[slot] || typeof bucket[slot] !== 'object')
92
+ continue;
93
+ const value = (0, exports.record)(bucket[slot]), minutes = (0, exports.duration)(value.windowDurationMins);
94
+ windows.push({ id: `${group}:${slot}`, label: windowLabel(minutes), scope: group === 'codex' ? 'account' : 'model',
95
+ model: group === 'codex' ? null : (typeof bucket.limitName === 'string' ? bucket.limitName : group).slice(0, 80),
96
+ usedPercent: (0, exports.percentage)(value.usedPercent), durationMinutes: minutes, resetsAt: timestamp(value.resetsAt, true) });
97
+ }
98
+ }
99
+ return windows;
100
+ }
101
+ function initialUsage(providerId, generation) {
102
+ return { providerId, installed: null, generation, availability: 'unavailable', refreshState: 'idle', freshness: 'unknown', plan: null,
103
+ windows: [], spend: null, source: null, observedAt: null, attemptedAt: null, retryAt: null, issue: null };
104
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDesktopUsageService = createDesktopUsageService;
4
+ const provider_detection_1 = require("../../../provider-detection");
5
+ const claude_1 = require("../adapters/claude");
6
+ const codex_1 = require("../adapters/codex");
7
+ const usage_service_1 = require("./usage-service");
8
+ function createDesktopUsageService() {
9
+ return (0, usage_service_1.createUsageService)({
10
+ installed: async (id) => {
11
+ const provider = (await (0, provider_detection_1.getDetectionSnapshot)()).providers[id];
12
+ return !!provider?.installed;
13
+ },
14
+ eligible: async (id) => {
15
+ const provider = (await (0, provider_detection_1.getDetectionSnapshot)()).providers[id];
16
+ return !!provider?.executable && provider.meetsMinimum !== false && !provider.vetoed;
17
+ },
18
+ readers: { claude: (0, claude_1.createClaudeReader)(), codex: (0, codex_1.createCodexReader)() },
19
+ });
20
+ }