agim-cli 1.2.128 → 1.2.130

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 (218) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/dist/core/llm/agent-loop.d.ts.map +1 -1
  3. package/dist/core/llm/agent-loop.js +9 -1
  4. package/dist/core/llm/agent-loop.js.map +1 -1
  5. package/dist/web/public/assets/{a2a-CbxNgf9H.js → a2a-Bp_OpTfW.js} +2 -2
  6. package/dist/web/public/assets/{a2a-CbxNgf9H.js.map → a2a-Bp_OpTfW.js.map} +1 -1
  7. package/dist/web/public/assets/{activity-C6r508cN.js → activity-B5erGuWa.js} +2 -2
  8. package/dist/web/public/assets/{activity-C6r508cN.js.map → activity-B5erGuWa.js.map} +1 -1
  9. package/dist/web/public/assets/{admins-C0BJw6X9.js → admins-D3j7wkvL.js} +3 -3
  10. package/dist/web/public/assets/{admins-C0BJw6X9.js.map → admins-D3j7wkvL.js.map} +1 -1
  11. package/dist/web/public/assets/{agents-DOW1_NGT.js → agents-Cb3Vb2-8.js} +3 -3
  12. package/dist/web/public/assets/{agents-DOW1_NGT.js.map → agents-Cb3Vb2-8.js.map} +1 -1
  13. package/dist/web/public/assets/{approvals-CyPhYcGG.js → approvals-BZULwrl5.js} +3 -3
  14. package/dist/web/public/assets/{approvals-CyPhYcGG.js.map → approvals-BZULwrl5.js.map} +1 -1
  15. package/dist/web/public/assets/arrow-down-OdSfpgG4.js +7 -0
  16. package/dist/web/public/assets/arrow-down-OdSfpgG4.js.map +1 -0
  17. package/dist/web/public/assets/arrow-up-DtrvOH7Z.js +7 -0
  18. package/dist/web/public/assets/arrow-up-DtrvOH7Z.js.map +1 -0
  19. package/dist/web/public/assets/{asks-B6L3PSml.js → asks-BaVT-eFe.js} +3 -3
  20. package/dist/web/public/assets/{asks-B6L3PSml.js.map → asks-BaVT-eFe.js.map} +1 -1
  21. package/dist/web/public/assets/audit-CSk2rv6z.js +2 -0
  22. package/dist/web/public/assets/{audit-CCGCdw6P.js.map → audit-CSk2rv6z.js.map} +1 -1
  23. package/dist/web/public/assets/{bell-OiL3Thk2.js → bell-DifbuUaI.js} +2 -2
  24. package/dist/web/public/assets/{bell-OiL3Thk2.js.map → bell-DifbuUaI.js.map} +1 -1
  25. package/dist/web/public/assets/{bgjobs-vhVtnLSx.js → bgjobs-D3wsuZBR.js} +3 -3
  26. package/dist/web/public/assets/{bgjobs-vhVtnLSx.js.map → bgjobs-D3wsuZBR.js.map} +1 -1
  27. package/dist/web/public/assets/{brain-n56pZ1TQ.js → brain-BH9ObIfA.js} +2 -2
  28. package/dist/web/public/assets/{brain-n56pZ1TQ.js.map → brain-BH9ObIfA.js.map} +1 -1
  29. package/dist/web/public/assets/{briefcase-BscVfAjp.js → briefcase-CZqK5oy3.js} +2 -2
  30. package/dist/web/public/assets/{briefcase-BscVfAjp.js.map → briefcase-CZqK5oy3.js.map} +1 -1
  31. package/dist/web/public/assets/{browser-ponyfill-BOcGq8h9.js → browser-ponyfill-BUutOaRz.js} +2 -2
  32. package/dist/web/public/assets/{browser-ponyfill-BOcGq8h9.js.map → browser-ponyfill-BUutOaRz.js.map} +1 -1
  33. package/dist/web/public/assets/chat-gOU1pe0E.js +7 -0
  34. package/dist/web/public/assets/chat-gOU1pe0E.js.map +1 -0
  35. package/dist/web/public/assets/chevron-left-BtuaBNRZ.js +7 -0
  36. package/dist/web/public/assets/chevron-left-BtuaBNRZ.js.map +1 -0
  37. package/dist/web/public/assets/{chevron-right-trO6yoBr.js → chevron-right-uDVVnuGu.js} +2 -2
  38. package/dist/web/public/assets/{chevron-right-trO6yoBr.js.map → chevron-right-uDVVnuGu.js.map} +1 -1
  39. package/dist/web/public/assets/{circle-check-B_d7dBl5.js → circle-check-VgYKnBhy.js} +2 -2
  40. package/dist/web/public/assets/{circle-check-B_d7dBl5.js.map → circle-check-VgYKnBhy.js.map} +1 -1
  41. package/dist/web/public/assets/{circle-check-big-D6TvCoDM.js → circle-check-big-7idAFtyL.js} +2 -2
  42. package/dist/web/public/assets/{circle-check-big-D6TvCoDM.js.map → circle-check-big-7idAFtyL.js.map} +1 -1
  43. package/dist/web/public/assets/{circle-x-OcRzGLRb.js → circle-x-8dhkvHlT.js} +2 -2
  44. package/dist/web/public/assets/{circle-x-OcRzGLRb.js.map → circle-x-8dhkvHlT.js.map} +1 -1
  45. package/dist/web/public/assets/confirm-dialog-_BtUs6oW.js +2 -0
  46. package/dist/web/public/assets/{confirm-dialog-DD1ZW1XE.js.map → confirm-dialog-_BtUs6oW.js.map} +1 -1
  47. package/dist/web/public/assets/copy-Ba1min4z.js +7 -0
  48. package/dist/web/public/assets/copy-Ba1min4z.js.map +1 -0
  49. package/dist/web/public/assets/{data-table-bhqK389v.js → data-table-BVcXWtPw.js} +3 -3
  50. package/dist/web/public/assets/{data-table-bhqK389v.js.map → data-table-BVcXWtPw.js.map} +1 -1
  51. package/dist/web/public/assets/dialog-BVYFRXlI.js +6 -0
  52. package/dist/web/public/assets/{dialog-D5BsJN2q.js.map → dialog-BVYFRXlI.js.map} +1 -1
  53. package/dist/web/public/assets/{download-CcO4RAuC.js → download-DYc5g_1W.js} +3 -3
  54. package/dist/web/public/assets/{download-CcO4RAuC.js.map → download-DYc5g_1W.js.map} +1 -1
  55. package/dist/web/public/assets/{email-Dy3UoyzF.js → email-6vlGBJXY.js} +3 -3
  56. package/dist/web/public/assets/{email-Dy3UoyzF.js.map → email-6vlGBJXY.js.map} +1 -1
  57. package/dist/web/public/assets/{empty-state-CwUKG8xX.js → empty-state-WHzNYVaT.js} +2 -2
  58. package/dist/web/public/assets/{empty-state-CwUKG8xX.js.map → empty-state-WHzNYVaT.js.map} +1 -1
  59. package/dist/web/public/assets/{external-link-wf5VhNXd.js → external-link-CfQZDer8.js} +2 -2
  60. package/dist/web/public/assets/{external-link-wf5VhNXd.js.map → external-link-CfQZDer8.js.map} +1 -1
  61. package/dist/web/public/assets/{eye-8lKlwbZE.js → eye-PzqPB6N6.js} +3 -3
  62. package/dist/web/public/assets/{eye-8lKlwbZE.js.map → eye-PzqPB6N6.js.map} +1 -1
  63. package/dist/web/public/assets/facts-NmBeyMpC.js +2 -0
  64. package/dist/web/public/assets/{facts-Cfu6Lg3H.js.map → facts-NmBeyMpC.js.map} +1 -1
  65. package/dist/web/public/assets/{goals-BQkhal_h.js → goals-BfMwQtYm.js} +4 -4
  66. package/dist/web/public/assets/{goals-BQkhal_h.js.map → goals-BfMwQtYm.js.map} +1 -1
  67. package/dist/web/public/assets/health-D46iQ6Hj.js +2 -0
  68. package/dist/web/public/assets/{health-BObMAngj.js.map → health-D46iQ6Hj.js.map} +1 -1
  69. package/dist/web/public/assets/{heart-pulse-DI33Rxyr.js → heart-pulse-BHz53Ggd.js} +2 -2
  70. package/dist/web/public/assets/{heart-pulse-DI33Rxyr.js.map → heart-pulse-BHz53Ggd.js.map} +1 -1
  71. package/dist/web/public/assets/{heartbeat-Bc4SZawQ.js → heartbeat-DBpc9rKL.js} +3 -3
  72. package/dist/web/public/assets/{heartbeat-Bc4SZawQ.js.map → heartbeat-DBpc9rKL.js.map} +1 -1
  73. package/dist/web/public/assets/{hot-BXYotT26.js → hot-D_-tARKX.js} +4 -9
  74. package/dist/web/public/assets/hot-D_-tARKX.js.map +1 -0
  75. package/dist/web/public/assets/{index-CGaI-i4K.js → index-DXI13nSQ.js} +29 -29
  76. package/dist/web/public/assets/index-DXI13nSQ.js.map +1 -0
  77. package/dist/web/public/assets/index-f1K5Q2Yz.css +1 -0
  78. package/dist/web/public/assets/{installed-DswmDcea.js → installed-BtOgT0Ea.js} +2 -2
  79. package/dist/web/public/assets/{installed-DswmDcea.js.map → installed-BtOgT0Ea.js.map} +1 -1
  80. package/dist/web/public/assets/jobs-DUoPbupO.js +2 -0
  81. package/dist/web/public/assets/{jobs-DWBDqKx-.js.map → jobs-DUoPbupO.js.map} +1 -1
  82. package/dist/web/public/assets/layout-BpS7td-S.js +2 -0
  83. package/dist/web/public/assets/layout-BpS7td-S.js.map +1 -0
  84. package/dist/web/public/assets/layout-C1EVvCs8.js +2 -0
  85. package/dist/web/public/assets/{layout-D7gNMUDZ.js.map → layout-C1EVvCs8.js.map} +1 -1
  86. package/dist/web/public/assets/layout-C3e8vPrG.js +2 -0
  87. package/dist/web/public/assets/{layout-DJKxW33x.js.map → layout-C3e8vPrG.js.map} +1 -1
  88. package/dist/web/public/assets/layout-DkoRqhBs.js +2 -0
  89. package/dist/web/public/assets/{layout-B5rK_h6Q.js.map → layout-DkoRqhBs.js.map} +1 -1
  90. package/dist/web/public/assets/layout-wuoOyazR.js +2 -0
  91. package/dist/web/public/assets/{layout-ByUY6XZQ.js.map → layout-wuoOyazR.js.map} +1 -1
  92. package/dist/web/public/assets/{llm-CPOd98Hy.js → llm-iuvigJxr.js} +2 -2
  93. package/dist/web/public/assets/{llm-CPOd98Hy.js.map → llm-iuvigJxr.js.map} +1 -1
  94. package/dist/web/public/assets/{loader-circle-BBIfyATA.js → loader-circle-BS5FFFg-.js} +2 -2
  95. package/dist/web/public/assets/{loader-circle-BBIfyATA.js.map → loader-circle-BS5FFFg-.js.map} +1 -1
  96. package/dist/web/public/assets/{map-pin-Bg7JuU7F.js → map-pin-CRS6YW4i.js} +2 -2
  97. package/dist/web/public/assets/{map-pin-Bg7JuU7F.js.map → map-pin-CRS6YW4i.js.map} +1 -1
  98. package/dist/web/public/assets/{mcp-DGxGN2iX.js → mcp-PWEuZOJ_.js} +3 -3
  99. package/dist/web/public/assets/{mcp-DGxGN2iX.js.map → mcp-PWEuZOJ_.js.map} +1 -1
  100. package/dist/web/public/assets/{memos-LpUpTmYL.js → memos-C6i1hbv9.js} +3 -3
  101. package/dist/web/public/assets/{memos-LpUpTmYL.js.map → memos-C6i1hbv9.js.map} +1 -1
  102. package/dist/web/public/assets/messengers-CZ3eL15d.js +2 -0
  103. package/dist/web/public/assets/messengers-CZ3eL15d.js.map +1 -0
  104. package/dist/web/public/assets/mobile-_rEEG_kX.js +7 -0
  105. package/dist/web/public/assets/mobile-_rEEG_kX.js.map +1 -0
  106. package/dist/web/public/assets/{native-agent-CPkYGY3I.js → native-agent-B-Id8sOl.js} +4 -4
  107. package/dist/web/public/assets/{native-agent-CPkYGY3I.js.map → native-agent-B-Id8sOl.js.map} +1 -1
  108. package/dist/web/public/assets/{network-DHrX3RcZ.js → network-MVE8s4TA.js} +2 -2
  109. package/dist/web/public/assets/{network-DHrX3RcZ.js.map → network-MVE8s4TA.js.map} +1 -1
  110. package/dist/web/public/assets/{outbox-T3NnYmK0.js → outbox-BRpgAP1d.js} +3 -3
  111. package/dist/web/public/assets/{outbox-T3NnYmK0.js.map → outbox-BRpgAP1d.js.map} +1 -1
  112. package/dist/web/public/assets/pagination-dm3r6K_2.js +12 -0
  113. package/dist/web/public/assets/pagination-dm3r6K_2.js.map +1 -0
  114. package/dist/web/public/assets/persona-Oq3C-gEw.js +2 -0
  115. package/dist/web/public/assets/{persona-CHz80XDk.js.map → persona-Oq3C-gEw.js.map} +1 -1
  116. package/dist/web/public/assets/{play-BNtSkb5l.js → play-COQw7BqX.js} +2 -2
  117. package/dist/web/public/assets/{play-BNtSkb5l.js.map → play-COQw7BqX.js.map} +1 -1
  118. package/dist/web/public/assets/{plus-CYsjCf6w.js → plus-CdOyGoU1.js} +2 -2
  119. package/dist/web/public/assets/{plus-CYsjCf6w.js.map → plus-CdOyGoU1.js.map} +1 -1
  120. package/dist/web/public/assets/policy-docXezae.js +2 -0
  121. package/dist/web/public/assets/{policy-CtKRzual.js.map → policy-docXezae.js.map} +1 -1
  122. package/dist/web/public/assets/qr-code-8putJTrW.js +7 -0
  123. package/dist/web/public/assets/qr-code-8putJTrW.js.map +1 -0
  124. package/dist/web/public/assets/{react-C9F3QeMB.js → react-Cb2sDjhD.js} +2 -2
  125. package/dist/web/public/assets/{react-C9F3QeMB.js.map → react-Cb2sDjhD.js.map} +1 -1
  126. package/dist/web/public/assets/{refresh-ccw-DpPWcwTg.js → refresh-ccw-BPKXoMZa.js} +2 -2
  127. package/dist/web/public/assets/{refresh-ccw-DpPWcwTg.js.map → refresh-ccw-BPKXoMZa.js.map} +1 -1
  128. package/dist/web/public/assets/{reminders-R14lWHEJ.js → reminders-CP2qtNSr.js} +3 -3
  129. package/dist/web/public/assets/{reminders-R14lWHEJ.js.map → reminders-CP2qtNSr.js.map} +1 -1
  130. package/dist/web/public/assets/{save-beGooRNy.js → save-BXCmgeEj.js} +2 -2
  131. package/dist/web/public/assets/{save-beGooRNy.js.map → save-BXCmgeEj.js.map} +1 -1
  132. package/dist/web/public/assets/{schedules-fxKnDnxp.js → schedules-DVaY38v1.js} +3 -3
  133. package/dist/web/public/assets/{schedules-fxKnDnxp.js.map → schedules-DVaY38v1.js.map} +1 -1
  134. package/dist/web/public/assets/{search-DzgimpPy.js → search-B-wDhzjs.js} +3 -3
  135. package/dist/web/public/assets/{search-DzgimpPy.js.map → search-B-wDhzjs.js.map} +1 -1
  136. package/dist/web/public/assets/{search-BzOAg0Rb.js → search-DzexDAbr.js} +2 -2
  137. package/dist/web/public/assets/{search-BzOAg0Rb.js.map → search-DzexDAbr.js.map} +1 -1
  138. package/dist/web/public/assets/security-FHN-b43T.js +2 -0
  139. package/dist/web/public/assets/{security-Dw1mh68G.js.map → security-FHN-b43T.js.map} +1 -1
  140. package/dist/web/public/assets/{service-CB55xtmh.js → service-DXGUZTCp.js} +3 -3
  141. package/dist/web/public/assets/{service-CB55xtmh.js.map → service-DXGUZTCp.js.map} +1 -1
  142. package/dist/web/public/assets/{shield-alert-C2IO43co.js → shield-alert-BM0-khVy.js} +2 -2
  143. package/dist/web/public/assets/{shield-alert-C2IO43co.js.map → shield-alert-BM0-khVy.js.map} +1 -1
  144. package/dist/web/public/assets/{status-badge-wL5IXJx_.js → status-badge-DeESb2dc.js} +2 -2
  145. package/dist/web/public/assets/{status-badge-wL5IXJx_.js.map → status-badge-DeESb2dc.js.map} +1 -1
  146. package/dist/web/public/assets/{subtasks-CbLAkygG.js → subtasks-DOwo6FnZ.js} +3 -3
  147. package/dist/web/public/assets/{subtasks-CbLAkygG.js.map → subtasks-DOwo6FnZ.js.map} +1 -1
  148. package/dist/web/public/assets/table-oUi0mGOn.js +2 -0
  149. package/dist/web/public/assets/{table-9FRavyyI.js.map → table-oUi0mGOn.js.map} +1 -1
  150. package/dist/web/public/assets/{topn-BE7RU5cV.js → topn-D1LQXoLo.js} +3 -3
  151. package/dist/web/public/assets/{topn-BE7RU5cV.js.map → topn-D1LQXoLo.js.map} +1 -1
  152. package/dist/web/public/assets/{trash-2-DL2FAuYX.js → trash-2-CTkSvnZX.js} +2 -2
  153. package/dist/web/public/assets/{trash-2-DL2FAuYX.js.map → trash-2-CTkSvnZX.js.map} +1 -1
  154. package/dist/web/public/assets/use-background-tasks-BkUIDOxX.js +2 -0
  155. package/dist/web/public/assets/{use-background-tasks-XHuIYwrT.js.map → use-background-tasks-BkUIDOxX.js.map} +1 -1
  156. package/dist/web/public/assets/{use-event-stream-BGeFcayX.js → use-event-stream-DgGpGKop.js} +2 -2
  157. package/dist/web/public/assets/{use-event-stream-BGeFcayX.js.map → use-event-stream-DgGpGKop.js.map} +1 -1
  158. package/dist/web/public/assets/use-llm-admin-BrJMMEz5.js +2 -0
  159. package/dist/web/public/assets/{use-llm-admin-Dm8PcjN-.js.map → use-llm-admin-BrJMMEz5.js.map} +1 -1
  160. package/dist/web/public/assets/use-memory-CbTYEBTc.js +2 -0
  161. package/dist/web/public/assets/{use-memory-C3GgMqiJ.js.map → use-memory-CbTYEBTc.js.map} +1 -1
  162. package/dist/web/public/assets/{use-observability-BQa4b0Uk.js → use-observability-Bum0mmDO.js} +2 -2
  163. package/dist/web/public/assets/{use-observability-BQa4b0Uk.js.map → use-observability-Bum0mmDO.js.map} +1 -1
  164. package/dist/web/public/assets/use-settings-DJlVLnjo.js +2 -0
  165. package/dist/web/public/assets/{use-settings-CrkXdLrr.js.map → use-settings-DJlVLnjo.js.map} +1 -1
  166. package/dist/web/public/assets/use-workspace-BJZUfkqw.js +2 -0
  167. package/dist/web/public/assets/{use-workspace-Csq4sxlY.js.map → use-workspace-BJZUfkqw.js.map} +1 -1
  168. package/dist/web/public/assets/useQuery-CEwGD94N.js +2 -0
  169. package/dist/web/public/assets/{useQuery-ByZlZXlw.js.map → useQuery-CEwGD94N.js.map} +1 -1
  170. package/dist/web/public/assets/vector-BqffHZmp.js +2 -0
  171. package/dist/web/public/assets/{vector-BmpvJTWt.js.map → vector-BqffHZmp.js.map} +1 -1
  172. package/dist/web/public/assets/{viewer-BOSX-lUS.js → viewer-CKTTV-Wt.js} +4 -4
  173. package/dist/web/public/assets/{viewer-BOSX-lUS.js.map → viewer-CKTTV-Wt.js.map} +1 -1
  174. package/dist/web/public/assets/{workspace-DTbEdEyD.js → workspace-DQphgYwy.js} +3 -3
  175. package/dist/web/public/assets/{workspace-DTbEdEyD.js.map → workspace-DQphgYwy.js.map} +1 -1
  176. package/dist/web/public/assets/workspaces-BOA3TuDS.js +7 -0
  177. package/dist/web/public/assets/{workspaces-BIZGVK8F.js.map → workspaces-BOA3TuDS.js.map} +1 -1
  178. package/dist/web/public/assets/{x-BLllJ8d_.js → x-OHUicFfn.js} +2 -2
  179. package/dist/web/public/assets/{x-BLllJ8d_.js.map → x-OHUicFfn.js.map} +1 -1
  180. package/dist/web/public/index.html +3 -3
  181. package/dist/web/public/m/login.html +124 -0
  182. package/dist/web/server.d.ts.map +1 -1
  183. package/dist/web/server.js +103 -1
  184. package/dist/web/server.js.map +1 -1
  185. package/package.json +1 -1
  186. package/dist/web/public/assets/arrow-up-CZr2LH5e.js +0 -12
  187. package/dist/web/public/assets/arrow-up-CZr2LH5e.js.map +0 -1
  188. package/dist/web/public/assets/audit-CCGCdw6P.js +0 -2
  189. package/dist/web/public/assets/confirm-dialog-DD1ZW1XE.js +0 -2
  190. package/dist/web/public/assets/dialog-D5BsJN2q.js +0 -6
  191. package/dist/web/public/assets/facts-Cfu6Lg3H.js +0 -2
  192. package/dist/web/public/assets/health-BObMAngj.js +0 -2
  193. package/dist/web/public/assets/hot-BXYotT26.js.map +0 -1
  194. package/dist/web/public/assets/index-CGaI-i4K.js.map +0 -1
  195. package/dist/web/public/assets/index-De8LfCtL.css +0 -1
  196. package/dist/web/public/assets/jobs-DWBDqKx-.js +0 -2
  197. package/dist/web/public/assets/layout-B5rK_h6Q.js +0 -2
  198. package/dist/web/public/assets/layout-ByUY6XZQ.js +0 -2
  199. package/dist/web/public/assets/layout-CX3nXpWb.js +0 -2
  200. package/dist/web/public/assets/layout-CX3nXpWb.js.map +0 -1
  201. package/dist/web/public/assets/layout-D7gNMUDZ.js +0 -2
  202. package/dist/web/public/assets/layout-DJKxW33x.js +0 -2
  203. package/dist/web/public/assets/messengers-CWMsJz1e.js +0 -7
  204. package/dist/web/public/assets/messengers-CWMsJz1e.js.map +0 -1
  205. package/dist/web/public/assets/pagination-ANxQzaRV.js +0 -17
  206. package/dist/web/public/assets/pagination-ANxQzaRV.js.map +0 -1
  207. package/dist/web/public/assets/persona-CHz80XDk.js +0 -2
  208. package/dist/web/public/assets/policy-CtKRzual.js +0 -2
  209. package/dist/web/public/assets/security-Dw1mh68G.js +0 -2
  210. package/dist/web/public/assets/table-9FRavyyI.js +0 -2
  211. package/dist/web/public/assets/use-background-tasks-XHuIYwrT.js +0 -2
  212. package/dist/web/public/assets/use-llm-admin-Dm8PcjN-.js +0 -2
  213. package/dist/web/public/assets/use-memory-C3GgMqiJ.js +0 -2
  214. package/dist/web/public/assets/use-settings-CrkXdLrr.js +0 -2
  215. package/dist/web/public/assets/use-workspace-Csq4sxlY.js +0 -2
  216. package/dist/web/public/assets/useQuery-ByZlZXlw.js +0 -2
  217. package/dist/web/public/assets/vector-BmpvJTWt.js +0 -2
  218. package/dist/web/public/assets/workspaces-BIZGVK8F.js +0 -7
