agim-cli 1.2.39 → 1.2.41

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 (145) hide show
  1. package/dist/core/onboarding.d.ts +11 -0
  2. package/dist/core/onboarding.d.ts.map +1 -1
  3. package/dist/core/onboarding.js.map +1 -1
  4. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +27 -10
  5. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts.map +1 -1
  6. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +148 -48
  7. package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -1
  8. package/dist/plugins/messengers/dingtalk/types.d.ts +24 -0
  9. package/dist/plugins/messengers/dingtalk/types.d.ts.map +1 -1
  10. package/dist/web/public/assets/{a2a-C7lYvkA4.js → a2a-Dvz7ig4m.js} +2 -2
  11. package/dist/web/public/assets/{a2a-C7lYvkA4.js.map → a2a-Dvz7ig4m.js.map} +1 -1
  12. package/dist/web/public/assets/{activity-DFB1UVF1.js → activity-BJqk7b-v.js} +2 -2
  13. package/dist/web/public/assets/{activity-DFB1UVF1.js.map → activity-BJqk7b-v.js.map} +1 -1
  14. package/dist/web/public/assets/{admins-BgmlFiRu.js → admins-DeiNQcMh.js} +2 -2
  15. package/dist/web/public/assets/{admins-BgmlFiRu.js.map → admins-DeiNQcMh.js.map} +1 -1
  16. package/dist/web/public/assets/{agents-D9GBT8Zl.js → agents-DJGdXKLv.js} +2 -2
  17. package/dist/web/public/assets/{agents-D9GBT8Zl.js.map → agents-DJGdXKLv.js.map} +1 -1
  18. package/dist/web/public/assets/{approvals-Be45xKtz.js → approvals-BOJ9et5G.js} +2 -2
  19. package/dist/web/public/assets/{approvals-Be45xKtz.js.map → approvals-BOJ9et5G.js.map} +1 -1
  20. package/dist/web/public/assets/{audit-BNx_EkjC.js → audit-Dnnevx6v.js} +2 -2
  21. package/dist/web/public/assets/{audit-BNx_EkjC.js.map → audit-Dnnevx6v.js.map} +1 -1
  22. package/dist/web/public/assets/{bgjobs-uQw6SA4h.js → bgjobs-BZAxNFpA.js} +2 -2
  23. package/dist/web/public/assets/{bgjobs-uQw6SA4h.js.map → bgjobs-BZAxNFpA.js.map} +1 -1
  24. package/dist/web/public/assets/{brain-CY9GRk9W.js → brain-fC59o4ZL.js} +2 -2
  25. package/dist/web/public/assets/{brain-CY9GRk9W.js.map → brain-fC59o4ZL.js.map} +1 -1
  26. package/dist/web/public/assets/{briefcase-6msjfYUU.js → briefcase-DJRv77W6.js} +2 -2
  27. package/dist/web/public/assets/{briefcase-6msjfYUU.js.map → briefcase-DJRv77W6.js.map} +1 -1
  28. package/dist/web/public/assets/{chevron-right-DECkw7Jd.js → chevron-right-DzyVDoQs.js} +2 -2
  29. package/dist/web/public/assets/{chevron-right-DECkw7Jd.js.map → chevron-right-DzyVDoQs.js.map} +1 -1
  30. package/dist/web/public/assets/{circle-check-BL5BCLn_.js → circle-check-B7B_CkmJ.js} +2 -2
  31. package/dist/web/public/assets/{circle-check-BL5BCLn_.js.map → circle-check-B7B_CkmJ.js.map} +1 -1
  32. package/dist/web/public/assets/{circle-check-big-DtKj0bvZ.js → circle-check-big-dmFsJv6U.js} +2 -2
  33. package/dist/web/public/assets/{circle-check-big-DtKj0bvZ.js.map → circle-check-big-dmFsJv6U.js.map} +1 -1
  34. package/dist/web/public/assets/{circle-x-Dv0fneWH.js → circle-x-epC-av6L.js} +2 -2
  35. package/dist/web/public/assets/{circle-x-Dv0fneWH.js.map → circle-x-epC-av6L.js.map} +1 -1
  36. package/dist/web/public/assets/{confirm-dialog-QaqXnzLc.js → confirm-dialog-BEzhDlk7.js} +2 -2
  37. package/dist/web/public/assets/{confirm-dialog-QaqXnzLc.js.map → confirm-dialog-BEzhDlk7.js.map} +1 -1
  38. package/dist/web/public/assets/{data-table-BRHemHNS.js → data-table-B_BxQrSj.js} +2 -2
  39. package/dist/web/public/assets/{data-table-BRHemHNS.js.map → data-table-B_BxQrSj.js.map} +1 -1
  40. package/dist/web/public/assets/{dialog-DzCAOdn8.js → dialog-BAZNQtMt.js} +2 -2
  41. package/dist/web/public/assets/{dialog-DzCAOdn8.js.map → dialog-BAZNQtMt.js.map} +1 -1
  42. package/dist/web/public/assets/{download-DGggXcuj.js → download-C08F-eA4.js} +2 -2
  43. package/dist/web/public/assets/{download-DGggXcuj.js.map → download-C08F-eA4.js.map} +1 -1
  44. package/dist/web/public/assets/{email-DZXu4PeQ.js → email-qzOnhITw.js} +2 -2
  45. package/dist/web/public/assets/{email-DZXu4PeQ.js.map → email-qzOnhITw.js.map} +1 -1
  46. package/dist/web/public/assets/{empty-state--qSLu4iL.js → empty-state-BKs1qKHx.js} +2 -2
  47. package/dist/web/public/assets/{empty-state--qSLu4iL.js.map → empty-state-BKs1qKHx.js.map} +1 -1
  48. package/dist/web/public/assets/{external-link-SkbgGADx.js → external-link-HML--jya.js} +2 -2
  49. package/dist/web/public/assets/{external-link-SkbgGADx.js.map → external-link-HML--jya.js.map} +1 -1
  50. package/dist/web/public/assets/{eye-Du4m0dYr.js → eye-C20O3zvh.js} +2 -2
  51. package/dist/web/public/assets/{eye-Du4m0dYr.js.map → eye-C20O3zvh.js.map} +1 -1
  52. package/dist/web/public/assets/{facts-cmX647ty.js → facts-B7VlqoVs.js} +2 -2
  53. package/dist/web/public/assets/{facts-cmX647ty.js.map → facts-B7VlqoVs.js.map} +1 -1
  54. package/dist/web/public/assets/{health-Co_2jH5V.js → health-IF_VcgWW.js} +2 -2
  55. package/dist/web/public/assets/{health-Co_2jH5V.js.map → health-IF_VcgWW.js.map} +1 -1
  56. package/dist/web/public/assets/{hot-BAX3WV0p.js → hot-D-aKQ8y2.js} +2 -2
  57. package/dist/web/public/assets/{hot-BAX3WV0p.js.map → hot-D-aKQ8y2.js.map} +1 -1
  58. package/dist/web/public/assets/{index-BAK3HT1o.js → index-B48azMO-.js} +4 -4
  59. package/dist/web/public/assets/{index-BAK3HT1o.js.map → index-B48azMO-.js.map} +1 -1
  60. package/dist/web/public/assets/index-Cvacw7Jg.css +1 -0
  61. package/dist/web/public/assets/{installed-vEt64SE3.js → installed-CkiQRc89.js} +2 -2
  62. package/dist/web/public/assets/{installed-vEt64SE3.js.map → installed-CkiQRc89.js.map} +1 -1
  63. package/dist/web/public/assets/{jobs-CmSWAbse.js → jobs-g1Wl8_zd.js} +2 -2
  64. package/dist/web/public/assets/{jobs-CmSWAbse.js.map → jobs-g1Wl8_zd.js.map} +1 -1
  65. package/dist/web/public/assets/{layout-DF92UGuZ.js → layout-CS9s-Q0a.js} +2 -2
  66. package/dist/web/public/assets/{layout-DF92UGuZ.js.map → layout-CS9s-Q0a.js.map} +1 -1
  67. package/dist/web/public/assets/{layout-BgbibVU6.js → layout-ChcpcCB8.js} +2 -2
  68. package/dist/web/public/assets/{layout-BgbibVU6.js.map → layout-ChcpcCB8.js.map} +1 -1
  69. package/dist/web/public/assets/{layout-Cbf_CCBN.js → layout-CjLzz--E.js} +2 -2
  70. package/dist/web/public/assets/{layout-Cbf_CCBN.js.map → layout-CjLzz--E.js.map} +1 -1
  71. package/dist/web/public/assets/{layout-Bl6t0Q6D.js → layout-D_CUXsIR.js} +2 -2
  72. package/dist/web/public/assets/{layout-Bl6t0Q6D.js.map → layout-D_CUXsIR.js.map} +1 -1
  73. package/dist/web/public/assets/{layout-DKUTeV-p.js → layout-fTZD9lJN.js} +2 -2
  74. package/dist/web/public/assets/{layout-DKUTeV-p.js.map → layout-fTZD9lJN.js.map} +1 -1
  75. package/dist/web/public/assets/{loader-circle-CXl24wsB.js → loader-circle-DBf4xFjo.js} +2 -2
  76. package/dist/web/public/assets/{loader-circle-CXl24wsB.js.map → loader-circle-DBf4xFjo.js.map} +1 -1
  77. package/dist/web/public/assets/{map-pin-CVRwkuru.js → map-pin-BYR0Sf5r.js} +2 -2
  78. package/dist/web/public/assets/{map-pin-CVRwkuru.js.map → map-pin-BYR0Sf5r.js.map} +1 -1
  79. package/dist/web/public/assets/{memos-k6FW9dd4.js → memos-ChfapnyG.js} +2 -2
  80. package/dist/web/public/assets/{memos-k6FW9dd4.js.map → memos-ChfapnyG.js.map} +1 -1
  81. package/dist/web/public/assets/messengers-zBIYakPW.js +7 -0
  82. package/dist/web/public/assets/messengers-zBIYakPW.js.map +1 -0
  83. package/dist/web/public/assets/{network-BLcJyt3y.js → network-CEqTiog6.js} +2 -2
  84. package/dist/web/public/assets/{network-BLcJyt3y.js.map → network-CEqTiog6.js.map} +1 -1
  85. package/dist/web/public/assets/{outbox-X2aiMbdq.js → outbox-D4IQcACJ.js} +2 -2
  86. package/dist/web/public/assets/{outbox-X2aiMbdq.js.map → outbox-D4IQcACJ.js.map} +1 -1
  87. package/dist/web/public/assets/{pagination-BD7XfwcX.js → pagination-R9mql8VB.js} +2 -2
  88. package/dist/web/public/assets/{pagination-BD7XfwcX.js.map → pagination-R9mql8VB.js.map} +1 -1
  89. package/dist/web/public/assets/{persona-CiMN6Pne.js → persona-Cj_C5frK.js} +2 -2
  90. package/dist/web/public/assets/{persona-CiMN6Pne.js.map → persona-Cj_C5frK.js.map} +1 -1
  91. package/dist/web/public/assets/{play-DTK7F9m6.js → play-CTWqoMcj.js} +2 -2
  92. package/dist/web/public/assets/{play-DTK7F9m6.js.map → play-CTWqoMcj.js.map} +1 -1
  93. package/dist/web/public/assets/{policy-awgRqM5Z.js → policy-BKEZ2ziu.js} +2 -2
  94. package/dist/web/public/assets/{policy-awgRqM5Z.js.map → policy-BKEZ2ziu.js.map} +1 -1
  95. package/dist/web/public/assets/{refresh-ccw-ChTs-DiT.js → refresh-ccw-Clj5sQNF.js} +2 -2
  96. package/dist/web/public/assets/{refresh-ccw-ChTs-DiT.js.map → refresh-ccw-Clj5sQNF.js.map} +1 -1
  97. package/dist/web/public/assets/{reminders-DZDyIu_n.js → reminders-C5bVkLgj.js} +2 -2
  98. package/dist/web/public/assets/{reminders-DZDyIu_n.js.map → reminders-C5bVkLgj.js.map} +1 -1
  99. package/dist/web/public/assets/{save-Bd0yyWyF.js → save-CAFra1jb.js} +2 -2
  100. package/dist/web/public/assets/{save-Bd0yyWyF.js.map → save-CAFra1jb.js.map} +1 -1
  101. package/dist/web/public/assets/{schedules-Bbq9N-Sz.js → schedules-KQCD7978.js} +2 -2
  102. package/dist/web/public/assets/{schedules-Bbq9N-Sz.js.map → schedules-KQCD7978.js.map} +1 -1
  103. package/dist/web/public/assets/{search-CUZFSMD0.js → search-bDqizeZv.js} +2 -2
  104. package/dist/web/public/assets/{search-CUZFSMD0.js.map → search-bDqizeZv.js.map} +1 -1
  105. package/dist/web/public/assets/{service-CPV-yW7V.js → service-DTeMmX2u.js} +2 -2
  106. package/dist/web/public/assets/{service-CPV-yW7V.js.map → service-DTeMmX2u.js.map} +1 -1
  107. package/dist/web/public/assets/{status-badge-DHLuTCYi.js → status-badge-_3Ve0Jef.js} +2 -2
  108. package/dist/web/public/assets/{status-badge-DHLuTCYi.js.map → status-badge-_3Ve0Jef.js.map} +1 -1
  109. package/dist/web/public/assets/{subtasks-dR1OyViz.js → subtasks-DROeZcfT.js} +2 -2
  110. package/dist/web/public/assets/{subtasks-dR1OyViz.js.map → subtasks-DROeZcfT.js.map} +1 -1
  111. package/dist/web/public/assets/{table-CTNMqGvo.js → table-CZwKizat.js} +2 -2
  112. package/dist/web/public/assets/{table-CTNMqGvo.js.map → table-CZwKizat.js.map} +1 -1
  113. package/dist/web/public/assets/{topn-Dk9JxsaD.js → topn-DpErN6N8.js} +2 -2
  114. package/dist/web/public/assets/{topn-Dk9JxsaD.js.map → topn-DpErN6N8.js.map} +1 -1
  115. package/dist/web/public/assets/{trash-2-CSId-EFx.js → trash-2-BkZrVFdH.js} +2 -2
  116. package/dist/web/public/assets/{trash-2-CSId-EFx.js.map → trash-2-BkZrVFdH.js.map} +1 -1
  117. package/dist/web/public/assets/{use-memory-B5fLcSLE.js → use-memory-CElm89Hg.js} +2 -2
  118. package/dist/web/public/assets/{use-memory-B5fLcSLE.js.map → use-memory-CElm89Hg.js.map} +1 -1
  119. package/dist/web/public/assets/{use-observability-CUbSm1kG.js → use-observability-D8qHfj0S.js} +2 -2
  120. package/dist/web/public/assets/{use-observability-CUbSm1kG.js.map → use-observability-D8qHfj0S.js.map} +1 -1
  121. package/dist/web/public/assets/{use-settings-CtTPlLXz.js → use-settings-DgU8YmGj.js} +2 -2
  122. package/dist/web/public/assets/{use-settings-CtTPlLXz.js.map → use-settings-DgU8YmGj.js.map} +1 -1
  123. package/dist/web/public/assets/{use-skills-DdmwXWK7.js → use-skills-Cp_ok0Uq.js} +2 -2
  124. package/dist/web/public/assets/{use-skills-DdmwXWK7.js.map → use-skills-Cp_ok0Uq.js.map} +1 -1
  125. package/dist/web/public/assets/{use-workspace-C_zPgOcX.js → use-workspace-Dc6rNi5d.js} +2 -2
  126. package/dist/web/public/assets/{use-workspace-C_zPgOcX.js.map → use-workspace-Dc6rNi5d.js.map} +1 -1
  127. package/dist/web/public/assets/{useQuery-CBD2h35Q.js → useQuery-BjFqOBV3.js} +2 -2
  128. package/dist/web/public/assets/{useQuery-CBD2h35Q.js.map → useQuery-BjFqOBV3.js.map} +1 -1
  129. package/dist/web/public/assets/{vector-vwq7t-U5.js → vector-Bb3l7TOa.js} +2 -2
  130. package/dist/web/public/assets/{vector-vwq7t-U5.js.map → vector-Bb3l7TOa.js.map} +1 -1
  131. package/dist/web/public/assets/{viewer-SR8OwQK3.js → viewer-BeyW50lw.js} +2 -2
  132. package/dist/web/public/assets/{viewer-SR8OwQK3.js.map → viewer-BeyW50lw.js.map} +1 -1
  133. package/dist/web/public/assets/{workspace-VRwymXux.js → workspace-Du8va-tD.js} +2 -2
  134. package/dist/web/public/assets/{workspace-VRwymXux.js.map → workspace-Du8va-tD.js.map} +1 -1
  135. package/dist/web/public/assets/{workspaces-5N_hYIVk.js → workspaces-BjgDtEnF.js} +2 -2
  136. package/dist/web/public/assets/{workspaces-5N_hYIVk.js.map → workspaces-BjgDtEnF.js.map} +1 -1
  137. package/dist/web/public/assets/{x-De56D6Eb.js → x-CHe1y-sG.js} +2 -2
  138. package/dist/web/public/assets/{x-De56D6Eb.js.map → x-CHe1y-sG.js.map} +1 -1
  139. package/dist/web/public/index.html +2 -2
  140. package/dist/web/server.js +27 -0
  141. package/dist/web/server.js.map +1 -1
  142. package/package.json +1 -1
  143. package/dist/web/public/assets/index-CDYTPZH0.css +0 -1
  144. package/dist/web/public/assets/messengers-iXrlzy93.js +0 -7
  145. package/dist/web/public/assets/messengers-iXrlzy93.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"eye-Du4m0dYr.js","sources":["../../node_modules/lucide-react/dist/esm/icons/eye-off.js","../../node_modules/lucide-react/dist/esm/icons/eye.js"],"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 EyeOff = createLucideIcon(\"EyeOff\", [\n [\n \"path\",\n {\n d: \"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\",\n key: \"ct8e1f\"\n }\n ],\n [\"path\", { d: \"M14.084 14.158a3 3 0 0 1-4.242-4.242\", key: \"151rxh\" }],\n [\n \"path\",\n {\n d: \"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\",\n key: \"13bj9a\"\n }\n ],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n]);\n\nexport { EyeOff as default };\n//# sourceMappingURL=eye-off.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 Eye = createLucideIcon(\"Eye\", [\n [\n \"path\",\n {\n d: \"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\",\n key: \"1nclc0\"\n }\n ],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n]);\n\nexport { Eye as default };\n//# sourceMappingURL=eye.js.map\n"],"names":["EyeOff","createLucideIcon","Eye"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAASC,EAAiB,SAAU,CACxC,CACE,OACA,CACE,EAAG,iGACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,uCAAwC,IAAK,QAAQ,CAAE,EACrE,CACE,OACA,CACE,EAAG,+FACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC,EC1BD;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACC,EAAMD,EAAiB,MAAO,CAClC,CACE,OACA,CACE,EAAG,wGACH,IAAK,QACX,CACA,EACE,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,IAAK,IAAK,QAAQ,CAAE,CAC1D,CAAC","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"eye-C20O3zvh.js","sources":["../../node_modules/lucide-react/dist/esm/icons/eye-off.js","../../node_modules/lucide-react/dist/esm/icons/eye.js"],"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 EyeOff = createLucideIcon(\"EyeOff\", [\n [\n \"path\",\n {\n d: \"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\",\n key: \"ct8e1f\"\n }\n ],\n [\"path\", { d: \"M14.084 14.158a3 3 0 0 1-4.242-4.242\", key: \"151rxh\" }],\n [\n \"path\",\n {\n d: \"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\",\n key: \"13bj9a\"\n }\n ],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n]);\n\nexport { EyeOff as default };\n//# sourceMappingURL=eye-off.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 Eye = createLucideIcon(\"Eye\", [\n [\n \"path\",\n {\n d: \"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\",\n key: \"1nclc0\"\n }\n ],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n]);\n\nexport { Eye as default };\n//# sourceMappingURL=eye.js.map\n"],"names":["EyeOff","createLucideIcon","Eye"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAASC,EAAiB,SAAU,CACxC,CACE,OACA,CACE,EAAG,iGACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,uCAAwC,IAAK,QAAQ,CAAE,EACrE,CACE,OACA,CACE,EAAG,+FACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC,EC1BD;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACC,EAAMD,EAAiB,MAAO,CAClC,CACE,OACA,CACE,EAAG,wGACH,IAAK,QACX,CACA,EACE,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,IAAK,IAAK,QAAQ,CAAE,CAC1D,CAAC","x_google_ignoreList":[0,1]}
@@ -1,2 +1,2 @@
1
- import{ac as K,ab as Y,Q as e,B as D,c as b,L as E,I as J,S as W,l as X,m as Z,j as ee,k,a2 as p,z as T}from"./index-BAK3HT1o.js";import{e as r}from"./react-C9F3QeMB.js";import{D as te}from"./data-table-BRHemHNS.js";import{E as B}from"./empty-state--qSLu4iL.js";import{P as se}from"./pagination-BD7XfwcX.js";import{C as M}from"./confirm-dialog-QaqXnzLc.js";import{d as ae,b as ne,u as ce}from"./use-memory-B5fLcSLE.js";import{T as A}from"./trash-2-CSId-EFx.js";import{B as R}from"./brain-CY9GRk9W.js";import{L as re}from"./loader-circle-CXl24wsB.js";import{R as ie}from"./refresh-ccw-ChTs-DiT.js";import{S as le}from"./search-CUZFSMD0.js";import"./table-CTNMqGvo.js";import"./chevron-right-DECkw7Jd.js";import"./dialog-DzCAOdn8.js";import"./x-De56D6Eb.js";import"./useQuery-CBD2h35Q.js";const oe=["fact","preference","goal","history","profile"],me=[25,50,100],F=50,de=300;function Ee(){const{t:s}=K(["memory","common"]),[n,L]=Y(),c=n.get("user")??"",i=n.get("q")??"",m=n.get("cat")??null,d=Math.max(1,Number(n.get("page"))||1),l=Number(n.get("per_page"))||F,[f,I]=r.useState(i);r.useEffect(()=>{if(f===i)return;const t=window.setTimeout(()=>h({q:f||null}),de);return()=>window.clearTimeout(t)},[f]);const q=r.useMemo(()=>({user_key:c,...i?{query:i}:{},...m?{category:m}:{},limit:l,offset:(d-1)*l}),[c,i,m,d,l]),{data:S,isLoading:z,isFetching:C,refetch:U}=ae(q,{enabled:!!c}),_=S?.facts??[],P=S?.total??0,G=Math.max(1,Math.ceil(P/l)),[u,g]=r.useState(new Set);r.useEffect(()=>{g(new Set)},[c,i,m,d,l]);const j=ne(),x=ce(),[y,v]=r.useState(null),[V,O]=r.useState(!1);function h(t){const a=new URLSearchParams(n);for(const[o,w]of Object.entries(t))w==null||w===""?a.delete(o):a.set(o,w);Object.keys(t).some(o=>o!=="page")&&a.delete("page"),L(a,{replace:!1})}async function Q(){if(!(y==null||!c))try{await j.mutateAsync({id:y,user_key:c}),p.success(s("facts.toast.deletedOne"))}catch(t){const{message:a}=T(t,s);throw p.error(a),t}}async function $(){if(!c||u.size===0)return;const t=Array.from(u).map(Number).filter(Number.isFinite);try{const a=await x.mutateAsync({user_key:c,body:{ids:t}});p.success(s("facts.toast.deletedMany",{count:a.deleted})),g(new Set)}catch(a){const{message:o}=T(a,s);throw p.error(o),a}}const H=r.useMemo(()=>[{id:"id",header:s("facts.col.id"),cell:t=>e.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",t.id]}),headClassName:"w-16"},{id:"what",header:s("facts.col.what"),cell:t=>e.jsx("span",{className:"line-clamp-2 text-text",children:t.what}),asCardTitle:!0},{id:"category",header:s("facts.col.category"),cell:t=>e.jsx(D,{variant:"outline",children:s(`facts.category.${t.category}`,{defaultValue:t.category})}),headClassName:"w-28"},{id:"confidence",header:s("facts.col.confidence"),cell:t=>e.jsx("span",{className:"tabular-nums text-text-dim",children:t.confidence.toFixed(2)}),headClassName:"w-24",hideOnMobile:!0},{id:"source",header:s("facts.col.source"),cell:t=>e.jsx("span",{className:"text-text-dim text-xs",children:t.source}),headClassName:"w-28",hideOnMobile:!0},{id:"createdAt",header:s("facts.col.createdAt"),cell:t=>e.jsx("span",{className:"text-text-dim",children:fe(t.created_at)}),headClassName:"w-32",hideOnMobile:!0},{id:"actions",header:"",cell:t=>e.jsx("div",{className:"flex justify-end",children:e.jsxs(b,{variant:"ghost",size:"sm",onClick:a=>{a.stopPropagation(),v(t.id)},disabled:j.isPending||x.isPending,"aria-label":s("facts.action.delete"),children:[e.jsx(A,{className:"h-3 w-3"}),e.jsx("span",{className:"sr-only sm:not-sr-only sm:ml-1",children:s("facts.action.delete")})]})}),headClassName:"w-24"}],[s,j.isPending,x.isPending]);if(!c)return e.jsx("div",{className:"mx-auto max-w-3xl",children:e.jsx(B,{icon:e.jsx(R,{}),title:s("noUserSelected.title"),description:s("noUserSelected.description")})});const N=u.size;return e.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("facts.title")}),e.jsxs(b,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>U(),disabled:C,"aria-label":s("actions.refresh",{ns:"common"}),children:[C?e.jsx(re,{className:"h-4 w-4 animate-spin"}):e.jsx(ie,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("subtitle")})]}),e.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[e.jsxs("div",{className:"relative flex-1 min-w-[200px] max-w-md",children:[e.jsx(E,{htmlFor:"search",className:"text-xs text-text-dim",children:s("facts.filter.search")}),e.jsx(le,{className:"pointer-events-none absolute left-2 bottom-2 h-4 w-4 text-text-muted"}),e.jsx(J,{id:"search",value:f,onChange:t=>I(t.target.value),className:"pl-7 mt-1"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(E,{htmlFor:"category",className:"text-xs text-text-dim",children:s("facts.filter.category")}),e.jsxs(W,{value:m??"__any__",onValueChange:t=>h({cat:t==="__any__"?null:t}),children:[e.jsx(X,{id:"category",className:"w-[140px]",children:e.jsx(Z,{})}),e.jsxs(ee,{children:[e.jsx(k,{value:"__any__",children:s("facts.filter.categoryAny")}),oe.map(t=>e.jsx(k,{value:t,children:s(`facts.category.${t}`)},t))]})]})]}),N>0&&e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[e.jsx(D,{variant:"secondary",children:s("facts.batch.selected",{count:N})}),e.jsxs(b,{variant:"destructive",size:"sm",onClick:()=>O(!0),disabled:x.isPending,children:[e.jsx(A,{className:"h-4 w-4"}),s("facts.batch.deleteSelected")]})]})]}),e.jsx(te,{columns:H,rows:_,getRowId:t=>String(t.id),loading:z,selection:u,onSelectionChange:g,emptyState:e.jsx(B,{icon:e.jsx(R,{}),title:s("facts.empty.title"),description:s("facts.empty.description")})}),(_.length>0||d>1)&&e.jsx(se,{page:d,totalPages:G,totalRows:P,perPage:l,perPageOptions:me,onPageChange:t=>h({page:t===1?null:String(t)}),onPerPageChange:t=>h({per_page:t===F?null:String(t)})}),e.jsx(M,{open:y!=null,onOpenChange:t=>{t||v(null)},title:s("facts.action.confirmDelete"),description:s("facts.action.confirmDeleteDesc"),intent:"danger",confirmLabel:s("facts.action.delete"),onConfirm:Q}),e.jsx(M,{open:V,onOpenChange:O,title:s("facts.batch.confirmDelete",{count:N}),description:s("facts.batch.confirmDeleteDesc"),intent:"danger",confirmLabel:s("facts.batch.deleteSelected"),onConfirm:$})]})}function fe(s){try{const n=new Date(s);return Number.isNaN(n.getTime())?String(s):n.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(s)}}export{Ee as default};
2
- //# sourceMappingURL=facts-cmX647ty.js.map
1
+ import{ac as K,ab as Y,Q as e,B as D,c as b,L as E,I as J,S as W,l as X,m as Z,j as ee,k,a2 as p,z as T}from"./index-B48azMO-.js";import{e as r}from"./react-C9F3QeMB.js";import{D as te}from"./data-table-B_BxQrSj.js";import{E as B}from"./empty-state-BKs1qKHx.js";import{P as se}from"./pagination-R9mql8VB.js";import{C as M}from"./confirm-dialog-BEzhDlk7.js";import{d as ae,b as ne,u as ce}from"./use-memory-CElm89Hg.js";import{T as A}from"./trash-2-BkZrVFdH.js";import{B as R}from"./brain-fC59o4ZL.js";import{L as re}from"./loader-circle-DBf4xFjo.js";import{R as ie}from"./refresh-ccw-Clj5sQNF.js";import{S as le}from"./search-bDqizeZv.js";import"./table-CZwKizat.js";import"./chevron-right-DzyVDoQs.js";import"./dialog-BAZNQtMt.js";import"./x-CHe1y-sG.js";import"./useQuery-BjFqOBV3.js";const oe=["fact","preference","goal","history","profile"],me=[25,50,100],F=50,de=300;function Ee(){const{t:s}=K(["memory","common"]),[n,L]=Y(),c=n.get("user")??"",i=n.get("q")??"",m=n.get("cat")??null,d=Math.max(1,Number(n.get("page"))||1),l=Number(n.get("per_page"))||F,[f,I]=r.useState(i);r.useEffect(()=>{if(f===i)return;const t=window.setTimeout(()=>h({q:f||null}),de);return()=>window.clearTimeout(t)},[f]);const q=r.useMemo(()=>({user_key:c,...i?{query:i}:{},...m?{category:m}:{},limit:l,offset:(d-1)*l}),[c,i,m,d,l]),{data:S,isLoading:z,isFetching:C,refetch:U}=ae(q,{enabled:!!c}),_=S?.facts??[],P=S?.total??0,G=Math.max(1,Math.ceil(P/l)),[u,g]=r.useState(new Set);r.useEffect(()=>{g(new Set)},[c,i,m,d,l]);const j=ne(),x=ce(),[y,v]=r.useState(null),[V,O]=r.useState(!1);function h(t){const a=new URLSearchParams(n);for(const[o,w]of Object.entries(t))w==null||w===""?a.delete(o):a.set(o,w);Object.keys(t).some(o=>o!=="page")&&a.delete("page"),L(a,{replace:!1})}async function Q(){if(!(y==null||!c))try{await j.mutateAsync({id:y,user_key:c}),p.success(s("facts.toast.deletedOne"))}catch(t){const{message:a}=T(t,s);throw p.error(a),t}}async function $(){if(!c||u.size===0)return;const t=Array.from(u).map(Number).filter(Number.isFinite);try{const a=await x.mutateAsync({user_key:c,body:{ids:t}});p.success(s("facts.toast.deletedMany",{count:a.deleted})),g(new Set)}catch(a){const{message:o}=T(a,s);throw p.error(o),a}}const H=r.useMemo(()=>[{id:"id",header:s("facts.col.id"),cell:t=>e.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",t.id]}),headClassName:"w-16"},{id:"what",header:s("facts.col.what"),cell:t=>e.jsx("span",{className:"line-clamp-2 text-text",children:t.what}),asCardTitle:!0},{id:"category",header:s("facts.col.category"),cell:t=>e.jsx(D,{variant:"outline",children:s(`facts.category.${t.category}`,{defaultValue:t.category})}),headClassName:"w-28"},{id:"confidence",header:s("facts.col.confidence"),cell:t=>e.jsx("span",{className:"tabular-nums text-text-dim",children:t.confidence.toFixed(2)}),headClassName:"w-24",hideOnMobile:!0},{id:"source",header:s("facts.col.source"),cell:t=>e.jsx("span",{className:"text-text-dim text-xs",children:t.source}),headClassName:"w-28",hideOnMobile:!0},{id:"createdAt",header:s("facts.col.createdAt"),cell:t=>e.jsx("span",{className:"text-text-dim",children:fe(t.created_at)}),headClassName:"w-32",hideOnMobile:!0},{id:"actions",header:"",cell:t=>e.jsx("div",{className:"flex justify-end",children:e.jsxs(b,{variant:"ghost",size:"sm",onClick:a=>{a.stopPropagation(),v(t.id)},disabled:j.isPending||x.isPending,"aria-label":s("facts.action.delete"),children:[e.jsx(A,{className:"h-3 w-3"}),e.jsx("span",{className:"sr-only sm:not-sr-only sm:ml-1",children:s("facts.action.delete")})]})}),headClassName:"w-24"}],[s,j.isPending,x.isPending]);if(!c)return e.jsx("div",{className:"mx-auto max-w-3xl",children:e.jsx(B,{icon:e.jsx(R,{}),title:s("noUserSelected.title"),description:s("noUserSelected.description")})});const N=u.size;return e.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("facts.title")}),e.jsxs(b,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>U(),disabled:C,"aria-label":s("actions.refresh",{ns:"common"}),children:[C?e.jsx(re,{className:"h-4 w-4 animate-spin"}):e.jsx(ie,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("subtitle")})]}),e.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[e.jsxs("div",{className:"relative flex-1 min-w-[200px] max-w-md",children:[e.jsx(E,{htmlFor:"search",className:"text-xs text-text-dim",children:s("facts.filter.search")}),e.jsx(le,{className:"pointer-events-none absolute left-2 bottom-2 h-4 w-4 text-text-muted"}),e.jsx(J,{id:"search",value:f,onChange:t=>I(t.target.value),className:"pl-7 mt-1"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(E,{htmlFor:"category",className:"text-xs text-text-dim",children:s("facts.filter.category")}),e.jsxs(W,{value:m??"__any__",onValueChange:t=>h({cat:t==="__any__"?null:t}),children:[e.jsx(X,{id:"category",className:"w-[140px]",children:e.jsx(Z,{})}),e.jsxs(ee,{children:[e.jsx(k,{value:"__any__",children:s("facts.filter.categoryAny")}),oe.map(t=>e.jsx(k,{value:t,children:s(`facts.category.${t}`)},t))]})]})]}),N>0&&e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[e.jsx(D,{variant:"secondary",children:s("facts.batch.selected",{count:N})}),e.jsxs(b,{variant:"destructive",size:"sm",onClick:()=>O(!0),disabled:x.isPending,children:[e.jsx(A,{className:"h-4 w-4"}),s("facts.batch.deleteSelected")]})]})]}),e.jsx(te,{columns:H,rows:_,getRowId:t=>String(t.id),loading:z,selection:u,onSelectionChange:g,emptyState:e.jsx(B,{icon:e.jsx(R,{}),title:s("facts.empty.title"),description:s("facts.empty.description")})}),(_.length>0||d>1)&&e.jsx(se,{page:d,totalPages:G,totalRows:P,perPage:l,perPageOptions:me,onPageChange:t=>h({page:t===1?null:String(t)}),onPerPageChange:t=>h({per_page:t===F?null:String(t)})}),e.jsx(M,{open:y!=null,onOpenChange:t=>{t||v(null)},title:s("facts.action.confirmDelete"),description:s("facts.action.confirmDeleteDesc"),intent:"danger",confirmLabel:s("facts.action.delete"),onConfirm:Q}),e.jsx(M,{open:V,onOpenChange:O,title:s("facts.batch.confirmDelete",{count:N}),description:s("facts.batch.confirmDeleteDesc"),intent:"danger",confirmLabel:s("facts.batch.deleteSelected"),onConfirm:$})]})}function fe(s){try{const n=new Date(s);return Number.isNaN(n.getTime())?String(s):n.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(s)}}export{Ee as default};
2
+ //# sourceMappingURL=facts-B7VlqoVs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"facts-cmX647ty.js","sources":["../../src/routes/memory/facts.tsx"],"sourcesContent":["/**\n * /memory/facts — list / search / delete the user's facts.\n *\n * Reads `?user=` from the URL (the layout writes it). Without a\n * user_key the route shows a friendly empty state pointing at the\n * picker — no query fires until a user is chosen.\n *\n * Search + category filter live in URL params so deep-link sharing\n * works (\"show me john's goals matching tax\"). The free-text input\n * is local-only with a 300ms debounce, same pattern as /memos, so\n * the FTS5 layer isn't hit on every keystroke.\n *\n * Single-row delete via the per-row Delete button; batch delete via\n * checkbox selection + the bulk-delete action bar. Both route\n * through ConfirmDialog.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Brain, Loader2, RefreshCcw, Search, Trash2 } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\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 { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useMemoryFacts,\n useDeleteFactById,\n useBulkDeleteFacts,\n} from '@/hooks/use-memory'\nimport { describeError } from '@/lib/api/errors'\nimport type { Fact, FactCategory, ListMemoryFactsQuery } from '@/types/api'\n\nconst CATEGORY_OPTIONS: FactCategory[] = ['fact', 'preference', 'goal', 'history', 'profile']\nconst PER_PAGE_OPTIONS = [25, 50, 100]\nconst DEFAULT_PER_PAGE = 50\nconst SEARCH_DEBOUNCE_MS = 300\n\nexport default function MemoryFactsRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const [params, setParams] = useSearchParams()\n\n const userKey = params.get('user') ?? ''\n const q = params.get('q') ?? ''\n const cat = (params.get('cat') as FactCategory | null) ?? null\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n\n const [qDraft, setQDraft] = useState(q)\n useEffect(() => {\n if (qDraft === q) return\n const timer = window.setTimeout(() => patchParams({ q: qDraft || null }), SEARCH_DEBOUNCE_MS)\n return () => window.clearTimeout(timer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [qDraft])\n\n const query: ListMemoryFactsQuery = useMemo(\n () => ({\n user_key: userKey,\n ...(q ? { query: q } : {}),\n ...(cat ? { category: cat } : {}),\n limit: perPage,\n offset: (page - 1) * perPage,\n }),\n [userKey, q, cat, page, perPage],\n )\n\n const { data, isLoading, isFetching, refetch } = useMemoryFacts(query, { enabled: Boolean(userKey) })\n const facts = data?.facts ?? []\n const total = data?.total ?? 0\n const totalPages = Math.max(1, Math.ceil(total / perPage))\n\n // Selection state for the bulk delete bar.\n const [selection, setSelection] = useState<Set<string>>(new Set())\n useEffect(() => { setSelection(new Set()) }, [userKey, q, cat, page, perPage])\n\n const deleteOne = useDeleteFactById()\n const bulkDelete = useBulkDeleteFacts()\n\n const [confirmOneId, setConfirmOneId] = useState<number | null>(null)\n const [confirmBulk, setConfirmBulk] = useState(false)\n\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 // Reset to page 1 on any filter mutation.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n async function onConfirmDeleteOne(): Promise<void> {\n if (confirmOneId == null || !userKey) return\n try {\n await deleteOne.mutateAsync({ id: confirmOneId, user_key: userKey })\n toast.success(t('facts.toast.deletedOne'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n async function onConfirmBulk(): Promise<void> {\n if (!userKey || selection.size === 0) return\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n try {\n const r = await bulkDelete.mutateAsync({ user_key: userKey, body: { ids } })\n toast.success(t('facts.toast.deletedMany', { count: r.deleted }))\n setSelection(new Set())\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<Fact>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('facts.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'what',\n header: t('facts.col.what'),\n cell: (r) => <span className=\"line-clamp-2 text-text\">{r.what}</span>,\n asCardTitle: true,\n },\n {\n id: 'category',\n header: t('facts.col.category'),\n cell: (r) => (\n <Badge variant=\"outline\">\n {t(`facts.category.${r.category}`, { defaultValue: r.category })}\n </Badge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'confidence',\n header: t('facts.col.confidence'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">{r.confidence.toFixed(2)}</span>,\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'source',\n header: t('facts.col.source'),\n cell: (r) => <span className=\"text-text-dim text-xs\">{r.source}</span>,\n headClassName: 'w-28',\n hideOnMobile: true,\n },\n {\n id: 'createdAt',\n header: t('facts.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatEpoch(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) => (\n <div className=\"flex justify-end\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmOneId(r.id)\n }}\n disabled={deleteOne.isPending || bulkDelete.isPending}\n aria-label={t('facts.action.delete')}\n >\n <Trash2 className=\"h-3 w-3\" />\n <span className=\"sr-only sm:not-sr-only sm:ml-1\">{t('facts.action.delete')}</span>\n </Button>\n </div>\n ),\n headClassName: 'w-24',\n },\n ],\n [t, deleteOne.isPending, bulkDelete.isPending],\n )\n\n if (!userKey) {\n return (\n <div className=\"mx-auto max-w-3xl\">\n <EmptyState\n icon={<Brain />}\n title={t('noUserSelected.title')}\n description={t('noUserSelected.description')}\n />\n </div>\n )\n }\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\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('facts.title')}</h1>\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('subtitle')}</p>\n </header>\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"relative flex-1 min-w-[200px] max-w-md\">\n <Label htmlFor=\"search\" className=\"text-xs text-text-dim\">\n {t('facts.filter.search')}\n </Label>\n <Search className=\"pointer-events-none absolute left-2 bottom-2 h-4 w-4 text-text-muted\" />\n <Input\n id=\"search\"\n value={qDraft}\n onChange={(e) => setQDraft(e.target.value)}\n className=\"pl-7 mt-1\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"category\" className=\"text-xs text-text-dim\">\n {t('facts.filter.category')}\n </Label>\n <Select\n value={cat ?? '__any__'}\n onValueChange={(v) => patchParams({ cat: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"category\" className=\"w-[140px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('facts.filter.categoryAny')}</SelectItem>\n {CATEGORY_OPTIONS.map((c) => (\n <SelectItem key={c} value={c}>\n {t(`facts.category.${c}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('facts.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmBulk(true)}\n disabled={bulkDelete.isPending}\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('facts.batch.deleteSelected')}\n </Button>\n </div>\n )}\n </div>\n\n <DataTable\n columns={columns}\n rows={facts}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Brain />}\n title={t('facts.empty.title')}\n description={t('facts.empty.description')}\n />\n }\n />\n\n {(facts.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={total}\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={confirmOneId != null}\n onOpenChange={(open) => { if (!open) setConfirmOneId(null) }}\n title={t('facts.action.confirmDelete')}\n description={t('facts.action.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('facts.action.delete')}\n onConfirm={onConfirmDeleteOne}\n />\n\n <ConfirmDialog\n open={confirmBulk}\n onOpenChange={setConfirmBulk}\n title={t('facts.batch.confirmDelete', { count: selectedCount })}\n description={t('facts.batch.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('facts.batch.deleteSelected')}\n onConfirm={onConfirmBulk}\n />\n </div>\n )\n}\n\n/** Format an epoch-ms number as a short locale string. */\nfunction formatEpoch(ms: number): string {\n try {\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return String(ms)\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return String(ms)\n }\n}\n"],"names":["CATEGORY_OPTIONS","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","SEARCH_DEBOUNCE_MS","MemoryFactsRoute","t","useTranslation","params","setParams","useSearchParams","userKey","q","cat","page","perPage","qDraft","setQDraft","useState","useEffect","timer","patchParams","query","useMemo","data","isLoading","isFetching","refetch","useMemoryFacts","facts","total","totalPages","selection","setSelection","deleteOne","useDeleteFactById","bulkDelete","useBulkDeleteFacts","confirmOneId","setConfirmOneId","confirmBulk","setConfirmBulk","patch","next","k","v","onConfirmDeleteOne","toast","err","message","describeError","onConfirmBulk","ids","r","columns","jsxs","jsx","Badge","formatEpoch","Button","e","Trash2","EmptyState","Brain","selectedCount","Loader2","RefreshCcw","Label","Search","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","c","DataTable","Pagination","p","pp","ConfirmDialog","open","ms","d"],"mappings":"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"}
1
+ {"version":3,"file":"facts-B7VlqoVs.js","sources":["../../src/routes/memory/facts.tsx"],"sourcesContent":["/**\n * /memory/facts — list / search / delete the user's facts.\n *\n * Reads `?user=` from the URL (the layout writes it). Without a\n * user_key the route shows a friendly empty state pointing at the\n * picker — no query fires until a user is chosen.\n *\n * Search + category filter live in URL params so deep-link sharing\n * works (\"show me john's goals matching tax\"). The free-text input\n * is local-only with a 300ms debounce, same pattern as /memos, so\n * the FTS5 layer isn't hit on every keystroke.\n *\n * Single-row delete via the per-row Delete button; batch delete via\n * checkbox selection + the bulk-delete action bar. Both route\n * through ConfirmDialog.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Brain, Loader2, RefreshCcw, Search, Trash2 } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\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 { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useMemoryFacts,\n useDeleteFactById,\n useBulkDeleteFacts,\n} from '@/hooks/use-memory'\nimport { describeError } from '@/lib/api/errors'\nimport type { Fact, FactCategory, ListMemoryFactsQuery } from '@/types/api'\n\nconst CATEGORY_OPTIONS: FactCategory[] = ['fact', 'preference', 'goal', 'history', 'profile']\nconst PER_PAGE_OPTIONS = [25, 50, 100]\nconst DEFAULT_PER_PAGE = 50\nconst SEARCH_DEBOUNCE_MS = 300\n\nexport default function MemoryFactsRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const [params, setParams] = useSearchParams()\n\n const userKey = params.get('user') ?? ''\n const q = params.get('q') ?? ''\n const cat = (params.get('cat') as FactCategory | null) ?? null\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n\n const [qDraft, setQDraft] = useState(q)\n useEffect(() => {\n if (qDraft === q) return\n const timer = window.setTimeout(() => patchParams({ q: qDraft || null }), SEARCH_DEBOUNCE_MS)\n return () => window.clearTimeout(timer)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [qDraft])\n\n const query: ListMemoryFactsQuery = useMemo(\n () => ({\n user_key: userKey,\n ...(q ? { query: q } : {}),\n ...(cat ? { category: cat } : {}),\n limit: perPage,\n offset: (page - 1) * perPage,\n }),\n [userKey, q, cat, page, perPage],\n )\n\n const { data, isLoading, isFetching, refetch } = useMemoryFacts(query, { enabled: Boolean(userKey) })\n const facts = data?.facts ?? []\n const total = data?.total ?? 0\n const totalPages = Math.max(1, Math.ceil(total / perPage))\n\n // Selection state for the bulk delete bar.\n const [selection, setSelection] = useState<Set<string>>(new Set())\n useEffect(() => { setSelection(new Set()) }, [userKey, q, cat, page, perPage])\n\n const deleteOne = useDeleteFactById()\n const bulkDelete = useBulkDeleteFacts()\n\n const [confirmOneId, setConfirmOneId] = useState<number | null>(null)\n const [confirmBulk, setConfirmBulk] = useState(false)\n\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 // Reset to page 1 on any filter mutation.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n async function onConfirmDeleteOne(): Promise<void> {\n if (confirmOneId == null || !userKey) return\n try {\n await deleteOne.mutateAsync({ id: confirmOneId, user_key: userKey })\n toast.success(t('facts.toast.deletedOne'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n async function onConfirmBulk(): Promise<void> {\n if (!userKey || selection.size === 0) return\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n try {\n const r = await bulkDelete.mutateAsync({ user_key: userKey, body: { ids } })\n toast.success(t('facts.toast.deletedMany', { count: r.deleted }))\n setSelection(new Set())\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<Fact>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('facts.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'what',\n header: t('facts.col.what'),\n cell: (r) => <span className=\"line-clamp-2 text-text\">{r.what}</span>,\n asCardTitle: true,\n },\n {\n id: 'category',\n header: t('facts.col.category'),\n cell: (r) => (\n <Badge variant=\"outline\">\n {t(`facts.category.${r.category}`, { defaultValue: r.category })}\n </Badge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'confidence',\n header: t('facts.col.confidence'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">{r.confidence.toFixed(2)}</span>,\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'source',\n header: t('facts.col.source'),\n cell: (r) => <span className=\"text-text-dim text-xs\">{r.source}</span>,\n headClassName: 'w-28',\n hideOnMobile: true,\n },\n {\n id: 'createdAt',\n header: t('facts.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatEpoch(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) => (\n <div className=\"flex justify-end\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmOneId(r.id)\n }}\n disabled={deleteOne.isPending || bulkDelete.isPending}\n aria-label={t('facts.action.delete')}\n >\n <Trash2 className=\"h-3 w-3\" />\n <span className=\"sr-only sm:not-sr-only sm:ml-1\">{t('facts.action.delete')}</span>\n </Button>\n </div>\n ),\n headClassName: 'w-24',\n },\n ],\n [t, deleteOne.isPending, bulkDelete.isPending],\n )\n\n if (!userKey) {\n return (\n <div className=\"mx-auto max-w-3xl\">\n <EmptyState\n icon={<Brain />}\n title={t('noUserSelected.title')}\n description={t('noUserSelected.description')}\n />\n </div>\n )\n }\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\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('facts.title')}</h1>\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('subtitle')}</p>\n </header>\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"relative flex-1 min-w-[200px] max-w-md\">\n <Label htmlFor=\"search\" className=\"text-xs text-text-dim\">\n {t('facts.filter.search')}\n </Label>\n <Search className=\"pointer-events-none absolute left-2 bottom-2 h-4 w-4 text-text-muted\" />\n <Input\n id=\"search\"\n value={qDraft}\n onChange={(e) => setQDraft(e.target.value)}\n className=\"pl-7 mt-1\"\n />\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"category\" className=\"text-xs text-text-dim\">\n {t('facts.filter.category')}\n </Label>\n <Select\n value={cat ?? '__any__'}\n onValueChange={(v) => patchParams({ cat: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"category\" className=\"w-[140px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('facts.filter.categoryAny')}</SelectItem>\n {CATEGORY_OPTIONS.map((c) => (\n <SelectItem key={c} value={c}>\n {t(`facts.category.${c}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('facts.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmBulk(true)}\n disabled={bulkDelete.isPending}\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('facts.batch.deleteSelected')}\n </Button>\n </div>\n )}\n </div>\n\n <DataTable\n columns={columns}\n rows={facts}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Brain />}\n title={t('facts.empty.title')}\n description={t('facts.empty.description')}\n />\n }\n />\n\n {(facts.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={total}\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={confirmOneId != null}\n onOpenChange={(open) => { if (!open) setConfirmOneId(null) }}\n title={t('facts.action.confirmDelete')}\n description={t('facts.action.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('facts.action.delete')}\n onConfirm={onConfirmDeleteOne}\n />\n\n <ConfirmDialog\n open={confirmBulk}\n onOpenChange={setConfirmBulk}\n title={t('facts.batch.confirmDelete', { count: selectedCount })}\n description={t('facts.batch.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('facts.batch.deleteSelected')}\n onConfirm={onConfirmBulk}\n />\n </div>\n )\n}\n\n/** Format an epoch-ms number as a short locale string. */\nfunction formatEpoch(ms: number): string {\n try {\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return String(ms)\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return String(ms)\n }\n}\n"],"names":["CATEGORY_OPTIONS","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","SEARCH_DEBOUNCE_MS","MemoryFactsRoute","t","useTranslation","params","setParams","useSearchParams","userKey","q","cat","page","perPage","qDraft","setQDraft","useState","useEffect","timer","patchParams","query","useMemo","data","isLoading","isFetching","refetch","useMemoryFacts","facts","total","totalPages","selection","setSelection","deleteOne","useDeleteFactById","bulkDelete","useBulkDeleteFacts","confirmOneId","setConfirmOneId","confirmBulk","setConfirmBulk","patch","next","k","v","onConfirmDeleteOne","toast","err","message","describeError","onConfirmBulk","ids","r","columns","jsxs","jsx","Badge","formatEpoch","Button","e","Trash2","EmptyState","Brain","selectedCount","Loader2","RefreshCcw","Label","Search","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","c","DataTable","Pagination","p","pp","ConfirmDialog","open","ms","d"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{ac as p,ab as f,Q as e,c as g,r as y}from"./index-BAK3HT1o.js";import{e as N}from"./react-C9F3QeMB.js";import{E as v}from"./empty-state--qSLu4iL.js";import{T as w,d as C,e as h,c as i,a as M,b as o}from"./table-CTNMqGvo.js";import{a as L}from"./use-observability-CUbSm1kG.js";import{L as T}from"./loader-circle-CXl24wsB.js";import{R as k}from"./refresh-ccw-ChTs-DiT.js";import{A as D}from"./activity-DFB1UVF1.js";import"./useQuery-CBD2h35Q.js";function P(){const{t:s}=p(["observability","common"]),[l]=f(),n=Math.max(1,Number(l.get("days"))||7),{data:c,isLoading:u,isFetching:m,refetch:b}=L(n),a=c?.totals,d=c?.byDay??[],j=N.useMemo(()=>d.reduce((t,x)=>x.calls>t?x.calls:t,0),[d]);return e.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("health.title")}),e.jsxs(g,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>b(),disabled:m,"aria-label":s("actions.refresh",{ns:"common"}),children:[m?e.jsx(T,{className:"h-4 w-4 animate-spin"}):e.jsx(k,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),c&&e.jsxs("p",{className:"text-xs text-text-dim tabular-nums",children:[c.since," → ",c.until]})]}),u?e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"}):!a||a.calls===0&&d.length===0?e.jsx(v,{icon:e.jsx(D,{}),title:s("health.empty.title"),description:s("health.empty.description")}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-6",children:[e.jsx(r,{label:s("health.kpi.calls"),value:String(a.calls),tone:"info"}),e.jsx(r,{label:s("health.kpi.cost"),value:`$${a.cost.toFixed(4)}`,tone:"info"}),e.jsx(r,{label:s("health.kpi.errors"),value:String(a.errors),tone:a.errors>0?"danger":"success"}),e.jsx(r,{label:s("health.kpi.errorRate"),value:`${(a.errorRate*100).toFixed(1)}%`,tone:a.errorRate>.05?"warning":"success"}),e.jsx(r,{label:s("health.kpi.avgLatencyMs"),value:`${Math.round(a.avgLatencyMs)}ms`,tone:"info"}),e.jsx(r,{label:s("health.kpi.p95LatencyMs"),value:`${Math.round(a.p95LatencyMs)}ms`,tone:"info"})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"mb-2 text-sm font-medium uppercase tracking-wide text-text-dim",children:s("health.byDay")}),e.jsxs(w,{children:[e.jsx(C,{children:e.jsxs(h,{children:[e.jsx(i,{className:"w-28",children:s("health.byDayCol.date")}),e.jsx(i,{children:s("health.byDayCol.calls")}),e.jsx(i,{className:"w-24",children:s("health.byDayCol.cost")}),e.jsx(i,{className:"w-24",children:s("health.byDayCol.errors")}),e.jsx(i,{className:"w-32",children:s("health.byDayCol.avgLatencyMs")})]})}),e.jsx(M,{children:d.map(t=>e.jsxs(h,{children:[e.jsx(o,{className:"font-mono text-xs",children:t.date}),e.jsx(o,{children:e.jsx(S,{value:t.calls,max:j})}),e.jsxs(o,{className:"tabular-nums",children:["$",t.cost.toFixed(4)]}),e.jsx(o,{className:"tabular-nums",children:e.jsx("span",{className:t.errors>0?"text-danger":"text-text-dim",children:t.errors})}),e.jsxs(o,{className:"tabular-nums",children:[Math.round(t.avgLatencyMs),"ms"]})]},t.date))})]})]})]})]})}const R={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 r({label:s,value:l,tone:n}){return e.jsxs("div",{className:y("rounded-md border bg-surface px-3 py-2",R[n]),children:[e.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:s}),e.jsx("div",{className:"text-xl font-semibold tabular-nums",children:l})]})}function S({value:s,max:l}){const n=l>0?s/l*100:0;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"relative h-3 w-full max-w-xs overflow-hidden rounded bg-surface-2",children:e.jsx("div",{className:"absolute inset-y-0 left-0 bg-accent/60",style:{width:`${n}%`}})}),e.jsx("span",{className:"tabular-nums text-sm text-text-dim",children:s})]})}export{P as default};
2
- //# sourceMappingURL=health-Co_2jH5V.js.map
1
+ import{ac as p,ab as f,Q as e,c as g,r as y}from"./index-B48azMO-.js";import{e as N}from"./react-C9F3QeMB.js";import{E as v}from"./empty-state-BKs1qKHx.js";import{T as w,d as C,e as h,c as i,a as M,b as o}from"./table-CZwKizat.js";import{a as L}from"./use-observability-D8qHfj0S.js";import{L as T}from"./loader-circle-DBf4xFjo.js";import{R as k}from"./refresh-ccw-Clj5sQNF.js";import{A as D}from"./activity-BJqk7b-v.js";import"./useQuery-BjFqOBV3.js";function P(){const{t:s}=p(["observability","common"]),[l]=f(),n=Math.max(1,Number(l.get("days"))||7),{data:c,isLoading:u,isFetching:m,refetch:b}=L(n),a=c?.totals,d=c?.byDay??[],j=N.useMemo(()=>d.reduce((t,x)=>x.calls>t?x.calls:t,0),[d]);return e.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("health.title")}),e.jsxs(g,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>b(),disabled:m,"aria-label":s("actions.refresh",{ns:"common"}),children:[m?e.jsx(T,{className:"h-4 w-4 animate-spin"}):e.jsx(k,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),c&&e.jsxs("p",{className:"text-xs text-text-dim tabular-nums",children:[c.since," → ",c.until]})]}),u?e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"}):!a||a.calls===0&&d.length===0?e.jsx(v,{icon:e.jsx(D,{}),title:s("health.empty.title"),description:s("health.empty.description")}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-6",children:[e.jsx(r,{label:s("health.kpi.calls"),value:String(a.calls),tone:"info"}),e.jsx(r,{label:s("health.kpi.cost"),value:`$${a.cost.toFixed(4)}`,tone:"info"}),e.jsx(r,{label:s("health.kpi.errors"),value:String(a.errors),tone:a.errors>0?"danger":"success"}),e.jsx(r,{label:s("health.kpi.errorRate"),value:`${(a.errorRate*100).toFixed(1)}%`,tone:a.errorRate>.05?"warning":"success"}),e.jsx(r,{label:s("health.kpi.avgLatencyMs"),value:`${Math.round(a.avgLatencyMs)}ms`,tone:"info"}),e.jsx(r,{label:s("health.kpi.p95LatencyMs"),value:`${Math.round(a.p95LatencyMs)}ms`,tone:"info"})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"mb-2 text-sm font-medium uppercase tracking-wide text-text-dim",children:s("health.byDay")}),e.jsxs(w,{children:[e.jsx(C,{children:e.jsxs(h,{children:[e.jsx(i,{className:"w-28",children:s("health.byDayCol.date")}),e.jsx(i,{children:s("health.byDayCol.calls")}),e.jsx(i,{className:"w-24",children:s("health.byDayCol.cost")}),e.jsx(i,{className:"w-24",children:s("health.byDayCol.errors")}),e.jsx(i,{className:"w-32",children:s("health.byDayCol.avgLatencyMs")})]})}),e.jsx(M,{children:d.map(t=>e.jsxs(h,{children:[e.jsx(o,{className:"font-mono text-xs",children:t.date}),e.jsx(o,{children:e.jsx(S,{value:t.calls,max:j})}),e.jsxs(o,{className:"tabular-nums",children:["$",t.cost.toFixed(4)]}),e.jsx(o,{className:"tabular-nums",children:e.jsx("span",{className:t.errors>0?"text-danger":"text-text-dim",children:t.errors})}),e.jsxs(o,{className:"tabular-nums",children:[Math.round(t.avgLatencyMs),"ms"]})]},t.date))})]})]})]})]})}const R={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 r({label:s,value:l,tone:n}){return e.jsxs("div",{className:y("rounded-md border bg-surface px-3 py-2",R[n]),children:[e.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:s}),e.jsx("div",{className:"text-xl font-semibold tabular-nums",children:l})]})}function S({value:s,max:l}){const n=l>0?s/l*100:0;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"relative h-3 w-full max-w-xs overflow-hidden rounded bg-surface-2",children:e.jsx("div",{className:"absolute inset-y-0 left-0 bg-accent/60",style:{width:`${n}%`}})}),e.jsx("span",{className:"tabular-nums text-sm text-text-dim",children:s})]})}export{P as default};
2
+ //# sourceMappingURL=health-IF_VcgWW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"health-Co_2jH5V.js","sources":["../../src/routes/observability/health.tsx"],"sourcesContent":["/**\n * /observability/health — invocation totals + per-day breakdown.\n *\n * No chart library yet (would push bundle past budget). Instead we\n * render a CSS bar chart inline: each byDay row gets a horizontal\n * bar proportional to the max calls across the window. Cheap,\n * readable, no JS dependency.\n */\n\nimport { useMemo } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Activity, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { Button } from '@/components/ui/button'\nimport { useHealthSummary } from '@/hooks/use-observability'\nimport { cn } from '@/lib/utils'\n\nexport default function ObservabilityHealthRoute(): JSX.Element {\n const { t } = useTranslation(['observability', 'common'])\n const [params] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n\n const { data, isLoading, isFetching, refetch } = useHealthSummary(days)\n const totals = data?.totals\n const byDay = data?.byDay ?? []\n\n const maxCalls = useMemo(\n () => byDay.reduce((m, r) => (r.calls > m ? r.calls : m), 0),\n [byDay],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\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('health.title')}</h1>\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 {data && (\n <p className=\"text-xs text-text-dim tabular-nums\">{data.since} → {data.until}</p>\n )}\n </header>\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : !totals || (totals.calls === 0 && byDay.length === 0) ? (\n <EmptyState\n icon={<Activity />}\n title={t('health.empty.title')}\n description={t('health.empty.description')}\n />\n ) : (\n <>\n {/* KPI strip */}\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-6\">\n <Kpi label={t('health.kpi.calls')} value={String(totals.calls)} tone=\"info\" />\n <Kpi label={t('health.kpi.cost')} value={`$${totals.cost.toFixed(4)}`} tone=\"info\" />\n <Kpi label={t('health.kpi.errors')} value={String(totals.errors)} tone={totals.errors > 0 ? 'danger' : 'success'} />\n <Kpi label={t('health.kpi.errorRate')} value={`${(totals.errorRate * 100).toFixed(1)}%`} tone={totals.errorRate > 0.05 ? 'warning' : 'success'} />\n <Kpi label={t('health.kpi.avgLatencyMs')} value={`${Math.round(totals.avgLatencyMs)}ms`} tone=\"info\" />\n <Kpi label={t('health.kpi.p95LatencyMs')} value={`${Math.round(totals.p95LatencyMs)}ms`} tone=\"info\" />\n </div>\n\n {/* By-day table with inline CSS bars */}\n <div>\n <h2 className=\"mb-2 text-sm font-medium uppercase tracking-wide text-text-dim\">\n {t('health.byDay')}\n </h2>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-28\">{t('health.byDayCol.date')}</TableHead>\n <TableHead>{t('health.byDayCol.calls')}</TableHead>\n <TableHead className=\"w-24\">{t('health.byDayCol.cost')}</TableHead>\n <TableHead className=\"w-24\">{t('health.byDayCol.errors')}</TableHead>\n <TableHead className=\"w-32\">{t('health.byDayCol.avgLatencyMs')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {byDay.map((r) => (\n <TableRow key={r.date}>\n <TableCell className=\"font-mono text-xs\">{r.date}</TableCell>\n <TableCell>\n <CallsBar value={r.calls} max={maxCalls} />\n </TableCell>\n <TableCell className=\"tabular-nums\">${r.cost.toFixed(4)}</TableCell>\n <TableCell className=\"tabular-nums\">\n <span className={r.errors > 0 ? 'text-danger' : 'text-text-dim'}>{r.errors}</span>\n </TableCell>\n <TableCell className=\"tabular-nums\">{Math.round(r.avgLatencyMs)}ms</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </>\n )}\n </div>\n )\n}\n\ninterface KpiProps {\n label: string\n value: string\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<KpiProps['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 Kpi({ label, value, tone }: KpiProps): JSX.Element {\n return (\n <div className={cn('rounded-md border bg-surface px-3 py-2', TONE_STYLES[tone])}>\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\ninterface CallsBarProps {\n value: number\n max: number\n}\n\n/** Inline CSS bar — width proportional to max across the window. */\nfunction CallsBar({ value, max }: CallsBarProps): JSX.Element {\n const pct = max > 0 ? (value / max) * 100 : 0\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"relative h-3 w-full max-w-xs overflow-hidden rounded bg-surface-2\">\n <div\n className=\"absolute inset-y-0 left-0 bg-accent/60\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"tabular-nums text-sm text-text-dim\">{value}</span>\n </div>\n )\n}\n"],"names":["ObservabilityHealthRoute","t","useTranslation","params","useSearchParams","days","data","isLoading","isFetching","refetch","useHealthSummary","totals","byDay","maxCalls","useMemo","m","r","jsxs","jsx","Button","Loader2","RefreshCcw","EmptyState","Activity","Fragment","Kpi","Table","TableHeader","TableRow","TableHead","TableBody","TableCell","CallsBar","TONE_STYLES","label","value","tone","cn","max","pct"],"mappings":"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"}
1
+ {"version":3,"file":"health-IF_VcgWW.js","sources":["../../src/routes/observability/health.tsx"],"sourcesContent":["/**\n * /observability/health — invocation totals + per-day breakdown.\n *\n * No chart library yet (would push bundle past budget). Instead we\n * render a CSS bar chart inline: each byDay row gets a horizontal\n * bar proportional to the max calls across the window. Cheap,\n * readable, no JS dependency.\n */\n\nimport { useMemo } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Activity, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { Button } from '@/components/ui/button'\nimport { useHealthSummary } from '@/hooks/use-observability'\nimport { cn } from '@/lib/utils'\n\nexport default function ObservabilityHealthRoute(): JSX.Element {\n const { t } = useTranslation(['observability', 'common'])\n const [params] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n\n const { data, isLoading, isFetching, refetch } = useHealthSummary(days)\n const totals = data?.totals\n const byDay = data?.byDay ?? []\n\n const maxCalls = useMemo(\n () => byDay.reduce((m, r) => (r.calls > m ? r.calls : m), 0),\n [byDay],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\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('health.title')}</h1>\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 {data && (\n <p className=\"text-xs text-text-dim tabular-nums\">{data.since} → {data.until}</p>\n )}\n </header>\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : !totals || (totals.calls === 0 && byDay.length === 0) ? (\n <EmptyState\n icon={<Activity />}\n title={t('health.empty.title')}\n description={t('health.empty.description')}\n />\n ) : (\n <>\n {/* KPI strip */}\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-6\">\n <Kpi label={t('health.kpi.calls')} value={String(totals.calls)} tone=\"info\" />\n <Kpi label={t('health.kpi.cost')} value={`$${totals.cost.toFixed(4)}`} tone=\"info\" />\n <Kpi label={t('health.kpi.errors')} value={String(totals.errors)} tone={totals.errors > 0 ? 'danger' : 'success'} />\n <Kpi label={t('health.kpi.errorRate')} value={`${(totals.errorRate * 100).toFixed(1)}%`} tone={totals.errorRate > 0.05 ? 'warning' : 'success'} />\n <Kpi label={t('health.kpi.avgLatencyMs')} value={`${Math.round(totals.avgLatencyMs)}ms`} tone=\"info\" />\n <Kpi label={t('health.kpi.p95LatencyMs')} value={`${Math.round(totals.p95LatencyMs)}ms`} tone=\"info\" />\n </div>\n\n {/* By-day table with inline CSS bars */}\n <div>\n <h2 className=\"mb-2 text-sm font-medium uppercase tracking-wide text-text-dim\">\n {t('health.byDay')}\n </h2>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-28\">{t('health.byDayCol.date')}</TableHead>\n <TableHead>{t('health.byDayCol.calls')}</TableHead>\n <TableHead className=\"w-24\">{t('health.byDayCol.cost')}</TableHead>\n <TableHead className=\"w-24\">{t('health.byDayCol.errors')}</TableHead>\n <TableHead className=\"w-32\">{t('health.byDayCol.avgLatencyMs')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {byDay.map((r) => (\n <TableRow key={r.date}>\n <TableCell className=\"font-mono text-xs\">{r.date}</TableCell>\n <TableCell>\n <CallsBar value={r.calls} max={maxCalls} />\n </TableCell>\n <TableCell className=\"tabular-nums\">${r.cost.toFixed(4)}</TableCell>\n <TableCell className=\"tabular-nums\">\n <span className={r.errors > 0 ? 'text-danger' : 'text-text-dim'}>{r.errors}</span>\n </TableCell>\n <TableCell className=\"tabular-nums\">{Math.round(r.avgLatencyMs)}ms</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </>\n )}\n </div>\n )\n}\n\ninterface KpiProps {\n label: string\n value: string\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<KpiProps['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 Kpi({ label, value, tone }: KpiProps): JSX.Element {\n return (\n <div className={cn('rounded-md border bg-surface px-3 py-2', TONE_STYLES[tone])}>\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\ninterface CallsBarProps {\n value: number\n max: number\n}\n\n/** Inline CSS bar — width proportional to max across the window. */\nfunction CallsBar({ value, max }: CallsBarProps): JSX.Element {\n const pct = max > 0 ? (value / max) * 100 : 0\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"relative h-3 w-full max-w-xs overflow-hidden rounded bg-surface-2\">\n <div\n className=\"absolute inset-y-0 left-0 bg-accent/60\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"tabular-nums text-sm text-text-dim\">{value}</span>\n </div>\n )\n}\n"],"names":["ObservabilityHealthRoute","t","useTranslation","params","useSearchParams","days","data","isLoading","isFetching","refetch","useHealthSummary","totals","byDay","maxCalls","useMemo","m","r","jsxs","jsx","Button","Loader2","RefreshCcw","EmptyState","Activity","Fragment","Kpi","Table","TableHeader","TableRow","TableHead","TableBody","TableCell","CallsBar","TONE_STYLES","label","value","tone","cn","max","pct"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{x as p,ac as x,Q as e,c as u,I as v,B as m,r as C,a2 as N}from"./index-BAK3HT1o.js";import{e as c}from"./react-C9F3QeMB.js";import{E as S}from"./empty-state--qSLu4iL.js";import{D as k,a as L,d as D,e as F,b as M}from"./dialog-DzCAOdn8.js";import{b as z}from"./use-skills-DdmwXWK7.js";import{E}from"./external-link-SkbgGADx.js";import{L as R}from"./loader-circle-CXl24wsB.js";import{R as I}from"./refresh-ccw-ChTs-DiT.js";import{S as T}from"./search-CUZFSMD0.js";import{D as A}from"./download-DGggXcuj.js";import"./x-De56D6Eb.js";import"./useQuery-CBD2h35Q.js";/**
1
+ import{x as p,ac as x,Q as e,c as u,I as v,B as m,r as C,a2 as N}from"./index-B48azMO-.js";import{e as c}from"./react-C9F3QeMB.js";import{E as S}from"./empty-state-BKs1qKHx.js";import{D as k,a as L,d as D,e as F,b as M}from"./dialog-BAZNQtMt.js";import{b as z}from"./use-skills-Cp_ok0Uq.js";import{E}from"./external-link-HML--jya.js";import{L as R}from"./loader-circle-DBf4xFjo.js";import{R as I}from"./refresh-ccw-Clj5sQNF.js";import{S as T}from"./search-bDqizeZv.js";import{D as A}from"./download-C08F-eA4.js";import"./x-CHe1y-sG.js";import"./useQuery-BjFqOBV3.js";/**
2
2
  * @license lucide-react v0.469.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -14,4 +14,4 @@ import{x as p,ac as x,Q as e,c as u,I as v,B as m,r as C,a2 as N}from"./index-BA
14
14
  * This source code is licensed under the ISC license.
15
15
  * See the LICENSE file in the root directory of this source tree.
16
16
  */const H=p("Star",[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]]);function ee(){const{t:s}=x(["skills","common"]),{data:l,isLoading:a,isFetching:r,refetch:i}=z(),n=l?.skills??[],[h,b]=c.useState(""),[f,g]=c.useState(null),j=c.useMemo(()=>{const t=h.trim().toLowerCase();return t?n.filter(d=>d.slug.toLowerCase().includes(t)||(d.name||"").toLowerCase().includes(t)||(d.description||"").toLowerCase().includes(t)||(d.category||"").toLowerCase().includes(t)):n},[n,h]),y=f?n.find(t=>t.slug===f)??null:null;return e.jsxs("div",{className:"mx-auto flex max-w-5xl flex-col gap-4",children:[e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("h1",{className:"text-xl font-semibold inline-flex items-center gap-2",children:[e.jsx(w,{className:"h-5 w-5 text-warning"}),s("hot.title")]}),e.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[e.jsx(u,{asChild:!0,variant:"ghost",size:"sm",children:e.jsxs("a",{href:"https://skillhub.cn",target:"_blank",rel:"noopener noreferrer",children:[e.jsx(E,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("hot.openHub")})]})}),e.jsxs(u,{variant:"ghost",size:"sm",onClick:()=>i(),disabled:r,"aria-label":s("actions.refresh",{ns:"common"}),children:[r?e.jsx(R,{className:"h-4 w-4 animate-spin"}):e.jsx(I,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("hot.subtitle")}),l&&e.jsx($,{cached:!!l.cached,stale:!!l.stale,fetchedAt:l.fetchedAt})]}),n.length>0&&e.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[e.jsxs("div",{className:"relative flex-1 min-w-[180px] max-w-md",children:[e.jsx(T,{className:"pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-text-muted"}),e.jsx(v,{value:h,onChange:t=>b(t.target.value),placeholder:s("actions.search",{ns:"common"}),className:"pl-7"})]}),e.jsxs(m,{variant:"secondary",className:"ml-auto",children:[j.length," / ",n.length]})]}),a?e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"}):n.length===0?e.jsx(S,{icon:e.jsx(w,{}),title:s("hot.empty")}):e.jsx("ul",{className:"flex flex-col gap-2",children:j.map(t=>e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>g(t.slug),className:C("flex w-full flex-col gap-1 rounded-md border border-border bg-surface px-3 py-2 text-left","transition-colors hover:border-border-strong hover:bg-surface-hover"),children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:t.name||t.slug}),t.version&&e.jsxs("span",{className:"text-text-muted text-xs font-mono",children:["v",t.version]}),t.category&&e.jsx(m,{variant:"outline",children:t.category}),e.jsxs("div",{className:"ml-auto flex items-center gap-3 text-xs text-text-dim tabular-nums",children:[e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(H,{className:"h-3 w-3"}),o(t.stars)]}),e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(A,{className:"h-3 w-3"}),o(t.installs)]})]})]}),e.jsx("code",{className:"text-text-muted text-xs font-mono",children:t.slug}),t.description&&e.jsx("p",{className:"line-clamp-2 text-sm text-text-dim",children:t.description})]})},t.slug))}),e.jsx(O,{skill:y,onOpenChange:t=>{t||g(null)}})]})}function $({cached:s,stale:l,fetchedAt:a}){const{t:r}=x("skills"),i=c.useMemo(()=>{try{const n=new Date(a);return Number.isNaN(n.getTime())?"":n.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return""}},[a]);return e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs text-text-muted",children:[e.jsx("span",{children:r("hot.updatedAt",{at:i})}),s&&e.jsx(m,{variant:"outline",children:r("hot.cached")}),l&&e.jsx(m,{variant:"warning",children:r("hot.stale")})]})}function O({skill:s,onOpenChange:l}){const{t:a}=x("skills"),r=c.useMemo(()=>s?[{key:"cliInstall",cmd:`skillhub install ${s.slug}`},{key:"cliSearch",cmd:`skillhub search ${s.slug}`},{key:"imAsk",cmd:`请用 skillhub 安装 ${s.slug} 技能`}]:[],[s]);return e.jsx(k,{open:s!=null,onOpenChange:l,children:e.jsxs(L,{className:"sm:max-w-2xl",children:[e.jsxs(D,{children:[e.jsx(F,{children:s?.name||s?.slug||""}),s?.description&&e.jsx(M,{children:s.description})]}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("dl",{className:"grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-xs",children:[e.jsx("dt",{className:"text-text-dim",children:"slug"}),e.jsx("dd",{className:"font-mono",children:s.slug}),s.version&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-text-dim",children:a("hot.detail.version")}),e.jsxs("dd",{className:"font-mono",children:["v",s.version]})]}),s.category&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-text-dim",children:a("hot.detail.category")}),e.jsx("dd",{children:s.category})]}),e.jsx("dt",{className:"text-text-dim",children:a("hot.detail.stars")}),e.jsx("dd",{className:"tabular-nums",children:o(s.stars)}),e.jsx("dt",{className:"text-text-dim",children:a("hot.detail.installs")}),e.jsx("dd",{className:"tabular-nums",children:o(s.installs)}),s.downloads!=null&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-text-dim",children:a("hot.detail.downloads")}),e.jsx("dd",{className:"tabular-nums",children:o(s.downloads)})]})]}),e.jsxs("div",{className:"mt-4 border-t border-border pt-3",children:[e.jsx("h3",{className:"text-sm font-medium",children:a("hot.detail.howInstall")}),e.jsx("ul",{className:"mt-2 flex flex-col gap-2",children:r.map(i=>e.jsxs("li",{className:"flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2",children:[e.jsx("span",{className:"text-xs text-text-dim sm:w-40 sm:shrink-0",children:a(`hot.detail.label.${i.key}`)}),e.jsx("code",{className:"flex-1 rounded bg-surface-2 px-2 py-1 font-mono text-xs break-all",children:i.cmd}),e.jsx(Q,{text:i.cmd})]},i.key))}),e.jsx("p",{className:"mt-3 text-[11px] text-text-muted",children:a("hot.detail.hint")})]})]})]})})}function Q({text:s}){const{t:l}=x("skills"),[a,r]=c.useState(!1);async function i(){try{await navigator.clipboard.writeText(s),r(!0),N.success(l("hot.detail.copied")),setTimeout(()=>r(!1),1500)}catch(n){N.error(String(n?.message??n))}}return e.jsxs(u,{type:"button",variant:"secondary",size:"sm",onClick:()=>void i(),className:"shrink-0",children:[e.jsx(B,{className:"h-3 w-3"}),l(a?"hot.detail.copied":"hot.detail.copy")]})}function o(s){return s==null||!Number.isFinite(s)?"—":s.toLocaleString()}export{ee as default};
17
- //# sourceMappingURL=hot-BAX3WV0p.js.map
17
+ //# sourceMappingURL=hot-D-aKQ8y2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hot-BAX3WV0p.js","sources":["../../node_modules/lucide-react/dist/esm/icons/copy.js","../../node_modules/lucide-react/dist/esm/icons/flame.js","../../node_modules/lucide-react/dist/esm/icons/star.js","../../src/routes/skills/hot.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 Copy = createLucideIcon(\"Copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.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 Flame = createLucideIcon(\"Flame\", [\n [\n \"path\",\n {\n d: \"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z\",\n key: \"96xj49\"\n }\n ]\n]);\n\nexport { Flame as default };\n//# sourceMappingURL=flame.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 Star = createLucideIcon(\"Star\", [\n [\n \"path\",\n {\n d: \"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\",\n key: \"r04s7s\"\n }\n ]\n]);\n\nexport { Star as default };\n//# sourceMappingURL=star.js.map\n","/**\n * /skills/hot — read-only browse of skillhub.cn's hot list.\n *\n * Backed by /api/skills/remote/hot (server proxies upstream with a\n * 5-min cache + stale-while-error). agim never auto-runs an install:\n * the detail dialog surfaces three copy-pasteable commands and the\n * operator decides where to execute.\n *\n * Restored from v1's tasks.html in 2026-05; the v2 SPA had the\n * installed-skills view but had dropped the hot list during the\n * memory-tab port.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Copy,\n Download,\n ExternalLink,\n Flame,\n Loader2,\n RefreshCcw,\n Search,\n Star,\n} from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog'\nimport { Input } from '@/components/ui/input'\nimport { useSkillsRemoteHot } from '@/hooks/use-skills'\nimport type { RemoteSkill } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nexport default function SkillsHotRoute(): JSX.Element {\n const { t } = useTranslation(['skills', 'common'])\n const { data, isLoading, isFetching, refetch } = useSkillsRemoteHot()\n\n const skills: RemoteSkill[] = data?.skills ?? []\n const [q, setQ] = useState('')\n const [openSlug, setOpenSlug] = useState<string | null>(null)\n\n const filtered = useMemo(() => {\n const needle = q.trim().toLowerCase()\n if (!needle) return skills\n return skills.filter((s) =>\n s.slug.toLowerCase().includes(needle)\n || (s.name || '').toLowerCase().includes(needle)\n || (s.description || '').toLowerCase().includes(needle)\n || (s.category || '').toLowerCase().includes(needle)\n )\n }, [skills, q])\n\n const openSkill = openSlug ? skills.find((s) => s.slug === openSlug) ?? null : null\n\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-4\">\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 inline-flex items-center gap-2\">\n <Flame className=\"h-5 w-5 text-warning\" />\n {t('hot.title')}\n </h1>\n <div className=\"ml-auto flex items-center gap-2\">\n <Button\n asChild\n variant=\"ghost\"\n size=\"sm\"\n >\n <a\n href=\"https://skillhub.cn\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <ExternalLink className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('hot.openHub')}</span>\n </a>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\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 </div>\n <p className=\"text-sm text-text-dim\">{t('hot.subtitle')}</p>\n {data && (\n <CacheMeta\n cached={!!data.cached}\n stale={!!data.stale}\n fetchedAt={data.fetchedAt}\n />\n )}\n </header>\n\n {skills.length > 0 && (\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"relative flex-1 min-w-[180px] max-w-md\">\n <Search className=\"pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-text-muted\" />\n <Input\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={t('actions.search', { ns: 'common' })}\n className=\"pl-7\"\n />\n </div>\n <Badge variant=\"secondary\" className=\"ml-auto\">\n {filtered.length} / {skills.length}\n </Badge>\n </div>\n )}\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : skills.length === 0 ? (\n <EmptyState icon={<Flame />} title={t('hot.empty')} />\n ) : (\n <ul className=\"flex flex-col gap-2\">\n {filtered.map((s) => (\n <li key={s.slug}>\n <button\n type=\"button\"\n onClick={() => setOpenSlug(s.slug)}\n className={cn(\n 'flex w-full flex-col gap-1 rounded-md border border-border bg-surface px-3 py-2 text-left',\n 'transition-colors hover:border-border-strong hover:bg-surface-hover',\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{s.name || s.slug}</span>\n {s.version && (\n <span className=\"text-text-muted text-xs font-mono\">v{s.version}</span>\n )}\n {s.category && (\n <Badge variant=\"outline\">{s.category}</Badge>\n )}\n <div className=\"ml-auto flex items-center gap-3 text-xs text-text-dim tabular-nums\">\n <span className=\"inline-flex items-center gap-1\">\n <Star className=\"h-3 w-3\" />\n {formatNum(s.stars)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Download className=\"h-3 w-3\" />\n {formatNum(s.installs)}\n </span>\n </div>\n </div>\n <code className=\"text-text-muted text-xs font-mono\">{s.slug}</code>\n {s.description && (\n <p className=\"line-clamp-2 text-sm text-text-dim\">{s.description}</p>\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n\n <RemoteSkillDialog\n skill={openSkill}\n onOpenChange={(open) => { if (!open) setOpenSlug(null) }}\n />\n </div>\n )\n}\n\nfunction CacheMeta({\n cached,\n stale,\n fetchedAt,\n}: {\n cached: boolean\n stale: boolean\n fetchedAt: number\n}): JSX.Element | null {\n const { t } = useTranslation('skills')\n const when = useMemo(() => {\n try {\n const d = new Date(fetchedAt)\n if (Number.isNaN(d.getTime())) return ''\n return d.toLocaleString(undefined, {\n month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit',\n })\n } catch {\n return ''\n }\n }, [fetchedAt])\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-text-muted\">\n <span>{t('hot.updatedAt', { at: when })}</span>\n {cached && <Badge variant=\"outline\">{t('hot.cached')}</Badge>}\n {stale && <Badge variant=\"warning\">{t('hot.stale')}</Badge>}\n </div>\n )\n}\n\ninterface RemoteSkillDialogProps {\n skill: RemoteSkill | null\n onOpenChange: (open: boolean) => void\n}\n\nfunction RemoteSkillDialog({ skill, onOpenChange }: RemoteSkillDialogProps): JSX.Element {\n const { t } = useTranslation('skills')\n\n // Three copy-pasteable install paths. agim never executes them itself\n // — the operator chooses CLI or IM.\n const commands = useMemo(() => {\n if (!skill) return []\n return [\n { key: 'cliInstall', cmd: `skillhub install ${skill.slug}` },\n { key: 'cliSearch', cmd: `skillhub search ${skill.slug}` },\n { key: 'imAsk', cmd: `请用 skillhub 安装 ${skill.slug} 技能` },\n ]\n }, [skill])\n\n return (\n <Dialog open={skill != null} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-2xl\">\n <DialogHeader>\n <DialogTitle>{skill?.name || skill?.slug || ''}</DialogTitle>\n {skill?.description && (\n <DialogDescription>{skill.description}</DialogDescription>\n )}\n </DialogHeader>\n\n {skill && (\n <>\n <dl className=\"grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-xs\">\n <dt className=\"text-text-dim\">slug</dt>\n <dd className=\"font-mono\">{skill.slug}</dd>\n {skill.version && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.version')}</dt>\n <dd className=\"font-mono\">v{skill.version}</dd>\n </>\n )}\n {skill.category && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.category')}</dt>\n <dd>{skill.category}</dd>\n </>\n )}\n <dt className=\"text-text-dim\">{t('hot.detail.stars')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.stars)}</dd>\n <dt className=\"text-text-dim\">{t('hot.detail.installs')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.installs)}</dd>\n {skill.downloads != null && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.downloads')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.downloads)}</dd>\n </>\n )}\n </dl>\n\n <div className=\"mt-4 border-t border-border pt-3\">\n <h3 className=\"text-sm font-medium\">{t('hot.detail.howInstall')}</h3>\n <ul className=\"mt-2 flex flex-col gap-2\">\n {commands.map((c) => (\n <li key={c.key} className=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2\">\n <span className=\"text-xs text-text-dim sm:w-40 sm:shrink-0\">\n {t(`hot.detail.label.${c.key}`)}\n </span>\n <code className=\"flex-1 rounded bg-surface-2 px-2 py-1 font-mono text-xs break-all\">\n {c.cmd}\n </code>\n <CopyButton text={c.cmd} />\n </li>\n ))}\n </ul>\n <p className=\"mt-3 text-[11px] text-text-muted\">{t('hot.detail.hint')}</p>\n </div>\n </>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction CopyButton({ text }: { text: string }): JSX.Element {\n const { t } = useTranslation('skills')\n const [copied, setCopied] = useState(false)\n async function onClick(): Promise<void> {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n toast.success(t('hot.detail.copied'))\n setTimeout(() => setCopied(false), 1500)\n } catch (err) {\n toast.error(String((err as Error)?.message ?? err))\n }\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onClick()}\n className=\"shrink-0\"\n >\n <Copy className=\"h-3 w-3\" />\n {copied ? t('hot.detail.copied') : t('hot.detail.copy')}\n </Button>\n )\n}\n\nfunction formatNum(n: number | undefined): string {\n if (n == null || !Number.isFinite(n)) return '—'\n return n.toLocaleString()\n}\n"],"names":["Copy","createLucideIcon","Flame","Star","SkillsHotRoute","t","useTranslation","data","isLoading","isFetching","refetch","useSkillsRemoteHot","skills","q","setQ","useState","openSlug","setOpenSlug","filtered","useMemo","needle","s","openSkill","jsxs","jsx","Button","ExternalLink","Loader2","RefreshCcw","CacheMeta","Search","Input","e","Badge","EmptyState","cn","formatNum","Download","RemoteSkillDialog","open","cached","stale","fetchedAt","when","d","skill","onOpenChange","commands","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","Fragment","c","CopyButton","text","copied","setCopied","onClick","toast","err","n"],"mappings":"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","x_google_ignoreList":[0,1,2]}
1
+ {"version":3,"file":"hot-D-aKQ8y2.js","sources":["../../node_modules/lucide-react/dist/esm/icons/copy.js","../../node_modules/lucide-react/dist/esm/icons/flame.js","../../node_modules/lucide-react/dist/esm/icons/star.js","../../src/routes/skills/hot.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 Copy = createLucideIcon(\"Copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.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 Flame = createLucideIcon(\"Flame\", [\n [\n \"path\",\n {\n d: \"M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z\",\n key: \"96xj49\"\n }\n ]\n]);\n\nexport { Flame as default };\n//# sourceMappingURL=flame.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 Star = createLucideIcon(\"Star\", [\n [\n \"path\",\n {\n d: \"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\",\n key: \"r04s7s\"\n }\n ]\n]);\n\nexport { Star as default };\n//# sourceMappingURL=star.js.map\n","/**\n * /skills/hot — read-only browse of skillhub.cn's hot list.\n *\n * Backed by /api/skills/remote/hot (server proxies upstream with a\n * 5-min cache + stale-while-error). agim never auto-runs an install:\n * the detail dialog surfaces three copy-pasteable commands and the\n * operator decides where to execute.\n *\n * Restored from v1's tasks.html in 2026-05; the v2 SPA had the\n * installed-skills view but had dropped the hot list during the\n * memory-tab port.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Copy,\n Download,\n ExternalLink,\n Flame,\n Loader2,\n RefreshCcw,\n Search,\n Star,\n} from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog'\nimport { Input } from '@/components/ui/input'\nimport { useSkillsRemoteHot } from '@/hooks/use-skills'\nimport type { RemoteSkill } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nexport default function SkillsHotRoute(): JSX.Element {\n const { t } = useTranslation(['skills', 'common'])\n const { data, isLoading, isFetching, refetch } = useSkillsRemoteHot()\n\n const skills: RemoteSkill[] = data?.skills ?? []\n const [q, setQ] = useState('')\n const [openSlug, setOpenSlug] = useState<string | null>(null)\n\n const filtered = useMemo(() => {\n const needle = q.trim().toLowerCase()\n if (!needle) return skills\n return skills.filter((s) =>\n s.slug.toLowerCase().includes(needle)\n || (s.name || '').toLowerCase().includes(needle)\n || (s.description || '').toLowerCase().includes(needle)\n || (s.category || '').toLowerCase().includes(needle)\n )\n }, [skills, q])\n\n const openSkill = openSlug ? skills.find((s) => s.slug === openSlug) ?? null : null\n\n return (\n <div className=\"mx-auto flex max-w-5xl flex-col gap-4\">\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 inline-flex items-center gap-2\">\n <Flame className=\"h-5 w-5 text-warning\" />\n {t('hot.title')}\n </h1>\n <div className=\"ml-auto flex items-center gap-2\">\n <Button\n asChild\n variant=\"ghost\"\n size=\"sm\"\n >\n <a\n href=\"https://skillhub.cn\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <ExternalLink className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('hot.openHub')}</span>\n </a>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\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 </div>\n <p className=\"text-sm text-text-dim\">{t('hot.subtitle')}</p>\n {data && (\n <CacheMeta\n cached={!!data.cached}\n stale={!!data.stale}\n fetchedAt={data.fetchedAt}\n />\n )}\n </header>\n\n {skills.length > 0 && (\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"relative flex-1 min-w-[180px] max-w-md\">\n <Search className=\"pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-text-muted\" />\n <Input\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder={t('actions.search', { ns: 'common' })}\n className=\"pl-7\"\n />\n </div>\n <Badge variant=\"secondary\" className=\"ml-auto\">\n {filtered.length} / {skills.length}\n </Badge>\n </div>\n )}\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : skills.length === 0 ? (\n <EmptyState icon={<Flame />} title={t('hot.empty')} />\n ) : (\n <ul className=\"flex flex-col gap-2\">\n {filtered.map((s) => (\n <li key={s.slug}>\n <button\n type=\"button\"\n onClick={() => setOpenSlug(s.slug)}\n className={cn(\n 'flex w-full flex-col gap-1 rounded-md border border-border bg-surface px-3 py-2 text-left',\n 'transition-colors hover:border-border-strong hover:bg-surface-hover',\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{s.name || s.slug}</span>\n {s.version && (\n <span className=\"text-text-muted text-xs font-mono\">v{s.version}</span>\n )}\n {s.category && (\n <Badge variant=\"outline\">{s.category}</Badge>\n )}\n <div className=\"ml-auto flex items-center gap-3 text-xs text-text-dim tabular-nums\">\n <span className=\"inline-flex items-center gap-1\">\n <Star className=\"h-3 w-3\" />\n {formatNum(s.stars)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Download className=\"h-3 w-3\" />\n {formatNum(s.installs)}\n </span>\n </div>\n </div>\n <code className=\"text-text-muted text-xs font-mono\">{s.slug}</code>\n {s.description && (\n <p className=\"line-clamp-2 text-sm text-text-dim\">{s.description}</p>\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n\n <RemoteSkillDialog\n skill={openSkill}\n onOpenChange={(open) => { if (!open) setOpenSlug(null) }}\n />\n </div>\n )\n}\n\nfunction CacheMeta({\n cached,\n stale,\n fetchedAt,\n}: {\n cached: boolean\n stale: boolean\n fetchedAt: number\n}): JSX.Element | null {\n const { t } = useTranslation('skills')\n const when = useMemo(() => {\n try {\n const d = new Date(fetchedAt)\n if (Number.isNaN(d.getTime())) return ''\n return d.toLocaleString(undefined, {\n month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit',\n })\n } catch {\n return ''\n }\n }, [fetchedAt])\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-text-muted\">\n <span>{t('hot.updatedAt', { at: when })}</span>\n {cached && <Badge variant=\"outline\">{t('hot.cached')}</Badge>}\n {stale && <Badge variant=\"warning\">{t('hot.stale')}</Badge>}\n </div>\n )\n}\n\ninterface RemoteSkillDialogProps {\n skill: RemoteSkill | null\n onOpenChange: (open: boolean) => void\n}\n\nfunction RemoteSkillDialog({ skill, onOpenChange }: RemoteSkillDialogProps): JSX.Element {\n const { t } = useTranslation('skills')\n\n // Three copy-pasteable install paths. agim never executes them itself\n // — the operator chooses CLI or IM.\n const commands = useMemo(() => {\n if (!skill) return []\n return [\n { key: 'cliInstall', cmd: `skillhub install ${skill.slug}` },\n { key: 'cliSearch', cmd: `skillhub search ${skill.slug}` },\n { key: 'imAsk', cmd: `请用 skillhub 安装 ${skill.slug} 技能` },\n ]\n }, [skill])\n\n return (\n <Dialog open={skill != null} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-2xl\">\n <DialogHeader>\n <DialogTitle>{skill?.name || skill?.slug || ''}</DialogTitle>\n {skill?.description && (\n <DialogDescription>{skill.description}</DialogDescription>\n )}\n </DialogHeader>\n\n {skill && (\n <>\n <dl className=\"grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1 text-xs\">\n <dt className=\"text-text-dim\">slug</dt>\n <dd className=\"font-mono\">{skill.slug}</dd>\n {skill.version && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.version')}</dt>\n <dd className=\"font-mono\">v{skill.version}</dd>\n </>\n )}\n {skill.category && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.category')}</dt>\n <dd>{skill.category}</dd>\n </>\n )}\n <dt className=\"text-text-dim\">{t('hot.detail.stars')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.stars)}</dd>\n <dt className=\"text-text-dim\">{t('hot.detail.installs')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.installs)}</dd>\n {skill.downloads != null && (\n <>\n <dt className=\"text-text-dim\">{t('hot.detail.downloads')}</dt>\n <dd className=\"tabular-nums\">{formatNum(skill.downloads)}</dd>\n </>\n )}\n </dl>\n\n <div className=\"mt-4 border-t border-border pt-3\">\n <h3 className=\"text-sm font-medium\">{t('hot.detail.howInstall')}</h3>\n <ul className=\"mt-2 flex flex-col gap-2\">\n {commands.map((c) => (\n <li key={c.key} className=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2\">\n <span className=\"text-xs text-text-dim sm:w-40 sm:shrink-0\">\n {t(`hot.detail.label.${c.key}`)}\n </span>\n <code className=\"flex-1 rounded bg-surface-2 px-2 py-1 font-mono text-xs break-all\">\n {c.cmd}\n </code>\n <CopyButton text={c.cmd} />\n </li>\n ))}\n </ul>\n <p className=\"mt-3 text-[11px] text-text-muted\">{t('hot.detail.hint')}</p>\n </div>\n </>\n )}\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction CopyButton({ text }: { text: string }): JSX.Element {\n const { t } = useTranslation('skills')\n const [copied, setCopied] = useState(false)\n async function onClick(): Promise<void> {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n toast.success(t('hot.detail.copied'))\n setTimeout(() => setCopied(false), 1500)\n } catch (err) {\n toast.error(String((err as Error)?.message ?? err))\n }\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onClick()}\n className=\"shrink-0\"\n >\n <Copy className=\"h-3 w-3\" />\n {copied ? t('hot.detail.copied') : t('hot.detail.copy')}\n </Button>\n )\n}\n\nfunction formatNum(n: number | undefined): string {\n if (n == null || !Number.isFinite(n)) return '—'\n return n.toLocaleString()\n}\n"],"names":["Copy","createLucideIcon","Flame","Star","SkillsHotRoute","t","useTranslation","data","isLoading","isFetching","refetch","useSkillsRemoteHot","skills","q","setQ","useState","openSlug","setOpenSlug","filtered","useMemo","needle","s","openSkill","jsxs","jsx","Button","ExternalLink","Loader2","RefreshCcw","CacheMeta","Search","Input","e","Badge","EmptyState","cn","formatNum","Download","RemoteSkillDialog","open","cached","stale","fetchedAt","when","d","skill","onOpenChange","commands","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","Fragment","c","CopyButton","text","copied","setCopied","onClick","toast","err","n"],"mappings":"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","x_google_ignoreList":[0,1,2]}