agim-cli 1.2.126 → 1.2.128
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.
- package/CHANGELOG.md +99 -1
- package/dist/core/llm/web-dispatcher.d.ts +9 -1
- package/dist/core/llm/web-dispatcher.d.ts.map +1 -1
- package/dist/core/llm/web-dispatcher.js +11 -3
- package/dist/core/llm/web-dispatcher.js.map +1 -1
- package/dist/web/public/assets/{a2a-DGmlA1kI.js → a2a-CbxNgf9H.js} +2 -2
- package/dist/web/public/assets/{a2a-DGmlA1kI.js.map → a2a-CbxNgf9H.js.map} +1 -1
- package/dist/web/public/assets/{activity-s8eXJqQ-.js → activity-C6r508cN.js} +2 -2
- package/dist/web/public/assets/{activity-s8eXJqQ-.js.map → activity-C6r508cN.js.map} +1 -1
- package/dist/web/public/assets/{admins-BSDr-HXb.js → admins-C0BJw6X9.js} +2 -2
- package/dist/web/public/assets/{admins-BSDr-HXb.js.map → admins-C0BJw6X9.js.map} +1 -1
- package/dist/web/public/assets/{agents-Dp4swPPC.js → agents-DOW1_NGT.js} +2 -2
- package/dist/web/public/assets/{agents-Dp4swPPC.js.map → agents-DOW1_NGT.js.map} +1 -1
- package/dist/web/public/assets/{approvals-BzShPdMC.js → approvals-CyPhYcGG.js} +2 -2
- package/dist/web/public/assets/{approvals-BzShPdMC.js.map → approvals-CyPhYcGG.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-B0EZtRDW.js → arrow-up-CZr2LH5e.js} +2 -2
- package/dist/web/public/assets/{arrow-up-B0EZtRDW.js.map → arrow-up-CZr2LH5e.js.map} +1 -1
- package/dist/web/public/assets/{asks-BQtIx6ky.js → asks-B6L3PSml.js} +2 -2
- package/dist/web/public/assets/{asks-BQtIx6ky.js.map → asks-B6L3PSml.js.map} +1 -1
- package/dist/web/public/assets/{audit-BDIEW7z9.js → audit-CCGCdw6P.js} +2 -2
- package/dist/web/public/assets/{audit-BDIEW7z9.js.map → audit-CCGCdw6P.js.map} +1 -1
- package/dist/web/public/assets/{bell-Dw3rtAnD.js → bell-OiL3Thk2.js} +2 -2
- package/dist/web/public/assets/{bell-Dw3rtAnD.js.map → bell-OiL3Thk2.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-DEQOeNl0.js → bgjobs-vhVtnLSx.js} +2 -2
- package/dist/web/public/assets/{bgjobs-DEQOeNl0.js.map → bgjobs-vhVtnLSx.js.map} +1 -1
- package/dist/web/public/assets/{brain-BqR8-Zwv.js → brain-n56pZ1TQ.js} +2 -2
- package/dist/web/public/assets/{brain-BqR8-Zwv.js.map → brain-n56pZ1TQ.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-_b-XDwyU.js → briefcase-BscVfAjp.js} +2 -2
- package/dist/web/public/assets/{briefcase-_b-XDwyU.js.map → briefcase-BscVfAjp.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-DkURvNIb.js → chevron-right-trO6yoBr.js} +2 -2
- package/dist/web/public/assets/{chevron-right-DkURvNIb.js.map → chevron-right-trO6yoBr.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-D0tRr1mi.js → circle-check-B_d7dBl5.js} +2 -2
- package/dist/web/public/assets/{circle-check-D0tRr1mi.js.map → circle-check-B_d7dBl5.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-C737-DM7.js → circle-check-big-D6TvCoDM.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-C737-DM7.js.map → circle-check-big-D6TvCoDM.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-KWl9wiZn.js → circle-x-OcRzGLRb.js} +2 -2
- package/dist/web/public/assets/{circle-x-KWl9wiZn.js.map → circle-x-OcRzGLRb.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-CyTBb_Dj.js → confirm-dialog-DD1ZW1XE.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-CyTBb_Dj.js.map → confirm-dialog-DD1ZW1XE.js.map} +1 -1
- package/dist/web/public/assets/{data-table-Br_AhsiO.js → data-table-bhqK389v.js} +2 -2
- package/dist/web/public/assets/{data-table-Br_AhsiO.js.map → data-table-bhqK389v.js.map} +1 -1
- package/dist/web/public/assets/{dialog-ChaF-Zu5.js → dialog-D5BsJN2q.js} +2 -2
- package/dist/web/public/assets/{dialog-ChaF-Zu5.js.map → dialog-D5BsJN2q.js.map} +1 -1
- package/dist/web/public/assets/{download-B7FO0Y5B.js → download-CcO4RAuC.js} +2 -2
- package/dist/web/public/assets/{download-B7FO0Y5B.js.map → download-CcO4RAuC.js.map} +1 -1
- package/dist/web/public/assets/{email-DIEmIapc.js → email-Dy3UoyzF.js} +2 -2
- package/dist/web/public/assets/{email-DIEmIapc.js.map → email-Dy3UoyzF.js.map} +1 -1
- package/dist/web/public/assets/{empty-state-CP9D3-8U.js → empty-state-CwUKG8xX.js} +2 -2
- package/dist/web/public/assets/{empty-state-CP9D3-8U.js.map → empty-state-CwUKG8xX.js.map} +1 -1
- package/dist/web/public/assets/{external-link-Ba2-bs-3.js → external-link-wf5VhNXd.js} +2 -2
- package/dist/web/public/assets/{external-link-Ba2-bs-3.js.map → external-link-wf5VhNXd.js.map} +1 -1
- package/dist/web/public/assets/{eye-CcL-RUbp.js → eye-8lKlwbZE.js} +2 -2
- package/dist/web/public/assets/{eye-CcL-RUbp.js.map → eye-8lKlwbZE.js.map} +1 -1
- package/dist/web/public/assets/{facts-DqwcWab7.js → facts-Cfu6Lg3H.js} +2 -2
- package/dist/web/public/assets/{facts-DqwcWab7.js.map → facts-Cfu6Lg3H.js.map} +1 -1
- package/dist/web/public/assets/{goals-DBghjX3s.js → goals-BQkhal_h.js} +2 -2
- package/dist/web/public/assets/{goals-DBghjX3s.js.map → goals-BQkhal_h.js.map} +1 -1
- package/dist/web/public/assets/{health-DV_mII-T.js → health-BObMAngj.js} +2 -2
- package/dist/web/public/assets/{health-DV_mII-T.js.map → health-BObMAngj.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-C3TFU_Th.js → heart-pulse-DI33Rxyr.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-C3TFU_Th.js.map → heart-pulse-DI33Rxyr.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-NRTRObLx.js → heartbeat-Bc4SZawQ.js} +2 -2
- package/dist/web/public/assets/{heartbeat-NRTRObLx.js.map → heartbeat-Bc4SZawQ.js.map} +1 -1
- package/dist/web/public/assets/{hot-BNH34Amf.js → hot-BXYotT26.js} +2 -2
- package/dist/web/public/assets/{hot-BNH34Amf.js.map → hot-BXYotT26.js.map} +1 -1
- package/dist/web/public/assets/{index-igqJknUt.js → index-CGaI-i4K.js} +31 -31
- package/dist/web/public/assets/index-CGaI-i4K.js.map +1 -0
- package/dist/web/public/assets/{installed-B2goeV3S.js → installed-DswmDcea.js} +2 -2
- package/dist/web/public/assets/{installed-B2goeV3S.js.map → installed-DswmDcea.js.map} +1 -1
- package/dist/web/public/assets/{jobs-CZSLi1IN.js → jobs-DWBDqKx-.js} +2 -2
- package/dist/web/public/assets/{jobs-CZSLi1IN.js.map → jobs-DWBDqKx-.js.map} +1 -1
- package/dist/web/public/assets/{layout-BOtnmIxG.js → layout-B5rK_h6Q.js} +2 -2
- package/dist/web/public/assets/{layout-BOtnmIxG.js.map → layout-B5rK_h6Q.js.map} +1 -1
- package/dist/web/public/assets/{layout-CBbV3YNj.js → layout-ByUY6XZQ.js} +2 -2
- package/dist/web/public/assets/{layout-CBbV3YNj.js.map → layout-ByUY6XZQ.js.map} +1 -1
- package/dist/web/public/assets/{layout-CsScgPAG.js → layout-CX3nXpWb.js} +2 -2
- package/dist/web/public/assets/{layout-CsScgPAG.js.map → layout-CX3nXpWb.js.map} +1 -1
- package/dist/web/public/assets/{layout-BboemGJs.js → layout-D7gNMUDZ.js} +2 -2
- package/dist/web/public/assets/{layout-BboemGJs.js.map → layout-D7gNMUDZ.js.map} +1 -1
- package/dist/web/public/assets/{layout-D8Kes1e7.js → layout-DJKxW33x.js} +2 -2
- package/dist/web/public/assets/{layout-D8Kes1e7.js.map → layout-DJKxW33x.js.map} +1 -1
- package/dist/web/public/assets/{llm-78WCRfgL.js → llm-CPOd98Hy.js} +2 -2
- package/dist/web/public/assets/{llm-78WCRfgL.js.map → llm-CPOd98Hy.js.map} +1 -1
- package/dist/web/public/assets/{loader-circle-BMJKoafx.js → loader-circle-BBIfyATA.js} +2 -2
- package/dist/web/public/assets/{loader-circle-BMJKoafx.js.map → loader-circle-BBIfyATA.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-QiHcQUfd.js → map-pin-Bg7JuU7F.js} +2 -2
- package/dist/web/public/assets/{map-pin-QiHcQUfd.js.map → map-pin-Bg7JuU7F.js.map} +1 -1
- package/dist/web/public/assets/{mcp-oeRvo7Aw.js → mcp-DGxGN2iX.js} +2 -2
- package/dist/web/public/assets/{mcp-oeRvo7Aw.js.map → mcp-DGxGN2iX.js.map} +1 -1
- package/dist/web/public/assets/{memos-D7RJn57X.js → memos-LpUpTmYL.js} +2 -2
- package/dist/web/public/assets/{memos-D7RJn57X.js.map → memos-LpUpTmYL.js.map} +1 -1
- package/dist/web/public/assets/{messengers-BORNy_SW.js → messengers-CWMsJz1e.js} +2 -2
- package/dist/web/public/assets/{messengers-BORNy_SW.js.map → messengers-CWMsJz1e.js.map} +1 -1
- package/dist/web/public/assets/native-agent-CPkYGY3I.js +22 -0
- package/dist/web/public/assets/native-agent-CPkYGY3I.js.map +1 -0
- package/dist/web/public/assets/{network-D--kF74M.js → network-DHrX3RcZ.js} +2 -2
- package/dist/web/public/assets/{network-D--kF74M.js.map → network-DHrX3RcZ.js.map} +1 -1
- package/dist/web/public/assets/{outbox-BvhcDpdc.js → outbox-T3NnYmK0.js} +2 -2
- package/dist/web/public/assets/{outbox-BvhcDpdc.js.map → outbox-T3NnYmK0.js.map} +1 -1
- package/dist/web/public/assets/{pagination-Dl8k4a91.js → pagination-ANxQzaRV.js} +2 -2
- package/dist/web/public/assets/{pagination-Dl8k4a91.js.map → pagination-ANxQzaRV.js.map} +1 -1
- package/dist/web/public/assets/{persona-Dy-fuCBR.js → persona-CHz80XDk.js} +2 -2
- package/dist/web/public/assets/{persona-Dy-fuCBR.js.map → persona-CHz80XDk.js.map} +1 -1
- package/dist/web/public/assets/{play-C0gIFP8e.js → play-BNtSkb5l.js} +2 -2
- package/dist/web/public/assets/{play-C0gIFP8e.js.map → play-BNtSkb5l.js.map} +1 -1
- package/dist/web/public/assets/{plus-DW6xBDJv.js → plus-CYsjCf6w.js} +2 -2
- package/dist/web/public/assets/{plus-DW6xBDJv.js.map → plus-CYsjCf6w.js.map} +1 -1
- package/dist/web/public/assets/{policy-DW_kZo8b.js → policy-CtKRzual.js} +2 -2
- package/dist/web/public/assets/{policy-DW_kZo8b.js.map → policy-CtKRzual.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-D6fZ_xYR.js → refresh-ccw-DpPWcwTg.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-D6fZ_xYR.js.map → refresh-ccw-DpPWcwTg.js.map} +1 -1
- package/dist/web/public/assets/{reminders-1V1_6Rij.js → reminders-R14lWHEJ.js} +2 -2
- package/dist/web/public/assets/{reminders-1V1_6Rij.js.map → reminders-R14lWHEJ.js.map} +1 -1
- package/dist/web/public/assets/{save-S79SG1Qr.js → save-beGooRNy.js} +2 -2
- package/dist/web/public/assets/{save-S79SG1Qr.js.map → save-beGooRNy.js.map} +1 -1
- package/dist/web/public/assets/{schedules-BsknKkCe.js → schedules-fxKnDnxp.js} +2 -2
- package/dist/web/public/assets/{schedules-BsknKkCe.js.map → schedules-fxKnDnxp.js.map} +1 -1
- package/dist/web/public/assets/{search-CKf3g91u.js → search-BzOAg0Rb.js} +2 -2
- package/dist/web/public/assets/{search-CKf3g91u.js.map → search-BzOAg0Rb.js.map} +1 -1
- package/dist/web/public/assets/{search-HQWlCBKK.js → search-DzgimpPy.js} +2 -2
- package/dist/web/public/assets/{search-HQWlCBKK.js.map → search-DzgimpPy.js.map} +1 -1
- package/dist/web/public/assets/security-Dw1mh68G.js +2 -0
- package/dist/web/public/assets/security-Dw1mh68G.js.map +1 -0
- package/dist/web/public/assets/{service-CB-aBmLS.js → service-CB55xtmh.js} +2 -2
- package/dist/web/public/assets/{service-CB-aBmLS.js.map → service-CB55xtmh.js.map} +1 -1
- package/dist/web/public/assets/shield-alert-C2IO43co.js +7 -0
- package/dist/web/public/assets/shield-alert-C2IO43co.js.map +1 -0
- package/dist/web/public/assets/{status-badge-BYFw2Sxd.js → status-badge-wL5IXJx_.js} +2 -2
- package/dist/web/public/assets/{status-badge-BYFw2Sxd.js.map → status-badge-wL5IXJx_.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-CBrBqNyr.js → subtasks-CbLAkygG.js} +2 -2
- package/dist/web/public/assets/{subtasks-CBrBqNyr.js.map → subtasks-CbLAkygG.js.map} +1 -1
- package/dist/web/public/assets/{table-D5hzEZ1F.js → table-9FRavyyI.js} +2 -2
- package/dist/web/public/assets/{table-D5hzEZ1F.js.map → table-9FRavyyI.js.map} +1 -1
- package/dist/web/public/assets/{topn-7_FUU4Zs.js → topn-BE7RU5cV.js} +2 -2
- package/dist/web/public/assets/{topn-7_FUU4Zs.js.map → topn-BE7RU5cV.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-BkaJ1KrC.js → trash-2-DL2FAuYX.js} +2 -2
- package/dist/web/public/assets/{trash-2-BkaJ1KrC.js.map → trash-2-DL2FAuYX.js.map} +1 -1
- package/dist/web/public/assets/{use-background-tasks-Crs1dlm6.js → use-background-tasks-XHuIYwrT.js} +2 -2
- package/dist/web/public/assets/{use-background-tasks-Crs1dlm6.js.map → use-background-tasks-XHuIYwrT.js.map} +1 -1
- package/dist/web/public/assets/{use-llm-admin-CQ3lbm_y.js → use-llm-admin-Dm8PcjN-.js} +2 -2
- package/dist/web/public/assets/{use-llm-admin-CQ3lbm_y.js.map → use-llm-admin-Dm8PcjN-.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-CMOa52NU.js → use-memory-C3GgMqiJ.js} +2 -2
- package/dist/web/public/assets/{use-memory-CMOa52NU.js.map → use-memory-C3GgMqiJ.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-BTRXt3kO.js → use-observability-BQa4b0Uk.js} +2 -2
- package/dist/web/public/assets/{use-observability-BTRXt3kO.js.map → use-observability-BQa4b0Uk.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-D2TsP4vN.js → use-settings-CrkXdLrr.js} +2 -2
- package/dist/web/public/assets/{use-settings-D2TsP4vN.js.map → use-settings-CrkXdLrr.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-BobEMtXw.js → use-workspace-Csq4sxlY.js} +2 -2
- package/dist/web/public/assets/{use-workspace-BobEMtXw.js.map → use-workspace-Csq4sxlY.js.map} +1 -1
- package/dist/web/public/assets/{useQuery-B6dy499I.js → useQuery-ByZlZXlw.js} +2 -2
- package/dist/web/public/assets/{useQuery-B6dy499I.js.map → useQuery-ByZlZXlw.js.map} +1 -1
- package/dist/web/public/assets/{vector-v7xjphrN.js → vector-BmpvJTWt.js} +2 -2
- package/dist/web/public/assets/{vector-v7xjphrN.js.map → vector-BmpvJTWt.js.map} +1 -1
- package/dist/web/public/assets/{viewer-BSC-2Lhp.js → viewer-BOSX-lUS.js} +2 -2
- package/dist/web/public/assets/{viewer-BSC-2Lhp.js.map → viewer-BOSX-lUS.js.map} +1 -1
- package/dist/web/public/assets/{workspace-BtGPH9Sx.js → workspace-DTbEdEyD.js} +2 -2
- package/dist/web/public/assets/{workspace-BtGPH9Sx.js.map → workspace-DTbEdEyD.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-_PTrUhIq.js → workspaces-BIZGVK8F.js} +2 -2
- package/dist/web/public/assets/{workspaces-_PTrUhIq.js.map → workspaces-BIZGVK8F.js.map} +1 -1
- package/dist/web/public/assets/{x-BHW436CN.js → x-BLllJ8d_.js} +2 -2
- package/dist/web/public/assets/{x-BHW436CN.js.map → x-BLllJ8d_.js.map} +1 -1
- package/dist/web/public/index.html +1 -1
- package/dist/web/server.js +25 -0
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/assets/index-igqJknUt.js.map +0 -1
- package/dist/web/public/assets/native-agent-CNPVWQ9T.js +0 -12
- package/dist/web/public/assets/native-agent-CNPVWQ9T.js.map +0 -1
- package/dist/web/public/assets/security-B8sBUf6e.js +0 -7
- package/dist/web/public/assets/security-B8sBUf6e.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{z as L,ac as E,ab as P,r as m,ae as A,ad as D,V as t,c as j,i as M,L as N,S as F,l as q,m as Q,j as V,k as y,I as z,a4 as v,G as B,t as K}from"./index-
|
|
1
|
+
import{z as L,ac as E,ab as P,r as m,ae as A,ad as D,V as t,c as j,i as M,L as N,S as F,l as q,m as Q,j as V,k as y,I as z,a4 as v,G as B,t as K}from"./index-CGaI-i4K.js";import{e as w}from"./react-C9F3QeMB.js";import{D as J}from"./data-table-bhqK389v.js";import{E as U}from"./empty-state-CwUKG8xX.js";import{S as $}from"./status-badge-wL5IXJx_.js";import{C as G}from"./confirm-dialog-DD1ZW1XE.js";import{u as C}from"./useQuery-ByZlZXlw.js";import{L as H}from"./loader-circle-BBIfyATA.js";import{R as Y}from"./refresh-ccw-DpPWcwTg.js";import"./table-9FRavyyI.js";import"./arrow-up-CZr2LH5e.js";import"./dialog-D5BsJN2q.js";import"./x-BLllJ8d_.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const W=L("Inbox",[["polyline",{points:"22 12 16 12 14 15 10 15 8 12 2 12",key:"o97t9d"}],["path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",key:"oot6mr"}]]),h={all:["outbox"],list:e=>["outbox","list",e],stats:["outbox","stats"]};function X(e){return C({queryKey:h.list(e),queryFn:()=>m.listOutbox(e),refetchInterval:5e3,refetchIntervalInBackground:!1})}function Z(){return C({queryKey:h.stats,queryFn:()=>m.getOutboxStats(),refetchInterval:1e4,refetchIntervalInBackground:!1})}function ee(){const e=E();return P({mutationFn:a=>m.retryOutbox(a),onSuccess:()=>e.invalidateQueries({queryKey:h.all})})}const te=["pending","delivered","giving_up"];function ge(){const{t:e}=A(["tasks","common"]),[a,r]=D(),l=a.get("status")??null,i=a.get("thread")??"",{data:_,isLoading:O,isFetching:p,refetch:k}=X({...l?{status:l}:{},...i?{thread:i}:{},limit:200}),I=_?.rows??[],o=Z().data,c=ee(),[d,f]=w.useState(null);function b(s){const n=new URLSearchParams(a);for(const[g,u]of Object.entries(s))u==null||u===""?n.delete(g):n.set(g,u);r(n,{replace:!0})}async function R(){if(d!=null)try{await c.mutateAsync(d),v.success(e("states.saved",{ns:"common"}))}catch(s){const{message:n}=B(s,e);throw v.error(n),s}}const T=w.useMemo(()=>[{id:"id",header:e("outbox.col.id"),cell:s=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",s.id]}),headClassName:"w-20"},{id:"status",header:e("outbox.col.status"),cell:s=>t.jsx($,{status:s.status,children:e(`outbox.status.${s.status}`,{defaultValue:s.status})}),headClassName:"w-28"},{id:"platform",header:e("outbox.col.platform"),cell:s=>t.jsx("span",{className:"font-medium",children:s.platform}),headClassName:"w-28"},{id:"preview",header:e("outbox.col.preview"),cell:s=>t.jsx("span",{className:"line-clamp-2 text-text",title:s.payload,children:ae(s.payload,s.kind)}),asCardTitle:!0},{id:"thread",header:e("outbox.col.thread"),cell:s=>t.jsx("span",{className:"font-mono text-xs text-text-dim line-clamp-1",title:s.thread_key,children:s.thread_key}),headClassName:"w-44",hideOnMobile:!0},{id:"kind",header:e("outbox.col.kind"),cell:s=>t.jsx("span",{className:"text-text-dim",children:s.kind}),headClassName:"w-20",hideOnMobile:!0},{id:"attempts",header:e("outbox.col.attempts"),cell:s=>t.jsx("span",{className:"tabular-nums",children:s.attempts}),headClassName:"w-20"},{id:"createdAt",header:e("outbox.col.createdAt"),cell:s=>t.jsx("span",{className:"text-text-dim",children:S(s.created_at)}),headClassName:"w-32",hideOnMobile:!0},{id:"lastError",header:e("outbox.col.lastError"),cell:s=>s.last_error?t.jsx("span",{className:"line-clamp-1 text-danger text-xs",title:s.last_error,children:s.last_error}):t.jsx("span",{className:"text-text-muted",children:"—"}),hideOnMobile:!1},{id:"actions",header:"",cell:s=>s.status==="giving_up"?t.jsxs(j,{variant:"outline",size:"sm",onClick:n=>{n.stopPropagation(),f(s.id)},disabled:c.isPending,children:[t.jsx(M,{className:"h-3 w-3"}),e("outbox.action.retry")]}):null,headClassName:"w-28"}],[e,c.isPending]);return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsxs("header",{className:"flex flex-col gap-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[t.jsx("h1",{className:"text-xl font-semibold",children:e("outbox.title")}),t.jsxs(j,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>k(),disabled:p,"aria-label":e("actions.refresh",{ns:"common"}),children:[p?t.jsx(H,{className:"h-4 w-4 animate-spin"}):t.jsx(Y,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),t.jsx("p",{className:"text-sm text-text-dim",children:e("outbox.subtitle")})]}),o&&t.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[t.jsx(x,{label:e("outbox.stats.pending"),value:o.pending,tone:"info"}),t.jsx(x,{label:e("outbox.stats.giving_up"),value:o.giving_up,tone:"danger"}),t.jsx(x,{label:e("outbox.stats.delivered"),value:o.delivered,tone:"success"}),t.jsxs("div",{className:"rounded-md border border-border bg-surface px-3 py-2",children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e("outbox.stats.lastDelivered")}),t.jsx("div",{className:"text-sm font-medium tabular-nums",children:o.lastDeliveredAt?S(o.lastDeliveredAt):"—"})]})]}),t.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(N,{htmlFor:"status-filter",className:"text-xs text-text-dim",children:e("outbox.filter.status")}),t.jsxs(F,{value:l??"__any__",onValueChange:s=>b({status:s==="__any__"?null:s}),children:[t.jsx(q,{id:"status-filter",className:"w-[160px]",children:t.jsx(Q,{})}),t.jsxs(V,{children:[t.jsx(y,{value:"__any__",children:e("outbox.filter.statusAny")}),te.map(s=>t.jsx(y,{value:s,children:e(`outbox.status.${s}`,{defaultValue:s})},s))]})]})]}),t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(N,{htmlFor:"thread-filter",className:"text-xs text-text-dim",children:e("outbox.filter.thread")}),t.jsx(z,{id:"thread-filter",value:i,onChange:s=>b({thread:s.target.value}),placeholder:"wechat:room:...",className:"w-72 font-mono text-xs"})]})]}),t.jsx(J,{columns:T,rows:I,getRowId:s=>String(s.id),loading:O,emptyState:t.jsx(U,{icon:t.jsx(W,{}),title:e("outbox.empty.title"),description:e("outbox.empty.description")})}),t.jsx(G,{open:d!=null,onOpenChange:s=>{s||f(null)},title:e("outbox.action.confirmRetry"),description:e("outbox.action.confirmRetryDesc"),confirmLabel:e("outbox.action.retry"),onConfirm:R})]})}const se={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function x({label:e,value:a,tone:r}){return t.jsxs("div",{className:K("rounded-md border bg-surface px-3 py-2",se[r]),children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e}),t.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:a})]})}function ae(e,a){if(!e)return"—";if(a==="text")return e;try{const r=JSON.parse(e),l=r.text??r.message??r.title??r.body??null;return typeof l=="string"&&l.length>0?l:JSON.stringify(r)}catch{return e}}function S(e){if(e==null)return"—";try{const a=new Date(e);return Number.isNaN(a.getTime())?e:a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}export{ge as default};
|
|
7
|
-
//# sourceMappingURL=outbox-
|
|
7
|
+
//# sourceMappingURL=outbox-T3NnYmK0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbox-BvhcDpdc.js","sources":["../../node_modules/lucide-react/dist/esm/icons/inbox.js","../../src/hooks/use-outbox.ts","../../src/routes/tasks/outbox.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 Inbox = createLucideIcon(\"Inbox\", [\n [\"polyline\", { points: \"22 12 16 12 14 15 10 15 8 12 2 12\", key: \"o97t9d\" }],\n [\n \"path\",\n {\n d: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n key: \"oot6mr\"\n }\n ]\n]);\n\nexport { Inbox as default };\n//# sourceMappingURL=inbox.js.map\n","/**\n * useOutbox — react-query wrappers for the delivery queue.\n *\n * useOutbox(query) — list rows (status / thread / limit)\n * useOutboxStats() — small summary for KPI cards\n * useRetryOutbox() — retry a giving_up row by id\n *\n * The outbox isn't on the SSE bus. Routes use the react-query\n * polling fallback (5s) plus the existing SSE `job` event, which\n * effectively covers any newly-enqueued row (a job that runs to\n * completion enqueues one or more outbox rows).\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListOutboxQuery, ListOutboxResponse, OutboxStats } from '@/types/api'\n\nexport const outboxKeys = {\n all: ['outbox'] as const,\n list: (q: ListOutboxQuery) => ['outbox', 'list', q] as const,\n stats: ['outbox', 'stats'] as const,\n}\n\nexport function useOutbox(query: ListOutboxQuery) {\n return useQuery<ListOutboxResponse>({\n queryKey: outboxKeys.list(query),\n queryFn: () => api.listOutbox(query),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useOutboxStats() {\n return useQuery<OutboxStats>({\n queryKey: outboxKeys.stats,\n queryFn: () => api.getOutboxStats(),\n refetchInterval: 10000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useInvalidateOutbox() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: outboxKeys.all })\n}\n\nexport function useRetryOutbox() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (id: number) => api.retryOutbox(id),\n onSuccess: () => qc.invalidateQueries({ queryKey: outboxKeys.all }),\n })\n}\n","/**\n * /tasks/outbox — IM-platform delivery queue. Read-mostly; the one\n * mutation is \"retry\" on rows stuck in `giving_up`. Per-row action\n * routes through ConfirmDialog so an accidental click doesn't re-\n * fire a possibly-flaky delivery against the user's IM channel.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Inbox, Loader2, RefreshCcw, RotateCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\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 useOutbox,\n useOutboxStats,\n useRetryOutbox,\n} from '@/hooks/use-outbox'\nimport type { OutboxRow, OutboxStatus } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst STATUS_OPTIONS: OutboxStatus[] = ['pending', 'delivered', 'giving_up']\n\nexport default function OutboxRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const status = (params.get('status') as OutboxStatus | null) ?? null\n const thread = params.get('thread') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useOutbox({\n ...(status ? { status } : {}),\n ...(thread ? { thread } : {}),\n limit: 200,\n })\n const rows = data?.rows ?? []\n const statsQuery = useOutboxStats()\n const stats = statsQuery.data\n\n const retryMut = useRetryOutbox()\n const [confirmRetryId, setConfirmRetryId] = useState<number | null>(null)\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 setParams(next, { replace: true })\n }\n\n async function onConfirmRetry(): Promise<void> {\n if (confirmRetryId == null) return\n try {\n await retryMut.mutateAsync(confirmRetryId)\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<OutboxRow>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('outbox.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'status',\n header: t('outbox.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`outbox.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'platform',\n header: t('outbox.col.platform'),\n cell: (r) => <span className=\"font-medium\">{r.platform}</span>,\n headClassName: 'w-28',\n },\n {\n id: 'preview',\n header: t('outbox.col.preview'),\n cell: (r) => (\n <span\n className=\"line-clamp-2 text-text\"\n title={r.payload}\n >\n {previewPayload(r.payload, r.kind)}\n </span>\n ),\n asCardTitle: true,\n },\n {\n id: 'thread',\n header: t('outbox.col.thread'),\n cell: (r) => (\n <span\n className=\"font-mono text-xs text-text-dim line-clamp-1\"\n title={r.thread_key}\n >\n {r.thread_key}\n </span>\n ),\n headClassName: 'w-44',\n hideOnMobile: true,\n },\n {\n id: 'kind',\n header: t('outbox.col.kind'),\n cell: (r) => <span className=\"text-text-dim\">{r.kind}</span>,\n headClassName: 'w-20',\n hideOnMobile: true,\n },\n {\n id: 'attempts',\n header: t('outbox.col.attempts'),\n cell: (r) => <span className=\"tabular-nums\">{r.attempts}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'createdAt',\n header: t('outbox.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'lastError',\n header: t('outbox.col.lastError'),\n cell: (r) =>\n r.last_error ? (\n <span className=\"line-clamp-1 text-danger text-xs\" title={r.last_error}>\n {r.last_error}\n </span>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n hideOnMobile: false,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) =>\n r.status === 'giving_up' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmRetryId(r.id)\n }}\n disabled={retryMut.isPending}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {t('outbox.action.retry')}\n </Button>\n ) : null,\n headClassName: 'w-28',\n },\n ],\n [t, retryMut.isPending],\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('outbox.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('outbox.subtitle')}</p>\n </header>\n\n {/* Stats strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('outbox.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('outbox.stats.giving_up')} value={stats.giving_up} tone=\"danger\" />\n <StatCard label={t('outbox.stats.delivered')} value={stats.delivered} tone=\"success\" />\n <div className=\"rounded-md border border-border bg-surface px-3 py-2\">\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">\n {t('outbox.stats.lastDelivered')}\n </div>\n <div className=\"text-sm font-medium tabular-nums\">\n {stats.lastDeliveredAt ? formatTime(stats.lastDeliveredAt) : '—'}\n </div>\n </div>\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"status-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.status')}\n </Label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('outbox.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`outbox.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"thread-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.thread')}\n </Label>\n <Input\n id=\"thread-filter\"\n value={thread}\n onChange={(e) => patchParams({ thread: e.target.value })}\n placeholder=\"wechat:room:...\"\n className=\"w-72 font-mono text-xs\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<Inbox />}\n title={t('outbox.empty.title')}\n description={t('outbox.empty.description')}\n />\n }\n />\n\n <ConfirmDialog\n open={confirmRetryId != null}\n onOpenChange={(open) => {\n if (!open) setConfirmRetryId(null)\n }}\n title={t('outbox.action.confirmRetry')}\n description={t('outbox.action.confirmRetryDesc')}\n confirmLabel={t('outbox.action.retry')}\n onConfirm={onConfirmRetry}\n />\n </div>\n )\n}\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\n/** Render a one-line preview of an outbox row's payload.\n *\n * Card payloads are JSON encoded by the agent. We pluck the most\n * likely \"message\" field if we can parse it; otherwise we fall back\n * to the raw string. Text payloads are returned as-is, truncated\n * by the surrounding `line-clamp-2`. */\nfunction previewPayload(payload: string, kind: string): string {\n if (!payload) return '—'\n if (kind === 'text') return payload\n try {\n const parsed = JSON.parse(payload) as Record<string, unknown>\n const text = (parsed.text ?? parsed.message ?? parsed.title ?? parsed.body ?? null) as string | null\n if (typeof text === 'string' && text.length > 0) return text\n // Fallback: serialise the object compactly so the operator still\n // sees something useful.\n return JSON.stringify(parsed)\n } catch {\n return payload\n }\n}\n\nfunction formatTime(iso: string | null): string {\n if (iso == null) return '—'\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["Inbox","createLucideIcon","outboxKeys","q","useOutbox","query","useQuery","api","useOutboxStats","useRetryOutbox","qc","useQueryClient","useMutation","id","STATUS_OPTIONS","OutboxRoute","t","useTranslation","params","setParams","useSearchParams","status","thread","data","isLoading","isFetching","refetch","rows","stats","retryMut","confirmRetryId","setConfirmRetryId","useState","patchParams","patch","next","k","v","onConfirmRetry","toast","err","message","describeError","columns","useMemo","r","jsxs","StatusBadge","jsx","previewPayload","formatTime","Button","e","RotateCcw","Loader2","RefreshCcw","StatCard","Label","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","DataTable","EmptyState","ConfirmDialog","open","TONE_STYLES","label","value","tone","cn","payload","kind","parsed","text","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"outbox-T3NnYmK0.js","sources":["../../node_modules/lucide-react/dist/esm/icons/inbox.js","../../src/hooks/use-outbox.ts","../../src/routes/tasks/outbox.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 Inbox = createLucideIcon(\"Inbox\", [\n [\"polyline\", { points: \"22 12 16 12 14 15 10 15 8 12 2 12\", key: \"o97t9d\" }],\n [\n \"path\",\n {\n d: \"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z\",\n key: \"oot6mr\"\n }\n ]\n]);\n\nexport { Inbox as default };\n//# sourceMappingURL=inbox.js.map\n","/**\n * useOutbox — react-query wrappers for the delivery queue.\n *\n * useOutbox(query) — list rows (status / thread / limit)\n * useOutboxStats() — small summary for KPI cards\n * useRetryOutbox() — retry a giving_up row by id\n *\n * The outbox isn't on the SSE bus. Routes use the react-query\n * polling fallback (5s) plus the existing SSE `job` event, which\n * effectively covers any newly-enqueued row (a job that runs to\n * completion enqueues one or more outbox rows).\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListOutboxQuery, ListOutboxResponse, OutboxStats } from '@/types/api'\n\nexport const outboxKeys = {\n all: ['outbox'] as const,\n list: (q: ListOutboxQuery) => ['outbox', 'list', q] as const,\n stats: ['outbox', 'stats'] as const,\n}\n\nexport function useOutbox(query: ListOutboxQuery) {\n return useQuery<ListOutboxResponse>({\n queryKey: outboxKeys.list(query),\n queryFn: () => api.listOutbox(query),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useOutboxStats() {\n return useQuery<OutboxStats>({\n queryKey: outboxKeys.stats,\n queryFn: () => api.getOutboxStats(),\n refetchInterval: 10000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useInvalidateOutbox() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: outboxKeys.all })\n}\n\nexport function useRetryOutbox() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (id: number) => api.retryOutbox(id),\n onSuccess: () => qc.invalidateQueries({ queryKey: outboxKeys.all }),\n })\n}\n","/**\n * /tasks/outbox — IM-platform delivery queue. Read-mostly; the one\n * mutation is \"retry\" on rows stuck in `giving_up`. Per-row action\n * routes through ConfirmDialog so an accidental click doesn't re-\n * fire a possibly-flaky delivery against the user's IM channel.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Inbox, Loader2, RefreshCcw, RotateCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\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 useOutbox,\n useOutboxStats,\n useRetryOutbox,\n} from '@/hooks/use-outbox'\nimport type { OutboxRow, OutboxStatus } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst STATUS_OPTIONS: OutboxStatus[] = ['pending', 'delivered', 'giving_up']\n\nexport default function OutboxRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const status = (params.get('status') as OutboxStatus | null) ?? null\n const thread = params.get('thread') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useOutbox({\n ...(status ? { status } : {}),\n ...(thread ? { thread } : {}),\n limit: 200,\n })\n const rows = data?.rows ?? []\n const statsQuery = useOutboxStats()\n const stats = statsQuery.data\n\n const retryMut = useRetryOutbox()\n const [confirmRetryId, setConfirmRetryId] = useState<number | null>(null)\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 setParams(next, { replace: true })\n }\n\n async function onConfirmRetry(): Promise<void> {\n if (confirmRetryId == null) return\n try {\n await retryMut.mutateAsync(confirmRetryId)\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n const columns: DataTableColumn<OutboxRow>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('outbox.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'status',\n header: t('outbox.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`outbox.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-28',\n },\n {\n id: 'platform',\n header: t('outbox.col.platform'),\n cell: (r) => <span className=\"font-medium\">{r.platform}</span>,\n headClassName: 'w-28',\n },\n {\n id: 'preview',\n header: t('outbox.col.preview'),\n cell: (r) => (\n <span\n className=\"line-clamp-2 text-text\"\n title={r.payload}\n >\n {previewPayload(r.payload, r.kind)}\n </span>\n ),\n asCardTitle: true,\n },\n {\n id: 'thread',\n header: t('outbox.col.thread'),\n cell: (r) => (\n <span\n className=\"font-mono text-xs text-text-dim line-clamp-1\"\n title={r.thread_key}\n >\n {r.thread_key}\n </span>\n ),\n headClassName: 'w-44',\n hideOnMobile: true,\n },\n {\n id: 'kind',\n header: t('outbox.col.kind'),\n cell: (r) => <span className=\"text-text-dim\">{r.kind}</span>,\n headClassName: 'w-20',\n hideOnMobile: true,\n },\n {\n id: 'attempts',\n header: t('outbox.col.attempts'),\n cell: (r) => <span className=\"tabular-nums\">{r.attempts}</span>,\n headClassName: 'w-20',\n },\n {\n id: 'createdAt',\n header: t('outbox.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-32',\n hideOnMobile: true,\n },\n {\n id: 'lastError',\n header: t('outbox.col.lastError'),\n cell: (r) =>\n r.last_error ? (\n <span className=\"line-clamp-1 text-danger text-xs\" title={r.last_error}>\n {r.last_error}\n </span>\n ) : (\n <span className=\"text-text-muted\">—</span>\n ),\n hideOnMobile: false,\n },\n {\n id: 'actions',\n header: '',\n cell: (r) =>\n r.status === 'giving_up' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n setConfirmRetryId(r.id)\n }}\n disabled={retryMut.isPending}\n >\n <RotateCcw className=\"h-3 w-3\" />\n {t('outbox.action.retry')}\n </Button>\n ) : null,\n headClassName: 'w-28',\n },\n ],\n [t, retryMut.isPending],\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('outbox.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('outbox.subtitle')}</p>\n </header>\n\n {/* Stats strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('outbox.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('outbox.stats.giving_up')} value={stats.giving_up} tone=\"danger\" />\n <StatCard label={t('outbox.stats.delivered')} value={stats.delivered} tone=\"success\" />\n <div className=\"rounded-md border border-border bg-surface px-3 py-2\">\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">\n {t('outbox.stats.lastDelivered')}\n </div>\n <div className=\"text-sm font-medium tabular-nums\">\n {stats.lastDeliveredAt ? formatTime(stats.lastDeliveredAt) : '—'}\n </div>\n </div>\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"status-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.status')}\n </Label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('outbox.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`outbox.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"thread-filter\" className=\"text-xs text-text-dim\">\n {t('outbox.filter.thread')}\n </Label>\n <Input\n id=\"thread-filter\"\n value={thread}\n onChange={(e) => patchParams({ thread: e.target.value })}\n placeholder=\"wechat:room:...\"\n className=\"w-72 font-mono text-xs\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<Inbox />}\n title={t('outbox.empty.title')}\n description={t('outbox.empty.description')}\n />\n }\n />\n\n <ConfirmDialog\n open={confirmRetryId != null}\n onOpenChange={(open) => {\n if (!open) setConfirmRetryId(null)\n }}\n title={t('outbox.action.confirmRetry')}\n description={t('outbox.action.confirmRetryDesc')}\n confirmLabel={t('outbox.action.retry')}\n onConfirm={onConfirmRetry}\n />\n </div>\n )\n}\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\n/** Render a one-line preview of an outbox row's payload.\n *\n * Card payloads are JSON encoded by the agent. We pluck the most\n * likely \"message\" field if we can parse it; otherwise we fall back\n * to the raw string. Text payloads are returned as-is, truncated\n * by the surrounding `line-clamp-2`. */\nfunction previewPayload(payload: string, kind: string): string {\n if (!payload) return '—'\n if (kind === 'text') return payload\n try {\n const parsed = JSON.parse(payload) as Record<string, unknown>\n const text = (parsed.text ?? parsed.message ?? parsed.title ?? parsed.body ?? null) as string | null\n if (typeof text === 'string' && text.length > 0) return text\n // Fallback: serialise the object compactly so the operator still\n // sees something useful.\n return JSON.stringify(parsed)\n } catch {\n return payload\n }\n}\n\nfunction formatTime(iso: string | null): string {\n if (iso == null) return '—'\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["Inbox","createLucideIcon","outboxKeys","q","useOutbox","query","useQuery","api","useOutboxStats","useRetryOutbox","qc","useQueryClient","useMutation","id","STATUS_OPTIONS","OutboxRoute","t","useTranslation","params","setParams","useSearchParams","status","thread","data","isLoading","isFetching","refetch","rows","stats","retryMut","confirmRetryId","setConfirmRetryId","useState","patchParams","patch","next","k","v","onConfirmRetry","toast","err","message","describeError","columns","useMemo","r","jsxs","StatusBadge","jsx","previewPayload","formatTime","Button","e","RotateCcw","Loader2","RefreshCcw","StatCard","Label","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","DataTable","EmptyState","ConfirmDialog","open","TONE_STYLES","label","value","tone","cn","payload","kind","parsed","text","iso","d"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{z as d,ae as f,V as e,S as b,l as g,m as N,j as k,k as C,c as r,t as y}from"./index-
|
|
1
|
+
import{z as d,ae as f,V as e,S as b,l as g,m as N,j as k,k as C,c as r,t as y}from"./index-CGaI-i4K.js";import{C as S}from"./chevron-right-trO6yoBr.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{z as d,ae as f,V as e,S as b,l as g,m as N,j as k,k as C,c as r,t as y}fr
|
|
|
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 M=d("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);function T({page:a,totalPages:c,totalRows:s,perPage:n,perPageOptions:o,onPageChange:l,onPerPageChange:x,className:p}){const{t:i}=f("common"),m=a>1,h=a<c,u=n!==void 0&&o&&o.length>0&&x,v=n?(a-1)*n+1:null,j=n&&s!==void 0?Math.min(a*n,s):null;return e.jsxs("div",{className:y("flex flex-wrap items-center justify-between gap-3 py-2",p),role:"navigation","aria-label":i("pagination.label"),children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-text-dim",children:[u&&e.jsxs("div",{className:"hidden sm:flex items-center gap-2",children:[e.jsx("span",{children:i("pagination.perPage")}),e.jsxs(b,{value:String(n),onValueChange:t=>x?.(Number(t)),children:[e.jsx(g,{className:"h-8 w-[80px]",children:e.jsx(N,{})}),e.jsx(k,{children:o.map(t=>e.jsx(C,{value:String(t),children:t},t))})]})]}),s!==void 0&&v!==null&&j!==null&&e.jsx("span",{"aria-live":"polite",children:i("pagination.range",{from:s===0?0:v,to:j,total:s})})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{variant:"ghost",size:"icon","aria-label":i("pagination.firstPage"),disabled:!m,onClick:()=>l(1),className:"hidden sm:inline-flex",children:e.jsx(z,{})}),e.jsx(r,{variant:"ghost",size:"icon","aria-label":i("actions.previous"),disabled:!m,onClick:()=>l(a-1),children:e.jsx(M,{})}),e.jsx("span",{className:"px-2 text-sm tabular-nums","aria-live":"polite",children:i("pagination.pageOfTotal",{page:a,totalPages:Math.max(1,c)})}),e.jsx(r,{variant:"ghost",size:"icon","aria-label":i("actions.next"),disabled:!h,onClick:()=>l(a+1),children:e.jsx(S,{})}),e.jsx(r,{variant:"ghost",size:"icon","aria-label":i("pagination.lastPage"),disabled:!h,onClick:()=>l(c),className:"hidden sm:inline-flex",children:e.jsx(L,{})})]})]})}T.displayName="Pagination";export{T as P};
|
|
17
|
-
//# sourceMappingURL=pagination-
|
|
17
|
+
//# sourceMappingURL=pagination-ANxQzaRV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination-
|
|
1
|
+
{"version":3,"file":"pagination-ANxQzaRV.js","sources":["../../node_modules/lucide-react/dist/esm/icons/chevron-first.js","../../node_modules/lucide-react/dist/esm/icons/chevron-last.js","../../node_modules/lucide-react/dist/esm/icons/chevron-left.js","../../src/components/common/pagination.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 ChevronFirst = createLucideIcon(\"ChevronFirst\", [\n [\"path\", { d: \"m17 18-6-6 6-6\", key: \"1yerx2\" }],\n [\"path\", { d: \"M7 6v12\", key: \"1p53r6\" }]\n]);\n\nexport { ChevronFirst as default };\n//# sourceMappingURL=chevron-first.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 ChevronLast = createLucideIcon(\"ChevronLast\", [\n [\"path\", { d: \"m7 18 6-6-6-6\", key: \"lwmzdw\" }],\n [\"path\", { d: \"M17 6v12\", key: \"1o0aio\" }]\n]);\n\nexport { ChevronLast as default };\n//# sourceMappingURL=chevron-last.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 ChevronLeft = createLucideIcon(\"ChevronLeft\", [\n [\"path\", { d: \"m15 18-6-6 6-6\", key: \"1wnfg3\" }]\n]);\n\nexport { ChevronLeft as default };\n//# sourceMappingURL=chevron-left.js.map\n","/**\n * Pagination — controlled page navigator. Drives the URL via the\n * `page` / `perPage` callbacks; the caller decides whether to write\n * useSearchParams (recommended), zustand, or just local state.\n *\n * Why controlled: each M2 page wants the page index in the URL so\n * deep-links work (\"here's row 42 — share it\"). Forcing the component\n * to manage its own state would either duplicate the search-params\n * read or trap callers into useEffect to sync. Controlled keeps the\n * data flow obvious.\n *\n * Mobile behavior:\n * - The page-size selector hides below sm (no room; default 20 is\n * fine on phone).\n * - The first / last buttons hide below sm (the page label keeps\n * the user oriented; prev / next is enough).\n * - All buttons have a 44×44 hit target via the `icon` size.\n *\n * Edge cases:\n * - page count of 0 / 1 → component still renders so the table\n * footer doesn't jump on the next page-flip; buttons are disabled.\n * - page > totalPages → clamp on the caller's side (we display the\n * label as-is so the caller sees the bug instead of us masking it).\n */\n\nimport { ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { useTranslation } from 'react-i18next'\nimport { Button } from '@/components/ui/button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { cn } from '@/lib/utils'\n\nexport interface PaginationProps {\n /** 1-based current page. */\n page: number\n /** Total number of pages. Pass `Math.max(1, Math.ceil(total / perPage))`. */\n totalPages: number\n /** Optional row count — when present, renders \"1–20 of 150\" alongside the page label. */\n totalRows?: number\n /** Optional rows-per-page slot. Pass `[10, 20, 50, 100]` to enable. */\n perPage?: number\n perPageOptions?: number[]\n onPageChange: (page: number) => void\n onPerPageChange?: (perPage: number) => void\n className?: string\n}\n\nfunction Pagination({\n page,\n totalPages,\n totalRows,\n perPage,\n perPageOptions,\n onPageChange,\n onPerPageChange,\n className,\n}: PaginationProps): JSX.Element {\n const { t } = useTranslation('common')\n const canPrev = page > 1\n const canNext = page < totalPages\n const showPerPage = perPage !== undefined && perPageOptions && perPageOptions.length > 0 && onPerPageChange\n\n const rangeFrom = perPage ? (page - 1) * perPage + 1 : null\n const rangeTo = perPage && totalRows !== undefined\n ? Math.min(page * perPage, totalRows)\n : null\n\n return (\n <div\n className={cn(\n 'flex flex-wrap items-center justify-between gap-3 py-2',\n className,\n )}\n role=\"navigation\"\n aria-label={t('pagination.label')}\n >\n <div className=\"flex items-center gap-2 text-sm text-text-dim\">\n {showPerPage && (\n <div className=\"hidden sm:flex items-center gap-2\">\n <span>{t('pagination.perPage')}</span>\n <Select\n value={String(perPage)}\n onValueChange={(v) => onPerPageChange?.(Number(v))}\n >\n <SelectTrigger className=\"h-8 w-[80px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {perPageOptions.map((n) => (\n <SelectItem key={n} value={String(n)}>\n {n}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n {totalRows !== undefined && rangeFrom !== null && rangeTo !== null && (\n <span aria-live=\"polite\">\n {t('pagination.range', {\n from: totalRows === 0 ? 0 : rangeFrom,\n to: rangeTo,\n total: totalRows,\n })}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.firstPage')}\n disabled={!canPrev}\n onClick={() => onPageChange(1)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronFirst />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.previous')}\n disabled={!canPrev}\n onClick={() => onPageChange(page - 1)}\n >\n <ChevronLeft />\n </Button>\n\n <span className=\"px-2 text-sm tabular-nums\" aria-live=\"polite\">\n {t('pagination.pageOfTotal', { page, totalPages: Math.max(1, totalPages) })}\n </span>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('actions.next')}\n disabled={!canNext}\n onClick={() => onPageChange(page + 1)}\n >\n <ChevronRight />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={t('pagination.lastPage')}\n disabled={!canNext}\n onClick={() => onPageChange(totalPages)}\n className=\"hidden sm:inline-flex\"\n >\n <ChevronLast />\n </Button>\n </div>\n </div>\n )\n}\nPagination.displayName = 'Pagination'\n\nexport { Pagination }\n"],"names":["ChevronFirst","createLucideIcon","ChevronLast","ChevronLeft","Pagination","page","totalPages","totalRows","perPage","perPageOptions","onPageChange","onPerPageChange","className","t","useTranslation","canPrev","canNext","showPerPage","rangeFrom","rangeTo","jsxs","cn","jsx","Select","v","SelectTrigger","SelectValue","SelectContent","n","SelectItem","Button","ChevronRight"],"mappings":"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","x_google_ignoreList":[0,1,2]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ae as p,ad as k,V as e,c as u,B as j,G as N,a4 as m,L as F,t as z}from"./index-
|
|
2
|
-
//# sourceMappingURL=persona-
|
|
1
|
+
import{ae as p,ad as k,V as e,c as u,B as j,G as N,a4 as m,L as F,t as z}from"./index-CGaI-i4K.js";import{e as y}from"./react-C9F3QeMB.js";import{E as P}from"./empty-state-CwUKG8xX.js";import{C as A}from"./confirm-dialog-DD1ZW1XE.js";import{e as R,g as U,a as _,h as M,c as G}from"./use-memory-C3GgMqiJ.js";import{B as D}from"./brain-n56pZ1TQ.js";import{L as x}from"./loader-circle-BBIfyATA.js";import{R as J}from"./refresh-ccw-DpPWcwTg.js";import{P as O}from"./play-BNtSkb5l.js";import{C as Q}from"./circle-check-big-D6TvCoDM.js";import{C as V}from"./circle-x-OcRzGLRb.js";import{T as X}from"./trash-2-DL2FAuYX.js";import"./dialog-D5BsJN2q.js";import"./x-BLllJ8d_.js";import"./useQuery-ByZlZXlw.js";function le(){const{t}=p(["memory","common"]),[s]=k(),r=s.get("user")??"";return r?e.jsx(q,{userKey:r}):e.jsx("div",{className:"mx-auto max-w-3xl",children:e.jsx(P,{icon:e.jsx(D,{}),title:t("noUserSelected.title"),description:t("noUserSelected.description")})})}function q({userKey:t}){const{t:s}=p(["memory","common"]),r=R(t),n=r.data,o=U(),a=_().data?.jobs[0],i=M(),f=G(),[E,h]=y.useState(!1),[d,g]=y.useState(n?.summary??"");y.useEffect(()=>{g(n?.summary??"")},[n?.summary]);const b=d!==(n?.summary??"");async function w(){const c=d.trim();if(c)try{await i.mutateAsync({user_key:t,body:{summary:c}}),m.success(s("persona.saved"))}catch(l){const{message:T}=N(l,s);m.error(T)}}async function L(){try{await f.mutateAsync(t),m.success(s("common:actions.delete"))}catch(c){const{message:l}=N(c,s);throw m.error(l),c}}async function B(){try{await o.mutateAsync()}catch(c){const{message:l}=N(c,s);m.error(l)}}return e.jsxs("div",{className:"mx-auto flex max-w-4xl 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("persona.title")}),e.jsxs(u,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>r.refetch(),disabled:r.isFetching,"aria-label":s("actions.refresh",{ns:"common"}),children:[r.isFetching?e.jsx(x,{className:"h-4 w-4 animate-spin"}):e.jsx(J,{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("persona.subtitle")})]}),e.jsxs("div",{className:"rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("span",{className:"font-medium text-sm text-text",children:s("persona.consolidate.trigger")}),e.jsx(H,{job:a}),e.jsxs(u,{variant:"default",size:"sm",onClick:()=>void B(),disabled:o.isPending||a?.phase==="running",className:"ml-auto",children:[o.isPending?e.jsx(x,{className:"h-4 w-4 animate-spin"}):e.jsx(O,{className:"h-4 w-4"}),o.isPending?s("persona.consolidate.triggering"):s("persona.consolidate.trigger")]})]}),a?.phase==="done"&&(a.result.users!=null||a.result.updated!=null)&&e.jsx("p",{className:"mt-2 text-xs text-text-dim",children:s("persona.consolidate.result",{users:a.result.users??0,updated:a.result.updated??0})}),a?.phase==="failed"&&a.result.error&&e.jsx("p",{className:"mt-2 text-xs text-danger",children:a.result.error})]}),r.isLoading?e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"}):n?e.jsxs(e.Fragment,{children:[n.updated_at>0&&e.jsx("div",{className:"text-xs text-text-dim",children:s("persona.updated",{at:S(n.updated_at)})}),e.jsx(C,{draft:d,onChange:g,onSave:()=>void w(),saving:i.isPending,dirty:b,canDelete:!0,onDelete:()=>h(!0)})]}):e.jsxs(e.Fragment,{children:[e.jsx(P,{icon:e.jsx(D,{}),title:s("persona.empty.title"),description:s("persona.empty.description")}),e.jsx(C,{draft:d,onChange:g,onSave:()=>void w(),saving:i.isPending,dirty:b,canDelete:!1,onDelete:()=>h(!0)})]}),e.jsx(A,{open:E,onOpenChange:h,title:s("persona.confirmDelete"),description:s("persona.confirmDeleteDesc"),intent:"danger",confirmLabel:s("persona.delete"),onConfirm:L})]})}function C({draft:t,onChange:s,onSave:r,saving:n,dirty:o,canDelete:v,onDelete:a}){const{t:i}=p("memory");return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(F,{htmlFor:"persona-editor",className:"text-sm text-text-dim",children:i("persona.editorLabel")}),e.jsx("textarea",{id:"persona-editor",value:t,onChange:f=>s(f.target.value),rows:12,className:z("w-full resize-y rounded-md border bg-bg px-3 py-2","font-mono text-sm leading-6","focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-1 focus:ring-offset-bg",o?"border-accent":"border-border")}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[v&&e.jsxs(u,{type:"button",variant:"outline",size:"sm",onClick:a,children:[e.jsx(X,{className:"h-3 w-3"}),i("persona.delete")]}),e.jsxs(u,{type:"button",size:"sm",className:"ml-auto",disabled:!o||n||t.trim().length===0,onClick:r,children:[n?e.jsx(x,{className:"h-4 w-4 animate-spin"}):null,i("persona.save")]})]})]})}function H({job:t}){const{t:s}=p("memory");return t?t.phase==="running"?e.jsxs(j,{variant:"info",children:[e.jsx(x,{className:"h-3 w-3 animate-spin"}),s("persona.consolidate.running")]}):t.phase==="done"?e.jsxs(j,{variant:"success",children:[e.jsx(Q,{className:"h-3 w-3"}),s("persona.consolidate.lastRun",{at:S(t.finishedAt??t.startedAt)})]}):e.jsxs(j,{variant:"danger",children:[e.jsx(V,{className:"h-3 w-3"}),s("persona.consolidate.doneFailed")]}):null}function S(t){try{const s=new Date(t);return Number.isNaN(s.getTime())?String(t):s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return String(t)}}export{le as default};
|
|
2
|
+
//# sourceMappingURL=persona-CHz80XDk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persona-Dy-fuCBR.js","sources":["../../src/routes/memory/persona.tsx"],"sourcesContent":["/**\n * /memory/persona — view + edit the per-user persona summary +\n * trigger the consolidation pass.\n *\n * Layout: status strip (last consolidate run + button) on top, then\n * the persona editor (textarea + Save + Delete). The editor enters\n * an \"unsaved changes\" state when the textarea diverges from the\n * server-rendered summary; Save flips back to clean.\n *\n * Consolidate flow:\n * * Trigger button POSTs /api/memory/consolidate; the backend\n * replies 202 with a jobId.\n * * /api/memory/consolidate/status is polled every 3s by the\n * hook so the operator sees phase transitions live (running →\n * done / failed) without manual refresh.\n * * On `done`, the persona query is invalidated — the new\n * summary appears in the textarea automatically.\n */\n\nimport { useEffect, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Brain, CheckCircle, Loader2, Play, RefreshCcw, Trash2, XCircle } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n useMemoryPersona,\n useUpdatePersona,\n useDeletePersona,\n useConsolidateStatus,\n useTriggerConsolidate,\n} from '@/hooks/use-memory'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\nimport type { ConsolidateJob } from '@/types/api'\n\nexport default function MemoryPersonaRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const [params] = useSearchParams()\n const userKey = params.get('user') ?? ''\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 return <PersonaEditor userKey={userKey} />\n}\n\ninterface PersonaEditorProps {\n userKey: string\n}\n\nfunction PersonaEditor({ userKey }: PersonaEditorProps): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const personaQuery = useMemoryPersona(userKey)\n const persona = personaQuery.data\n\n const consolidate = useTriggerConsolidate()\n const status = useConsolidateStatus()\n const latestJob = status.data?.jobs[0]\n\n const updatePersona = useUpdatePersona()\n const deletePersona = useDeletePersona()\n const [confirmDelete, setConfirmDelete] = useState(false)\n\n /** Editor state — initialised from the server summary; tracks\n * dirtiness via reference comparison after each save. */\n const [draft, setDraft] = useState(persona?.summary ?? '')\n useEffect(() => {\n setDraft(persona?.summary ?? '')\n }, [persona?.summary])\n const dirty = draft !== (persona?.summary ?? '')\n\n async function onSave(): Promise<void> {\n const trimmed = draft.trim()\n if (!trimmed) return\n try {\n await updatePersona.mutateAsync({ user_key: userKey, body: { summary: trimmed } })\n toast.success(t('persona.saved'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n async function onConfirmDelete(): Promise<void> {\n try {\n await deletePersona.mutateAsync(userKey)\n toast.success(t('common:actions.delete'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n async function onTrigger(): Promise<void> {\n try {\n await consolidate.mutateAsync()\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-4xl 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('persona.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => personaQuery.refetch()}\n disabled={personaQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {personaQuery.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('persona.subtitle')}</p>\n </header>\n\n {/* Consolidate strip */}\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"font-medium text-sm text-text\">{t('persona.consolidate.trigger')}</span>\n <ConsolidateBadge job={latestJob} />\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => void onTrigger()}\n disabled={consolidate.isPending || latestJob?.phase === 'running'}\n className=\"ml-auto\"\n >\n {consolidate.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Play className=\"h-4 w-4\" />}\n {consolidate.isPending\n ? t('persona.consolidate.triggering')\n : t('persona.consolidate.trigger')}\n </Button>\n </div>\n {latestJob?.phase === 'done' && (latestJob.result.users != null || latestJob.result.updated != null) && (\n <p className=\"mt-2 text-xs text-text-dim\">\n {t('persona.consolidate.result', {\n users: latestJob.result.users ?? 0,\n updated: latestJob.result.updated ?? 0,\n })}\n </p>\n )}\n {latestJob?.phase === 'failed' && latestJob.result.error && (\n <p className=\"mt-2 text-xs text-danger\">{latestJob.result.error}</p>\n )}\n </div>\n\n {/* Editor */}\n {personaQuery.isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : !persona ? (\n <>\n <EmptyState\n icon={<Brain />}\n title={t('persona.empty.title')}\n description={t('persona.empty.description')}\n />\n {/* Even with no persona, the operator can still type one in\n and save — the upsert handler creates a new row. */}\n <PersonaTextarea\n draft={draft}\n onChange={setDraft}\n onSave={() => void onSave()}\n saving={updatePersona.isPending}\n dirty={dirty}\n canDelete={false}\n onDelete={() => setConfirmDelete(true)}\n />\n </>\n ) : (\n <>\n {persona.updated_at > 0 && (\n <div className=\"text-xs text-text-dim\">\n {t('persona.updated', { at: formatEpoch(persona.updated_at) })}\n </div>\n )}\n <PersonaTextarea\n draft={draft}\n onChange={setDraft}\n onSave={() => void onSave()}\n saving={updatePersona.isPending}\n dirty={dirty}\n canDelete\n onDelete={() => setConfirmDelete(true)}\n />\n </>\n )}\n\n <ConfirmDialog\n open={confirmDelete}\n onOpenChange={setConfirmDelete}\n title={t('persona.confirmDelete')}\n description={t('persona.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('persona.delete')}\n onConfirm={onConfirmDelete}\n />\n </div>\n )\n}\n\ninterface PersonaTextareaProps {\n draft: string\n onChange: (next: string) => void\n onSave: () => void\n saving: boolean\n dirty: boolean\n canDelete: boolean\n onDelete: () => void\n}\n\nfunction PersonaTextarea({\n draft, onChange, onSave, saving, dirty, canDelete, onDelete,\n}: PersonaTextareaProps): JSX.Element {\n const { t } = useTranslation('memory')\n return (\n <div className=\"flex flex-col gap-2\">\n <Label htmlFor=\"persona-editor\" className=\"text-sm text-text-dim\">\n {t('persona.editorLabel')}\n </Label>\n <textarea\n id=\"persona-editor\"\n value={draft}\n onChange={(e) => onChange(e.target.value)}\n rows={12}\n className={cn(\n 'w-full resize-y rounded-md border bg-bg px-3 py-2',\n 'font-mono text-sm leading-6',\n 'focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-1 focus:ring-offset-bg',\n dirty ? 'border-accent' : 'border-border',\n )}\n />\n <div className=\"flex flex-wrap items-center gap-2\">\n {canDelete && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={onDelete}\n >\n <Trash2 className=\"h-3 w-3\" />\n {t('persona.delete')}\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"ml-auto\"\n disabled={!dirty || saving || draft.trim().length === 0}\n onClick={onSave}\n >\n {saving ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : null}\n {t('persona.save')}\n </Button>\n </div>\n </div>\n )\n}\n\ninterface ConsolidateBadgeProps {\n job: ConsolidateJob | undefined\n}\n\nfunction ConsolidateBadge({ job }: ConsolidateBadgeProps): JSX.Element | null {\n const { t } = useTranslation('memory')\n if (!job) return null\n if (job.phase === 'running') {\n return (\n <Badge variant=\"info\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n {t('persona.consolidate.running')}\n </Badge>\n )\n }\n if (job.phase === 'done') {\n return (\n <Badge variant=\"success\">\n <CheckCircle className=\"h-3 w-3\" />\n {t('persona.consolidate.lastRun', { at: formatEpoch(job.finishedAt ?? job.startedAt) })}\n </Badge>\n )\n }\n return (\n <Badge variant=\"danger\">\n <XCircle className=\"h-3 w-3\" />\n {t('persona.consolidate.doneFailed')}\n </Badge>\n )\n}\n\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":["MemoryPersonaRoute","useTranslation","params","useSearchParams","userKey","jsx","PersonaEditor","EmptyState","Brain","t","personaQuery","useMemoryPersona","persona","consolidate","useTriggerConsolidate","latestJob","useConsolidateStatus","updatePersona","useUpdatePersona","deletePersona","useDeletePersona","confirmDelete","setConfirmDelete","useState","draft","setDraft","useEffect","dirty","onSave","trimmed","toast","err","message","describeError","onConfirmDelete","onTrigger","jsxs","Button","Loader2","RefreshCcw","ConsolidateBadge","Play","Fragment","formatEpoch","PersonaTextarea","ConfirmDialog","onChange","saving","canDelete","onDelete","Label","e","cn","Trash2","job","Badge","CheckCircle","XCircle","ms","d"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persona-CHz80XDk.js","sources":["../../src/routes/memory/persona.tsx"],"sourcesContent":["/**\n * /memory/persona — view + edit the per-user persona summary +\n * trigger the consolidation pass.\n *\n * Layout: status strip (last consolidate run + button) on top, then\n * the persona editor (textarea + Save + Delete). The editor enters\n * an \"unsaved changes\" state when the textarea diverges from the\n * server-rendered summary; Save flips back to clean.\n *\n * Consolidate flow:\n * * Trigger button POSTs /api/memory/consolidate; the backend\n * replies 202 with a jobId.\n * * /api/memory/consolidate/status is polled every 3s by the\n * hook so the operator sees phase transitions live (running →\n * done / failed) without manual refresh.\n * * On `done`, the persona query is invalidated — the new\n * summary appears in the textarea automatically.\n */\n\nimport { useEffect, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Brain, CheckCircle, Loader2, Play, RefreshCcw, Trash2, XCircle } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n useMemoryPersona,\n useUpdatePersona,\n useDeletePersona,\n useConsolidateStatus,\n useTriggerConsolidate,\n} from '@/hooks/use-memory'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\nimport type { ConsolidateJob } from '@/types/api'\n\nexport default function MemoryPersonaRoute(): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const [params] = useSearchParams()\n const userKey = params.get('user') ?? ''\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 return <PersonaEditor userKey={userKey} />\n}\n\ninterface PersonaEditorProps {\n userKey: string\n}\n\nfunction PersonaEditor({ userKey }: PersonaEditorProps): JSX.Element {\n const { t } = useTranslation(['memory', 'common'])\n const personaQuery = useMemoryPersona(userKey)\n const persona = personaQuery.data\n\n const consolidate = useTriggerConsolidate()\n const status = useConsolidateStatus()\n const latestJob = status.data?.jobs[0]\n\n const updatePersona = useUpdatePersona()\n const deletePersona = useDeletePersona()\n const [confirmDelete, setConfirmDelete] = useState(false)\n\n /** Editor state — initialised from the server summary; tracks\n * dirtiness via reference comparison after each save. */\n const [draft, setDraft] = useState(persona?.summary ?? '')\n useEffect(() => {\n setDraft(persona?.summary ?? '')\n }, [persona?.summary])\n const dirty = draft !== (persona?.summary ?? '')\n\n async function onSave(): Promise<void> {\n const trimmed = draft.trim()\n if (!trimmed) return\n try {\n await updatePersona.mutateAsync({ user_key: userKey, body: { summary: trimmed } })\n toast.success(t('persona.saved'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n async function onConfirmDelete(): Promise<void> {\n try {\n await deletePersona.mutateAsync(userKey)\n toast.success(t('common:actions.delete'))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err\n }\n }\n\n async function onTrigger(): Promise<void> {\n try {\n await consolidate.mutateAsync()\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-4xl 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('persona.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => personaQuery.refetch()}\n disabled={personaQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {personaQuery.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('persona.subtitle')}</p>\n </header>\n\n {/* Consolidate strip */}\n <div className=\"rounded-md border border-border bg-surface p-3\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"font-medium text-sm text-text\">{t('persona.consolidate.trigger')}</span>\n <ConsolidateBadge job={latestJob} />\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => void onTrigger()}\n disabled={consolidate.isPending || latestJob?.phase === 'running'}\n className=\"ml-auto\"\n >\n {consolidate.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Play className=\"h-4 w-4\" />}\n {consolidate.isPending\n ? t('persona.consolidate.triggering')\n : t('persona.consolidate.trigger')}\n </Button>\n </div>\n {latestJob?.phase === 'done' && (latestJob.result.users != null || latestJob.result.updated != null) && (\n <p className=\"mt-2 text-xs text-text-dim\">\n {t('persona.consolidate.result', {\n users: latestJob.result.users ?? 0,\n updated: latestJob.result.updated ?? 0,\n })}\n </p>\n )}\n {latestJob?.phase === 'failed' && latestJob.result.error && (\n <p className=\"mt-2 text-xs text-danger\">{latestJob.result.error}</p>\n )}\n </div>\n\n {/* Editor */}\n {personaQuery.isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : !persona ? (\n <>\n <EmptyState\n icon={<Brain />}\n title={t('persona.empty.title')}\n description={t('persona.empty.description')}\n />\n {/* Even with no persona, the operator can still type one in\n and save — the upsert handler creates a new row. */}\n <PersonaTextarea\n draft={draft}\n onChange={setDraft}\n onSave={() => void onSave()}\n saving={updatePersona.isPending}\n dirty={dirty}\n canDelete={false}\n onDelete={() => setConfirmDelete(true)}\n />\n </>\n ) : (\n <>\n {persona.updated_at > 0 && (\n <div className=\"text-xs text-text-dim\">\n {t('persona.updated', { at: formatEpoch(persona.updated_at) })}\n </div>\n )}\n <PersonaTextarea\n draft={draft}\n onChange={setDraft}\n onSave={() => void onSave()}\n saving={updatePersona.isPending}\n dirty={dirty}\n canDelete\n onDelete={() => setConfirmDelete(true)}\n />\n </>\n )}\n\n <ConfirmDialog\n open={confirmDelete}\n onOpenChange={setConfirmDelete}\n title={t('persona.confirmDelete')}\n description={t('persona.confirmDeleteDesc')}\n intent=\"danger\"\n confirmLabel={t('persona.delete')}\n onConfirm={onConfirmDelete}\n />\n </div>\n )\n}\n\ninterface PersonaTextareaProps {\n draft: string\n onChange: (next: string) => void\n onSave: () => void\n saving: boolean\n dirty: boolean\n canDelete: boolean\n onDelete: () => void\n}\n\nfunction PersonaTextarea({\n draft, onChange, onSave, saving, dirty, canDelete, onDelete,\n}: PersonaTextareaProps): JSX.Element {\n const { t } = useTranslation('memory')\n return (\n <div className=\"flex flex-col gap-2\">\n <Label htmlFor=\"persona-editor\" className=\"text-sm text-text-dim\">\n {t('persona.editorLabel')}\n </Label>\n <textarea\n id=\"persona-editor\"\n value={draft}\n onChange={(e) => onChange(e.target.value)}\n rows={12}\n className={cn(\n 'w-full resize-y rounded-md border bg-bg px-3 py-2',\n 'font-mono text-sm leading-6',\n 'focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-1 focus:ring-offset-bg',\n dirty ? 'border-accent' : 'border-border',\n )}\n />\n <div className=\"flex flex-wrap items-center gap-2\">\n {canDelete && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={onDelete}\n >\n <Trash2 className=\"h-3 w-3\" />\n {t('persona.delete')}\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"ml-auto\"\n disabled={!dirty || saving || draft.trim().length === 0}\n onClick={onSave}\n >\n {saving ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : null}\n {t('persona.save')}\n </Button>\n </div>\n </div>\n )\n}\n\ninterface ConsolidateBadgeProps {\n job: ConsolidateJob | undefined\n}\n\nfunction ConsolidateBadge({ job }: ConsolidateBadgeProps): JSX.Element | null {\n const { t } = useTranslation('memory')\n if (!job) return null\n if (job.phase === 'running') {\n return (\n <Badge variant=\"info\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n {t('persona.consolidate.running')}\n </Badge>\n )\n }\n if (job.phase === 'done') {\n return (\n <Badge variant=\"success\">\n <CheckCircle className=\"h-3 w-3\" />\n {t('persona.consolidate.lastRun', { at: formatEpoch(job.finishedAt ?? job.startedAt) })}\n </Badge>\n )\n }\n return (\n <Badge variant=\"danger\">\n <XCircle className=\"h-3 w-3\" />\n {t('persona.consolidate.doneFailed')}\n </Badge>\n )\n}\n\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":["MemoryPersonaRoute","useTranslation","params","useSearchParams","userKey","jsx","PersonaEditor","EmptyState","Brain","t","personaQuery","useMemoryPersona","persona","consolidate","useTriggerConsolidate","latestJob","useConsolidateStatus","updatePersona","useUpdatePersona","deletePersona","useDeletePersona","confirmDelete","setConfirmDelete","useState","draft","setDraft","useEffect","dirty","onSave","trimmed","toast","err","message","describeError","onConfirmDelete","onTrigger","jsxs","Button","Loader2","RefreshCcw","ConsolidateBadge","Play","Fragment","formatEpoch","PersonaTextarea","ConfirmDialog","onChange","saving","canDelete","onDelete","Label","e","cn","Trash2","job","Badge","CheckCircle","XCircle","ms","d"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{z as o}from"./index-
|
|
1
|
+
import{z as o}from"./index-CGaI-i4K.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const e=o("Play",[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]]);export{e as P};
|
|
7
|
-
//# sourceMappingURL=play-
|
|
7
|
+
//# sourceMappingURL=play-BNtSkb5l.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play-
|
|
1
|
+
{"version":3,"file":"play-BNtSkb5l.js","sources":["../../node_modules/lucide-react/dist/esm/icons/play.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 Play = createLucideIcon(\"Play\", [\n [\"polygon\", { points: \"6 3 20 12 6 21 6 3\", key: \"1oa8hb\" }]\n]);\n\nexport { Play as default };\n//# sourceMappingURL=play.js.map\n"],"names":["Play","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAOC,EAAiB,OAAQ,CACpC,CAAC,UAAW,CAAE,OAAQ,qBAAsB,IAAK,QAAQ,CAAE,CAC7D,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{z as e}from"./index-
|
|
1
|
+
import{z as e}from"./index-CGaI-i4K.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const a=e("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{a as P};
|
|
7
|
-
//# sourceMappingURL=plus-
|
|
7
|
+
//# sourceMappingURL=plus-CYsjCf6w.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plus-
|
|
1
|
+
{"version":3,"file":"plus-CYsjCf6w.js","sources":["../../node_modules/lucide-react/dist/esm/icons/plus.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 Plus = createLucideIcon(\"Plus\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n]);\n\nexport { Plus as default };\n//# sourceMappingURL=plus.js.map\n"],"names":["Plus","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAOC,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ae as r,V as e,c as d,a4 as m,G as E,B as f,q as w,t as x,S as _,l as I,m as M,j as A,k as c}from"./index-
|
|
2
|
-
//# sourceMappingURL=policy-
|
|
1
|
+
import{ae as r,V as e,c as d,a4 as m,G as E,B as f,q as w,t as x,S as _,l as I,m as M,j as A,k as c}from"./index-CGaI-i4K.js";import{d as C,p as B}from"./use-settings-CrkXdLrr.js";import{L as S}from"./loader-circle-BBIfyATA.js";import{R as U}from"./refresh-ccw-DpPWcwTg.js";import"./react-C9F3QeMB.js";import"./useQuery-ByZlZXlw.js";function o(s){if(s==null)return!1;const a=s.toLowerCase();return a==="1"||a==="true"||a==="yes"||a==="on"}function V(){const{t:s}=r(["settings","common"]),a=C(),i=B();async function t(n,v){try{await i.mutateAsync({updates:{[n]:v}}),m.success(s("policy.savingToast"))}catch(y){m.error(E(y,s).message)}}const l=a.data?.env??{},h=o(l.IMHUB_DANGEROUSLY_SKIP_PERMISSIONS),g=o(l.IMHUB_MEMORY_ENABLED),j=o(l.IMHUB_VIEWER_ENABLED),N=(l.IMHUB_TIMEOUT_DEFAULT??"").toLowerCase()==="allow",b=(l.IMHUB_A2A_NOTIFY_MODE??"essential").toLowerCase();return e.jsxs("div",{className:"mx-auto flex max-w-4xl 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("policy.title")}),e.jsxs(d,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>a.refetch(),disabled:a.isFetching,"aria-label":s("actions.refresh",{ns:"common"}),children:[a.isFetching?e.jsx(S,{className:"h-4 w-4 animate-spin"}):e.jsx(U,{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("policy.subtitle")})]}),a.isLoading?e.jsx("div",{className:"h-96 rounded-md bg-surface-2 animate-pulse"}):e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(O,{value:h,disabled:i.isPending,onChange:n=>void t("IMHUB_DANGEROUSLY_SKIP_PERMISSIONS",n?"1":"0")}),e.jsx(L,{allowOnTimeout:N,disabled:i.isPending,onChange:n=>void t("IMHUB_TIMEOUT_DEFAULT",n)}),e.jsx(p,{sectionKey:"memory",value:g,disabled:i.isPending,onChange:n=>void t("IMHUB_MEMORY_ENABLED",n?"1":"0")}),e.jsx(p,{sectionKey:"viewer",value:j,disabled:i.isPending,onChange:n=>void t("IMHUB_VIEWER_ENABLED",n?"1":"0")}),e.jsx(T,{value:b,disabled:i.isPending,onChange:n=>void t("IMHUB_A2A_NOTIFY_MODE",n)})]})]})}function O({value:s,disabled:a,onChange:i}){const{t}=r("settings");return e.jsx("section",{className:x("rounded-md border p-4",s?"border-danger/60 bg-danger-bg/30":"border-border bg-surface"),children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:t("policy.safety.title")}),s&&e.jsxs(f,{variant:"danger",children:[e.jsx(w,{className:"h-3 w-3"}),"ON"]})]}),e.jsx("p",{className:"mt-1 text-sm text-text-dim",children:t("policy.safety.description")}),!s&&e.jsx("p",{className:"mt-1 text-xs text-text-muted",children:t("policy.safety.tagWarn")}),e.jsx("code",{className:"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted",children:t("policy.safety.envKey")})]}),e.jsx(u,{value:s,disabled:a,onChange:i})]})})}function L({allowOnTimeout:s,disabled:a,onChange:i}){const{t}=r("settings");return e.jsx("section",{className:"rounded-md border border-border bg-surface p-4",children:e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:t("policy.approval.title")}),e.jsx("p",{className:"text-sm text-text-dim",children:t("policy.approval.description")}),e.jsx("code",{className:"self-start rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted",children:t("policy.approval.envKey")}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-2",children:[e.jsx(d,{type:"button",variant:s?"outline":"default",size:"sm",disabled:a,onClick:()=>i("deny"),children:t("policy.approval.valDeny")}),e.jsx(d,{type:"button",variant:s?"default":"outline",size:"sm",disabled:a,onClick:()=>i("allow"),children:t("policy.approval.valAllow")})]})]})})}function p({sectionKey:s,value:a,disabled:i,onChange:t}){const{t:l}=r("settings");return e.jsx("section",{className:"rounded-md border border-border bg-surface p-4",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:l(`policy.${s}.title`)}),e.jsx(f,{variant:a?"success":"outline",children:a?"ON":"OFF"})]}),e.jsx("p",{className:"mt-1 text-sm text-text-dim",children:l(`policy.${s}.description`)}),e.jsx("code",{className:"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted",children:l(`policy.${s}.envKey`)})]}),e.jsx(u,{value:a,disabled:i,onChange:t})]})})}function T({value:s,disabled:a,onChange:i}){const{t}=r("settings");return e.jsx("section",{className:"rounded-md border border-border bg-surface p-4",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsxs("div",{className:"flex-1",children:[e.jsx("span",{className:"font-medium text-text",children:t("policy.a2aNotify.title")}),e.jsx("p",{className:"mt-1 text-sm text-text-dim",children:t("policy.a2aNotify.description")}),e.jsx("code",{className:"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted",children:t("policy.a2aNotify.envKey")})]}),e.jsxs(_,{value:s,onValueChange:i,disabled:a,children:[e.jsx(I,{className:"w-36",children:e.jsx(M,{})}),e.jsxs(A,{children:[e.jsx(c,{value:"essential",children:t("policy.a2aNotify.valEssential")}),e.jsx(c,{value:"verbose",children:t("policy.a2aNotify.valVerbose")}),e.jsx(c,{value:"off",children:t("policy.a2aNotify.valOff")})]})]})]})})}function u({value:s,disabled:a,onChange:i}){return e.jsx("button",{type:"button",role:"switch","aria-checked":s,disabled:a,onClick:()=>i(!s),className:x("relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-bg","disabled:cursor-not-allowed disabled:opacity-50",s?"bg-accent":"bg-surface-2 border border-border"),children:e.jsx("span",{className:x("inline-block h-5 w-5 rounded-full bg-white shadow transition-transform",s?"translate-x-5":"translate-x-0.5")})})}export{V as default};
|
|
2
|
+
//# sourceMappingURL=policy-CtKRzual.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-DW_kZo8b.js","sources":["../../src/routes/settings/policy.tsx"],"sourcesContent":["/**\n * /settings/policy — dedicated UI for the highest-frequency env\n * toggles. Each is a one-click switch (or 2-3 option select) that\n * persists to `~/.agim/.env` via PUT /api/env immediately.\n *\n * Surfaced here:\n * * IMHUB_DANGEROUSLY_SKIP_PERMISSIONS (safety)\n * * IMHUB_TIMEOUT_DEFAULT (approval bus default)\n * * IMHUB_MEMORY_ENABLED (memory subsystem)\n * * IMHUB_VIEWER_ENABLED (long-message viewer)\n * * IMHUB_A2A_NOTIFY_MODE (cross-agent notify verbosity)\n *\n * All five are still editable in /settings/env. This page exists\n * because:\n * 1. They're the ones operators flip most often\n * 2. The env editor's table doesn't communicate \"this is a\n * boolean / 2-state / 3-state value\" — operators have to\n * know the literal strings \"1\"/\"0\"/\"allow\"/\"deny\"/etc.\n * 3. Safety toggle deserves a visible warning + danger color\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { AlertTriangle, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv } from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\n/** Treat the env value as a boolean — '1' / 'true' / 'yes' / 'on'\n * → true; everything else → false. Matches the backend's casual\n * truthy parsing in core/* modules. */\nfunction envBool(v: string | undefined): boolean {\n if (v == null) return false\n const t = v.toLowerCase()\n return t === '1' || t === 'true' || t === 'yes' || t === 'on'\n}\n\nexport default function SettingsPolicyRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const envQuery = useEnv()\n const updateEnv = useUpdateEnv()\n\n async function setValue(key: string, value: string | null): Promise<void> {\n try {\n await updateEnv.mutateAsync({ updates: { [key]: value } })\n toast.success(t('policy.savingToast'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n const env = envQuery.data?.env ?? {}\n const skipPerms = envBool(env.IMHUB_DANGEROUSLY_SKIP_PERMISSIONS)\n const memEnabled = envBool(env.IMHUB_MEMORY_ENABLED)\n const viewerEnabled = envBool(env.IMHUB_VIEWER_ENABLED)\n const timeoutAllow = (env.IMHUB_TIMEOUT_DEFAULT ?? '').toLowerCase() === 'allow'\n const a2aMode = (env.IMHUB_A2A_NOTIFY_MODE ?? 'essential').toLowerCase()\n\n return (\n <div className=\"mx-auto flex max-w-4xl 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('policy.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => envQuery.refetch()}\n disabled={envQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.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('policy.subtitle')}</p>\n </header>\n\n {envQuery.isLoading ? (\n <div className=\"h-96 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <div className=\"flex flex-col gap-3\">\n <SafetyCard\n value={skipPerms}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_DANGEROUSLY_SKIP_PERMISSIONS', v ? '1' : '0')}\n />\n <ApprovalCard\n allowOnTimeout={timeoutAllow}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_TIMEOUT_DEFAULT', v)}\n />\n <ToggleCard\n sectionKey=\"memory\"\n value={memEnabled}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_MEMORY_ENABLED', v ? '1' : '0')}\n />\n <ToggleCard\n sectionKey=\"viewer\"\n value={viewerEnabled}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_VIEWER_ENABLED', v ? '1' : '0')}\n />\n <A2ANotifyCard\n value={a2aMode}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_A2A_NOTIFY_MODE', v)}\n />\n </div>\n )}\n </div>\n )\n}\n\n/* ─────────────── Cards ─────────────── */\n\ninterface SafetyCardProps {\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\nfunction SafetyCard({ value, disabled, onChange }: SafetyCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section\n className={cn(\n 'rounded-md border p-4',\n value ? 'border-danger/60 bg-danger-bg/30' : 'border-border bg-surface',\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{t('policy.safety.title')}</span>\n {value && (\n <Badge variant=\"danger\">\n <AlertTriangle className=\"h-3 w-3\" />\n ON\n </Badge>\n )}\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">{t('policy.safety.description')}</p>\n {!value && (\n <p className=\"mt-1 text-xs text-text-muted\">{t('policy.safety.tagWarn')}</p>\n )}\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.safety.envKey')}\n </code>\n </div>\n <Toggle value={value} disabled={disabled} onChange={onChange} />\n </div>\n </section>\n )\n}\n\ninterface ApprovalCardProps {\n allowOnTimeout: boolean\n disabled: boolean\n onChange: (value: 'allow' | 'deny') => void\n}\n\nfunction ApprovalCard({ allowOnTimeout, disabled, onChange }: ApprovalCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex flex-col gap-2\">\n <span className=\"font-medium text-text\">{t('policy.approval.title')}</span>\n <p className=\"text-sm text-text-dim\">{t('policy.approval.description')}</p>\n <code className=\"self-start rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.approval.envKey')}\n </code>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n variant={!allowOnTimeout ? 'default' : 'outline'}\n size=\"sm\"\n disabled={disabled}\n onClick={() => onChange('deny')}\n >\n {t('policy.approval.valDeny')}\n </Button>\n <Button\n type=\"button\"\n variant={allowOnTimeout ? 'default' : 'outline'}\n size=\"sm\"\n disabled={disabled}\n onClick={() => onChange('allow')}\n >\n {t('policy.approval.valAllow')}\n </Button>\n </div>\n </div>\n </section>\n )\n}\n\ninterface ToggleCardProps {\n sectionKey: 'memory' | 'viewer'\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\nfunction ToggleCard({ sectionKey, value, disabled, onChange }: ToggleCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{t(`policy.${sectionKey}.title`)}</span>\n <Badge variant={value ? 'success' : 'outline'}>{value ? 'ON' : 'OFF'}</Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">{t(`policy.${sectionKey}.description`)}</p>\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t(`policy.${sectionKey}.envKey`)}\n </code>\n </div>\n <Toggle value={value} disabled={disabled} onChange={onChange} />\n </div>\n </section>\n )\n}\n\ninterface A2ANotifyCardProps {\n value: string\n disabled: boolean\n onChange: (v: string) => void\n}\n\nfunction A2ANotifyCard({ value, disabled, onChange }: A2ANotifyCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <span className=\"font-medium text-text\">{t('policy.a2aNotify.title')}</span>\n <p className=\"mt-1 text-sm text-text-dim\">{t('policy.a2aNotify.description')}</p>\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.a2aNotify.envKey')}\n </code>\n </div>\n <Select value={value} onValueChange={onChange} disabled={disabled}>\n <SelectTrigger className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"essential\">{t('policy.a2aNotify.valEssential')}</SelectItem>\n <SelectItem value=\"verbose\">{t('policy.a2aNotify.valVerbose')}</SelectItem>\n <SelectItem value=\"off\">{t('policy.a2aNotify.valOff')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </section>\n )\n}\n\ninterface ToggleProps {\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\n/** Thumb-style switch styled to the agim accent. Tailwind-only,\n * no Radix dep — keeps the click feel snappy. */\nfunction Toggle({ value, disabled, onChange }: ToggleProps): JSX.Element {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n disabled={disabled}\n onClick={() => onChange(!value)}\n className={cn(\n 'relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-bg',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n value ? 'bg-accent' : 'bg-surface-2 border border-border',\n )}\n >\n <span\n className={cn(\n 'inline-block h-5 w-5 rounded-full bg-white shadow transition-transform',\n value ? 'translate-x-5' : 'translate-x-0.5',\n )}\n />\n </button>\n )\n}\n"],"names":["envBool","v","t","SettingsPolicyRoute","useTranslation","envQuery","useEnv","updateEnv","useUpdateEnv","setValue","key","value","toast","err","describeError","env","skipPerms","memEnabled","viewerEnabled","timeoutAllow","a2aMode","jsxs","jsx","Button","Loader2","RefreshCcw","SafetyCard","ApprovalCard","ToggleCard","A2ANotifyCard","disabled","onChange","cn","Badge","AlertTriangle","Toggle","allowOnTimeout","sectionKey","Select","SelectTrigger","SelectValue","SelectContent","SelectItem"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"policy-CtKRzual.js","sources":["../../src/routes/settings/policy.tsx"],"sourcesContent":["/**\n * /settings/policy — dedicated UI for the highest-frequency env\n * toggles. Each is a one-click switch (or 2-3 option select) that\n * persists to `~/.agim/.env` via PUT /api/env immediately.\n *\n * Surfaced here:\n * * IMHUB_DANGEROUSLY_SKIP_PERMISSIONS (safety)\n * * IMHUB_TIMEOUT_DEFAULT (approval bus default)\n * * IMHUB_MEMORY_ENABLED (memory subsystem)\n * * IMHUB_VIEWER_ENABLED (long-message viewer)\n * * IMHUB_A2A_NOTIFY_MODE (cross-agent notify verbosity)\n *\n * All five are still editable in /settings/env. This page exists\n * because:\n * 1. They're the ones operators flip most often\n * 2. The env editor's table doesn't communicate \"this is a\n * boolean / 2-state / 3-state value\" — operators have to\n * know the literal strings \"1\"/\"0\"/\"allow\"/\"deny\"/etc.\n * 3. Safety toggle deserves a visible warning + danger color\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { AlertTriangle, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useEnv, useUpdateEnv } from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\n/** Treat the env value as a boolean — '1' / 'true' / 'yes' / 'on'\n * → true; everything else → false. Matches the backend's casual\n * truthy parsing in core/* modules. */\nfunction envBool(v: string | undefined): boolean {\n if (v == null) return false\n const t = v.toLowerCase()\n return t === '1' || t === 'true' || t === 'yes' || t === 'on'\n}\n\nexport default function SettingsPolicyRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const envQuery = useEnv()\n const updateEnv = useUpdateEnv()\n\n async function setValue(key: string, value: string | null): Promise<void> {\n try {\n await updateEnv.mutateAsync({ updates: { [key]: value } })\n toast.success(t('policy.savingToast'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n const env = envQuery.data?.env ?? {}\n const skipPerms = envBool(env.IMHUB_DANGEROUSLY_SKIP_PERMISSIONS)\n const memEnabled = envBool(env.IMHUB_MEMORY_ENABLED)\n const viewerEnabled = envBool(env.IMHUB_VIEWER_ENABLED)\n const timeoutAllow = (env.IMHUB_TIMEOUT_DEFAULT ?? '').toLowerCase() === 'allow'\n const a2aMode = (env.IMHUB_A2A_NOTIFY_MODE ?? 'essential').toLowerCase()\n\n return (\n <div className=\"mx-auto flex max-w-4xl 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('policy.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => envQuery.refetch()}\n disabled={envQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {envQuery.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('policy.subtitle')}</p>\n </header>\n\n {envQuery.isLoading ? (\n <div className=\"h-96 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <div className=\"flex flex-col gap-3\">\n <SafetyCard\n value={skipPerms}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_DANGEROUSLY_SKIP_PERMISSIONS', v ? '1' : '0')}\n />\n <ApprovalCard\n allowOnTimeout={timeoutAllow}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_TIMEOUT_DEFAULT', v)}\n />\n <ToggleCard\n sectionKey=\"memory\"\n value={memEnabled}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_MEMORY_ENABLED', v ? '1' : '0')}\n />\n <ToggleCard\n sectionKey=\"viewer\"\n value={viewerEnabled}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_VIEWER_ENABLED', v ? '1' : '0')}\n />\n <A2ANotifyCard\n value={a2aMode}\n disabled={updateEnv.isPending}\n onChange={(v) => void setValue('IMHUB_A2A_NOTIFY_MODE', v)}\n />\n </div>\n )}\n </div>\n )\n}\n\n/* ─────────────── Cards ─────────────── */\n\ninterface SafetyCardProps {\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\nfunction SafetyCard({ value, disabled, onChange }: SafetyCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section\n className={cn(\n 'rounded-md border p-4',\n value ? 'border-danger/60 bg-danger-bg/30' : 'border-border bg-surface',\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{t('policy.safety.title')}</span>\n {value && (\n <Badge variant=\"danger\">\n <AlertTriangle className=\"h-3 w-3\" />\n ON\n </Badge>\n )}\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">{t('policy.safety.description')}</p>\n {!value && (\n <p className=\"mt-1 text-xs text-text-muted\">{t('policy.safety.tagWarn')}</p>\n )}\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.safety.envKey')}\n </code>\n </div>\n <Toggle value={value} disabled={disabled} onChange={onChange} />\n </div>\n </section>\n )\n}\n\ninterface ApprovalCardProps {\n allowOnTimeout: boolean\n disabled: boolean\n onChange: (value: 'allow' | 'deny') => void\n}\n\nfunction ApprovalCard({ allowOnTimeout, disabled, onChange }: ApprovalCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex flex-col gap-2\">\n <span className=\"font-medium text-text\">{t('policy.approval.title')}</span>\n <p className=\"text-sm text-text-dim\">{t('policy.approval.description')}</p>\n <code className=\"self-start rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.approval.envKey')}\n </code>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n variant={!allowOnTimeout ? 'default' : 'outline'}\n size=\"sm\"\n disabled={disabled}\n onClick={() => onChange('deny')}\n >\n {t('policy.approval.valDeny')}\n </Button>\n <Button\n type=\"button\"\n variant={allowOnTimeout ? 'default' : 'outline'}\n size=\"sm\"\n disabled={disabled}\n onClick={() => onChange('allow')}\n >\n {t('policy.approval.valAllow')}\n </Button>\n </div>\n </div>\n </section>\n )\n}\n\ninterface ToggleCardProps {\n sectionKey: 'memory' | 'viewer'\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\nfunction ToggleCard({ sectionKey, value, disabled, onChange }: ToggleCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{t(`policy.${sectionKey}.title`)}</span>\n <Badge variant={value ? 'success' : 'outline'}>{value ? 'ON' : 'OFF'}</Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-dim\">{t(`policy.${sectionKey}.description`)}</p>\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t(`policy.${sectionKey}.envKey`)}\n </code>\n </div>\n <Toggle value={value} disabled={disabled} onChange={onChange} />\n </div>\n </section>\n )\n}\n\ninterface A2ANotifyCardProps {\n value: string\n disabled: boolean\n onChange: (v: string) => void\n}\n\nfunction A2ANotifyCard({ value, disabled, onChange }: A2ANotifyCardProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1\">\n <span className=\"font-medium text-text\">{t('policy.a2aNotify.title')}</span>\n <p className=\"mt-1 text-sm text-text-dim\">{t('policy.a2aNotify.description')}</p>\n <code className=\"mt-2 inline-block rounded bg-surface-2 px-1.5 py-0.5 text-xs text-text-muted\">\n {t('policy.a2aNotify.envKey')}\n </code>\n </div>\n <Select value={value} onValueChange={onChange} disabled={disabled}>\n <SelectTrigger className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"essential\">{t('policy.a2aNotify.valEssential')}</SelectItem>\n <SelectItem value=\"verbose\">{t('policy.a2aNotify.valVerbose')}</SelectItem>\n <SelectItem value=\"off\">{t('policy.a2aNotify.valOff')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </section>\n )\n}\n\ninterface ToggleProps {\n value: boolean\n disabled: boolean\n onChange: (v: boolean) => void\n}\n\n/** Thumb-style switch styled to the agim accent. Tailwind-only,\n * no Radix dep — keeps the click feel snappy. */\nfunction Toggle({ value, disabled, onChange }: ToggleProps): JSX.Element {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n disabled={disabled}\n onClick={() => onChange(!value)}\n className={cn(\n 'relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-bg',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n value ? 'bg-accent' : 'bg-surface-2 border border-border',\n )}\n >\n <span\n className={cn(\n 'inline-block h-5 w-5 rounded-full bg-white shadow transition-transform',\n value ? 'translate-x-5' : 'translate-x-0.5',\n )}\n />\n </button>\n )\n}\n"],"names":["envBool","v","t","SettingsPolicyRoute","useTranslation","envQuery","useEnv","updateEnv","useUpdateEnv","setValue","key","value","toast","err","describeError","env","skipPerms","memEnabled","viewerEnabled","timeoutAllow","a2aMode","jsxs","jsx","Button","Loader2","RefreshCcw","SafetyCard","ApprovalCard","ToggleCard","A2ANotifyCard","disabled","onChange","cn","Badge","AlertTriangle","Toggle","allowOnTimeout","sectionKey","Select","SelectTrigger","SelectValue","SelectContent","SelectItem"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{z as e}from"./index-
|
|
1
|
+
import{z as e}from"./index-CGaI-i4K.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const a=e("RefreshCcw",[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]]);export{a as R};
|
|
7
|
-
//# sourceMappingURL=refresh-ccw-
|
|
7
|
+
//# sourceMappingURL=refresh-ccw-DpPWcwTg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh-ccw-
|
|
1
|
+
{"version":3,"file":"refresh-ccw-DpPWcwTg.js","sources":["../../node_modules/lucide-react/dist/esm/icons/refresh-ccw.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 RefreshCcw = createLucideIcon(\"RefreshCcw\", [\n [\"path\", { d: \"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\", key: \"14sxne\" }],\n [\"path\", { d: \"M3 3v5h5\", key: \"1xhq8a\" }],\n [\"path\", { d: \"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16\", key: \"1hlbsb\" }],\n [\"path\", { d: \"M16 16h5v5\", key: \"ccwih5\" }]\n]);\n\nexport { RefreshCcw as default };\n//# sourceMappingURL=refresh-ccw.js.map\n"],"names":["RefreshCcw","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAaC,EAAiB,aAAc,CAChD,CAAC,OAAQ,CAAE,EAAG,qDAAsD,IAAK,QAAQ,CAAE,EACnF,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,sDAAuD,IAAK,QAAQ,CAAE,EACpF,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC","x_google_ignoreList":[0]}
|