@@ -0,0 +1 @@
1
+ :root{--ag-bg: 220 14% 96%;--ag-surface: 0 0% 100%;--ag-surface-2: 220 14% 94%;--ag-surface-hover:220 14% 92%;--ag-border: 220 13% 90%;--ag-border-strong: 220 10% 80%;--ag-text: 220 13% 13%;--ag-text-dim: 220 6% 38%;--ag-text-muted: 220 6% 58%;--ag-accent: 246 80% 60%;--ag-accent-fg: 0 0% 100%;--ag-accent-hover: 246 80% 52%;--ag-accent-bg: 246 100% 96%;--ag-success: 158 75% 39%;--ag-success-bg:158 75% 95%;--ag-warning: 38 95% 50%;--ag-warning-bg: 38 95% 95%;--ag-danger: 0 78% 56%;--ag-danger-bg: 0 78% 96%;--ag-info: 217 91% 60%;--ag-info-bg: 217 91% 96%;--ag-shadow-sm: 0 1px 2px hsl(220 13% 13% / .05);--ag-shadow-md: 0 2px 8px hsl(220 13% 13% / .08);--ag-shadow-lg: 0 8px 24px hsl(220 13% 13% / .12)}:root[data-theme=dark]{--ag-bg: 220 10% 7%;--ag-surface: 220 12% 11%;--ag-surface-2: 220 12% 14%;--ag-surface-hover:220 12% 16%;--ag-border: 220 10% 20%;--ag-border-strong: 220 10% 28%;--ag-text: 220 14% 91%;--ag-text-dim: 220 8% 68%;--ag-text-muted: 220 8% 50%;--ag-accent: 246 90% 72%;--ag-accent-fg: 220 30% 5%;--ag-accent-hover: 246 90% 80%;--ag-accent-bg: 246 30% 22%;--ag-success: 158 70% 50%;--ag-success-bg:158 60% 20%;--ag-warning: 38 90% 60%;--ag-warning-bg: 38 60% 20%;--ag-danger: 0 85% 67%;--ag-danger-bg: 0 60% 22%;--ag-info: 217 90% 70%;--ag-info-bg: 217 60% 25%;--ag-shadow-sm: 0 1px 2px hsl(0 0% 0% / .4);--ag-shadow-md: 0 2px 8px hsl(0 0% 0% / .5);--ag-shadow-lg: 0 8px 24px hsl(0 0% 0% / .6)}@media (prefers-color-scheme: dark){:root:not([data-theme=light]):not([data-theme=dark]){--ag-bg: 220 10% 7%;--ag-surface: 220 12% 11%;--ag-surface-2: 220 12% 14%;--ag-surface-hover:220 12% 16%;--ag-border: 220 10% 20%;--ag-border-strong: 220 10% 28%;--ag-text: 220 14% 91%;--ag-text-dim: 220 8% 68%;--ag-text-muted: 220 8% 50%;--ag-accent: 246 90% 72%;--ag-accent-fg: 220 30% 5%;--ag-accent-hover: 246 90% 80%;--ag-accent-bg: 246 30% 22%;--ag-success: 158 70% 50%;--ag-success-bg:158 60% 20%;--ag-warning: 38 90% 60%;--ag-warning-bg: 38 60% 20%;--ag-danger: 0 85% 67%;--ag-danger-bg: 0 60% 22%;--ag-info: 217 90% 70%;--ag-info-bg: 217 60% 25%;--ag-shadow-sm: 0 1px 2px hsl(0 0% 0% / .4);--ag-shadow-md: 0 2px 8px hsl(0 0% 0% / .5);--ag-shadow-lg: 0 8px 24px hsl(0 0% 0% / .6)}}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html,body,#root{height:100%}body{background-color:hsl(var(--ag-bg));color:hsl(var(--ag-text));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji",sans-serif;touch-action:manipulation;-webkit-tap-highlight-color:hsl(var(--ag-accent) / .15)}button,[role=button],a,input[type=button],input[type=submit]{-webkit-tap-highlight-color:hsl(var(--ag-accent) / .15)}@media (pointer: fine){*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-thumb{background:hsl(var(--ag-border-strong));border-radius:999px;border:2px solid transparent;background-clip:content-box}*::-webkit-scrollbar-thumb:hover{background:hsl(var(--ag-text-muted));background-clip:content-box}}.container{width:100%;margin-right:auto;margin-left:auto;padding-right:16px;padding-left:16px}@media (min-width: 640px){.container{max-width:640px;padding-right:24px;padding-left:24px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px;padding-right:32px;padding-left:32px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1400px){.container{max-width:1400px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-2{bottom:8px}.bottom-24{bottom:6rem}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:8px}.left-\[50\%\]{left:50%}.right-0{right:0}.right-4{right:16px}.top-0{top:0}.top-1\/2{top:50%}.top-10{top:2.5rem}.top-4{top:16px}.top-\[50\%\]{top:50%}.top-\[var\(--topbar-h\,0\)\]{top:var(--topbar-h,0)}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.-mx-1{margin-left:-4px;margin-right:-4px}.-mx-3{margin-left:-12px;margin-right:-12px}.mx-4{margin-left:16px;margin-right:16px}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:4px;margin-bottom:4px}.my-2{margin-top:8px;margin-bottom:8px}.-ml-2{margin-left:-8px}.mb-0\.5{margin-bottom:2px}.mb-1{margin-bottom:4px}.mb-1\.5{margin-bottom:6px}.mb-2{margin-bottom:8px}.mb-3{margin-bottom:12px}.ml-1{margin-left:4px}.ml-2{margin-left:8px}.ml-3{margin-left:12px}.ml-5{margin-left:20px}.ml-auto{margin-left:auto}.mr-1{margin-right:4px}.mr-2{margin-right:8px}.mt-0\.5{margin-top:2px}.mt-1{margin-top:4px}.mt-1\.5{margin-top:6px}.mt-2{margin-top:8px}.mt-3{margin-top:12px}.mt-4{margin-top:16px}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.size-4{width:16px;height:16px}.h-1{height:4px}.h-1\.5{height:6px}.h-10{height:2.5rem}.h-12{height:3rem}.h-2{height:8px}.h-24{height:6rem}.h-3{height:12px}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:16px}.h-48{height:12rem}.h-5{height:20px}.h-6{height:24px}.h-64{height:16rem}.h-7{height:32px}.h-72{height:18rem}.h-8{height:48px}.h-9{height:64px}.h-96{height:24rem}.h-\[280px\]{height:280px}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-dvh{height:100dvh}.h-px{height:1px}.max-h-32{max-height:8rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-64{max-height:16rem}.max-h-96{max-height:24rem}.max-h-\[85dvh\]{max-height:85dvh}.min-h-8{min-height:48px}.min-h-9{min-height:64px}.min-h-\[500px\]{min-height:500px}.min-h-dvh{min-height:100dvh}.w-1\.5{width:6px}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:8px}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:12px}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:16px}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:20px}.w-56{width:14rem}.w-6{width:24px}.w-64{width:16rem}.w-72{width:18rem}.w-8{width:48px}.w-9{width:64px}.w-\[140px\]{width:140px}.w-\[160px\]{width:160px}.w-\[180px\]{width:180px}.w-\[280px\]{width:280px}.w-\[80px\]{width:80px}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[180px\]{min-width:180px}.min-w-\[200px\]{min-width:200px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-\[85\%\]{max-width:85%}.max-w-\[calc\(100vw-2rem\)\]{max-width:calc(100vw - 2rem)}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0\.5{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-5{--tw-translate-x: 20px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-none{resize:none}.resize-y{resize:vertical}.scroll-mx-4{scroll-margin-left:16px;scroll-margin-right:16px}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[max-content_1fr\]{grid-template-columns:max-content 1fr}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:2px}.gap-1{gap:4px}.gap-1\.5{gap:6px}.gap-2{gap:8px}.gap-3{gap:12px}.gap-4{gap:16px}.gap-6{gap:24px}.gap-x-3{-moz-column-gap:12px;column-gap:12px}.gap-x-4{-moz-column-gap:16px;column-gap:16px}.gap-y-1{row-gap:4px}.gap-y-2{row-gap:8px}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2px * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(4px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(4px * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(8px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(12px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(12px * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border>:not([hidden])~:not([hidden]){border-color:hsl(var(--ag-border))}.self-start{align-self:flex-start}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:6px}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:10px}.rounded-md{border-radius:6px}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-accent{border-color:hsl(var(--ag-accent))}.border-border{border-color:hsl(var(--ag-border))}.border-border\/40{border-color:hsl(var(--ag-border) / .4)}.border-danger{border-color:hsl(var(--ag-danger))}.border-danger\/30{border-color:hsl(var(--ag-danger) / .3)}.border-danger\/60{border-color:hsl(var(--ag-danger) / .6)}.border-info{border-color:hsl(var(--ag-info))}.border-info\/30{border-color:hsl(var(--ag-info) / .3)}.border-success{border-color:hsl(var(--ag-success))}.border-success\/30{border-color:hsl(var(--ag-success) / .3)}.border-success\/60{border-color:hsl(var(--ag-success) / .6)}.border-transparent{border-color:transparent}.border-warning{border-color:hsl(var(--ag-warning))}.border-warning\/30{border-color:hsl(var(--ag-warning) / .3)}.border-warning\/40{border-color:hsl(var(--ag-warning) / .4)}.border-warning\/60{border-color:hsl(var(--ag-warning) / .6)}.bg-accent{background-color:hsl(var(--ag-accent))}.bg-accent-bg{background-color:hsl(var(--ag-accent-bg))}.bg-accent\/60{background-color:hsl(var(--ag-accent) / .6)}.bg-bg{background-color:hsl(var(--ag-bg))}.bg-black\/50{background-color:#00000080}.bg-border{background-color:hsl(var(--ag-border))}.bg-danger{background-color:hsl(var(--ag-danger))}.bg-danger-bg{background-color:hsl(var(--ag-danger-bg))}.bg-danger-bg\/30{background-color:hsl(var(--ag-danger-bg) / .3)}.bg-info-bg{background-color:hsl(var(--ag-info-bg))}.bg-success{background-color:hsl(var(--ag-success))}.bg-success-bg{background-color:hsl(var(--ag-success-bg))}.bg-surface{background-color:hsl(var(--ag-surface))}.bg-surface-2{background-color:hsl(var(--ag-surface-2))}.bg-surface-2\/50{background-color:hsl(var(--ag-surface-2) / .5)}.bg-text{background-color:hsl(var(--ag-text))}.bg-text-muted{background-color:hsl(var(--ag-text-muted))}.bg-transparent{background-color:transparent}.bg-warning{background-color:hsl(var(--ag-warning))}.bg-warning-bg{background-color:hsl(var(--ag-warning-bg))}.bg-warning-bg\/40{background-color:hsl(var(--ag-warning-bg) / .4)}.bg-warning\/5{background-color:hsl(var(--ag-warning) / .05)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.fill-current{fill:currentColor}.p-0{padding:0}.p-1{padding:4px}.p-12{padding:3rem}.p-2{padding:8px}.p-3{padding:12px}.p-4{padding:16px}.p-5{padding:20px}.p-6{padding:24px}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:4px;padding-right:4px}.px-1\.5{padding-left:6px;padding-right:6px}.px-2{padding-left:8px;padding-right:8px}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:12px;padding-right:12px}.px-4{padding-left:16px;padding-right:16px}.px-5{padding-left:20px;padding-right:20px}.py-0\.5{padding-top:2px;padding-bottom:2px}.py-1{padding-top:4px;padding-bottom:4px}.py-1\.5{padding-top:6px;padding-bottom:6px}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:8px;padding-bottom:8px}.py-3{padding-top:12px;padding-bottom:12px}.py-4{padding-top:16px;padding-bottom:16px}.py-6{padding-top:24px;padding-bottom:24px}.py-8{padding-top:48px;padding-bottom:48px}.pb-2{padding-bottom:8px}.pb-3{padding-bottom:12px}.pb-\[calc\(env\(safe-area-inset-bottom\)\+1\.5rem\)\]{padding-bottom:calc(env(safe-area-inset-bottom) + 1.5rem)}.pl-3{padding-left:12px}.pl-7{padding-left:32px}.pl-8{padding-left:48px}.pr-2{padding-right:8px}.pt-0{padding-top:0}.pt-2{padding-top:8px}.pt-3{padding-top:12px}.text-left{text-align:left}.text-center{text-align:center}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:30px;line-height:38px}.text-6xl{font-size:3.75rem;line-height:1}.text-\[0\.85em\]{font-size:.85em}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[15px\]{font-size:15px}.text-base{font-size:15px;line-height:22px}.text-lg{font-size:20px;line-height:28px}.text-md{font-size:16px;line-height:24px}.text-sm{font-size:13px;line-height:20px}.text-xl{font-size:24px;line-height:32px}.text-xs{font-size:12px;line-height:16px}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-accent{color:hsl(var(--ag-accent))}.text-accent-fg{color:hsl(var(--ag-accent-fg))}.text-bg{color:hsl(var(--ag-bg))}.text-danger{color:hsl(var(--ag-danger))}.text-info{color:hsl(var(--ag-info))}.text-success{color:hsl(var(--ag-success))}.text-text{color:hsl(var(--ag-text))}.text-text-dim{color:hsl(var(--ag-text-dim))}.text-text-muted{color:hsl(var(--ag-text-muted))}.text-warning{color:hsl(var(--ag-warning))}.underline{text-decoration-line:underline}.no-underline{text-decoration-line:none}.decoration-accent\/40{text-decoration-color:hsl(var(--ag-accent) / .4)}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.accent-accent{accent-color:hsl(var(--ag-accent))}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow{--tw-shadow: var(--ag-shadow-md);--tw-shadow-colored: var(--ag-shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: var(--ag-shadow-lg);--tw-shadow-colored: var(--ag-shadow-lg);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--ag-shadow-md);--tw-shadow-colored: var(--ag-shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--ag-shadow-sm);--tw-shadow-colored: var(--ag-shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.duration-200{animation-duration:.2s}.running{animation-play-state:running}.paused{animation-play-state:paused}.pt-safe{padding-top:calc(env(safe-area-inset-top) + .5rem)}.pb-safe{padding-bottom:calc(env(safe-area-inset-bottom) + .5rem)}.h-dvh{height:100vh;height:100dvh}.min-h-dvh{min-height:100vh;min-height:100dvh}.tap-target{min-height:32px;min-width:32px}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:13px;line-height:20px}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-text-muted::-moz-placeholder{color:hsl(var(--ag-text-muted))}.placeholder\:text-text-muted::placeholder{color:hsl(var(--ag-text-muted))}.last\:border-b-0:last-child{border-bottom-width:0px}.hover\:border-border-strong:hover{border-color:hsl(var(--ag-border-strong))}.hover\:bg-accent-hover:hover{background-color:hsl(var(--ag-accent-hover))}.hover\:bg-danger:hover{background-color:hsl(var(--ag-danger))}.hover\:bg-surface-2:hover{background-color:hsl(var(--ag-surface-2))}.hover\:text-accent:hover{color:hsl(var(--ag-accent))}.hover\:text-danger:hover{color:hsl(var(--ag-danger))}.hover\:text-text:hover{color:hsl(var(--ag-text))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:decoration-accent:hover{text-decoration-color:hsl(var(--ag-accent))}.focus\:border-accent:focus{border-color:hsl(var(--ag-accent))}.focus\:text-text:focus{color:hsl(var(--ag-text))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-accent:focus{--tw-ring-color: hsl(var(--ag-accent))}.focus\:ring-danger:focus{--tw-ring-color: hsl(var(--ag-danger))}.focus\:ring-offset-1:focus{--tw-ring-offset-width: 1px}.focus\:ring-offset-bg:focus{--tw-ring-offset-color: hsl(var(--ag-bg))}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-accent:focus-visible{--tw-ring-color: hsl(var(--ag-accent))}.focus-visible\:ring-offset-1:focus-visible{--tw-ring-offset-width: 1px}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-bg:focus-visible{--tw-ring-offset-color: hsl(var(--ag-bg))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-55:disabled{opacity:.55}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: 4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: 4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -4px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=selected\]\:bg-accent-bg[data-state=selected]{background-color:hsl(var(--ag-accent-bg))}.data-\[state\=active\]\:text-accent[data-state=active]{color:hsl(var(--ag-accent))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=delayed-open\]\:animate-in[data-state=delayed-open],.data-\[state\=open\]\:animate-in[data-state=open]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial}.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity: 0}.data-\[state\=delayed-open\]\:fade-in-0[data-state=delayed-open],.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity: 0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale: .95}.data-\[state\=delayed-open\]\:zoom-in-95[data-state=delayed-open],.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale: .95}.data-\[state\=closed\]\:slide-out-to-left-1\/2[data-state=closed]{--tw-exit-translate-x: -50%}.data-\[state\=closed\]\:slide-out-to-top-\[48\%\][data-state=closed]{--tw-exit-translate-y: -48%}.data-\[state\=open\]\:slide-in-from-left-1\/2[data-state=open]{--tw-enter-translate-x: -50%}.data-\[state\=open\]\:slide-in-from-top-\[48\%\][data-state=open]{--tw-enter-translate-y: -48%}.data-\[state\=active\]\:after\:absolute[data-state=active]:after{content:var(--tw-content);position:absolute}.data-\[state\=active\]\:after\:inset-x-0[data-state=active]:after{content:var(--tw-content);left:0;right:0}.data-\[state\=active\]\:after\:-bottom-px[data-state=active]:after{content:var(--tw-content);bottom:-1px}.data-\[state\=active\]\:after\:h-0\.5[data-state=active]:after{content:var(--tw-content);height:2px}.data-\[state\=active\]\:after\:rounded[data-state=active]:after{content:var(--tw-content);border-radius:6px}.data-\[state\=active\]\:after\:bg-accent[data-state=active]:after{content:var(--tw-content);background-color:hsl(var(--ag-accent))}@media (min-width: 640px){.sm\:not-sr-only{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:-mx-4{margin-left:-16px;margin-right:-16px}.sm\:ml-1{margin-left:4px}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:inline-flex{display:inline-flex}.sm\:hidden{display:none}.sm\:w-20{width:5rem}.sm\:w-28{width:7rem}.sm\:w-36{width:9rem}.sm\:w-40{width:10rem}.sm\:min-w-0{min-width:0px}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-\[75\%\]{max-width:75%}.sm\:max-w-lg{max-width:32rem}.sm\:flex-1{flex:1 1 0%}.sm\:shrink-0{flex-shrink:0}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-\[180px_1fr\]{grid-template-columns:180px 1fr}.sm\:grid-cols-\[180px_1fr_auto\]{grid-template-columns:180px 1fr auto}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:items-end{align-items:flex-end}.sm\:items-center{align-items:center}.sm\:justify-end{justify-content:flex-end}.sm\:gap-2{gap:8px}.sm\:gap-3{gap:12px}.sm\:p-4{padding:16px}.sm\:p-6{padding:24px}.sm\:px-4{padding-left:16px;padding-right:16px}.sm\:px-6{padding-left:24px;padding-right:24px}.sm\:py-2{padding-top:8px;padding-bottom:8px}.sm\:pt-0{padding-top:0}}@media (min-width: 768px){.md\:block{display:block}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-\[280px\,1fr\]{grid-template-columns:280px 1fr}}@media (min-width: 1024px){.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}.\[\&\:\:-webkit-scrollbar-thumb\]\:bg-border::-webkit-scrollbar-thumb{background-color:hsl(var(--ag-border))}.\[\&\:\:-webkit-scrollbar\]\:h-1::-webkit-scrollbar{height:4px}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>\*\:first-child\]\:mt-0>*:first-child{margin-top:0}.\[\&\>\*\:last-child\]\:mb-0>*:last-child{margin-bottom:0}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:16px;height:16px}.\[\&_svg\]\:h-6 svg{height:24px}.\[\&_svg\]\:w-6 svg{width:24px}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}.\[\&_tr\]\:border-border tr{border-color:hsl(var(--ag-border))}
@@ -1,4 +1,4 @@
1
- import{z as q,ac as b,ab as y,s as p,ae as j,V as e,B as u,c as f,a4 as m,L as B,I as F}from"./index-CGaI-i4K.js";import{e as x}from"./react-C9F3QeMB.js";import{u as L}from"./useQuery-ByZlZXlw.js";import{L as N}from"./loader-circle-BBIfyATA.js";import{R as M}from"./refresh-ccw-DpPWcwTg.js";import{T as P}from"./trash-2-DL2FAuYX.js";import{S as T}from"./save-beGooRNy.js";/**
1
+ import{n as q,a as b,b as y,o as p,u as j,j as e,k as u,B as f,l as m,L as B,I as F}from"./index-DXI13nSQ.js";import{r as x}from"./react-Cb2sDjhD.js";import{u as L}from"./useQuery-CEwGD94N.js";import{L as N}from"./loader-circle-BS5FFFg-.js";import{R as M}from"./refresh-ccw-BPKXoMZa.js";import{T as P}from"./trash-2-CTkSvnZX.js";import{S as T}from"./save-BXCmgeEj.js";/**
2
2
  * @license lucide-react v0.469.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -28,4 +28,4 @@ Write the body the agent should read when this skill applies.
28
28
  1. step one
29
29
  2. step two
30
30
  `;function se(){const{t:s}=j(["settings","common"]),t=K(),o=O(),[a,i]=x.useState(null);x.useEffect(()=>{!a&&t.data?.skills.length&&i(t.data.skills[0]?.name??null)},[a,t.data]);const l=t.data?.skills??[],d=t.data?.maxBodyChars??32e3;async function c(){try{const n=await o.mutateAsync();m.success(s("agimSkills.reloadedToast",{count:n.count}))}catch(n){m.error(n?.message??String(n))}}return e.jsxs("div",{className:"mx-auto flex max-w-6xl flex-col gap-4",children:[e.jsxs("header",{className:"flex items-center gap-3",children:[e.jsx(z,{className:"h-5 w-5 text-text-dim"}),e.jsx("h1",{className:"text-xl font-semibold",children:s("agimSkills.title")}),e.jsx(u,{variant:"info",children:l.length}),e.jsxs(f,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>void c(),disabled:o.isPending,children:[o.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(M,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("agimSkills.reload")})]}),e.jsx(H,{onCreate:n=>i(n)})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("agimSkills.subtitle")}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]",children:[e.jsx(U,{skills:l,selected:a,onSelect:i,loading:t.isLoading}),a?e.jsx(W,{name:a,maxBody:d,onDeleted:()=>i(null)},a):e.jsx("section",{className:"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim",children:s("agimSkills.selectHint")})]})]})}function U({skills:s,selected:t,onSelect:o,loading:a}){const{t:i}=j(["settings","common"]);return a?e.jsx("div",{className:"h-48 rounded-md bg-surface-2 animate-pulse"}):s.length===0?e.jsx("section",{className:"rounded-md border border-border bg-surface p-4 text-sm text-text-dim",children:i("agimSkills.emptyList")}):e.jsx("nav",{className:"rounded-md border border-border bg-surface",children:e.jsx("ul",{className:"divide-y divide-border",children:s.map(l=>{const d=t===l.name,c=l.available?l.always?e.jsx(u,{variant:"success",children:i("agimSkills.alwaysOn")}):null:e.jsx(u,{variant:"outline",title:l.unavailableReason,children:i("agimSkills.unavailable")}),n=l.source==="workspace"?e.jsx(u,{variant:"info",children:i("agimSkills.sourceWs")}):e.jsx(u,{variant:"outline",children:i("agimSkills.sourceBuiltin")});return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>o(l.name),className:"flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 "+(d?"bg-surface-2 font-semibold":""),children:[e.jsxs("span",{className:"flex w-full items-center gap-2 font-mono text-[12px]",children:[e.jsx("span",{className:"grow truncate",children:l.name}),n,c]}),e.jsx("span",{className:"line-clamp-2 text-[11px] text-text-dim",children:l.description})]})},l.name)})})})}function W({name:s,maxBody:t,onDeleted:o}){const{t:a}=j(["settings","common"]),i=Q(s),l=D(),d=I(),[c,n]=x.useState(""),[g,v]=x.useState("");x.useEffect(()=>{i.data&&g!==s&&(n(i.data.body),v(s))},[i.data,s,g]);const r=i.data?.meta,S=r?.source==="builtin",w=i.data?.body??"",C=x.useMemo(()=>c!==w,[c,w]);async function A(){try{await l.mutateAsync({name:s,body:c}),m.success(a("agimSkills.savedToast",{name:s}))}catch(h){m.error(h?.message??String(h))}}async function R(){if(!S&&confirm(a("agimSkills.deleteConfirm",{name:s})))try{await d.mutateAsync(s),m.success(a("agimSkills.deletedToast",{name:s})),o()}catch(h){m.error(h?.message??String(h))}}return i.isLoading?e.jsx("section",{className:"h-72 rounded-md bg-surface-2 animate-pulse"}):r?e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("header",{className:"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2",children:[e.jsx("span",{className:"font-mono text-sm font-semibold",children:r.name}),r.source==="workspace"?e.jsx(u,{variant:"info",children:a("agimSkills.sourceWorkspace")}):e.jsx(u,{variant:"outline",children:a("agimSkills.sourceBuiltinReadonly")}),r.always&&e.jsx(u,{variant:"success",children:a("agimSkills.alwaysOn")}),!r.available&&e.jsx(u,{variant:"outline",title:r.unavailableReason,children:a("agimSkills.unavailable")}),e.jsxs("span",{className:"ml-auto text-[11px] text-text-dim",children:[c.length," / ",t]})]}),e.jsx("textarea",{value:c,onChange:h=>n(h.target.value),disabled:S&&!C,spellCheck:!1,className:"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none"}),e.jsxs("div",{className:"text-[11px] text-text-dim",children:[a("agimSkills.pathLabel")," ",e.jsx("code",{children:r.dir})," ·",a("agimSkills.binsLabel")," ",e.jsx("code",{children:r.requiresBins.join(", ")||a("agimSkills.none")})," ·",a("agimSkills.envLabel")," ",e.jsx("code",{children:r.requiresEnv.join(", ")||a("agimSkills.none")})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[S&&e.jsx("span",{className:"text-[11px] text-text-dim",children:a("agimSkills.builtinShadowHint")}),e.jsx("span",{className:"ml-auto"}),!S&&e.jsxs(f,{variant:"ghost",size:"sm",onClick:()=>void R(),disabled:d.isPending,className:"text-danger hover:text-danger",children:[e.jsx(P,{className:"h-4 w-4"}),a("agimSkills.delete")]}),e.jsxs(f,{size:"sm",onClick:()=>void A(),disabled:l.isPending||!C,children:[l.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(T,{className:"h-4 w-4"}),a(S?"agimSkills.saveShadow":"agimSkills.save")]})]})]}):e.jsx("section",{className:"rounded-md border border-border bg-surface p-4 text-sm text-danger",children:a("agimSkills.notFound")})}function H({onCreate:s}){const{t}=j(["settings","common"]),o=_(),[a,i]=x.useState(!1),[l,d]=x.useState("");async function c(n){n.preventDefault();const g=l.trim();if(!g){m.error(t("agimSkills.nameRequired"));return}if(!/^[A-Za-z0-9._-]+$/.test(g)){m.error("safe chars only: [A-Za-z0-9._-]");return}const v=$.replace("name: my-skill",`name: ${g}`);try{const r=await o.mutateAsync({name:g,body:v});m.success(t("agimSkills.createdToast",{name:r.meta.name})),i(!1),d(""),s(r.meta.name)}catch(r){m.error(r?.message??String(r))}}return a?e.jsxs("form",{onSubmit:n=>void c(n),className:"flex items-center gap-1",children:[e.jsx(B,{className:"sr-only",children:t("agimSkills.newName")}),e.jsx(F,{autoFocus:!0,value:l,onChange:n=>d(n.target.value),placeholder:t("agimSkills.newNamePlaceholder"),className:"h-8 w-44 font-mono text-xs"}),e.jsx(f,{type:"submit",size:"sm",disabled:o.isPending,children:o.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):t("agimSkills.newCreate")}),e.jsx(f,{type:"button",variant:"ghost",size:"sm",onClick:()=>{i(!1),d("")},children:t("actions.cancel",{ns:"common"})})]}):e.jsxs(f,{size:"sm",onClick:()=>i(!0),children:[e.jsx(E,{className:"h-4 w-4"})," ",t("agimSkills.new")]})}export{se as default};
31
- //# sourceMappingURL=installed-DswmDcea.js.map
31
+ //# sourceMappingURL=installed-BtOgT0Ea.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installed-DswmDcea.js","sources":["../../node_modules/lucide-react/dist/esm/icons/book-open.js","../../node_modules/lucide-react/dist/esm/icons/file-plus-2.js","../../src/hooks/use-agim-skills.ts","../../src/routes/settings/agim-skills/installed.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst BookOpen = createLucideIcon(\"BookOpen\", [\n [\"path\", { d: \"M12 7v14\", key: \"1akyts\" }],\n [\n \"path\",\n {\n d: \"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\",\n key: \"ruj8y\"\n }\n ]\n]);\n\nexport { BookOpen as default };\n//# sourceMappingURL=book-open.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FilePlus2 = createLucideIcon(\"FilePlus2\", [\n [\"path\", { d: \"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\", key: \"1pf5j1\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M3 15h6\", key: \"4e2qda\" }],\n [\"path\", { d: \"M6 12v6\", key: \"1u72j0\" }]\n]);\n\nexport { FilePlus2 as default };\n//# sourceMappingURL=file-plus-2.js.map\n","/**\n * use-agim-skills — react-query wrappers for the agim SKILL.md\n * editor (`/api/agim-skills/*`).\n *\n * Distinct from the pre-existing `useSkills*` hooks against\n * `/api/skills` (which lists per-agent workspace CLI skills);\n * this set targets the in-process loader from\n * src/core/skills/loader.ts.\n */\n\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { client } from '@/lib/api/client'\n\nexport interface AgimSkillMeta {\n name: string\n description: string\n source: 'workspace' | 'builtin'\n always: boolean\n available: boolean\n unavailableReason?: string\n requiresBins: string[]\n requiresEnv: string[]\n dir: string\n}\n\nexport interface AgimSkillsListResponse {\n skills: AgimSkillMeta[]\n count: number\n maxBodyChars: number\n}\n\nexport interface AgimSkillDetailResponse {\n meta: AgimSkillMeta\n body: string\n}\n\nconst skillKeys = {\n all: ['agim-skills'] as const,\n list: ['agim-skills', 'list'] as const,\n one: (name: string) => ['agim-skills', 'one', name] as const,\n}\n\nexport function useAgimSkillsList() {\n return useQuery<AgimSkillsListResponse>({\n queryKey: skillKeys.list,\n queryFn: () => client.get<AgimSkillsListResponse>('/api/agim-skills'),\n })\n}\n\nexport function useAgimSkill(name: string | null) {\n return useQuery<AgimSkillDetailResponse>({\n queryKey: name ? skillKeys.one(name) : ['agim-skills', 'one', '__none__'],\n queryFn: () => client.get<AgimSkillDetailResponse>(`/api/agim-skills/${encodeURIComponent(name!)}`),\n enabled: !!name,\n })\n}\n\nexport function useAgimSkillCreate() {\n const qc = useQueryClient()\n return useMutation<{ meta: AgimSkillMeta }, Error, { name: string; body: string }>({\n mutationFn: (body) => client.post('/api/agim-skills', { body }),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillUpdate() {\n const qc = useQueryClient()\n return useMutation<{ meta: AgimSkillMeta }, Error, { name: string; body: string }>({\n mutationFn: ({ name, body }) => client.put(\n `/api/agim-skills/${encodeURIComponent(name)}`, { body: { body } },\n ),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillDelete() {\n const qc = useQueryClient()\n return useMutation<unknown, Error, string>({\n mutationFn: (name) => client.delete(`/api/agim-skills/${encodeURIComponent(name)}`),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillsRefresh() {\n const qc = useQueryClient()\n return useMutation<{ count: number }, Error, void>({\n mutationFn: () => client.post('/api/agim-skills/refresh'),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n","/**\n * /settings/agim-skills — manage the agim SKILL.md library\n * (P1 follow-up).\n *\n * Two-pane layout:\n * · Left: skill list (source + availability + always-on tags;\n * click to load body into the editor).\n * · Right: SKILL.md editor (textarea) + Save + Delete (workspace\n * skills only) + Create New + Refresh from disk.\n *\n * Builtin skills are read-only here — to override one, just create\n * a workspace skill with the same name; the loader shadows builtins\n * by name (see core/skills/loader.ts § discovery + shadowing).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n BookOpen, FilePlus2, Loader2, RefreshCcw, Save, Trash2,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useAgimSkillsList, useAgimSkill,\n useAgimSkillCreate, useAgimSkillUpdate, useAgimSkillDelete,\n useAgimSkillsRefresh,\n type AgimSkillMeta,\n} from '@/hooks/use-agim-skills'\n\nconst STARTER_TEMPLATE = `---\nname: my-skill\ndescription: One-line summary the LLM uses to decide whether to load this skill.\nalways: false\n---\n\n# My Skill\n\nWrite the body the agent should read when this skill applies.\n\n## When to use this skill\n\n- bullet 1\n- bullet 2\n\n## Steps\n\n1. step one\n2. step two\n`\n\nexport default function SettingsAgimSkillsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useAgimSkillsList()\n const refresh = useAgimSkillsRefresh()\n const [selected, setSelected] = useState<string | null>(null)\n\n // Pre-select the first skill once the list arrives.\n useEffect(() => {\n if (!selected && listQuery.data?.skills.length) {\n setSelected(listQuery.data.skills[0]?.name ?? null)\n }\n }, [selected, listQuery.data])\n\n const skills = listQuery.data?.skills ?? []\n const maxBody = listQuery.data?.maxBodyChars ?? 32_000\n\n async function onRefresh(): Promise<void> {\n try {\n const r = await refresh.mutateAsync()\n toast.success(t('agimSkills.reloadedToast', { count: r.count }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <BookOpen className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('agimSkills.title')}</h1>\n <Badge variant=\"info\">{skills.length}</Badge>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={refresh.isPending}\n >\n {refresh.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('agimSkills.reload')}</span>\n </Button>\n <NewSkillButton onCreate={(n) => setSelected(n)} />\n </header>\n <p className=\"text-sm text-text-dim\">{t('agimSkills.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]\">\n <SkillsList\n skills={skills}\n selected={selected}\n onSelect={setSelected}\n loading={listQuery.isLoading}\n />\n {selected ? (\n <SkillEditor\n key={selected}\n name={selected}\n maxBody={maxBody}\n onDeleted={() => setSelected(null)}\n />\n ) : (\n <section className=\"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim\">\n {t('agimSkills.selectHint')}\n </section>\n )}\n </div>\n </div>\n )\n}\n\n/* ─────────────── List pane ─────────────── */\n\nfunction SkillsList({\n skills, selected, onSelect, loading,\n}: { skills: AgimSkillMeta[]; selected: string | null; onSelect: (n: string) => void; loading: boolean }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n if (loading) return <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n if (skills.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-text-dim\">\n {t('agimSkills.emptyList')}\n </section>\n )\n }\n return (\n <nav className=\"rounded-md border border-border bg-surface\">\n <ul className=\"divide-y divide-border\">\n {skills.map((s) => {\n const isSelected = selected === s.name\n const flag = !s.available\n ? <Badge variant=\"outline\" title={s.unavailableReason}>{t('agimSkills.unavailable')}</Badge>\n : s.always\n ? <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>\n : null\n const src = s.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWs')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltin')}</Badge>\n return (\n <li key={s.name}>\n <button\n type=\"button\"\n onClick={() => onSelect(s.name)}\n className={\n 'flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 '\n + (isSelected ? 'bg-surface-2 font-semibold' : '')\n }\n >\n <span className=\"flex w-full items-center gap-2 font-mono text-[12px]\">\n <span className=\"grow truncate\">{s.name}</span>\n {src}\n {flag}\n </span>\n <span className=\"line-clamp-2 text-[11px] text-text-dim\">{s.description}</span>\n </button>\n </li>\n )\n })}\n </ul>\n </nav>\n )\n}\n\n/* ─────────────── Editor pane ─────────────── */\n\nfunction SkillEditor({\n name, maxBody, onDeleted,\n}: { name: string; maxBody: number; onDeleted: () => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const detail = useAgimSkill(name)\n const update = useAgimSkillUpdate()\n const remove = useAgimSkillDelete()\n\n const [draft, setDraft] = useState('')\n const [syncedFor, setSyncedFor] = useState<string>('')\n\n useEffect(() => {\n if (detail.data && syncedFor !== name) {\n setDraft(detail.data.body)\n setSyncedFor(name)\n }\n }, [detail.data, name, syncedFor])\n\n const meta = detail.data?.meta\n const isBuiltin = meta?.source === 'builtin'\n const initial = detail.data?.body ?? ''\n const isDirty = useMemo(() => draft !== initial, [draft, initial])\n\n async function onSave(): Promise<void> {\n try {\n await update.mutateAsync({ name, body: draft })\n toast.success(t('agimSkills.savedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onDelete(): Promise<void> {\n if (isBuiltin) return\n if (!confirm(t('agimSkills.deleteConfirm', { name }))) return\n try {\n await remove.mutateAsync(name)\n toast.success(t('agimSkills.deletedToast', { name }))\n onDeleted()\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (detail.isLoading) return <section className=\"h-72 rounded-md bg-surface-2 animate-pulse\" />\n if (!meta) return <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-danger\">{t('agimSkills.notFound')}</section>\n\n return (\n <section className=\"flex flex-col gap-2\">\n <header className=\"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2\">\n <span className=\"font-mono text-sm font-semibold\">{meta.name}</span>\n {meta.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWorkspace')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltinReadonly')}</Badge>}\n {meta.always && <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>}\n {!meta.available && <Badge variant=\"outline\" title={meta.unavailableReason}>{t('agimSkills.unavailable')}</Badge>}\n <span className=\"ml-auto text-[11px] text-text-dim\">{draft.length} / {maxBody}</span>\n </header>\n <textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n disabled={isBuiltin && !isDirty}\n spellCheck={false}\n className=\"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none\"\n />\n <div className=\"text-[11px] text-text-dim\">\n {t('agimSkills.pathLabel')} <code>{meta.dir}</code> ·\n {t('agimSkills.binsLabel')} <code>{meta.requiresBins.join(', ') || t('agimSkills.none')}</code> ·\n {t('agimSkills.envLabel')} <code>{meta.requiresEnv.join(', ') || t('agimSkills.none')}</code>\n </div>\n <div className=\"flex items-center gap-2\">\n {isBuiltin && (\n <span className=\"text-[11px] text-text-dim\">\n {t('agimSkills.builtinShadowHint')}\n </span>\n )}\n <span className=\"ml-auto\" />\n {!isBuiltin && (\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onDelete()}\n disabled={remove.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('agimSkills.delete')}\n </Button>\n )}\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={update.isPending || !isDirty}\n >\n {update.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isBuiltin ? t('agimSkills.saveShadow') : t('agimSkills.save')}\n </Button>\n </div>\n </section>\n )\n}\n\n/* ─────────────── New skill ─────────────── */\n\nfunction NewSkillButton({ onCreate }: { onCreate: (name: string) => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const create = useAgimSkillCreate()\n const [open, setOpen] = useState(false)\n const [name, setName] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n const trimmed = name.trim()\n if (!trimmed) { toast.error(t('agimSkills.nameRequired')); return }\n if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {\n toast.error('safe chars only: [A-Za-z0-9._-]'); return\n }\n const body = STARTER_TEMPLATE.replace('name: my-skill', `name: ${trimmed}`)\n try {\n const r = await create.mutateAsync({ name: trimmed, body })\n toast.success(t('agimSkills.createdToast', { name: r.meta.name }))\n setOpen(false)\n setName('')\n onCreate(r.meta.name)\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (!open) {\n return (\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <FilePlus2 className=\"h-4 w-4\" /> {t('agimSkills.new')}\n </Button>\n )\n }\n\n return (\n <form onSubmit={(e) => void onSubmit(e)} className=\"flex items-center gap-1\">\n <Label className=\"sr-only\">{t('agimSkills.newName')}</Label>\n <Input\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t('agimSkills.newNamePlaceholder')}\n className=\"h-8 w-44 font-mono text-xs\"\n />\n <Button type=\"submit\" size=\"sm\" disabled={create.isPending}>\n {create.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : t('agimSkills.newCreate')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { setOpen(false); setName('') }}>\n {t('actions.cancel', { ns: 'common' })}\n </Button>\n </form>\n )\n}\n"],"names":["BookOpen","createLucideIcon","FilePlus2","skillKeys","name","useAgimSkillsList","useQuery","client","useAgimSkill","useAgimSkillCreate","qc","useQueryClient","useMutation","body","useAgimSkillUpdate","useAgimSkillDelete","useAgimSkillsRefresh","STARTER_TEMPLATE","SettingsAgimSkillsRoute","t","useTranslation","listQuery","refresh","selected","setSelected","useState","useEffect","skills","maxBody","onRefresh","r","toast","err","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","NewSkillButton","SkillsList","SkillEditor","onSelect","loading","s","isSelected","flag","src","onDeleted","detail","update","remove","draft","setDraft","syncedFor","setSyncedFor","meta","isBuiltin","initial","isDirty","useMemo","onSave","onDelete","e","Trash2","Save","onCreate","create","open","setOpen","setName","onSubmit","trimmed","Label","Input"],"mappings":"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","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"installed-BtOgT0Ea.js","sources":["../../node_modules/lucide-react/dist/esm/icons/book-open.js","../../node_modules/lucide-react/dist/esm/icons/file-plus-2.js","../../src/hooks/use-agim-skills.ts","../../src/routes/settings/agim-skills/installed.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst BookOpen = createLucideIcon(\"BookOpen\", [\n [\"path\", { d: \"M12 7v14\", key: \"1akyts\" }],\n [\n \"path\",\n {\n d: \"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\",\n key: \"ruj8y\"\n }\n ]\n]);\n\nexport { BookOpen as default };\n//# sourceMappingURL=book-open.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FilePlus2 = createLucideIcon(\"FilePlus2\", [\n [\"path\", { d: \"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\", key: \"1pf5j1\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M3 15h6\", key: \"4e2qda\" }],\n [\"path\", { d: \"M6 12v6\", key: \"1u72j0\" }]\n]);\n\nexport { FilePlus2 as default };\n//# sourceMappingURL=file-plus-2.js.map\n","/**\n * use-agim-skills — react-query wrappers for the agim SKILL.md\n * editor (`/api/agim-skills/*`).\n *\n * Distinct from the pre-existing `useSkills*` hooks against\n * `/api/skills` (which lists per-agent workspace CLI skills);\n * this set targets the in-process loader from\n * src/core/skills/loader.ts.\n */\n\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { client } from '@/lib/api/client'\n\nexport interface AgimSkillMeta {\n name: string\n description: string\n source: 'workspace' | 'builtin'\n always: boolean\n available: boolean\n unavailableReason?: string\n requiresBins: string[]\n requiresEnv: string[]\n dir: string\n}\n\nexport interface AgimSkillsListResponse {\n skills: AgimSkillMeta[]\n count: number\n maxBodyChars: number\n}\n\nexport interface AgimSkillDetailResponse {\n meta: AgimSkillMeta\n body: string\n}\n\nconst skillKeys = {\n all: ['agim-skills'] as const,\n list: ['agim-skills', 'list'] as const,\n one: (name: string) => ['agim-skills', 'one', name] as const,\n}\n\nexport function useAgimSkillsList() {\n return useQuery<AgimSkillsListResponse>({\n queryKey: skillKeys.list,\n queryFn: () => client.get<AgimSkillsListResponse>('/api/agim-skills'),\n })\n}\n\nexport function useAgimSkill(name: string | null) {\n return useQuery<AgimSkillDetailResponse>({\n queryKey: name ? skillKeys.one(name) : ['agim-skills', 'one', '__none__'],\n queryFn: () => client.get<AgimSkillDetailResponse>(`/api/agim-skills/${encodeURIComponent(name!)}`),\n enabled: !!name,\n })\n}\n\nexport function useAgimSkillCreate() {\n const qc = useQueryClient()\n return useMutation<{ meta: AgimSkillMeta }, Error, { name: string; body: string }>({\n mutationFn: (body) => client.post('/api/agim-skills', { body }),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillUpdate() {\n const qc = useQueryClient()\n return useMutation<{ meta: AgimSkillMeta }, Error, { name: string; body: string }>({\n mutationFn: ({ name, body }) => client.put(\n `/api/agim-skills/${encodeURIComponent(name)}`, { body: { body } },\n ),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillDelete() {\n const qc = useQueryClient()\n return useMutation<unknown, Error, string>({\n mutationFn: (name) => client.delete(`/api/agim-skills/${encodeURIComponent(name)}`),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n\nexport function useAgimSkillsRefresh() {\n const qc = useQueryClient()\n return useMutation<{ count: number }, Error, void>({\n mutationFn: () => client.post('/api/agim-skills/refresh'),\n onSuccess: () => qc.invalidateQueries({ queryKey: skillKeys.all }),\n })\n}\n","/**\n * /settings/agim-skills — manage the agim SKILL.md library\n * (P1 follow-up).\n *\n * Two-pane layout:\n * · Left: skill list (source + availability + always-on tags;\n * click to load body into the editor).\n * · Right: SKILL.md editor (textarea) + Save + Delete (workspace\n * skills only) + Create New + Refresh from disk.\n *\n * Builtin skills are read-only here — to override one, just create\n * a workspace skill with the same name; the loader shadows builtins\n * by name (see core/skills/loader.ts § discovery + shadowing).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n BookOpen, FilePlus2, Loader2, RefreshCcw, Save, Trash2,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useAgimSkillsList, useAgimSkill,\n useAgimSkillCreate, useAgimSkillUpdate, useAgimSkillDelete,\n useAgimSkillsRefresh,\n type AgimSkillMeta,\n} from '@/hooks/use-agim-skills'\n\nconst STARTER_TEMPLATE = `---\nname: my-skill\ndescription: One-line summary the LLM uses to decide whether to load this skill.\nalways: false\n---\n\n# My Skill\n\nWrite the body the agent should read when this skill applies.\n\n## When to use this skill\n\n- bullet 1\n- bullet 2\n\n## Steps\n\n1. step one\n2. step two\n`\n\nexport default function SettingsAgimSkillsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useAgimSkillsList()\n const refresh = useAgimSkillsRefresh()\n const [selected, setSelected] = useState<string | null>(null)\n\n // Pre-select the first skill once the list arrives.\n useEffect(() => {\n if (!selected && listQuery.data?.skills.length) {\n setSelected(listQuery.data.skills[0]?.name ?? null)\n }\n }, [selected, listQuery.data])\n\n const skills = listQuery.data?.skills ?? []\n const maxBody = listQuery.data?.maxBodyChars ?? 32_000\n\n async function onRefresh(): Promise<void> {\n try {\n const r = await refresh.mutateAsync()\n toast.success(t('agimSkills.reloadedToast', { count: r.count }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <BookOpen className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('agimSkills.title')}</h1>\n <Badge variant=\"info\">{skills.length}</Badge>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={refresh.isPending}\n >\n {refresh.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('agimSkills.reload')}</span>\n </Button>\n <NewSkillButton onCreate={(n) => setSelected(n)} />\n </header>\n <p className=\"text-sm text-text-dim\">{t('agimSkills.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]\">\n <SkillsList\n skills={skills}\n selected={selected}\n onSelect={setSelected}\n loading={listQuery.isLoading}\n />\n {selected ? (\n <SkillEditor\n key={selected}\n name={selected}\n maxBody={maxBody}\n onDeleted={() => setSelected(null)}\n />\n ) : (\n <section className=\"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim\">\n {t('agimSkills.selectHint')}\n </section>\n )}\n </div>\n </div>\n )\n}\n\n/* ─────────────── List pane ─────────────── */\n\nfunction SkillsList({\n skills, selected, onSelect, loading,\n}: { skills: AgimSkillMeta[]; selected: string | null; onSelect: (n: string) => void; loading: boolean }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n if (loading) return <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n if (skills.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-text-dim\">\n {t('agimSkills.emptyList')}\n </section>\n )\n }\n return (\n <nav className=\"rounded-md border border-border bg-surface\">\n <ul className=\"divide-y divide-border\">\n {skills.map((s) => {\n const isSelected = selected === s.name\n const flag = !s.available\n ? <Badge variant=\"outline\" title={s.unavailableReason}>{t('agimSkills.unavailable')}</Badge>\n : s.always\n ? <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>\n : null\n const src = s.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWs')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltin')}</Badge>\n return (\n <li key={s.name}>\n <button\n type=\"button\"\n onClick={() => onSelect(s.name)}\n className={\n 'flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 '\n + (isSelected ? 'bg-surface-2 font-semibold' : '')\n }\n >\n <span className=\"flex w-full items-center gap-2 font-mono text-[12px]\">\n <span className=\"grow truncate\">{s.name}</span>\n {src}\n {flag}\n </span>\n <span className=\"line-clamp-2 text-[11px] text-text-dim\">{s.description}</span>\n </button>\n </li>\n )\n })}\n </ul>\n </nav>\n )\n}\n\n/* ─────────────── Editor pane ─────────────── */\n\nfunction SkillEditor({\n name, maxBody, onDeleted,\n}: { name: string; maxBody: number; onDeleted: () => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const detail = useAgimSkill(name)\n const update = useAgimSkillUpdate()\n const remove = useAgimSkillDelete()\n\n const [draft, setDraft] = useState('')\n const [syncedFor, setSyncedFor] = useState<string>('')\n\n useEffect(() => {\n if (detail.data && syncedFor !== name) {\n setDraft(detail.data.body)\n setSyncedFor(name)\n }\n }, [detail.data, name, syncedFor])\n\n const meta = detail.data?.meta\n const isBuiltin = meta?.source === 'builtin'\n const initial = detail.data?.body ?? ''\n const isDirty = useMemo(() => draft !== initial, [draft, initial])\n\n async function onSave(): Promise<void> {\n try {\n await update.mutateAsync({ name, body: draft })\n toast.success(t('agimSkills.savedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onDelete(): Promise<void> {\n if (isBuiltin) return\n if (!confirm(t('agimSkills.deleteConfirm', { name }))) return\n try {\n await remove.mutateAsync(name)\n toast.success(t('agimSkills.deletedToast', { name }))\n onDeleted()\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (detail.isLoading) return <section className=\"h-72 rounded-md bg-surface-2 animate-pulse\" />\n if (!meta) return <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-danger\">{t('agimSkills.notFound')}</section>\n\n return (\n <section className=\"flex flex-col gap-2\">\n <header className=\"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2\">\n <span className=\"font-mono text-sm font-semibold\">{meta.name}</span>\n {meta.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWorkspace')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltinReadonly')}</Badge>}\n {meta.always && <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>}\n {!meta.available && <Badge variant=\"outline\" title={meta.unavailableReason}>{t('agimSkills.unavailable')}</Badge>}\n <span className=\"ml-auto text-[11px] text-text-dim\">{draft.length} / {maxBody}</span>\n </header>\n <textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n disabled={isBuiltin && !isDirty}\n spellCheck={false}\n className=\"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none\"\n />\n <div className=\"text-[11px] text-text-dim\">\n {t('agimSkills.pathLabel')} <code>{meta.dir}</code> ·\n {t('agimSkills.binsLabel')} <code>{meta.requiresBins.join(', ') || t('agimSkills.none')}</code> ·\n {t('agimSkills.envLabel')} <code>{meta.requiresEnv.join(', ') || t('agimSkills.none')}</code>\n </div>\n <div className=\"flex items-center gap-2\">\n {isBuiltin && (\n <span className=\"text-[11px] text-text-dim\">\n {t('agimSkills.builtinShadowHint')}\n </span>\n )}\n <span className=\"ml-auto\" />\n {!isBuiltin && (\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onDelete()}\n disabled={remove.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('agimSkills.delete')}\n </Button>\n )}\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={update.isPending || !isDirty}\n >\n {update.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isBuiltin ? t('agimSkills.saveShadow') : t('agimSkills.save')}\n </Button>\n </div>\n </section>\n )\n}\n\n/* ─────────────── New skill ─────────────── */\n\nfunction NewSkillButton({ onCreate }: { onCreate: (name: string) => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const create = useAgimSkillCreate()\n const [open, setOpen] = useState(false)\n const [name, setName] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n const trimmed = name.trim()\n if (!trimmed) { toast.error(t('agimSkills.nameRequired')); return }\n if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {\n toast.error('safe chars only: [A-Za-z0-9._-]'); return\n }\n const body = STARTER_TEMPLATE.replace('name: my-skill', `name: ${trimmed}`)\n try {\n const r = await create.mutateAsync({ name: trimmed, body })\n toast.success(t('agimSkills.createdToast', { name: r.meta.name }))\n setOpen(false)\n setName('')\n onCreate(r.meta.name)\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (!open) {\n return (\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <FilePlus2 className=\"h-4 w-4\" /> {t('agimSkills.new')}\n </Button>\n )\n }\n\n return (\n <form onSubmit={(e) => void onSubmit(e)} className=\"flex items-center gap-1\">\n <Label className=\"sr-only\">{t('agimSkills.newName')}</Label>\n <Input\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t('agimSkills.newNamePlaceholder')}\n className=\"h-8 w-44 font-mono text-xs\"\n />\n <Button type=\"submit\" size=\"sm\" disabled={create.isPending}>\n {create.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : t('agimSkills.newCreate')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { setOpen(false); setName('') }}>\n {t('actions.cancel', { ns: 'common' })}\n </Button>\n </form>\n )\n}\n"],"names":["BookOpen","createLucideIcon","FilePlus2","skillKeys","name","useAgimSkillsList","useQuery","client","useAgimSkill","useAgimSkillCreate","qc","useQueryClient","useMutation","body","useAgimSkillUpdate","useAgimSkillDelete","useAgimSkillsRefresh","STARTER_TEMPLATE","SettingsAgimSkillsRoute","t","useTranslation","listQuery","refresh","selected","setSelected","useState","useEffect","skills","maxBody","onRefresh","r","toast","err","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","NewSkillButton","SkillsList","SkillEditor","onSelect","loading","s","isSelected","flag","src","onDeleted","detail","update","remove","draft","setDraft","syncedFor","setSyncedFor","meta","isBuiltin","initial","isDirty","useMemo","onSave","onDelete","e","Trash2","Save","onCreate","create","open","setOpen","setName","onSubmit","trimmed","Label","Input"],"mappings":"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","x_google_ignoreList":[0,1]}
@@ -0,0 +1,2 @@
1
+ import{a as D,b as q,d as M,u as I,e as V,j as t,c as A,B as P,S as K,f as Q,g as U,h as z,i as T,k as G,l as O,m as X}from"./index-DXI13nSQ.js";import{r as u}from"./react-Cb2sDjhD.js";import{D as Y}from"./data-table-BVcXWtPw.js";import{E as H}from"./empty-state-WHzNYVaT.js";import{S as W}from"./status-badge-DeESb2dc.js";import{P as Z}from"./pagination-dm3r6K_2.js";import{C as ee}from"./confirm-dialog-_BtUs6oW.js";import{u as te}from"./useQuery-CEwGD94N.js";import{u as se}from"./use-event-stream-DgGpGKop.js";import{L as ae}from"./loader-circle-BS5FFFg-.js";import{R as ne}from"./refresh-ccw-BPKXoMZa.js";import{C as ie}from"./circle-x-8dhkvHlT.js";import{B as oe}from"./briefcase-CZqK5oy3.js";import"./table-oUi0mGOn.js";import"./arrow-up-DtrvOH7Z.js";import"./arrow-down-OdSfpgG4.js";import"./chevron-left-BtuaBNRZ.js";import"./chevron-right-uDVVnuGu.js";import"./dialog-BVYFRXlI.js";import"./x-OHUicFfn.js";const N={all:["jobs"],list:e=>["jobs","list",e]};function re(e){return te({queryKey:N.list(e),queryFn:()=>M.listJobs(e)})}function le(){const e=D();return()=>e.invalidateQueries({queryKey:N.all})}function ce(){const e=D();return q({mutationFn:a=>M.batchCancelJobs(a),onSuccess:()=>e.invalidateQueries({queryKey:N.all})})}const de=[10,20,50,100],E=20,me=["pending","running","completed","delivered","failed","cancelled","interrupted","replaced","abandoned"],ue={connected:"text-success",connecting:"text-text-dim",reconnecting:"text-warning",closed:"text-text-muted"};function $e(){const{t:e}=I(["tasks","common"]),[a,i]=V(),d=le(),r=Math.max(1,Number(a.get("page"))||1),l=Number(a.get("per_page"))||E,m=a.get("status")??null,L=u.useMemo(()=>({limit:l,offset:(r-1)*l,...m?{status:m}:{}}),[r,l,m]),{data:S,isLoading:R,isFetching:C,refetch:$}=re(L),h=S?.jobs??[],n=S?.stats,v=se({job:()=>d()}),[p,w]=u.useState(new Set),[B,y]=u.useState(!1),_=ce();async function F(){const s=Array.from(p).map(Number).filter(Number.isFinite);if(s.length!==0)try{await _.mutateAsync({ids:s}),w(new Set),O.success(e("states.saved",{ns:"common"}))}catch(o){const{message:c}=X(o,e);throw O.error(c),o}}function f(s){const o=new URLSearchParams(a);for(const[c,j]of Object.entries(s))j==null||j===""?o.delete(c):o.set(c,j);Object.keys(s).some(c=>c!=="page")&&o.delete("page"),i(o,{replace:!1})}const g=n?n.pending+n.running+n.completed+n.failed+(n.delivered??0):void 0,k=g?Math.max(1,Math.ceil(g/l)):h.length===l?r+1:r,J=u.useMemo(()=>[{id:"id",header:e("jobs.col.id"),cell:s=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",s.id]}),headClassName:"w-16",hideOnMobile:!1},{id:"agent",header:e("jobs.col.agent"),cell:s=>t.jsx("span",{className:"font-medium",children:s.agent}),headClassName:"w-32"},{id:"prompt",header:e("jobs.col.prompt"),cell:s=>t.jsx("span",{className:"line-clamp-2 text-text-dim",children:s.prompt}),asCardTitle:!0},{id:"status",header:e("jobs.col.status"),cell:s=>t.jsx(W,{status:s.status,children:e(`jobs.status.${s.status}`,{defaultValue:s.status})}),headClassName:"w-32"},{id:"createdAt",header:e("jobs.col.createdAt"),cell:s=>t.jsx("span",{className:"text-text-dim",children:he(s.created_at)}),headClassName:"w-40",hideOnMobile:!0},{id:"duration",header:e("jobs.col.duration"),cell:s=>t.jsx("span",{className:"tabular-nums text-text-dim",children:pe(s.duration_ms)}),headClassName:"w-24",hideOnMobile:!0},{id:"cost",header:e("jobs.col.cost"),cell:s=>t.jsx("span",{className:"tabular-nums text-text-dim",children:s.cost!=null?`$${s.cost.toFixed(4)}`:"—"}),headClassName:"w-24",hideOnMobile:!0}],[e]),b=p.size;return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsxs("header",{className:"flex flex-col gap-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[t.jsx("h1",{className:"text-xl font-semibold",children:e("jobs.title")}),t.jsx("span",{className:A("text-xs font-medium tabular-nums",ue[v]),children:e(`jobs.live.${v}`)}),t.jsxs(P,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>$(),disabled:C,"aria-label":e("actions.refresh",{ns:"common"}),children:[C?t.jsx(ae,{className:"h-4 w-4 animate-spin"}):t.jsx(ne,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),t.jsx("p",{className:"text-sm text-text-dim",children:e("jobs.subtitle")})]}),n&&t.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[t.jsx(x,{label:e("jobs.stats.pending"),value:n.pending,tone:"info"}),t.jsx(x,{label:e("jobs.stats.running"),value:n.running,tone:"warning"}),t.jsx(x,{label:e("jobs.stats.completed"),value:n.completed,tone:"success"}),t.jsx(x,{label:e("jobs.stats.failed"),value:n.failed,tone:"danger"})]}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("label",{className:"text-sm text-text-dim",htmlFor:"status-filter",children:e("jobs.filter.status")}),t.jsxs(K,{value:m??"__any__",onValueChange:s=>f({status:s==="__any__"?null:s}),children:[t.jsx(Q,{id:"status-filter",className:"w-[160px]",children:t.jsx(U,{})}),t.jsxs(z,{children:[t.jsx(T,{value:"__any__",children:e("jobs.filter.statusAny")}),me.map(s=>t.jsx(T,{value:s,children:e(`jobs.status.${s}`,{defaultValue:s})},s))]})]})]}),b>0&&t.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[t.jsx(G,{variant:"secondary",children:e("jobs.batch.selected",{count:b})}),t.jsxs(P,{variant:"destructive",size:"sm",onClick:()=>y(!0),disabled:_.isPending,children:[t.jsx(ie,{className:"h-4 w-4"}),e("jobs.batch.cancel")]})]})]}),t.jsx(Y,{columns:J,rows:h,getRowId:s=>String(s.id),loading:R,selection:p,onSelectionChange:w,emptyState:t.jsx(H,{icon:t.jsx(oe,{}),title:e("jobs.empty.title"),description:e("jobs.empty.description")})}),(h.length>0||r>1)&&t.jsx(Z,{page:r,totalPages:k,totalRows:g,perPage:l,perPageOptions:de,onPageChange:s=>f({page:s===1?null:String(s)}),onPerPageChange:s=>f({per_page:s===E?null:String(s)})}),t.jsx(ee,{open:B,onOpenChange:y,title:e("jobs.batch.confirmCancel",{count:b}),description:e("jobs.batch.confirmCancelDesc"),intent:"danger",confirmLabel:e("jobs.batch.cancel"),onConfirm:F})]})}const xe={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function x({label:e,value:a,tone:i}){return t.jsxs("div",{className:A("rounded-md border bg-surface px-3 py-2",xe[i]),children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e}),t.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:a})]})}function he(e){try{const a=new Date(e);if(Number.isNaN(a.getTime()))return e;const i=new Date;return a.toDateString()===i.toDateString()?a.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit"}):a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}function pe(e){if(e==null)return"—";if(e<1e3)return`${e}ms`;const a=e/1e3;if(a<60)return`${a.toFixed(1)}s`;const i=Math.floor(a/60),d=Math.round(a-i*60);return`${i}m${d}s`}export{$e as default};
2
+ //# sourceMappingURL=jobs-DUoPbupO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-DWBDqKx-.js","sources":["../../src/hooks/use-jobs.ts","../../src/routes/tasks/jobs.tsx"],"sourcesContent":["/**\n * useJobs — react-query wrappers for the jobs domain.\n *\n * useJobs(query) — list with filter / pagination\n * useBatchCancelJobs() — bulk cancel mutation\n * useBatchRunJobs() — bulk re-run mutation\n *\n * Query keys: `['jobs', 'list', stableQuery]` so SSE invalidation\n * via useEventStream({ job: () => qc.invalidateQueries(['jobs']) })\n * clears every list view at once. The serialised query object is\n * stable across renders (react-query handles deep equality), so\n * keying on it directly is safe.\n *\n * Why hooks not raw `useQuery`: every route hits the same listJobs\n * endpoint with similar shapes; centralising the key + error toast\n * (caller-supplied) here keeps the route files focused on layout.\n */\n\nimport { useQueryClient, useMutation, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { BatchJobBody, ListJobsQuery, ListJobsResponse } from '@/types/api'\n\nexport const jobsKeys = {\n all: ['jobs'] as const,\n list: (q: ListJobsQuery) => ['jobs', 'list', q] as const,\n}\n\nexport function useJobs(query: ListJobsQuery) {\n return useQuery<ListJobsResponse>({\n queryKey: jobsKeys.list(query),\n queryFn: () => api.listJobs(query),\n })\n}\n\n/** Force-refresh every jobs list view. Call this from the SSE\n * `job` handler in route files. */\nexport function useInvalidateJobs() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: jobsKeys.all })\n}\n\nexport function useBatchCancelJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchCancelJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n\nexport function useBatchRunJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchRunJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n","/**\n * /tasks/jobs — the long-running agent invocations list.\n *\n * Composes every PR-8/9 primitive: DataTable + StatusBadge + Pagination\n * + ConfirmDialog + EmptyState + useEventStream. The route is a thin\n * presenter: data via useJobs (react-query), URL state via useSearchParams,\n * live refresh via the SSE `job` event invalidating the jobs query key.\n *\n * URL contract (all params optional):\n * ?page=2&per_page=20&status=running\n *\n * Why URL state rather than zustand:\n * * deep-link friendly (\"show me failed jobs page 3\")\n * * back/forward browser history navigates filter state\n * * no risk of a leftover filter showing wrong rows after route swap\n *\n * Mobile: the DataTable already swaps to a card view below md. The\n * stats strip wraps; the filter row stacks vertically.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Briefcase, Loader2, RefreshCcw, XCircle } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Pagination } from '@/components/common/pagination'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useJobs,\n useInvalidateJobs,\n useBatchCancelJobs,\n} from '@/hooks/use-jobs'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Job, JobStatus, ListJobsQuery } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst PER_PAGE_OPTIONS = [10, 20, 50, 100]\nconst DEFAULT_PER_PAGE = 20\n\nconst STATUS_OPTIONS: JobStatus[] = [\n 'pending',\n 'running',\n 'completed',\n 'delivered',\n 'failed',\n 'cancelled',\n 'interrupted',\n 'replaced',\n 'abandoned',\n]\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function JobsRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidateJobs = useInvalidateJobs()\n\n // ─── URL state ───\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n const status = (params.get('status') as JobStatus | null) ?? null\n\n const query: ListJobsQuery = useMemo(\n () => ({\n limit: perPage,\n offset: (page - 1) * perPage,\n ...(status ? { status } : {}),\n }),\n [page, perPage, status],\n )\n\n const { data, isLoading, isFetching, refetch } = useJobs(query)\n const jobs = data?.jobs ?? []\n const stats = data?.stats\n\n // ─── Live refresh via SSE ───\n const live = useEventStream({\n job: () => invalidateJobs(),\n })\n\n // ─── Selection ───\n const [selection, setSelection] = useState<Set<string>>(new Set())\n\n // ─── Confirm dialog ───\n const [confirmCancelOpen, setConfirmCancelOpen] = useState(false)\n const batchCancel = useBatchCancelJobs()\n\n async function onConfirmBatchCancel(): Promise<void> {\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n if (ids.length === 0) return\n try {\n await batchCancel.mutateAsync({ ids })\n setSelection(new Set())\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err // keep dialog open\n }\n }\n\n // ─── URL writers (single source of truth for filter state) ───\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null || v === '') next.delete(k)\n else next.set(k, v)\n }\n // Any filter change implicitly resets to page 1.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n // ─── Derived ───\n // The backend doesn't ship a true total-count field. Until it does\n // we infer pagination from the page itself: if a page returns a\n // full page, assume there's at least one more; otherwise this is\n // the last one. Stats give an exact total of pending/running but\n // not \"all kinds\", so the page label stays \"Page X of N\" with N\n // derived conservatively.\n const totalRows = stats\n ? (stats.pending + stats.running + stats.completed + stats.failed + (stats.delivered ?? 0))\n : undefined\n const totalPages = totalRows\n ? Math.max(1, Math.ceil(totalRows / perPage))\n : jobs.length === perPage ? page + 1 : page\n\n // ─── Columns ───\n const columns: DataTableColumn<Job>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('jobs.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n hideOnMobile: false,\n },\n {\n id: 'agent',\n header: t('jobs.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('jobs.col.prompt'),\n cell: (r) => (\n <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>\n ),\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('jobs.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`jobs.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'createdAt',\n header: t('jobs.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n {\n id: 'duration',\n header: t('jobs.col.duration'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">{formatDuration(r.duration_ms)}</span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'cost',\n header: t('jobs.col.cost'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">\n {r.cost != null ? `$${r.cost.toFixed(4)}` : '—'}\n </span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n {/* Page header */}\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('jobs.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('jobs.subtitle')}</p>\n </header>\n\n {/* Stats KPI strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('jobs.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('jobs.stats.running')} value={stats.running} tone=\"warning\" />\n <StatCard label={t('jobs.stats.completed')} value={stats.completed} tone=\"success\" />\n <StatCard label={t('jobs.stats.failed')} value={stats.failed} tone=\"danger\" />\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-dim\" htmlFor=\"status-filter\">\n {t('jobs.filter.status')}\n </label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('jobs.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`jobs.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Bulk action bar — appears when rows are selected. */}\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('jobs.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmCancelOpen(true)}\n disabled={batchCancel.isPending}\n >\n <XCircle className=\"h-4 w-4\" />\n {t('jobs.batch.cancel')}\n </Button>\n </div>\n )}\n </div>\n\n {/* Table */}\n <DataTable\n columns={columns}\n rows={jobs}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Briefcase />}\n title={t('jobs.empty.title')}\n description={t('jobs.empty.description')}\n />\n }\n />\n\n {/* Footer pagination */}\n {(jobs.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={totalRows}\n perPage={perPage}\n perPageOptions={PER_PAGE_OPTIONS}\n onPageChange={(p) => patchParams({ page: p === 1 ? null : String(p) })}\n onPerPageChange={(pp) => patchParams({ per_page: pp === DEFAULT_PER_PAGE ? null : String(pp) })}\n />\n )}\n\n <ConfirmDialog\n open={confirmCancelOpen}\n onOpenChange={setConfirmCancelOpen}\n title={t('jobs.batch.confirmCancel', { count: selectedCount })}\n description={t('jobs.batch.confirmCancelDesc')}\n intent=\"danger\"\n confirmLabel={t('jobs.batch.cancel')}\n onConfirm={onConfirmBatchCancel}\n />\n </div>\n )\n}\n\n// ─── Helpers ───\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n\nfunction formatDuration(ms: number | undefined): string {\n if (ms == null) return '—'\n if (ms < 1000) return `${ms}ms`\n const s = ms / 1000\n if (s < 60) return `${s.toFixed(1)}s`\n const m = Math.floor(s / 60)\n const rs = Math.round(s - m * 60)\n return `${m}m${rs}s`\n}\n"],"names":["jobsKeys","q","useJobs","query","useQuery","api","useInvalidateJobs","qc","useQueryClient","useBatchCancelJobs","useMutation","body","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","STATUS_OPTIONS","LIVE_STATUS_CLASS","JobsRoute","t","useTranslation","params","setParams","useSearchParams","invalidateJobs","page","perPage","status","useMemo","data","isLoading","isFetching","refetch","jobs","stats","live","useEventStream","selection","setSelection","useState","confirmCancelOpen","setConfirmCancelOpen","batchCancel","onConfirmBatchCancel","ids","toast","err","message","describeError","patchParams","patch","next","k","v","totalRows","totalPages","columns","r","jsxs","jsx","StatusBadge","formatTime","formatDuration","selectedCount","cn","Button","Loader2","RefreshCcw","StatCard","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Badge","XCircle","DataTable","EmptyState","Briefcase","Pagination","p","pp","ConfirmDialog","TONE_STYLES","label","value","tone","iso","d","now","ms","s","m","rs"],"mappings":"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"}
1
+ {"version":3,"file":"jobs-DUoPbupO.js","sources":["../../src/hooks/use-jobs.ts","../../src/routes/tasks/jobs.tsx"],"sourcesContent":["/**\n * useJobs — react-query wrappers for the jobs domain.\n *\n * useJobs(query) — list with filter / pagination\n * useBatchCancelJobs() — bulk cancel mutation\n * useBatchRunJobs() — bulk re-run mutation\n *\n * Query keys: `['jobs', 'list', stableQuery]` so SSE invalidation\n * via useEventStream({ job: () => qc.invalidateQueries(['jobs']) })\n * clears every list view at once. The serialised query object is\n * stable across renders (react-query handles deep equality), so\n * keying on it directly is safe.\n *\n * Why hooks not raw `useQuery`: every route hits the same listJobs\n * endpoint with similar shapes; centralising the key + error toast\n * (caller-supplied) here keeps the route files focused on layout.\n */\n\nimport { useQueryClient, useMutation, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { BatchJobBody, ListJobsQuery, ListJobsResponse } from '@/types/api'\n\nexport const jobsKeys = {\n all: ['jobs'] as const,\n list: (q: ListJobsQuery) => ['jobs', 'list', q] as const,\n}\n\nexport function useJobs(query: ListJobsQuery) {\n return useQuery<ListJobsResponse>({\n queryKey: jobsKeys.list(query),\n queryFn: () => api.listJobs(query),\n })\n}\n\n/** Force-refresh every jobs list view. Call this from the SSE\n * `job` handler in route files. */\nexport function useInvalidateJobs() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: jobsKeys.all })\n}\n\nexport function useBatchCancelJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchCancelJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n\nexport function useBatchRunJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchRunJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n","/**\n * /tasks/jobs — the long-running agent invocations list.\n *\n * Composes every PR-8/9 primitive: DataTable + StatusBadge + Pagination\n * + ConfirmDialog + EmptyState + useEventStream. The route is a thin\n * presenter: data via useJobs (react-query), URL state via useSearchParams,\n * live refresh via the SSE `job` event invalidating the jobs query key.\n *\n * URL contract (all params optional):\n * ?page=2&per_page=20&status=running\n *\n * Why URL state rather than zustand:\n * * deep-link friendly (\"show me failed jobs page 3\")\n * * back/forward browser history navigates filter state\n * * no risk of a leftover filter showing wrong rows after route swap\n *\n * Mobile: the DataTable already swaps to a card view below md. The\n * stats strip wraps; the filter row stacks vertically.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Briefcase, Loader2, RefreshCcw, XCircle } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Pagination } from '@/components/common/pagination'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useJobs,\n useInvalidateJobs,\n useBatchCancelJobs,\n} from '@/hooks/use-jobs'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Job, JobStatus, ListJobsQuery } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst PER_PAGE_OPTIONS = [10, 20, 50, 100]\nconst DEFAULT_PER_PAGE = 20\n\nconst STATUS_OPTIONS: JobStatus[] = [\n 'pending',\n 'running',\n 'completed',\n 'delivered',\n 'failed',\n 'cancelled',\n 'interrupted',\n 'replaced',\n 'abandoned',\n]\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function JobsRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidateJobs = useInvalidateJobs()\n\n // ─── URL state ───\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n const status = (params.get('status') as JobStatus | null) ?? null\n\n const query: ListJobsQuery = useMemo(\n () => ({\n limit: perPage,\n offset: (page - 1) * perPage,\n ...(status ? { status } : {}),\n }),\n [page, perPage, status],\n )\n\n const { data, isLoading, isFetching, refetch } = useJobs(query)\n const jobs = data?.jobs ?? []\n const stats = data?.stats\n\n // ─── Live refresh via SSE ───\n const live = useEventStream({\n job: () => invalidateJobs(),\n })\n\n // ─── Selection ───\n const [selection, setSelection] = useState<Set<string>>(new Set())\n\n // ─── Confirm dialog ───\n const [confirmCancelOpen, setConfirmCancelOpen] = useState(false)\n const batchCancel = useBatchCancelJobs()\n\n async function onConfirmBatchCancel(): Promise<void> {\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n if (ids.length === 0) return\n try {\n await batchCancel.mutateAsync({ ids })\n setSelection(new Set())\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err // keep dialog open\n }\n }\n\n // ─── URL writers (single source of truth for filter state) ───\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null || v === '') next.delete(k)\n else next.set(k, v)\n }\n // Any filter change implicitly resets to page 1.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n // ─── Derived ───\n // The backend doesn't ship a true total-count field. Until it does\n // we infer pagination from the page itself: if a page returns a\n // full page, assume there's at least one more; otherwise this is\n // the last one. Stats give an exact total of pending/running but\n // not \"all kinds\", so the page label stays \"Page X of N\" with N\n // derived conservatively.\n const totalRows = stats\n ? (stats.pending + stats.running + stats.completed + stats.failed + (stats.delivered ?? 0))\n : undefined\n const totalPages = totalRows\n ? Math.max(1, Math.ceil(totalRows / perPage))\n : jobs.length === perPage ? page + 1 : page\n\n // ─── Columns ───\n const columns: DataTableColumn<Job>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('jobs.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n hideOnMobile: false,\n },\n {\n id: 'agent',\n header: t('jobs.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('jobs.col.prompt'),\n cell: (r) => (\n <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>\n ),\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('jobs.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`jobs.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'createdAt',\n header: t('jobs.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n {\n id: 'duration',\n header: t('jobs.col.duration'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">{formatDuration(r.duration_ms)}</span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'cost',\n header: t('jobs.col.cost'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">\n {r.cost != null ? `$${r.cost.toFixed(4)}` : '—'}\n </span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n {/* Page header */}\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('jobs.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('jobs.subtitle')}</p>\n </header>\n\n {/* Stats KPI strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('jobs.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('jobs.stats.running')} value={stats.running} tone=\"warning\" />\n <StatCard label={t('jobs.stats.completed')} value={stats.completed} tone=\"success\" />\n <StatCard label={t('jobs.stats.failed')} value={stats.failed} tone=\"danger\" />\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-dim\" htmlFor=\"status-filter\">\n {t('jobs.filter.status')}\n </label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('jobs.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`jobs.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Bulk action bar — appears when rows are selected. */}\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('jobs.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmCancelOpen(true)}\n disabled={batchCancel.isPending}\n >\n <XCircle className=\"h-4 w-4\" />\n {t('jobs.batch.cancel')}\n </Button>\n </div>\n )}\n </div>\n\n {/* Table */}\n <DataTable\n columns={columns}\n rows={jobs}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Briefcase />}\n title={t('jobs.empty.title')}\n description={t('jobs.empty.description')}\n />\n }\n />\n\n {/* Footer pagination */}\n {(jobs.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={totalRows}\n perPage={perPage}\n perPageOptions={PER_PAGE_OPTIONS}\n onPageChange={(p) => patchParams({ page: p === 1 ? null : String(p) })}\n onPerPageChange={(pp) => patchParams({ per_page: pp === DEFAULT_PER_PAGE ? null : String(pp) })}\n />\n )}\n\n <ConfirmDialog\n open={confirmCancelOpen}\n onOpenChange={setConfirmCancelOpen}\n title={t('jobs.batch.confirmCancel', { count: selectedCount })}\n description={t('jobs.batch.confirmCancelDesc')}\n intent=\"danger\"\n confirmLabel={t('jobs.batch.cancel')}\n onConfirm={onConfirmBatchCancel}\n />\n </div>\n )\n}\n\n// ─── Helpers ───\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n\nfunction formatDuration(ms: number | undefined): string {\n if (ms == null) return '—'\n if (ms < 1000) return `${ms}ms`\n const s = ms / 1000\n if (s < 60) return `${s.toFixed(1)}s`\n const m = Math.floor(s / 60)\n const rs = Math.round(s - m * 60)\n return `${m}m${rs}s`\n}\n"],"names":["jobsKeys","q","useJobs","query","useQuery","api","useInvalidateJobs","qc","useQueryClient","useBatchCancelJobs","useMutation","body","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","STATUS_OPTIONS","LIVE_STATUS_CLASS","JobsRoute","t","useTranslation","params","setParams","useSearchParams","invalidateJobs","page","perPage","status","useMemo","data","isLoading","isFetching","refetch","jobs","stats","live","useEventStream","selection","setSelection","useState","confirmCancelOpen","setConfirmCancelOpen","batchCancel","onConfirmBatchCancel","ids","toast","err","message","describeError","patchParams","patch","next","k","v","totalRows","totalPages","columns","r","jsxs","jsx","StatusBadge","formatTime","formatDuration","selectedCount","cn","Button","Loader2","RefreshCcw","StatCard","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Badge","XCircle","DataTable","EmptyState","Briefcase","Pagination","p","pp","ConfirmDialog","TONE_STYLES","label","value","tone","iso","d","now","ms","s","m","rs"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{u as a,j as e,T as i,N as r,c as n,O as m}from"./index-DXI13nSQ.js";import"./react-Cb2sDjhD.js";const u=[{to:"messengers",i18nKey:"tabs.messengers",mounted:!0},{to:"email",i18nKey:"tabs.email",mounted:!0},{to:"viewer",i18nKey:"tabs.viewer",mounted:!0},{to:"agents",i18nKey:"tabs.agents",mounted:!0},{to:"llm",i18nKey:"tabs.llm",mounted:!0},{to:"mcp",i18nKey:"tabs.mcp",mounted:!0},{to:"native-agent",i18nKey:"tabs.nativeAgent",mounted:!0},{to:"search",i18nKey:"tabs.search",mounted:!0},{to:"mobile",i18nKey:"tabs.mobile",mounted:!0},{to:"agim-skills",i18nKey:"tabs.agimSkills",mounted:!0},{to:"policy",i18nKey:"tabs.policy",mounted:!0},{to:"security",i18nKey:"tabs.security",mounted:!0},{to:"workspaces",i18nKey:"tabs.workspaces",mounted:!0},{to:"admins",i18nKey:"tabs.admins",mounted:!0},{to:"service",i18nKey:"tabs.service",mounted:!0}];function d(){const{t:s}=a("settings");return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(i,{}),e.jsx("nav",{className:n("sticky top-0 z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":s("pageTitle"),children:u.filter(t=>t.mounted).map(t=>e.jsx(r,{to:t.to,className:({isActive:o})=>n("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",o?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:s(t.i18nKey)},t.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(m,{})})]})}export{d as default};
2
+ //# sourceMappingURL=layout-BpS7td-S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-BpS7td-S.js","sources":["../../src/routes/settings/layout.tsx"],"sourcesContent":["/**\n * /settings — layout shell with sub-tab nav (environment / service).\n *\n * Workspaces / WeChat QR / Admin allowlist will land as additional\n * sub-tabs in PR-19b/c. The `mounted` flag gates their nav links.\n */\n\nimport { NavLink, Outlet } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'messengers', i18nKey: 'tabs.messengers', mounted: true },\n { to: 'email', i18nKey: 'tabs.email', mounted: true },\n { to: 'viewer', i18nKey: 'tabs.viewer', mounted: true },\n { to: 'agents', i18nKey: 'tabs.agents', mounted: true },\n // Stage 6 — native LLM stack. Three tabs in a logical group:\n // LLM backends (config + secrets) -> MCP external servers ->\n // native agent / evaluator / heartbeat behavior knobs.\n { to: 'llm', i18nKey: 'tabs.llm', mounted: true },\n { to: 'mcp', i18nKey: 'tabs.mcp', mounted: true },\n { to: 'native-agent', i18nKey: 'tabs.nativeAgent', mounted: true },\n // v1.2.126 — web_search provider chain + per-provider keys.\n { to: 'search', i18nKey: 'tabs.search', mounted: true },\n // v1.2.129 — mobile QR generator (open /m/chat from a phone).\n { to: 'mobile', i18nKey: 'tabs.mobile', mounted: true },\n // P1 follow-up — agim SKILL.md editor.\n { to: 'agim-skills', i18nKey: 'tabs.agimSkills', mounted: true },\n { to: 'policy', i18nKey: 'tabs.policy', mounted: true },\n { to: 'security', i18nKey: 'tabs.security', mounted: true },\n { to: 'workspaces', i18nKey: 'tabs.workspaces', mounted: true },\n { to: 'admins', i18nKey: 'tabs.admins', mounted: true },\n // R13 follow-up — /settings/env catch-all editor removed; raw env-var\n // editing belongs in `~/.agim/env` on the host, not in a web form.\n { to: 'service', i18nKey: 'tabs.service', mounted: true },\n]\n\nexport default function SettingsLayout(): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","SettingsLayout","t","useTranslation","jsxs","jsx","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"uGAkBA,MAAMA,EAAqB,CACzB,CAAE,GAAI,aAAgB,QAAS,kBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,QAAgB,QAAS,aAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAI7D,CAAE,GAAI,MAAgB,QAAS,WAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,MAAgB,QAAS,WAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,eAAgB,QAAS,mBAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,cAAgB,QAAS,kBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,WAAgB,QAAS,gBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,aAAgB,QAAS,kBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAG7D,CAAE,GAAI,UAAgB,QAAS,eAAqB,QAAS,EAAA,CAC/D,EAEA,SAAwBC,GAA8B,CACpD,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,UAAU,EACvC,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,EAERD,EAAAA,IAAC,MAAA,CACC,UAAWE,EACT,oBACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAYL,EAAE,WAAW,EAExB,SAAAF,EAAS,OAAQQ,GAAQA,EAAI,OAAO,EAAE,IAAKA,GAC1CH,EAAAA,IAACI,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAAR,EAAEM,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAH,EAAAA,IAACM,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
@@ -0,0 +1,2 @@
1
+ import{u as m,j as e,S as d,f as u,g as p,h,i,e as f,T as b,N as j,c as x,O as g}from"./index-DXI13nSQ.js";import{u as y}from"./use-memory-CbTYEBTc.js";import"./react-Cb2sDjhD.js";import"./useQuery-CEwGD94N.js";function _({value:c,onChange:n,className:l}){const{t:r}=m("memory"),{data:o,isLoading:s}=y(),a=o?.users??[];return e.jsxs(d,{value:c||"__placeholder__",onValueChange:t=>n(t==="__placeholder__"?"":t),disabled:s||a.length===0,children:[e.jsx(u,{className:l??"h-9 w-72 max-w-full",children:e.jsx(p,{placeholder:r("userPicker.placeholder")})}),e.jsxs(h,{children:[e.jsx(i,{value:"__placeholder__",disabled:!0,children:r("userPicker.placeholder")}),a.map(t=>e.jsx(i,{value:t.user_key,children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs",children:t.user_key}),e.jsx("span",{className:"text-text-dim text-xs",children:r("userPicker.factsLabel",{count:t.fact_count})}),t.has_persona&&e.jsxs("span",{className:"text-accent text-xs",children:["·",r("userPicker.personaTag"),"·"]})]})},t.user_key))]})]})}const v=[{to:"facts",i18nKey:"tabs.facts",mounted:!0},{to:"persona",i18nKey:"tabs.persona",mounted:!0},{to:"vector",i18nKey:"tabs.vector",mounted:!0}];function T(){const{t:c}=m("memory"),[n,l]=f(),r=n.get("user")??"";function o(s){const a=new URLSearchParams(n);s?a.set("user",s):a.delete("user"),l(a,{replace:!0})}return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(b,{}),e.jsx("div",{className:"border-b border-border bg-surface px-3 sm:px-4 py-2",children:e.jsxs("div",{className:"mx-auto flex max-w-7xl items-center gap-3",children:[e.jsx("span",{className:"text-sm text-text-dim shrink-0",children:c("userPicker.label")}),e.jsx(_,{value:r,onChange:o})]})}),e.jsx("nav",{className:x("sticky top-0 z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":c("pageTitle"),children:v.filter(s=>s.mounted).map(s=>e.jsx(j,{to:s.to,className:({isActive:a})=>x("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",a?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:c(s.i18nKey)},s.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(g,{})})]})}export{T as default};
2
+ //# sourceMappingURL=layout-C1EVvCs8.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout-D7gNMUDZ.js","sources":["../../src/components/memory/user-picker.tsx","../../src/routes/memory/layout.tsx"],"sourcesContent":["/**\n * MemoryUserPicker — Select for the user_key the /memory route\n * targets. Sources the option list from useMemoryUsers, shows the\n * per-user fact_count + persona-presence as inline metadata so the\n * operator can tell which users are interesting at a glance.\n *\n * Loading: while users fetch, the trigger shows the placeholder so\n * the page doesn't jump.\n *\n * Empty bank: no users → the dropdown is disabled with a tooltip\n * explaining there's nothing to pick. Avoids a confusing \"no items\"\n * dropdown state.\n */\n\nimport { useTranslation } from 'react-i18next'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useMemoryUsers } from '@/hooks/use-memory'\n\nexport interface MemoryUserPickerProps {\n value: string\n onChange: (next: string) => void\n className?: string\n}\n\nexport function MemoryUserPicker({ value, onChange, className }: MemoryUserPickerProps): JSX.Element {\n const { t } = useTranslation('memory')\n const { data, isLoading } = useMemoryUsers()\n const users = data?.users ?? []\n\n return (\n <Select\n value={value || '__placeholder__'}\n onValueChange={(v) => onChange(v === '__placeholder__' ? '' : v)}\n disabled={isLoading || users.length === 0}\n >\n <SelectTrigger className={className ?? 'h-9 w-72 max-w-full'}>\n <SelectValue placeholder={t('userPicker.placeholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__placeholder__\" disabled>\n {t('userPicker.placeholder')}\n </SelectItem>\n {users.map((u) => (\n <SelectItem key={u.user_key} value={u.user_key}>\n <span className=\"flex items-center gap-2\">\n <span className=\"font-mono text-xs\">{u.user_key}</span>\n <span className=\"text-text-dim text-xs\">\n {t('userPicker.factsLabel', { count: u.fact_count })}\n </span>\n {u.has_persona && (\n <span className=\"text-accent text-xs\">·{t('userPicker.personaTag')}·</span>\n )}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n}\n","/**\n * /memory — layout shell shared by every sub-tab.\n *\n * Memory is partitioned per user_key. The picker lives in the\n * layout so it's the first thing the operator sees and stays put\n * across sub-tabs (facts / persona / vector / skills). The chosen\n * user is held in URL state (?user=) so sub-tabs read it via\n * useSearchParams.\n *\n * Sub-tabs: facts / persona / vector. Skills used to live here too\n * but was promoted to its own top-level /skills tab in 2026-05 — the\n * router keeps a redirect for old /memory/skills bookmarks.\n */\n\nimport { NavLink, Outlet, useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { MemoryUserPicker } from '@/components/memory/user-picker'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'facts', i18nKey: 'tabs.facts', mounted: true },\n { to: 'persona', i18nKey: 'tabs.persona', mounted: true },\n { to: 'vector', i18nKey: 'tabs.vector', mounted: true },\n // 'skills' was here; promoted to top-level /skills in 2026-05.\n]\n\nexport default function MemoryLayout(): JSX.Element {\n const { t } = useTranslation('memory')\n const [params, setParams] = useSearchParams()\n const userKey = params.get('user') ?? ''\n\n function setUserKey(next: string): void {\n const p = new URLSearchParams(params)\n if (!next) p.delete('user')\n else p.set('user', next)\n setParams(p, { replace: true })\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n {/* User picker — the primary navigation control for this page */}\n <div className=\"border-b border-border bg-surface px-3 sm:px-4 py-2\">\n <div className=\"mx-auto flex max-w-7xl items-center gap-3\">\n <span className=\"text-sm text-text-dim shrink-0\">{t('userPicker.label')}</span>\n <MemoryUserPicker value={userKey} onChange={setUserKey} />\n </div>\n </div>\n\n {/* Sub-tab nav */}\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["MemoryUserPicker","value","onChange","className","t","useTranslation","data","isLoading","useMemoryUsers","users","jsxs","Select","v","jsx","SelectTrigger","SelectValue","SelectContent","SelectItem","u","SUB_TABS","MemoryLayout","params","setParams","useSearchParams","userKey","setUserKey","next","p","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"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"}
1
+ {"version":3,"file":"layout-C1EVvCs8.js","sources":["../../src/components/memory/user-picker.tsx","../../src/routes/memory/layout.tsx"],"sourcesContent":["/**\n * MemoryUserPicker — Select for the user_key the /memory route\n * targets. Sources the option list from useMemoryUsers, shows the\n * per-user fact_count + persona-presence as inline metadata so the\n * operator can tell which users are interesting at a glance.\n *\n * Loading: while users fetch, the trigger shows the placeholder so\n * the page doesn't jump.\n *\n * Empty bank: no users → the dropdown is disabled with a tooltip\n * explaining there's nothing to pick. Avoids a confusing \"no items\"\n * dropdown state.\n */\n\nimport { useTranslation } from 'react-i18next'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useMemoryUsers } from '@/hooks/use-memory'\n\nexport interface MemoryUserPickerProps {\n value: string\n onChange: (next: string) => void\n className?: string\n}\n\nexport function MemoryUserPicker({ value, onChange, className }: MemoryUserPickerProps): JSX.Element {\n const { t } = useTranslation('memory')\n const { data, isLoading } = useMemoryUsers()\n const users = data?.users ?? []\n\n return (\n <Select\n value={value || '__placeholder__'}\n onValueChange={(v) => onChange(v === '__placeholder__' ? '' : v)}\n disabled={isLoading || users.length === 0}\n >\n <SelectTrigger className={className ?? 'h-9 w-72 max-w-full'}>\n <SelectValue placeholder={t('userPicker.placeholder')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__placeholder__\" disabled>\n {t('userPicker.placeholder')}\n </SelectItem>\n {users.map((u) => (\n <SelectItem key={u.user_key} value={u.user_key}>\n <span className=\"flex items-center gap-2\">\n <span className=\"font-mono text-xs\">{u.user_key}</span>\n <span className=\"text-text-dim text-xs\">\n {t('userPicker.factsLabel', { count: u.fact_count })}\n </span>\n {u.has_persona && (\n <span className=\"text-accent text-xs\">·{t('userPicker.personaTag')}·</span>\n )}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n}\n","/**\n * /memory — layout shell shared by every sub-tab.\n *\n * Memory is partitioned per user_key. The picker lives in the\n * layout so it's the first thing the operator sees and stays put\n * across sub-tabs (facts / persona / vector / skills). The chosen\n * user is held in URL state (?user=) so sub-tabs read it via\n * useSearchParams.\n *\n * Sub-tabs: facts / persona / vector. Skills used to live here too\n * but was promoted to its own top-level /skills tab in 2026-05 — the\n * router keeps a redirect for old /memory/skills bookmarks.\n */\n\nimport { NavLink, Outlet, useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { MemoryUserPicker } from '@/components/memory/user-picker'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'facts', i18nKey: 'tabs.facts', mounted: true },\n { to: 'persona', i18nKey: 'tabs.persona', mounted: true },\n { to: 'vector', i18nKey: 'tabs.vector', mounted: true },\n // 'skills' was here; promoted to top-level /skills in 2026-05.\n]\n\nexport default function MemoryLayout(): JSX.Element {\n const { t } = useTranslation('memory')\n const [params, setParams] = useSearchParams()\n const userKey = params.get('user') ?? ''\n\n function setUserKey(next: string): void {\n const p = new URLSearchParams(params)\n if (!next) p.delete('user')\n else p.set('user', next)\n setParams(p, { replace: true })\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n {/* User picker — the primary navigation control for this page */}\n <div className=\"border-b border-border bg-surface px-3 sm:px-4 py-2\">\n <div className=\"mx-auto flex max-w-7xl items-center gap-3\">\n <span className=\"text-sm text-text-dim shrink-0\">{t('userPicker.label')}</span>\n <MemoryUserPicker value={userKey} onChange={setUserKey} />\n </div>\n </div>\n\n {/* Sub-tab nav */}\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["MemoryUserPicker","value","onChange","className","t","useTranslation","data","isLoading","useMemoryUsers","users","jsxs","Select","v","jsx","SelectTrigger","SelectValue","SelectContent","SelectItem","u","SUB_TABS","MemoryLayout","params","setParams","useSearchParams","userKey","setUserKey","next","p","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{u as c,e as x,j as e,T as d,S as m,f as p,g as u,h,i as b,N as g,c as n,O as y}from"./index-DXI13nSQ.js";import"./react-Cb2sDjhD.js";const f=[{to:"health",i18nKey:"tabs.health"},{to:"topn",i18nKey:"tabs.topn"},{to:"audit",i18nKey:"tabs.audit"}],j=[1,7,30,90];function N(){const{t}=c("observability"),[r,i]=x(),l=Math.max(1,Number(r.get("days"))||7);function o(s){const a=new URLSearchParams(r);s===7?a.delete("days"):a.set("days",String(s)),i(a,{replace:!0})}return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(d,{}),e.jsx("div",{className:"border-b border-border bg-surface px-3 sm:px-4 py-2",children:e.jsxs("div",{className:"mx-auto flex max-w-7xl items-center gap-3",children:[e.jsx("span",{className:"text-sm text-text-dim shrink-0",children:t("window.label")}),e.jsxs(m,{value:String(l),onValueChange:s=>o(Number(s)),children:[e.jsx(p,{className:"w-32",children:e.jsx(u,{})}),e.jsx(h,{children:j.map(s=>e.jsx(b,{value:String(s),children:t("window.days",{count:s})},s))})]})]})}),e.jsx("nav",{className:n("sticky top-0 z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":t("pageTitle"),children:f.map(s=>e.jsx(g,{to:s.to,className:({isActive:a})=>n("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",a?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:t(s.i18nKey)},s.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(y,{})})]})}export{N as default};
2
+ //# sourceMappingURL=layout-C3e8vPrG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout-DJKxW33x.js","sources":["../../src/routes/observability/layout.tsx"],"sourcesContent":["/**\n * /observability — layout shell with sub-tab nav (health / topn /\n * audit) + a global time-window selector that every sub-tab reads\n * via useSearchParams (?days=).\n */\n\nimport { NavLink, Outlet, useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { cn } from '@/lib/utils'\n\nconst SUB_TABS = [\n { to: 'health', i18nKey: 'tabs.health' },\n { to: 'topn', i18nKey: 'tabs.topn' },\n { to: 'audit', i18nKey: 'tabs.audit' },\n]\n\nconst DAY_WINDOWS = [1, 7, 30, 90]\n\nexport default function ObservabilityLayout(): JSX.Element {\n const { t } = useTranslation('observability')\n const [params, setParams] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n\n function setDays(next: number): void {\n const p = new URLSearchParams(params)\n if (next === 7) p.delete('days')\n else p.set('days', String(next))\n setParams(p, { replace: true })\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <div className=\"border-b border-border bg-surface px-3 sm:px-4 py-2\">\n <div className=\"mx-auto flex max-w-7xl items-center gap-3\">\n <span className=\"text-sm text-text-dim shrink-0\">{t('window.label')}</span>\n <Select value={String(days)} onValueChange={(v) => setDays(Number(v))}>\n <SelectTrigger className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DAY_WINDOWS.map((n) => (\n <SelectItem key={n} value={String(n)}>\n {t('window.days', { count: n })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","DAY_WINDOWS","ObservabilityLayout","useTranslation","params","setParams","useSearchParams","days","setDays","next","p","jsxs","jsx","Topbar","Select","v","SelectTrigger","SelectValue","SelectContent","n","SelectItem","cn","tab","NavLink","isActive","Outlet"],"mappings":"mJAkBA,MAAMA,EAAW,CACf,CAAE,GAAI,SAAU,QAAS,aAAA,EACzB,CAAE,GAAI,OAAU,QAAS,WAAA,EACzB,CAAE,GAAI,QAAU,QAAS,YAAA,CAC3B,EAEMC,EAAc,CAAC,EAAG,EAAG,GAAI,EAAE,EAEjC,SAAwBC,GAAmC,CACzD,KAAM,CAAE,CAAA,EAAMC,EAAe,eAAe,EACtC,CAACC,EAAQC,CAAS,EAAIC,EAAA,EACtBC,EAAO,KAAK,IAAI,EAAG,OAAOH,EAAO,IAAI,MAAM,CAAC,GAAK,CAAC,EAExD,SAASI,EAAQC,EAAoB,CACnC,MAAMC,EAAI,IAAI,gBAAgBN,CAAM,EAChCK,IAAS,EAAGC,EAAE,OAAO,MAAM,EAC1BA,EAAE,IAAI,OAAQ,OAAOD,CAAI,CAAC,EAC/BJ,EAAUK,EAAG,CAAE,QAAS,EAAA,CAAM,CAChC,CAEA,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,QAEP,MAAA,CAAI,UAAU,sDACb,SAAAF,EAAAA,KAAC,MAAA,CAAI,UAAU,4CACb,SAAA,CAAAC,MAAC,OAAA,CAAK,UAAU,iCAAkC,SAAA,EAAE,cAAc,EAAE,EACpED,EAAAA,KAACG,EAAA,CAAO,MAAO,OAAOP,CAAI,EAAG,cAAgBQ,GAAMP,EAAQ,OAAOO,CAAC,CAAC,EAClE,SAAA,CAAAH,MAACI,EAAA,CAAc,UAAU,OACvB,SAAAJ,MAACK,IAAY,EACf,EACAL,MAACM,GACE,SAAAjB,EAAY,IAAKkB,GAChBP,EAAAA,IAACQ,GAAmB,MAAO,OAAOD,CAAC,EAChC,SAAA,EAAE,cAAe,CAAE,MAAOA,EAAG,CAAA,EADfA,CAEjB,CACD,CAAA,CACH,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACF,EAEAP,EAAAA,IAAC,MAAA,CACC,UAAWS,EACT,oBACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAY,EAAE,WAAW,EAExB,SAAArB,EAAS,IAAKsB,GACbV,EAAAA,IAACW,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAA,EAAEF,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAV,EAAAA,IAACa,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
1
+ {"version":3,"file":"layout-C3e8vPrG.js","sources":["../../src/routes/observability/layout.tsx"],"sourcesContent":["/**\n * /observability — layout shell with sub-tab nav (health / topn /\n * audit) + a global time-window selector that every sub-tab reads\n * via useSearchParams (?days=).\n */\n\nimport { NavLink, Outlet, useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { cn } from '@/lib/utils'\n\nconst SUB_TABS = [\n { to: 'health', i18nKey: 'tabs.health' },\n { to: 'topn', i18nKey: 'tabs.topn' },\n { to: 'audit', i18nKey: 'tabs.audit' },\n]\n\nconst DAY_WINDOWS = [1, 7, 30, 90]\n\nexport default function ObservabilityLayout(): JSX.Element {\n const { t } = useTranslation('observability')\n const [params, setParams] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n\n function setDays(next: number): void {\n const p = new URLSearchParams(params)\n if (next === 7) p.delete('days')\n else p.set('days', String(next))\n setParams(p, { replace: true })\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <div className=\"border-b border-border bg-surface px-3 sm:px-4 py-2\">\n <div className=\"mx-auto flex max-w-7xl items-center gap-3\">\n <span className=\"text-sm text-text-dim shrink-0\">{t('window.label')}</span>\n <Select value={String(days)} onValueChange={(v) => setDays(Number(v))}>\n <SelectTrigger className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DAY_WINDOWS.map((n) => (\n <SelectItem key={n} value={String(n)}>\n {t('window.days', { count: n })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","DAY_WINDOWS","ObservabilityLayout","useTranslation","params","setParams","useSearchParams","days","setDays","next","p","jsxs","jsx","Topbar","Select","v","SelectTrigger","SelectValue","SelectContent","n","SelectItem","cn","tab","NavLink","isActive","Outlet"],"mappings":"4IAkBA,MAAMA,EAAW,CACf,CAAE,GAAI,SAAU,QAAS,aAAA,EACzB,CAAE,GAAI,OAAU,QAAS,WAAA,EACzB,CAAE,GAAI,QAAU,QAAS,YAAA,CAC3B,EAEMC,EAAc,CAAC,EAAG,EAAG,GAAI,EAAE,EAEjC,SAAwBC,GAAmC,CACzD,KAAM,CAAE,CAAA,EAAMC,EAAe,eAAe,EACtC,CAACC,EAAQC,CAAS,EAAIC,EAAA,EACtBC,EAAO,KAAK,IAAI,EAAG,OAAOH,EAAO,IAAI,MAAM,CAAC,GAAK,CAAC,EAExD,SAASI,EAAQC,EAAoB,CACnC,MAAMC,EAAI,IAAI,gBAAgBN,CAAM,EAChCK,IAAS,EAAGC,EAAE,OAAO,MAAM,EAC1BA,EAAE,IAAI,OAAQ,OAAOD,CAAI,CAAC,EAC/BJ,EAAUK,EAAG,CAAE,QAAS,EAAA,CAAM,CAChC,CAEA,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,QAEP,MAAA,CAAI,UAAU,sDACb,SAAAF,EAAAA,KAAC,MAAA,CAAI,UAAU,4CACb,SAAA,CAAAC,MAAC,OAAA,CAAK,UAAU,iCAAkC,SAAA,EAAE,cAAc,EAAE,EACpED,EAAAA,KAACG,EAAA,CAAO,MAAO,OAAOP,CAAI,EAAG,cAAgBQ,GAAMP,EAAQ,OAAOO,CAAC,CAAC,EAClE,SAAA,CAAAH,MAACI,EAAA,CAAc,UAAU,OACvB,SAAAJ,MAACK,IAAY,EACf,EACAL,MAACM,GACE,SAAAjB,EAAY,IAAKkB,GAChBP,EAAAA,IAACQ,GAAmB,MAAO,OAAOD,CAAC,EAChC,SAAA,EAAE,cAAe,CAAE,MAAOA,EAAG,CAAA,EADfA,CAEjB,CACD,CAAA,CACH,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACF,EAEAP,EAAAA,IAAC,MAAA,CACC,UAAWS,EACT,oBACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAY,EAAE,WAAW,EAExB,SAAArB,EAAS,IAAKsB,GACbV,EAAAA,IAACW,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAA,EAAEF,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAV,EAAAA,IAACa,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
@@ -0,0 +1,2 @@
1
+ import{u as n,j as e,T as u,N as r,c as a,O as i}from"./index-DXI13nSQ.js";import"./react-Cb2sDjhD.js";const b=[{to:"jobs",i18nKey:"subnav.jobs",mounted:!0},{to:"subtasks",i18nKey:"subnav.subtasks",mounted:!0},{to:"bgjobs",i18nKey:"subnav.bgjobs",mounted:!0},{to:"schedules",i18nKey:"subnav.schedules",mounted:!0},{to:"outbox",i18nKey:"subnav.outbox",mounted:!0},{to:"a2a",i18nKey:"subnav.a2a",mounted:!0},{to:"heartbeat",i18nKey:"subnav.heartbeat",mounted:!0},{to:"goals",i18nKey:"subnav.goals",mounted:!0},{to:"asks",i18nKey:"subnav.asks",mounted:!0}];function l(){const{t:s}=n("tasks");return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(u,{}),e.jsx("nav",{className:a("sticky top-[var(--topbar-h,0)] z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":s("pageTitle"),children:b.filter(t=>t.mounted).map(t=>e.jsx(r,{to:t.to,className:({isActive:o})=>a("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",o?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:s(t.i18nKey)},t.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(i,{})})]})}export{l as default};
2
+ //# sourceMappingURL=layout-DkoRqhBs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout-B5rK_h6Q.js","sources":["../../src/routes/tasks/layout.tsx"],"sourcesContent":["/**\n * /tasks — layout shell shared by every sub-tab.\n *\n * Renders the application Topbar plus a sub-tab strip below it. The\n * actual sub-tab body comes from <Outlet /> — one file per tab under\n * routes/tasks/.\n *\n * Sub-tab order matches plan: jobs / subtasks / bgjobs / schedules /\n * outbox / a2a. Each sub-tab is gated on its route being mounted; in\n * PR-10a only `/tasks/jobs` is wired up so the others stay out of the\n * nav until their PRs land.\n */\n\nimport { NavLink, Outlet } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'jobs', i18nKey: 'subnav.jobs', mounted: true },\n { to: 'subtasks', i18nKey: 'subnav.subtasks', mounted: true },\n { to: 'bgjobs', i18nKey: 'subnav.bgjobs', mounted: true },\n { to: 'schedules', i18nKey: 'subnav.schedules', mounted: true },\n { to: 'outbox', i18nKey: 'subnav.outbox', mounted: true },\n { to: 'a2a', i18nKey: 'subnav.a2a', mounted: true },\n // P1 follow-up — per-thread background primitives.\n { to: 'heartbeat', i18nKey: 'subnav.heartbeat', mounted: true },\n { to: 'goals', i18nKey: 'subnav.goals', mounted: true },\n { to: 'asks', i18nKey: 'subnav.asks', mounted: true },\n]\n\nexport default function TasksLayout(): JSX.Element {\n const { t } = useTranslation('tasks')\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <nav\n className={cn(\n 'sticky top-[var(--topbar-h,0)] z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","TasksLayout","t","useTranslation","jsxs","jsx","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"wGAwBA,MAAMA,EAAqB,CACzB,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,WAAa,QAAS,kBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,MAAa,QAAS,aAAoB,QAAS,EAAA,EAEzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,QAAa,QAAS,eAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,CAC3D,EAEA,SAAwBC,GAA2B,CACjD,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,OAAO,EACpC,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,EAERD,EAAAA,IAAC,MAAA,CACC,UAAWE,EACT,sCACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAYL,EAAE,WAAW,EAExB,SAAAF,EAAS,OAAQQ,GAAQA,EAAI,OAAO,EAAE,IAAKA,GAC1CH,EAAAA,IAACI,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAAR,EAAEM,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAH,EAAAA,IAACM,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
1
+ {"version":3,"file":"layout-DkoRqhBs.js","sources":["../../src/routes/tasks/layout.tsx"],"sourcesContent":["/**\n * /tasks — layout shell shared by every sub-tab.\n *\n * Renders the application Topbar plus a sub-tab strip below it. The\n * actual sub-tab body comes from <Outlet /> — one file per tab under\n * routes/tasks/.\n *\n * Sub-tab order matches plan: jobs / subtasks / bgjobs / schedules /\n * outbox / a2a. Each sub-tab is gated on its route being mounted; in\n * PR-10a only `/tasks/jobs` is wired up so the others stay out of the\n * nav until their PRs land.\n */\n\nimport { NavLink, Outlet } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'jobs', i18nKey: 'subnav.jobs', mounted: true },\n { to: 'subtasks', i18nKey: 'subnav.subtasks', mounted: true },\n { to: 'bgjobs', i18nKey: 'subnav.bgjobs', mounted: true },\n { to: 'schedules', i18nKey: 'subnav.schedules', mounted: true },\n { to: 'outbox', i18nKey: 'subnav.outbox', mounted: true },\n { to: 'a2a', i18nKey: 'subnav.a2a', mounted: true },\n // P1 follow-up — per-thread background primitives.\n { to: 'heartbeat', i18nKey: 'subnav.heartbeat', mounted: true },\n { to: 'goals', i18nKey: 'subnav.goals', mounted: true },\n { to: 'asks', i18nKey: 'subnav.asks', mounted: true },\n]\n\nexport default function TasksLayout(): JSX.Element {\n const { t } = useTranslation('tasks')\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <nav\n className={cn(\n 'sticky top-[var(--topbar-h,0)] z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","TasksLayout","t","useTranslation","jsxs","jsx","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"uGAwBA,MAAMA,EAAqB,CACzB,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,WAAa,QAAS,kBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,MAAa,QAAS,aAAoB,QAAS,EAAA,EAEzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,QAAa,QAAS,eAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,CAC3D,EAEA,SAAwBC,GAA2B,CACjD,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,OAAO,EACpC,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,EAERD,EAAAA,IAAC,MAAA,CACC,UAAWE,EACT,sCACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAYL,EAAE,WAAW,EAExB,SAAAF,EAAS,OAAQQ,GAAQA,EAAI,OAAO,EAAE,IAAKA,GAC1CH,EAAAA,IAACI,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAAR,EAAEM,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAH,EAAAA,IAACM,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
@@ -0,0 +1,2 @@
1
+ import{u as o,j as t,N as n,c as a,O as l}from"./index-DXI13nSQ.js";import"./react-Cb2sDjhD.js";const r=[{to:"installed",i18nKey:"agimSkills.tab.installed"},{to:"hot",i18nKey:"agimSkills.tab.hot"}];function c(){const{t:s}=o(["settings"]);return t.jsxs("div",{className:"flex flex-col gap-4",children:[t.jsx("nav",{className:a("flex items-center gap-1","border-b border-border","-mx-3 sm:-mx-4 px-3 sm:px-4 pb-2","overflow-x-auto"),"aria-label":s("agimSkills.title"),children:r.map(e=>t.jsx(n,{to:e.to,className:({isActive:i})=>a("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",i?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:s(e.i18nKey)},e.to))}),t.jsx(l,{})]})}export{c as default};
2
+ //# sourceMappingURL=layout-wuoOyazR.js.map