agim-cli 1.2.131 → 1.2.133
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 +107 -0
- package/dist/core/llm/agent-loop.d.ts.map +1 -1
- package/dist/core/llm/agent-loop.js +16 -5
- package/dist/core/llm/agent-loop.js.map +1 -1
- package/dist/web/public/assets/{a2a-Rq5d7Xk5.js → a2a-TmaKRhXV.js} +2 -2
- package/dist/web/public/assets/{a2a-Rq5d7Xk5.js.map → a2a-TmaKRhXV.js.map} +1 -1
- package/dist/web/public/assets/{activity-FCJjBNRM.js → activity-Cckc7fGG.js} +2 -2
- package/dist/web/public/assets/{activity-FCJjBNRM.js.map → activity-Cckc7fGG.js.map} +1 -1
- package/dist/web/public/assets/{admins-9fFdLRCv.js → admins-1hMCDolP.js} +2 -2
- package/dist/web/public/assets/{admins-9fFdLRCv.js.map → admins-1hMCDolP.js.map} +1 -1
- package/dist/web/public/assets/{agents-CiWiDAvY.js → agents-3sUHlKzx.js} +2 -2
- package/dist/web/public/assets/{agents-CiWiDAvY.js.map → agents-3sUHlKzx.js.map} +1 -1
- package/dist/web/public/assets/{approvals-4gNB4E5r.js → approvals-CY-_Lg4Y.js} +2 -2
- package/dist/web/public/assets/{approvals-4gNB4E5r.js.map → approvals-CY-_Lg4Y.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-CL6JRd2c.js → arrow-down-BkZ50IzL.js} +2 -2
- package/dist/web/public/assets/{arrow-down-CL6JRd2c.js.map → arrow-down-BkZ50IzL.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-B47-Pj-X.js → arrow-up-NWC5K6Jw.js} +2 -2
- package/dist/web/public/assets/{arrow-up-B47-Pj-X.js.map → arrow-up-NWC5K6Jw.js.map} +1 -1
- package/dist/web/public/assets/{asks-DPTxh_Os.js → asks-VzAmpsEh.js} +2 -2
- package/dist/web/public/assets/{asks-DPTxh_Os.js.map → asks-VzAmpsEh.js.map} +1 -1
- package/dist/web/public/assets/{audit-Dw3mL-g7.js → audit-fOn2LH4D.js} +2 -2
- package/dist/web/public/assets/{audit-Dw3mL-g7.js.map → audit-fOn2LH4D.js.map} +1 -1
- package/dist/web/public/assets/{bell-ojwGPpS7.js → bell-FF7PJo1N.js} +2 -2
- package/dist/web/public/assets/{bell-ojwGPpS7.js.map → bell-FF7PJo1N.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-DDTjejCS.js → bgjobs-L0v-UwPW.js} +2 -2
- package/dist/web/public/assets/{bgjobs-DDTjejCS.js.map → bgjobs-L0v-UwPW.js.map} +1 -1
- package/dist/web/public/assets/{brain-wzaKeCbt.js → brain-CdkDpFr1.js} +2 -2
- package/dist/web/public/assets/{brain-wzaKeCbt.js.map → brain-CdkDpFr1.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-CCAq-ik6.js → briefcase-BXbOdl7E.js} +2 -2
- package/dist/web/public/assets/{briefcase-CCAq-ik6.js.map → briefcase-BXbOdl7E.js.map} +1 -1
- package/dist/web/public/assets/{chat-CbSvPFpG.js → chat-BazMi-ik.js} +3 -3
- package/dist/web/public/assets/{chat-CbSvPFpG.js.map → chat-BazMi-ik.js.map} +1 -1
- package/dist/web/public/assets/{chevron-left-bpKHh9Bu.js → chevron-left-Di1Tz64J.js} +2 -2
- package/dist/web/public/assets/{chevron-left-bpKHh9Bu.js.map → chevron-left-Di1Tz64J.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-CUlLpETY.js → chevron-right-BLjhBkqs.js} +2 -2
- package/dist/web/public/assets/{chevron-right-CUlLpETY.js.map → chevron-right-BLjhBkqs.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-D98QQwz0.js → circle-check-BaxzYLlE.js} +2 -2
- package/dist/web/public/assets/{circle-check-D98QQwz0.js.map → circle-check-BaxzYLlE.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-BP-0K1le.js → circle-check-big-C4BGLUvw.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-BP-0K1le.js.map → circle-check-big-C4BGLUvw.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-Et3rwVPd.js → circle-x-THl-PO3_.js} +2 -2
- package/dist/web/public/assets/{circle-x-Et3rwVPd.js.map → circle-x-THl-PO3_.js.map} +1 -1
- package/dist/web/public/assets/clock-iitpdQjZ.js +7 -0
- package/dist/web/public/assets/clock-iitpdQjZ.js.map +1 -0
- package/dist/web/public/assets/{confirm-dialog-6dKowsEt.js → confirm-dialog-r9HgkIYf.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-6dKowsEt.js.map → confirm-dialog-r9HgkIYf.js.map} +1 -1
- package/dist/web/public/assets/{copy-kCWCP9Wu.js → copy-DwyF4MOL.js} +2 -2
- package/dist/web/public/assets/{copy-kCWCP9Wu.js.map → copy-DwyF4MOL.js.map} +1 -1
- package/dist/web/public/assets/{data-table-BbNkr6tW.js → data-table-B80M8zdu.js} +2 -2
- package/dist/web/public/assets/{data-table-BbNkr6tW.js.map → data-table-B80M8zdu.js.map} +1 -1
- package/dist/web/public/assets/dialog-fGS0IXOo.js +6 -0
- package/dist/web/public/assets/{dialog-Cv87qelJ.js.map → dialog-fGS0IXOo.js.map} +1 -1
- package/dist/web/public/assets/{download-Cv8u9PxC.js → download-5ihiF2Gj.js} +2 -2
- package/dist/web/public/assets/{download-Cv8u9PxC.js.map → download-5ihiF2Gj.js.map} +1 -1
- package/dist/web/public/assets/{email-BS3f2y7i.js → email-LmRMqLRU.js} +3 -3
- package/dist/web/public/assets/{email-BS3f2y7i.js.map → email-LmRMqLRU.js.map} +1 -1
- package/dist/web/public/assets/{empty-state-CRnid5FY.js → empty-state-CrPnUC6d.js} +2 -2
- package/dist/web/public/assets/{empty-state-CRnid5FY.js.map → empty-state-CrPnUC6d.js.map} +1 -1
- package/dist/web/public/assets/{external-link-CzQc-c_P.js → external-link-DIJK1MAH.js} +2 -2
- package/dist/web/public/assets/{external-link-CzQc-c_P.js.map → external-link-DIJK1MAH.js.map} +1 -1
- package/dist/web/public/assets/{eye-DEBkfJiC.js → eye-DJJw0Ald.js} +2 -2
- package/dist/web/public/assets/{eye-DEBkfJiC.js.map → eye-DJJw0Ald.js.map} +1 -1
- package/dist/web/public/assets/{facts-O3FFqdD1.js → facts-BzImxpJD.js} +2 -2
- package/dist/web/public/assets/{facts-O3FFqdD1.js.map → facts-BzImxpJD.js.map} +1 -1
- package/dist/web/public/assets/{goals-pr5ky9rG.js → goals-C6p21B9N.js} +2 -2
- package/dist/web/public/assets/{goals-pr5ky9rG.js.map → goals-C6p21B9N.js.map} +1 -1
- package/dist/web/public/assets/{health-D_rfBsgq.js → health-D-ugz2Gp.js} +2 -2
- package/dist/web/public/assets/{health-D_rfBsgq.js.map → health-D-ugz2Gp.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-203oH09r.js → heart-pulse-DlZXcdL0.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-203oH09r.js.map → heart-pulse-DlZXcdL0.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-B5yJoH-X.js → heartbeat-DSasg-3y.js} +2 -2
- package/dist/web/public/assets/{heartbeat-B5yJoH-X.js.map → heartbeat-DSasg-3y.js.map} +1 -1
- package/dist/web/public/assets/{hot-CXGeh4Oo.js → hot-D67pYtaV.js} +2 -2
- package/dist/web/public/assets/{hot-CXGeh4Oo.js.map → hot-D67pYtaV.js.map} +1 -1
- package/dist/web/public/assets/{index-CuNnG-5O.js → index-CqwhfPlr.js} +9 -9
- package/dist/web/public/assets/index-CqwhfPlr.js.map +1 -0
- package/dist/web/public/assets/{installed-CQKXZNEU.js → installed-CrIsSoQE.js} +2 -2
- package/dist/web/public/assets/{installed-CQKXZNEU.js.map → installed-CrIsSoQE.js.map} +1 -1
- package/dist/web/public/assets/{jobs-DPxN8Ko0.js → jobs-yAwphb1W.js} +2 -2
- package/dist/web/public/assets/{jobs-DPxN8Ko0.js.map → jobs-yAwphb1W.js.map} +1 -1
- package/dist/web/public/assets/{layout-CxQy-DtV.js → layout-BXZKGQAk.js} +2 -2
- package/dist/web/public/assets/{layout-CxQy-DtV.js.map → layout-BXZKGQAk.js.map} +1 -1
- package/dist/web/public/assets/layout-CL5HFvHN.js +2 -0
- package/dist/web/public/assets/layout-CL5HFvHN.js.map +1 -0
- package/dist/web/public/assets/{layout-CQXWA5Ak.js → layout-CrtmlC8G.js} +2 -2
- package/dist/web/public/assets/{layout-CQXWA5Ak.js.map → layout-CrtmlC8G.js.map} +1 -1
- package/dist/web/public/assets/{layout-4C_GhacH.js → layout-awbFImGg.js} +2 -2
- package/dist/web/public/assets/{layout-4C_GhacH.js.map → layout-awbFImGg.js.map} +1 -1
- package/dist/web/public/assets/{layout-VOwsqNph.js → layout-cacmfseo.js} +2 -2
- package/dist/web/public/assets/{layout-VOwsqNph.js.map → layout-cacmfseo.js.map} +1 -1
- package/dist/web/public/assets/{llm-i15cVS6k.js → llm-C19AX6q2.js} +2 -2
- package/dist/web/public/assets/{llm-i15cVS6k.js.map → llm-C19AX6q2.js.map} +1 -1
- package/dist/web/public/assets/{loader-circle-CVEo3Hwx.js → loader-circle-U-jPjmeD.js} +2 -2
- package/dist/web/public/assets/{loader-circle-CVEo3Hwx.js.map → loader-circle-U-jPjmeD.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-BlmDrPGJ.js → map-pin-4rE1NK87.js} +2 -2
- package/dist/web/public/assets/{map-pin-BlmDrPGJ.js.map → map-pin-4rE1NK87.js.map} +1 -1
- package/dist/web/public/assets/{mcp-9MlUdHAS.js → mcp-B94wc6Vi.js} +2 -2
- package/dist/web/public/assets/{mcp-9MlUdHAS.js.map → mcp-B94wc6Vi.js.map} +1 -1
- package/dist/web/public/assets/{memos-MDYe436b.js → memos-CrG4zgfI.js} +3 -3
- package/dist/web/public/assets/{memos-MDYe436b.js.map → memos-CrG4zgfI.js.map} +1 -1
- package/dist/web/public/assets/{messengers-D0F-cgJ0.js → messengers-UWarJd_C.js} +2 -2
- package/dist/web/public/assets/{messengers-D0F-cgJ0.js.map → messengers-UWarJd_C.js.map} +1 -1
- package/dist/web/public/assets/{mobile-Bezz5MnW.js → mobile-QhAUKqcJ.js} +2 -2
- package/dist/web/public/assets/{mobile-Bezz5MnW.js.map → mobile-QhAUKqcJ.js.map} +1 -1
- package/dist/web/public/assets/{native-agent-bRS7DRfj.js → native-agent-DMf0u4dm.js} +2 -2
- package/dist/web/public/assets/{native-agent-bRS7DRfj.js.map → native-agent-DMf0u4dm.js.map} +1 -1
- package/dist/web/public/assets/{network-3O1O1jsk.js → network-l6l5gLHO.js} +2 -2
- package/dist/web/public/assets/{network-3O1O1jsk.js.map → network-l6l5gLHO.js.map} +1 -1
- package/dist/web/public/assets/{outbox-D2iX9mcs.js → outbox-BenX_yUQ.js} +2 -2
- package/dist/web/public/assets/{outbox-D2iX9mcs.js.map → outbox-BenX_yUQ.js.map} +1 -1
- package/dist/web/public/assets/{pagination-79ms7QFI.js → pagination-B4g1CBsi.js} +2 -2
- package/dist/web/public/assets/{pagination-79ms7QFI.js.map → pagination-B4g1CBsi.js.map} +1 -1
- package/dist/web/public/assets/{persona-D37NzRbz.js → persona--3cjtl9q.js} +2 -2
- package/dist/web/public/assets/{persona-D37NzRbz.js.map → persona--3cjtl9q.js.map} +1 -1
- package/dist/web/public/assets/plans-DsHtDRlS.js +12 -0
- package/dist/web/public/assets/plans-DsHtDRlS.js.map +1 -0
- package/dist/web/public/assets/{play-BedplEoY.js → play-BG0hyTnO.js} +2 -2
- package/dist/web/public/assets/{play-BedplEoY.js.map → play-BG0hyTnO.js.map} +1 -1
- package/dist/web/public/assets/{plus-4GdEpvTV.js → plus-Dof9AQvU.js} +2 -2
- package/dist/web/public/assets/{plus-4GdEpvTV.js.map → plus-Dof9AQvU.js.map} +1 -1
- package/dist/web/public/assets/{policy-Gmd4rmzp.js → policy-BzHy4WbV.js} +2 -2
- package/dist/web/public/assets/{policy-Gmd4rmzp.js.map → policy-BzHy4WbV.js.map} +1 -1
- package/dist/web/public/assets/{qr-code-DVgHWDky.js → qr-code-yD_ztCf6.js} +2 -2
- package/dist/web/public/assets/{qr-code-DVgHWDky.js.map → qr-code-yD_ztCf6.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-DZHRYuFA.js → refresh-ccw-CBiHL1tY.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-DZHRYuFA.js.map → refresh-ccw-CBiHL1tY.js.map} +1 -1
- package/dist/web/public/assets/reminders-CDJlFR2Y.js +7 -0
- package/dist/web/public/assets/reminders-CDJlFR2Y.js.map +1 -0
- package/dist/web/public/assets/{save-DQlBAXAl.js → save-DVHI3V6o.js} +2 -2
- package/dist/web/public/assets/{save-DQlBAXAl.js.map → save-DVHI3V6o.js.map} +1 -1
- package/dist/web/public/assets/{schedules-BtuWAAd7.js → schedules-DYf64Fpr.js} +2 -2
- package/dist/web/public/assets/{schedules-BtuWAAd7.js.map → schedules-DYf64Fpr.js.map} +1 -1
- package/dist/web/public/assets/{search-dBGBHpnH.js → search-BYPDbBkC.js} +2 -2
- package/dist/web/public/assets/{search-dBGBHpnH.js.map → search-BYPDbBkC.js.map} +1 -1
- package/dist/web/public/assets/{search-DJXxphzz.js → search-aw0y39Qs.js} +2 -2
- package/dist/web/public/assets/{search-DJXxphzz.js.map → search-aw0y39Qs.js.map} +1 -1
- package/dist/web/public/assets/{security-CP0MP_Gx.js → security-DhN1kRac.js} +2 -2
- package/dist/web/public/assets/{security-CP0MP_Gx.js.map → security-DhN1kRac.js.map} +1 -1
- package/dist/web/public/assets/{service-BJFnNe7Y.js → service-BhvI7Mb5.js} +2 -2
- package/dist/web/public/assets/{service-BJFnNe7Y.js.map → service-BhvI7Mb5.js.map} +1 -1
- package/dist/web/public/assets/{shield-alert-DRh8fC8Z.js → shield-alert-DjqqnTMk.js} +2 -2
- package/dist/web/public/assets/{shield-alert-DRh8fC8Z.js.map → shield-alert-DjqqnTMk.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-CTRG6Pb2.js → status-badge-nSFUUEfy.js} +2 -2
- package/dist/web/public/assets/{status-badge-CTRG6Pb2.js.map → status-badge-nSFUUEfy.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-BiZ2mCPs.js → subtasks-C_x1RLJA.js} +2 -2
- package/dist/web/public/assets/{subtasks-BiZ2mCPs.js.map → subtasks-C_x1RLJA.js.map} +1 -1
- package/dist/web/public/assets/{table-Dbriy3Jz.js → table-BNqo2xb8.js} +2 -2
- package/dist/web/public/assets/{table-Dbriy3Jz.js.map → table-BNqo2xb8.js.map} +1 -1
- package/dist/web/public/assets/{topn-BEi7Uvlg.js → topn-NGtwNz38.js} +2 -2
- package/dist/web/public/assets/{topn-BEi7Uvlg.js.map → topn-NGtwNz38.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-BgltvQpz.js → trash-2-BoFq2ZOF.js} +2 -2
- package/dist/web/public/assets/{trash-2-BgltvQpz.js.map → trash-2-BoFq2ZOF.js.map} +1 -1
- package/dist/web/public/assets/use-background-tasks-CY2gWPBZ.js +2 -0
- package/dist/web/public/assets/{use-background-tasks-DHo3Hnu9.js.map → use-background-tasks-CY2gWPBZ.js.map} +1 -1
- package/dist/web/public/assets/{use-llm-admin-EU1V1WQ5.js → use-llm-admin-CA5tUbEU.js} +2 -2
- package/dist/web/public/assets/{use-llm-admin-EU1V1WQ5.js.map → use-llm-admin-CA5tUbEU.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-D0FD5n0A.js → use-memory-CxasvYqR.js} +2 -2
- package/dist/web/public/assets/{use-memory-D0FD5n0A.js.map → use-memory-CxasvYqR.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-CZg_sS2t.js → use-observability-BOepIjX5.js} +2 -2
- package/dist/web/public/assets/{use-observability-CZg_sS2t.js.map → use-observability-BOepIjX5.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-D3vI1Dwg.js → use-settings-DBXvAYm9.js} +2 -2
- package/dist/web/public/assets/{use-settings-D3vI1Dwg.js.map → use-settings-DBXvAYm9.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-DWm4dRVD.js → use-workspace-dw_69jpb.js} +2 -2
- package/dist/web/public/assets/{use-workspace-DWm4dRVD.js.map → use-workspace-dw_69jpb.js.map} +1 -1
- package/dist/web/public/assets/{useQuery-DIlm0vJ-.js → useQuery-Ds6-WURB.js} +2 -2
- package/dist/web/public/assets/{useQuery-DIlm0vJ-.js.map → useQuery-Ds6-WURB.js.map} +1 -1
- package/dist/web/public/assets/{vector-CaijGbpn.js → vector-C5WBAtlL.js} +2 -2
- package/dist/web/public/assets/{vector-CaijGbpn.js.map → vector-C5WBAtlL.js.map} +1 -1
- package/dist/web/public/assets/{viewer-nU6uZJWq.js → viewer-DQG9P7-t.js} +2 -2
- package/dist/web/public/assets/{viewer-nU6uZJWq.js.map → viewer-DQG9P7-t.js.map} +1 -1
- package/dist/web/public/assets/{workspace-BluXJmIg.js → workspace-Dku83Qqr.js} +3 -3
- package/dist/web/public/assets/{workspace-BluXJmIg.js.map → workspace-Dku83Qqr.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-B2nSpx9t.js → workspaces-ClLQ253x.js} +2 -2
- package/dist/web/public/assets/{workspaces-B2nSpx9t.js.map → workspaces-ClLQ253x.js.map} +1 -1
- package/dist/web/public/assets/{x-D_eFtxsK.js → x-ClXUlQDe.js} +2 -2
- package/dist/web/public/assets/{x-D_eFtxsK.js.map → x-ClXUlQDe.js.map} +1 -1
- package/dist/web/public/index.html +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +28 -0
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/assets/dialog-Cv87qelJ.js +0 -6
- package/dist/web/public/assets/index-CuNnG-5O.js.map +0 -1
- package/dist/web/public/assets/layout-tAyuz3-F.js +0 -2
- package/dist/web/public/assets/layout-tAyuz3-F.js.map +0 -1
- package/dist/web/public/assets/reminders-C00V-Fs9.js +0 -12
- package/dist/web/public/assets/reminders-C00V-Fs9.js.map +0 -1
- package/dist/web/public/assets/use-background-tasks-DHo3Hnu9.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-CiWiDAvY.js","sources":["../../node_modules/lucide-react/dist/esm/icons/bot.js","../../src/routes/settings/agents.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 Bot = createLucideIcon(\"Bot\", [\n [\"path\", { d: \"M12 8V4H8\", key: \"hb8ula\" }],\n [\"rect\", { width: \"16\", height: \"12\", x: \"4\", y: \"8\", rx: \"2\", key: \"enze0r\" }],\n [\"path\", { d: \"M2 14h2\", key: \"vft8re\" }],\n [\"path\", { d: \"M20 14h2\", key: \"4cs60a\" }],\n [\"path\", { d: \"M15 13v2\", key: \"1xurst\" }],\n [\"path\", { d: \"M9 13v2\", key: \"rq6x2g\" }]\n]);\n\nexport { Bot as default };\n//# sourceMappingURL=bot.js.map\n","/**\n * /settings/agents — built-in adapters + remote (ACP) agents.\n *\n * Two cards on one page:\n * 1. Built-in adapters (claude-code / codex / opencode):\n * enable/disable + default-agent picker. Mirrors v1's \"Agents\".\n * 2. Remote (ACP) agents: name/endpoint/auth-type table + manual\n * add form. Mirrors v1's \"Remote Agents (ACP)\" card. Discover\n * via `<baseUrl>/.well-known/acp` is available as a secondary\n * bulk-import form.\n *\n * Both cards share one save bar — PUT /api/config writes `agents[]`,\n * `defaultAgent`, and `acpAgents[]` atomically so the default never\n * goes out of sync with the enabled list, and partial ACP edits\n * don't ship without the user's intent.\n *\n * Masked tokens: GET returns `ab****yz` for ACP auth.token; PUT\n * detects this pattern and preserves the on-disk value so we never\n * overwrite a real token with its mask. New tokens (typed into the\n * add form or \"edit\" inline) flow through verbatim.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Bot, Loader2, Network, Plus, RefreshCcw, Save, Search, Trash2, X,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { useAgentsStatus } from '@/hooks/use-workspace'\nimport {\n useConfig,\n useDiscoverAcp,\n useTestAcp,\n useUpdateConfig,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\nimport type { ACPAgentConfig, ACPAuthConfig, ACPAuthType } from '@/types/api'\n\n/** Mirror of v1 settings.html:BUILTIN_AGENTS. Hardcoded because\n * backend doesn't expose this metadata yet; the table changes\n * rarely enough that copying it here is fine. */\nconst BUILTIN_AGENTS: Record<string, { aliases: string[]; pkg: string }> = {\n 'claude-code': { aliases: ['cc', 'claude'], pkg: '@anthropic-ai/claude-code' },\n 'codex': { aliases: ['cx'], pkg: '@openai/codex' },\n 'opencode': { aliases: ['oc'], pkg: 'opencode-ai' },\n 'cursor': { aliases: ['cs', 'cur'], pkg: 'cursor-agent (curl https://cursor.com/install)' },\n}\n\nconst AGENT_NAMES = Object.keys(BUILTIN_AGENTS)\n\nexport default function SettingsAgentsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const statusQuery = useAgentsStatus()\n const updateCfg = useUpdateConfig()\n\n const cfg = cfgQuery.data\n const status = statusQuery.data ?? {}\n\n /** Local draft so toggles + default-picker + ACP edits can stage\n * changes before a single Save. `null` means \"sync from cfg on\n * next paint\". */\n const [draftEnabled, setDraftEnabled] = useState<string[] | null>(null)\n const [draftDefault, setDraftDefault] = useState<string | null>(null)\n const [draftAcp, setDraftAcp] = useState<ACPAgentConfig[] | null>(null)\n\n useEffect(() => {\n if (cfg && draftEnabled == null) setDraftEnabled(cfg.agents ?? [])\n if (cfg && draftDefault == null) setDraftDefault(cfg.defaultAgent ?? '')\n if (cfg && draftAcp == null) setDraftAcp(cfg.acpAgents ?? [])\n }, [cfg, draftEnabled, draftDefault, draftAcp])\n\n const enabled = draftEnabled ?? cfg?.agents ?? []\n const defaultAgent = draftDefault ?? cfg?.defaultAgent ?? ''\n const acpAgents = draftAcp ?? cfg?.acpAgents ?? []\n\n const isDirty = useMemo(() => {\n if (!cfg) return false\n const enabledSame =\n enabled.length === (cfg.agents?.length ?? 0)\n && enabled.every((a) => cfg.agents?.includes(a))\n const defaultSame = defaultAgent === (cfg.defaultAgent ?? '')\n const acpSame = acpEqual(acpAgents, cfg.acpAgents ?? [])\n return !enabledSame || !defaultSame || !acpSame\n }, [cfg, enabled, defaultAgent, acpAgents])\n\n /** Eligible defaults = installed + enabled. Picker disables when\n * empty (no agent is both). */\n const eligibleDefaults = useMemo(\n () => AGENT_NAMES.filter((a) => enabled.includes(a) && status[a]),\n [enabled, status],\n )\n\n function toggleAgent(name: string, on: boolean): void {\n const next = on\n ? Array.from(new Set([...enabled, name]))\n : enabled.filter((a) => a !== name)\n setDraftEnabled(next)\n // If the default just got disabled, clear it so save doesn't\n // ship an inconsistent pair.\n if (!on && name === defaultAgent) setDraftDefault('')\n }\n\n async function onSave(): Promise<void> {\n if (!cfg) return\n try {\n await updateCfg.mutateAsync({\n ...cfg,\n agents: enabled,\n defaultAgent: defaultAgent || cfg.defaultAgent,\n acpAgents,\n })\n toast.success(t('agents.toast.saved'))\n // Reset drafts so the next paint reads from refreshed cfg.\n setDraftEnabled(null)\n setDraftDefault(null)\n setDraftAcp(null)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onDiscard(): void {\n setDraftEnabled(null)\n setDraftDefault(null)\n setDraftAcp(null)\n }\n\n function updateAcp(next: ACPAgentConfig[]): void {\n setDraftAcp(next)\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('agents.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => {\n void cfgQuery.refetch()\n void statusQuery.refetch()\n }}\n disabled={cfgQuery.isFetching || statusQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {(cfgQuery.isFetching || statusQuery.isFetching)\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <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('agents.subtitle')}</p>\n </header>\n\n {cfgQuery.isLoading ? (\n <div className=\"h-64 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n {/* Agent rows */}\n <div className=\"flex flex-col divide-y divide-border rounded-md border border-border bg-surface\">\n {AGENT_NAMES.map((name) => {\n const info = BUILTIN_AGENTS[name]!\n const installed = !!status[name]\n const isEnabled = enabled.includes(name)\n return (\n <AgentRow\n key={name}\n name={name}\n aliases={info.aliases}\n pkg={info.pkg}\n installed={installed}\n enabled={isEnabled}\n onToggle={(on) => toggleAgent(name, on)}\n />\n )\n })}\n </div>\n\n {/* Default agent picker */}\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <Label htmlFor=\"default-agent\" className=\"text-sm font-medium\">\n {t('agents.defaultAgent')}\n </Label>\n <p className=\"mt-1 text-xs text-text-dim\">{t('agents.defaultAgentHint')}</p>\n <Select\n value={defaultAgent || '__none__'}\n onValueChange={(v) => setDraftDefault(v === '__none__' ? '' : v)}\n disabled={eligibleDefaults.length === 0}\n >\n <SelectTrigger id=\"default-agent\" className=\"mt-2 w-64\">\n <SelectValue placeholder={t('agents.noEligible')} />\n </SelectTrigger>\n <SelectContent>\n {eligibleDefaults.length === 0 ? (\n <SelectItem value=\"__none__\" disabled>{t('agents.noEligible')}</SelectItem>\n ) : (\n eligibleDefaults.map((a) => (\n <SelectItem key={a} value={a}>{a}</SelectItem>\n ))\n )}\n </SelectContent>\n </Select>\n </section>\n\n {/* Remote (ACP) agents — gated by features.remoteAgent\n (IMHUB_ENABLE_REMOTE_AGENT on server). Card is omitted\n entirely; no breadcrumb hint shown. */}\n {cfg?.features?.remoteAgent ? (\n <AcpCard\n agents={acpAgents}\n onChange={updateAcp}\n />\n ) : null}\n\n {/* Save bar */}\n {isDirty && (\n <div className=\"sticky bottom-0 flex items-center gap-2 rounded-md border border-border bg-surface px-4 py-2 shadow-md\">\n <Badge variant=\"info\">{t('agents.dirtyHint')}</Badge>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={updateCfg.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('agents.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateCfg.isPending}\n >\n {updateCfg.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {updateCfg.isPending ? t('agents.saving') : t('agents.saveBtn')}\n </Button>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n\n/* ─────────────── Row ─────────────── */\n\ninterface AgentRowProps {\n name: string\n aliases: string[]\n pkg: string\n installed: boolean\n enabled: boolean\n onToggle: (on: boolean) => void\n}\n\nfunction AgentRow({\n name, aliases, pkg, installed, enabled, onToggle,\n}: AgentRowProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex items-start gap-3 px-3 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-surface-2 text-text-dim\">\n <Bot className=\"h-4 w-4\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{name}</span>\n <Badge variant={installed ? 'success' : 'outline'} className=\"text-[10px]\">\n <span className={cn(\n 'inline-block h-1.5 w-1.5 rounded-full',\n installed ? 'bg-success' : 'bg-text-muted',\n )} />\n {installed ? t('agents.online') : t('agents.offline')}\n </Badge>\n </div>\n <p className=\"mt-0.5 text-xs text-text-dim\">\n <span className=\"text-text-muted\">{t('agents.aliasesLabel')}: </span>\n <span className=\"font-mono\">{aliases.map((a) => `/${a}`).join(', ')}</span>\n </p>\n {!installed && (\n <p className=\"mt-1 text-xs text-warning\">\n {t('agents.installHint', { pkg })}\n </p>\n )}\n </div>\n <input\n type=\"checkbox\"\n checked={enabled}\n onChange={(e) => onToggle(e.target.checked)}\n className=\"h-4 w-4 mt-2 accent-accent cursor-pointer\"\n />\n </div>\n )\n}\n\n/* ─────────────── Remote (ACP) ─────────────── */\n\nconst AUTH_TYPES: ACPAuthType[] = ['none', 'apikey', 'bearer']\nconst NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/\n\n/** Compare two ACP lists by value. Order matters because the backend\n * preserves index identity (`existing.acpAgents[i]`) when merging\n * masked tokens — reordering = mask drift risk. */\nfunction acpEqual(a: ACPAgentConfig[], b: ACPAgentConfig[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!\n const y = b[i]!\n if (x.name !== y.name) return false\n if (x.endpoint !== y.endpoint) return false\n if ((x.enabled ?? true) !== (y.enabled ?? true)) return false\n const xa = (x.aliases ?? []).join(',')\n const ya = (y.aliases ?? []).join(',')\n if (xa !== ya) return false\n const xat = x.auth?.type ?? 'none'\n const yat = y.auth?.type ?? 'none'\n if (xat !== yat) return false\n if ((x.auth?.token ?? '') !== (y.auth?.token ?? '')) return false\n }\n return true\n}\n\ninterface AcpCardProps {\n agents: ACPAgentConfig[]\n onChange: (next: ACPAgentConfig[]) => void\n}\n\nfunction AcpCard({ agents, onChange }: AcpCardProps): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const testMut = useTestAcp()\n const discoverMut = useDiscoverAcp()\n\n // Add-form state. We keep the typed token in plain state so the\n // user can paste before save; the masked round-trip from backend\n // only matters for existing rows.\n const [name, setName] = useState('')\n const [aliasesText, setAliasesText] = useState('')\n const [endpoint, setEndpoint] = useState('')\n const [authType, setAuthType] = useState<ACPAuthType>('none')\n const [token, setToken] = useState('')\n\n // Bulk-discover sub-form state. Hidden behind a toggle so the\n // primary path (manual add) stays uncluttered.\n const [showDiscover, setShowDiscover] = useState(false)\n const [baseUrl, setBaseUrl] = useState('')\n\n const trimmedName = name.trim()\n const nameValid = trimmedName.length > 0 && NAME_RE.test(trimmedName)\n const dup = agents.some((a) => a.name === trimmedName)\n const tokenRequired = authType !== 'none'\n const tokenOk = !tokenRequired || token.trim().length > 0\n const canAdd = nameValid && endpoint.trim().length > 0 && tokenOk && !dup\n const canTestNew = endpoint.trim().length > 0 && tokenOk\n\n function clearForm(): void {\n setName('')\n setAliasesText('')\n setEndpoint('')\n setAuthType('none')\n setToken('')\n }\n\n function parseAliases(text: string): string[] {\n return text.split(',').map((s) => s.trim()).filter(Boolean)\n }\n\n function buildAuth(type: ACPAuthType, tok: string): ACPAuthConfig | undefined {\n if (type === 'none') return { type: 'none' }\n const trimmed = tok.trim()\n if (!trimmed) return { type } // no token yet; save will reject\n return { type, token: trimmed }\n }\n\n async function onAdd(): Promise<void> {\n if (!canAdd) return\n const next: ACPAgentConfig = {\n name: trimmedName,\n endpoint: endpoint.trim(),\n aliases: parseAliases(aliasesText),\n auth: buildAuth(authType, token),\n enabled: true,\n }\n onChange([...agents, next])\n clearForm()\n toast.success(t('agents.acp.toast.staged'))\n }\n\n async function onTestNew(): Promise<void> {\n if (!canTestNew) return\n try {\n const res = await testMut.mutateAsync({\n endpoint: endpoint.trim(),\n auth: buildAuth(authType, token),\n })\n toast.success(t('agents.acp.toast.testOk', { name: res.name }))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onTestRow(idx: number): Promise<void> {\n const a = agents[idx]\n if (!a) return\n // Masked tokens stay masked on the wire — backend's PUT mask-detect\n // is symmetric, but the test endpoint reads what we send. We can't\n // unmask client-side; warn the operator.\n if (a.auth?.type !== 'none' && a.auth?.token && isMaskedToken(a.auth.token)) {\n toast.error(t('agents.acp.toast.testMasked'))\n return\n }\n try {\n const res = await testMut.mutateAsync({\n endpoint: a.endpoint,\n auth: a.auth,\n })\n toast.success(t('agents.acp.toast.testOk', { name: res.name }))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onToggleRow(idx: number, on: boolean): void {\n const next = agents.map((a, i) => (i === idx ? { ...a, enabled: on } : a))\n onChange(next)\n }\n\n function onRemoveRow(idx: number): void {\n onChange(agents.filter((_, i) => i !== idx))\n }\n\n async function onDiscoverRun(): Promise<void> {\n const url = baseUrl.trim()\n if (!url) return\n try {\n const res = await discoverMut.mutateAsync({ baseUrl: url, register: false })\n // Stage new agents that aren't already in the list (by name).\n const existing = new Set(agents.map((a) => a.name))\n const incoming = res.agents.filter((a) => !existing.has(a.name))\n if (incoming.length === 0) {\n toast.info(t('agents.acp.toast.discoverEmpty'))\n return\n }\n onChange([...agents, ...incoming.map((a) => ({ ...a, enabled: true }))])\n toast.success(t('agents.acp.toast.discoverAdded', { count: incoming.length }))\n setBaseUrl('')\n setShowDiscover(false)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <Network className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('agents.acp.title')}</h2>\n <Badge variant=\"outline\" className=\"text-[10px]\">{agents.length}</Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => setShowDiscover((v) => !v)}\n >\n <Search className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('agents.acp.discoverBtn')}</span>\n </Button>\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('agents.acp.subtitle')}</p>\n\n {/* Discover form (collapsed by default) */}\n {showDiscover && (\n <div className=\"border-t border-border bg-surface-2 px-4 py-3\">\n <Label htmlFor=\"acp-baseurl\" className=\"text-xs font-medium\">\n {t('agents.acp.baseUrl')}\n </Label>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('agents.acp.baseUrlHint')}</p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <Input\n id=\"acp-baseurl\"\n value={baseUrl}\n onChange={(e) => setBaseUrl(e.target.value)}\n placeholder=\"https://agents.example.com\"\n className=\"flex-1 min-w-[200px] font-mono text-xs\"\n />\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onDiscoverRun()}\n disabled={!baseUrl.trim() || discoverMut.isPending}\n >\n {discoverMut.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Search className=\"h-4 w-4\" />}\n {t('agents.acp.runDiscover')}\n </Button>\n </div>\n </div>\n )}\n\n {/* Registered ACP agents */}\n {agents.length === 0 ? (\n <div className=\"px-4 py-6\">\n <EmptyState\n icon={<Network />}\n title={t('agents.acp.empty.title')}\n description={t('agents.acp.empty.description')}\n />\n </div>\n ) : (\n <ul className=\"divide-y divide-border\">\n {agents.map((a, i) => (\n <AcpRow\n key={`${a.name}-${i}`}\n agent={a}\n onToggle={(on) => onToggleRow(i, on)}\n onTest={() => void onTestRow(i)}\n onRemove={() => onRemoveRow(i)}\n testing={testMut.isPending}\n />\n ))}\n </ul>\n )}\n\n {/* Add-agent form */}\n <div className=\"border-t border-border px-4 py-3\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-dim\">\n {t('agents.acp.addTitle')}\n </h3>\n <div className=\"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <Field label={t('agents.acp.name')} hint={t('agents.acp.nameHint')}>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"my-agent\"\n aria-invalid={name.length > 0 && !nameValid}\n />\n </Field>\n <Field label={t('agents.acp.aliases')} hint={t('agents.acp.aliasesHint')}>\n <Input\n value={aliasesText}\n onChange={(e) => setAliasesText(e.target.value)}\n placeholder=\"ma, agent1\"\n />\n </Field>\n <Field label={t('agents.acp.endpoint')} hint={t('agents.acp.endpointHint')}>\n <Input\n value={endpoint}\n onChange={(e) => setEndpoint(e.target.value)}\n placeholder=\"https://example.com/agents/weather\"\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field label={t('agents.acp.authType')}>\n <Select value={authType} onValueChange={(v) => setAuthType(v as ACPAuthType)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {AUTH_TYPES.map((a) => (\n <SelectItem key={a} value={a}>{t(`agents.acp.auth.${a}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n {authType !== 'none' && (\n <Field label={t('agents.acp.token')} className=\"sm:col-span-2\">\n <Input\n type=\"password\"\n value={token}\n onChange={(e) => setToken(e.target.value)}\n placeholder={t('agents.acp.tokenPlaceholder')}\n autoComplete=\"new-password\"\n />\n </Field>\n )}\n </div>\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onTestNew()}\n disabled={!canTestNew || testMut.isPending}\n >\n {testMut.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Search className=\"h-4 w-4\" />}\n {t('agents.acp.testBtn')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onAdd()}\n disabled={!canAdd}\n >\n <Plus className=\"h-4 w-4\" />\n {t('agents.acp.addBtn')}\n </Button>\n {dup && (\n <span className=\"self-center text-xs text-warning\">\n {t('agents.acp.dupName')}\n </span>\n )}\n </div>\n </div>\n </section>\n )\n}\n\ninterface AcpRowProps {\n agent: ACPAgentConfig\n onToggle: (on: boolean) => void\n onTest: () => void\n onRemove: () => void\n testing: boolean\n}\n\nfunction AcpRow({ agent, onToggle, onTest, onRemove, testing }: AcpRowProps): JSX.Element {\n const { t } = useTranslation('settings')\n const isOn = agent.enabled !== false\n const authType = agent.auth?.type ?? 'none'\n return (\n <li className=\"flex flex-wrap items-center gap-3 px-4 py-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{agent.name}</span>\n <Badge variant=\"outline\" className=\"text-[10px] uppercase\">\n {t(`agents.acp.auth.${authType}`)}\n </Badge>\n {agent.aliases && agent.aliases.length > 0 && (\n <span className=\"text-xs text-text-muted font-mono\">\n {agent.aliases.map((a) => `/${a}`).join(', ')}\n </span>\n )}\n </div>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-dim\" title={agent.endpoint}>\n {agent.endpoint}\n </p>\n </div>\n <label className=\"flex items-center gap-1.5 text-xs text-text-dim\">\n <input\n type=\"checkbox\"\n checked={isOn}\n onChange={(e) => onToggle(e.target.checked)}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n {isOn ? t('agents.acp.on') : t('agents.acp.off')}\n </label>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onTest}\n disabled={testing}\n aria-label={t('agents.acp.testBtn')}\n >\n {testing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Search className=\"h-4 w-4\" />}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onRemove}\n aria-label={t('agents.acp.removeBtn')}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </li>\n )\n}\n\ninterface FieldProps {\n label: string\n hint?: string\n className?: string\n children: React.ReactNode\n}\n\nfunction Field({ label, hint, className, children }: FieldProps): JSX.Element {\n return (\n <div className={cn('flex flex-col gap-1', className)}>\n <Label className=\"text-xs font-medium\">{label}</Label>\n {children}\n {hint && <p className=\"text-[11px] text-text-dim\">{hint}</p>}\n </div>\n )\n}\n\n/** Tokens look like `ab****yz` from the masked GET response. We\n * shouldn't send them back unchanged for test (the backend would\n * fail auth), and we shouldn't include them in the test mutation\n * body either. Treat any string with 3+ consecutive `*` as masked. */\nfunction isMaskedToken(s: string): boolean {\n return /\\*{3,}/.test(s)\n}\n"],"names":["Bot","createLucideIcon","BUILTIN_AGENTS","AGENT_NAMES","SettingsAgentsRoute","useTranslation","cfgQuery","useConfig","statusQuery","useAgentsStatus","updateCfg","useUpdateConfig","cfg","status","draftEnabled","setDraftEnabled","useState","draftDefault","setDraftDefault","draftAcp","setDraftAcp","useEffect","enabled","defaultAgent","acpAgents","isDirty","useMemo","enabledSame","a","defaultSame","acpSame","acpEqual","eligibleDefaults","toggleAgent","name","on","next","onSave","toast","err","describeError","onDiscard","updateAcp","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","info","installed","isEnabled","AgentRow","Label","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","AcpCard","Badge","X","Save","aliases","pkg","onToggle","t","cn","e","AUTH_TYPES","NAME_RE","b","i","x","y","xa","ya","xat","yat","agents","onChange","testMut","useTestAcp","discoverMut","useDiscoverAcp","setName","aliasesText","setAliasesText","endpoint","setEndpoint","authType","setAuthType","token","setToken","showDiscover","setShowDiscover","baseUrl","setBaseUrl","trimmedName","nameValid","dup","tokenOk","canAdd","canTestNew","clearForm","parseAliases","text","s","buildAuth","type","tok","trimmed","onAdd","onTestNew","res","onTestRow","idx","isMaskedToken","onToggleRow","onRemoveRow","_","onDiscoverRun","url","existing","incoming","Network","Search","Input","EmptyState","AcpRow","Field","Plus","agent","onTest","onRemove","testing","isOn","Trash2","label","hint","className","children"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"agents-3sUHlKzx.js","sources":["../../node_modules/lucide-react/dist/esm/icons/bot.js","../../src/routes/settings/agents.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 Bot = createLucideIcon(\"Bot\", [\n [\"path\", { d: \"M12 8V4H8\", key: \"hb8ula\" }],\n [\"rect\", { width: \"16\", height: \"12\", x: \"4\", y: \"8\", rx: \"2\", key: \"enze0r\" }],\n [\"path\", { d: \"M2 14h2\", key: \"vft8re\" }],\n [\"path\", { d: \"M20 14h2\", key: \"4cs60a\" }],\n [\"path\", { d: \"M15 13v2\", key: \"1xurst\" }],\n [\"path\", { d: \"M9 13v2\", key: \"rq6x2g\" }]\n]);\n\nexport { Bot as default };\n//# sourceMappingURL=bot.js.map\n","/**\n * /settings/agents — built-in adapters + remote (ACP) agents.\n *\n * Two cards on one page:\n * 1. Built-in adapters (claude-code / codex / opencode):\n * enable/disable + default-agent picker. Mirrors v1's \"Agents\".\n * 2. Remote (ACP) agents: name/endpoint/auth-type table + manual\n * add form. Mirrors v1's \"Remote Agents (ACP)\" card. Discover\n * via `<baseUrl>/.well-known/acp` is available as a secondary\n * bulk-import form.\n *\n * Both cards share one save bar — PUT /api/config writes `agents[]`,\n * `defaultAgent`, and `acpAgents[]` atomically so the default never\n * goes out of sync with the enabled list, and partial ACP edits\n * don't ship without the user's intent.\n *\n * Masked tokens: GET returns `ab****yz` for ACP auth.token; PUT\n * detects this pattern and preserves the on-disk value so we never\n * overwrite a real token with its mask. New tokens (typed into the\n * add form or \"edit\" inline) flow through verbatim.\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Bot, Loader2, Network, Plus, RefreshCcw, Save, Search, Trash2, X,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { useAgentsStatus } from '@/hooks/use-workspace'\nimport {\n useConfig,\n useDiscoverAcp,\n useTestAcp,\n useUpdateConfig,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\nimport type { ACPAgentConfig, ACPAuthConfig, ACPAuthType } from '@/types/api'\n\n/** Mirror of v1 settings.html:BUILTIN_AGENTS. Hardcoded because\n * backend doesn't expose this metadata yet; the table changes\n * rarely enough that copying it here is fine. */\nconst BUILTIN_AGENTS: Record<string, { aliases: string[]; pkg: string }> = {\n 'claude-code': { aliases: ['cc', 'claude'], pkg: '@anthropic-ai/claude-code' },\n 'codex': { aliases: ['cx'], pkg: '@openai/codex' },\n 'opencode': { aliases: ['oc'], pkg: 'opencode-ai' },\n 'cursor': { aliases: ['cs', 'cur'], pkg: 'cursor-agent (curl https://cursor.com/install)' },\n}\n\nconst AGENT_NAMES = Object.keys(BUILTIN_AGENTS)\n\nexport default function SettingsAgentsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const statusQuery = useAgentsStatus()\n const updateCfg = useUpdateConfig()\n\n const cfg = cfgQuery.data\n const status = statusQuery.data ?? {}\n\n /** Local draft so toggles + default-picker + ACP edits can stage\n * changes before a single Save. `null` means \"sync from cfg on\n * next paint\". */\n const [draftEnabled, setDraftEnabled] = useState<string[] | null>(null)\n const [draftDefault, setDraftDefault] = useState<string | null>(null)\n const [draftAcp, setDraftAcp] = useState<ACPAgentConfig[] | null>(null)\n\n useEffect(() => {\n if (cfg && draftEnabled == null) setDraftEnabled(cfg.agents ?? [])\n if (cfg && draftDefault == null) setDraftDefault(cfg.defaultAgent ?? '')\n if (cfg && draftAcp == null) setDraftAcp(cfg.acpAgents ?? [])\n }, [cfg, draftEnabled, draftDefault, draftAcp])\n\n const enabled = draftEnabled ?? cfg?.agents ?? []\n const defaultAgent = draftDefault ?? cfg?.defaultAgent ?? ''\n const acpAgents = draftAcp ?? cfg?.acpAgents ?? []\n\n const isDirty = useMemo(() => {\n if (!cfg) return false\n const enabledSame =\n enabled.length === (cfg.agents?.length ?? 0)\n && enabled.every((a) => cfg.agents?.includes(a))\n const defaultSame = defaultAgent === (cfg.defaultAgent ?? '')\n const acpSame = acpEqual(acpAgents, cfg.acpAgents ?? [])\n return !enabledSame || !defaultSame || !acpSame\n }, [cfg, enabled, defaultAgent, acpAgents])\n\n /** Eligible defaults = installed + enabled. Picker disables when\n * empty (no agent is both). */\n const eligibleDefaults = useMemo(\n () => AGENT_NAMES.filter((a) => enabled.includes(a) && status[a]),\n [enabled, status],\n )\n\n function toggleAgent(name: string, on: boolean): void {\n const next = on\n ? Array.from(new Set([...enabled, name]))\n : enabled.filter((a) => a !== name)\n setDraftEnabled(next)\n // If the default just got disabled, clear it so save doesn't\n // ship an inconsistent pair.\n if (!on && name === defaultAgent) setDraftDefault('')\n }\n\n async function onSave(): Promise<void> {\n if (!cfg) return\n try {\n await updateCfg.mutateAsync({\n ...cfg,\n agents: enabled,\n defaultAgent: defaultAgent || cfg.defaultAgent,\n acpAgents,\n })\n toast.success(t('agents.toast.saved'))\n // Reset drafts so the next paint reads from refreshed cfg.\n setDraftEnabled(null)\n setDraftDefault(null)\n setDraftAcp(null)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onDiscard(): void {\n setDraftEnabled(null)\n setDraftDefault(null)\n setDraftAcp(null)\n }\n\n function updateAcp(next: ACPAgentConfig[]): void {\n setDraftAcp(next)\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('agents.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => {\n void cfgQuery.refetch()\n void statusQuery.refetch()\n }}\n disabled={cfgQuery.isFetching || statusQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {(cfgQuery.isFetching || statusQuery.isFetching)\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <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('agents.subtitle')}</p>\n </header>\n\n {cfgQuery.isLoading ? (\n <div className=\"h-64 rounded-md bg-surface-2 animate-pulse\" />\n ) : (\n <>\n {/* Agent rows */}\n <div className=\"flex flex-col divide-y divide-border rounded-md border border-border bg-surface\">\n {AGENT_NAMES.map((name) => {\n const info = BUILTIN_AGENTS[name]!\n const installed = !!status[name]\n const isEnabled = enabled.includes(name)\n return (\n <AgentRow\n key={name}\n name={name}\n aliases={info.aliases}\n pkg={info.pkg}\n installed={installed}\n enabled={isEnabled}\n onToggle={(on) => toggleAgent(name, on)}\n />\n )\n })}\n </div>\n\n {/* Default agent picker */}\n <section className=\"rounded-md border border-border bg-surface p-4\">\n <Label htmlFor=\"default-agent\" className=\"text-sm font-medium\">\n {t('agents.defaultAgent')}\n </Label>\n <p className=\"mt-1 text-xs text-text-dim\">{t('agents.defaultAgentHint')}</p>\n <Select\n value={defaultAgent || '__none__'}\n onValueChange={(v) => setDraftDefault(v === '__none__' ? '' : v)}\n disabled={eligibleDefaults.length === 0}\n >\n <SelectTrigger id=\"default-agent\" className=\"mt-2 w-64\">\n <SelectValue placeholder={t('agents.noEligible')} />\n </SelectTrigger>\n <SelectContent>\n {eligibleDefaults.length === 0 ? (\n <SelectItem value=\"__none__\" disabled>{t('agents.noEligible')}</SelectItem>\n ) : (\n eligibleDefaults.map((a) => (\n <SelectItem key={a} value={a}>{a}</SelectItem>\n ))\n )}\n </SelectContent>\n </Select>\n </section>\n\n {/* Remote (ACP) agents — gated by features.remoteAgent\n (IMHUB_ENABLE_REMOTE_AGENT on server). Card is omitted\n entirely; no breadcrumb hint shown. */}\n {cfg?.features?.remoteAgent ? (\n <AcpCard\n agents={acpAgents}\n onChange={updateAcp}\n />\n ) : null}\n\n {/* Save bar */}\n {isDirty && (\n <div className=\"sticky bottom-0 flex items-center gap-2 rounded-md border border-border bg-surface px-4 py-2 shadow-md\">\n <Badge variant=\"info\">{t('agents.dirtyHint')}</Badge>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={onDiscard}\n disabled={updateCfg.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('agents.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateCfg.isPending}\n >\n {updateCfg.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {updateCfg.isPending ? t('agents.saving') : t('agents.saveBtn')}\n </Button>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n\n/* ─────────────── Row ─────────────── */\n\ninterface AgentRowProps {\n name: string\n aliases: string[]\n pkg: string\n installed: boolean\n enabled: boolean\n onToggle: (on: boolean) => void\n}\n\nfunction AgentRow({\n name, aliases, pkg, installed, enabled, onToggle,\n}: AgentRowProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex items-start gap-3 px-3 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-surface-2 text-text-dim\">\n <Bot className=\"h-4 w-4\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{name}</span>\n <Badge variant={installed ? 'success' : 'outline'} className=\"text-[10px]\">\n <span className={cn(\n 'inline-block h-1.5 w-1.5 rounded-full',\n installed ? 'bg-success' : 'bg-text-muted',\n )} />\n {installed ? t('agents.online') : t('agents.offline')}\n </Badge>\n </div>\n <p className=\"mt-0.5 text-xs text-text-dim\">\n <span className=\"text-text-muted\">{t('agents.aliasesLabel')}: </span>\n <span className=\"font-mono\">{aliases.map((a) => `/${a}`).join(', ')}</span>\n </p>\n {!installed && (\n <p className=\"mt-1 text-xs text-warning\">\n {t('agents.installHint', { pkg })}\n </p>\n )}\n </div>\n <input\n type=\"checkbox\"\n checked={enabled}\n onChange={(e) => onToggle(e.target.checked)}\n className=\"h-4 w-4 mt-2 accent-accent cursor-pointer\"\n />\n </div>\n )\n}\n\n/* ─────────────── Remote (ACP) ─────────────── */\n\nconst AUTH_TYPES: ACPAuthType[] = ['none', 'apikey', 'bearer']\nconst NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/\n\n/** Compare two ACP lists by value. Order matters because the backend\n * preserves index identity (`existing.acpAgents[i]`) when merging\n * masked tokens — reordering = mask drift risk. */\nfunction acpEqual(a: ACPAgentConfig[], b: ACPAgentConfig[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!\n const y = b[i]!\n if (x.name !== y.name) return false\n if (x.endpoint !== y.endpoint) return false\n if ((x.enabled ?? true) !== (y.enabled ?? true)) return false\n const xa = (x.aliases ?? []).join(',')\n const ya = (y.aliases ?? []).join(',')\n if (xa !== ya) return false\n const xat = x.auth?.type ?? 'none'\n const yat = y.auth?.type ?? 'none'\n if (xat !== yat) return false\n if ((x.auth?.token ?? '') !== (y.auth?.token ?? '')) return false\n }\n return true\n}\n\ninterface AcpCardProps {\n agents: ACPAgentConfig[]\n onChange: (next: ACPAgentConfig[]) => void\n}\n\nfunction AcpCard({ agents, onChange }: AcpCardProps): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const testMut = useTestAcp()\n const discoverMut = useDiscoverAcp()\n\n // Add-form state. We keep the typed token in plain state so the\n // user can paste before save; the masked round-trip from backend\n // only matters for existing rows.\n const [name, setName] = useState('')\n const [aliasesText, setAliasesText] = useState('')\n const [endpoint, setEndpoint] = useState('')\n const [authType, setAuthType] = useState<ACPAuthType>('none')\n const [token, setToken] = useState('')\n\n // Bulk-discover sub-form state. Hidden behind a toggle so the\n // primary path (manual add) stays uncluttered.\n const [showDiscover, setShowDiscover] = useState(false)\n const [baseUrl, setBaseUrl] = useState('')\n\n const trimmedName = name.trim()\n const nameValid = trimmedName.length > 0 && NAME_RE.test(trimmedName)\n const dup = agents.some((a) => a.name === trimmedName)\n const tokenRequired = authType !== 'none'\n const tokenOk = !tokenRequired || token.trim().length > 0\n const canAdd = nameValid && endpoint.trim().length > 0 && tokenOk && !dup\n const canTestNew = endpoint.trim().length > 0 && tokenOk\n\n function clearForm(): void {\n setName('')\n setAliasesText('')\n setEndpoint('')\n setAuthType('none')\n setToken('')\n }\n\n function parseAliases(text: string): string[] {\n return text.split(',').map((s) => s.trim()).filter(Boolean)\n }\n\n function buildAuth(type: ACPAuthType, tok: string): ACPAuthConfig | undefined {\n if (type === 'none') return { type: 'none' }\n const trimmed = tok.trim()\n if (!trimmed) return { type } // no token yet; save will reject\n return { type, token: trimmed }\n }\n\n async function onAdd(): Promise<void> {\n if (!canAdd) return\n const next: ACPAgentConfig = {\n name: trimmedName,\n endpoint: endpoint.trim(),\n aliases: parseAliases(aliasesText),\n auth: buildAuth(authType, token),\n enabled: true,\n }\n onChange([...agents, next])\n clearForm()\n toast.success(t('agents.acp.toast.staged'))\n }\n\n async function onTestNew(): Promise<void> {\n if (!canTestNew) return\n try {\n const res = await testMut.mutateAsync({\n endpoint: endpoint.trim(),\n auth: buildAuth(authType, token),\n })\n toast.success(t('agents.acp.toast.testOk', { name: res.name }))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n async function onTestRow(idx: number): Promise<void> {\n const a = agents[idx]\n if (!a) return\n // Masked tokens stay masked on the wire — backend's PUT mask-detect\n // is symmetric, but the test endpoint reads what we send. We can't\n // unmask client-side; warn the operator.\n if (a.auth?.type !== 'none' && a.auth?.token && isMaskedToken(a.auth.token)) {\n toast.error(t('agents.acp.toast.testMasked'))\n return\n }\n try {\n const res = await testMut.mutateAsync({\n endpoint: a.endpoint,\n auth: a.auth,\n })\n toast.success(t('agents.acp.toast.testOk', { name: res.name }))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n function onToggleRow(idx: number, on: boolean): void {\n const next = agents.map((a, i) => (i === idx ? { ...a, enabled: on } : a))\n onChange(next)\n }\n\n function onRemoveRow(idx: number): void {\n onChange(agents.filter((_, i) => i !== idx))\n }\n\n async function onDiscoverRun(): Promise<void> {\n const url = baseUrl.trim()\n if (!url) return\n try {\n const res = await discoverMut.mutateAsync({ baseUrl: url, register: false })\n // Stage new agents that aren't already in the list (by name).\n const existing = new Set(agents.map((a) => a.name))\n const incoming = res.agents.filter((a) => !existing.has(a.name))\n if (incoming.length === 0) {\n toast.info(t('agents.acp.toast.discoverEmpty'))\n return\n }\n onChange([...agents, ...incoming.map((a) => ({ ...a, enabled: true }))])\n toast.success(t('agents.acp.toast.discoverAdded', { count: incoming.length }))\n setBaseUrl('')\n setShowDiscover(false)\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n return (\n <section className=\"rounded-md border border-border bg-surface\">\n <header className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <Network className=\"h-4 w-4 text-text-dim\" />\n <h2 className=\"text-sm font-semibold\">{t('agents.acp.title')}</h2>\n <Badge variant=\"outline\" className=\"text-[10px]\">{agents.length}</Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => setShowDiscover((v) => !v)}\n >\n <Search className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('agents.acp.discoverBtn')}</span>\n </Button>\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('agents.acp.subtitle')}</p>\n\n {/* Discover form (collapsed by default) */}\n {showDiscover && (\n <div className=\"border-t border-border bg-surface-2 px-4 py-3\">\n <Label htmlFor=\"acp-baseurl\" className=\"text-xs font-medium\">\n {t('agents.acp.baseUrl')}\n </Label>\n <p className=\"mt-1 text-[11px] text-text-dim\">{t('agents.acp.baseUrlHint')}</p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <Input\n id=\"acp-baseurl\"\n value={baseUrl}\n onChange={(e) => setBaseUrl(e.target.value)}\n placeholder=\"https://agents.example.com\"\n className=\"flex-1 min-w-[200px] font-mono text-xs\"\n />\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onDiscoverRun()}\n disabled={!baseUrl.trim() || discoverMut.isPending}\n >\n {discoverMut.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Search className=\"h-4 w-4\" />}\n {t('agents.acp.runDiscover')}\n </Button>\n </div>\n </div>\n )}\n\n {/* Registered ACP agents */}\n {agents.length === 0 ? (\n <div className=\"px-4 py-6\">\n <EmptyState\n icon={<Network />}\n title={t('agents.acp.empty.title')}\n description={t('agents.acp.empty.description')}\n />\n </div>\n ) : (\n <ul className=\"divide-y divide-border\">\n {agents.map((a, i) => (\n <AcpRow\n key={`${a.name}-${i}`}\n agent={a}\n onToggle={(on) => onToggleRow(i, on)}\n onTest={() => void onTestRow(i)}\n onRemove={() => onRemoveRow(i)}\n testing={testMut.isPending}\n />\n ))}\n </ul>\n )}\n\n {/* Add-agent form */}\n <div className=\"border-t border-border px-4 py-3\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wide text-text-dim\">\n {t('agents.acp.addTitle')}\n </h3>\n <div className=\"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <Field label={t('agents.acp.name')} hint={t('agents.acp.nameHint')}>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"my-agent\"\n aria-invalid={name.length > 0 && !nameValid}\n />\n </Field>\n <Field label={t('agents.acp.aliases')} hint={t('agents.acp.aliasesHint')}>\n <Input\n value={aliasesText}\n onChange={(e) => setAliasesText(e.target.value)}\n placeholder=\"ma, agent1\"\n />\n </Field>\n <Field label={t('agents.acp.endpoint')} hint={t('agents.acp.endpointHint')}>\n <Input\n value={endpoint}\n onChange={(e) => setEndpoint(e.target.value)}\n placeholder=\"https://example.com/agents/weather\"\n className=\"font-mono text-xs\"\n />\n </Field>\n <Field label={t('agents.acp.authType')}>\n <Select value={authType} onValueChange={(v) => setAuthType(v as ACPAuthType)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {AUTH_TYPES.map((a) => (\n <SelectItem key={a} value={a}>{t(`agents.acp.auth.${a}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n {authType !== 'none' && (\n <Field label={t('agents.acp.token')} className=\"sm:col-span-2\">\n <Input\n type=\"password\"\n value={token}\n onChange={(e) => setToken(e.target.value)}\n placeholder={t('agents.acp.tokenPlaceholder')}\n autoComplete=\"new-password\"\n />\n </Field>\n )}\n </div>\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => void onTestNew()}\n disabled={!canTestNew || testMut.isPending}\n >\n {testMut.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Search className=\"h-4 w-4\" />}\n {t('agents.acp.testBtn')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onAdd()}\n disabled={!canAdd}\n >\n <Plus className=\"h-4 w-4\" />\n {t('agents.acp.addBtn')}\n </Button>\n {dup && (\n <span className=\"self-center text-xs text-warning\">\n {t('agents.acp.dupName')}\n </span>\n )}\n </div>\n </div>\n </section>\n )\n}\n\ninterface AcpRowProps {\n agent: ACPAgentConfig\n onToggle: (on: boolean) => void\n onTest: () => void\n onRemove: () => void\n testing: boolean\n}\n\nfunction AcpRow({ agent, onToggle, onTest, onRemove, testing }: AcpRowProps): JSX.Element {\n const { t } = useTranslation('settings')\n const isOn = agent.enabled !== false\n const authType = agent.auth?.type ?? 'none'\n return (\n <li className=\"flex flex-wrap items-center gap-3 px-4 py-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{agent.name}</span>\n <Badge variant=\"outline\" className=\"text-[10px] uppercase\">\n {t(`agents.acp.auth.${authType}`)}\n </Badge>\n {agent.aliases && agent.aliases.length > 0 && (\n <span className=\"text-xs text-text-muted font-mono\">\n {agent.aliases.map((a) => `/${a}`).join(', ')}\n </span>\n )}\n </div>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-dim\" title={agent.endpoint}>\n {agent.endpoint}\n </p>\n </div>\n <label className=\"flex items-center gap-1.5 text-xs text-text-dim\">\n <input\n type=\"checkbox\"\n checked={isOn}\n onChange={(e) => onToggle(e.target.checked)}\n className=\"h-4 w-4 accent-accent cursor-pointer\"\n />\n {isOn ? t('agents.acp.on') : t('agents.acp.off')}\n </label>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onTest}\n disabled={testing}\n aria-label={t('agents.acp.testBtn')}\n >\n {testing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Search className=\"h-4 w-4\" />}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onRemove}\n aria-label={t('agents.acp.removeBtn')}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </li>\n )\n}\n\ninterface FieldProps {\n label: string\n hint?: string\n className?: string\n children: React.ReactNode\n}\n\nfunction Field({ label, hint, className, children }: FieldProps): JSX.Element {\n return (\n <div className={cn('flex flex-col gap-1', className)}>\n <Label className=\"text-xs font-medium\">{label}</Label>\n {children}\n {hint && <p className=\"text-[11px] text-text-dim\">{hint}</p>}\n </div>\n )\n}\n\n/** Tokens look like `ab****yz` from the masked GET response. We\n * shouldn't send them back unchanged for test (the backend would\n * fail auth), and we shouldn't include them in the test mutation\n * body either. Treat any string with 3+ consecutive `*` as masked. */\nfunction isMaskedToken(s: string): boolean {\n return /\\*{3,}/.test(s)\n}\n"],"names":["Bot","createLucideIcon","BUILTIN_AGENTS","AGENT_NAMES","SettingsAgentsRoute","useTranslation","cfgQuery","useConfig","statusQuery","useAgentsStatus","updateCfg","useUpdateConfig","cfg","status","draftEnabled","setDraftEnabled","useState","draftDefault","setDraftDefault","draftAcp","setDraftAcp","useEffect","enabled","defaultAgent","acpAgents","isDirty","useMemo","enabledSame","a","defaultSame","acpSame","acpEqual","eligibleDefaults","toggleAgent","name","on","next","onSave","toast","err","describeError","onDiscard","updateAcp","jsxs","jsx","Button","Loader2","RefreshCcw","Fragment","info","installed","isEnabled","AgentRow","Label","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","AcpCard","Badge","X","Save","aliases","pkg","onToggle","t","cn","e","AUTH_TYPES","NAME_RE","b","i","x","y","xa","ya","xat","yat","agents","onChange","testMut","useTestAcp","discoverMut","useDiscoverAcp","setName","aliasesText","setAliasesText","endpoint","setEndpoint","authType","setAuthType","token","setToken","showDiscover","setShowDiscover","baseUrl","setBaseUrl","trimmedName","nameValid","dup","tokenOk","canAdd","canTestNew","clearForm","parseAliases","text","s","buildAuth","type","tok","trimmed","onAdd","onTestNew","res","onTestRow","idx","isMaskedToken","onToggleRow","onRemoveRow","_","onDiscoverRun","url","existing","incoming","Network","Search","Input","EmptyState","AcpRow","Field","Plus","agent","onTest","onRemove","testing","isOn","Trash2","label","hint","className","children"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{u as b,j as e,k as j,p as C,c as m,B as f,
|
|
1
|
+
import{u as b,j as e,k as j,p as C,c as m,B as f,q as k,a as N,b as E,d as w,T as q,r as $,l as v,m as I}from"./index-CqwhfPlr.js";import{r as M}from"./react-Cb2sDjhD.js";import{X as R}from"./x-ClXUlQDe.js";import{E as L}from"./empty-state-CrPnUC6d.js";import{u as K}from"./useQuery-Ds6-WURB.js";import{u as O}from"./use-event-stream-DgGpGKop.js";import{L as Q}from"./loader-circle-U-jPjmeD.js";import{R as _}from"./refresh-ccw-CBiHL1tY.js";function z({approval:s,onResolve:t,busy:a=!1,className:l}){const{t:n}=b("approvals"),u=B(s.ageMs),o=F(s.input,12);return e.jsxs("div",{className:m("flex flex-col gap-3","rounded-md border bg-surface p-4",s.ageMs>9e4?"border-danger/60":"border-border",l),children:[e.jsxs("header",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-medium text-text",children:s.toolName}),e.jsx(j,{variant:"secondary",children:s.platform}),s.autoAllow&&e.jsx(j,{variant:"info",title:n("autoAllowedTitle"),children:n("autoAllowedTag")}),e.jsxs("span",{className:"ml-auto inline-flex items-center gap-1 text-xs text-text-dim",children:[s.ageMs>9e4&&e.jsx(C,{className:"h-3 w-3 text-danger"}),u]})]}),e.jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[e.jsx("div",{className:"text-text-muted",children:n("threadLabel")}),e.jsx("code",{className:"rounded bg-surface-2 px-1.5 py-0.5 font-mono text-xs text-text-dim line-clamp-1",title:s.threadId,children:s.threadId})]}),e.jsx("pre",{className:m("max-h-48 overflow-auto rounded-md","bg-surface-2 px-2 py-2","font-mono text-xs leading-5 text-text-dim","whitespace-pre-wrap break-words"),children:o}),e.jsxs("footer",{className:"flex justify-end gap-2",children:[e.jsxs(f,{type:"button",variant:"destructive",size:"sm",disabled:a,onClick:()=>void t("deny"),children:[e.jsx(R,{className:"h-4 w-4"}),n("deny")]}),e.jsxs(f,{type:"button",size:"sm",disabled:a,onClick:()=>void t("allow"),children:[e.jsx(k,{className:"h-4 w-4"}),n("allow")]})]})]})}function B(s){if(s<1e3)return`${s}ms`;const t=Math.floor(s/1e3);if(t<60)return`${t}s`;const a=Math.floor(t/60);return a<60?`${a}m`:`${Math.floor(a/60)}h`}function F(s,t){let a;try{a=JSON.stringify(s,null,2)}catch{a=String(s)}const l=a.split(`
|
|
2
2
|
`);return l.length<=t?a:`${l.slice(0,t).join(`
|
|
3
3
|
`)}
|
|
4
4
|
… +${l.length-t} more`}const p={all:["approvals"],list:["approvals","list"]};function D(){return K({queryKey:p.list,queryFn:()=>w.listApprovals()})}function J(){const s=N();return()=>s.invalidateQueries({queryKey:p.all})}function P(){const s=N();return E({mutationFn:({reqId:t,body:a})=>w.resolveApproval(t,a),onSuccess:()=>s.invalidateQueries({queryKey:p.all})})}const U={connected:"text-success",connecting:"text-text-dim",reconnecting:"text-warning",closed:"text-text-muted"};function ae(){const{t:s}=b(["approvals","common"]),t=J(),{data:a,isLoading:l,isFetching:n,refetch:u}=D(),o=a?.pending??[],i=a?.metrics,h=O({approval:()=>t()}),y=P(),[A,g]=M.useState(null);async function S(r,c){g(r);try{await y.mutateAsync({reqId:r,body:{behavior:c}}),v.success(s(c==="allow"?"toast.allowedShort":"toast.deniedShort"))}catch(d){const{message:T}=I(d,s);v.error(T)}finally{g(d=>d===r?null:d)}}return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(q,{}),e.jsxs("main",{className:"mx-auto flex w-full max-w-5xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 pb-safe",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("pageTitle")}),e.jsx("span",{className:m("text-xs font-medium tabular-nums",U[h]),children:s(`live.${h}`)}),e.jsxs(f,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>u(),disabled:n,"aria-label":s("actions.refresh",{ns:"common"}),children:[n?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(_,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("actions.refresh",{ns:"common"})})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("subtitle")})]}),i&&e.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[e.jsx(x,{label:s("stats.pending"),value:i.pending,tone:"info"}),e.jsx(x,{label:s("stats.totalAllowed"),value:i.totalAllowed,tone:"success"}),e.jsx(x,{label:s("stats.totalDenied"),value:i.totalDenied,tone:"danger"}),e.jsx(x,{label:s("stats.totalTimedOut"),value:i.totalTimedOut,tone:"warning"})]}),l?e.jsx(X,{}):o.length===0?e.jsx(L,{icon:e.jsx($,{}),title:s("empty.title"),description:s("empty.description")}):e.jsx("div",{className:"flex flex-col gap-3",children:o.map(r=>e.jsx(z,{approval:r,busy:A===r.reqId,onResolve:c=>S(r.reqId,c)},r.reqId))})]})]})}const V={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:s,value:t,tone:a}){return e.jsxs("div",{className:m("rounded-md border bg-surface px-3 py-2",V[a]),children:[e.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:s}),e.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:t})]})}function X(){return e.jsx("div",{className:"flex flex-col gap-3",children:Array.from({length:2}).map((s,t)=>e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-border bg-surface p-4",children:[e.jsx("div",{className:"h-4 w-1/3 rounded bg-surface-2 animate-pulse"}),e.jsx("div",{className:"h-3 w-1/2 rounded bg-surface-2 animate-pulse"}),e.jsx("div",{className:"h-24 w-full rounded bg-surface-2 animate-pulse"}),e.jsxs("div",{className:"ml-auto flex gap-2",children:[e.jsx("div",{className:"h-8 w-16 rounded bg-surface-2 animate-pulse"}),e.jsx("div",{className:"h-8 w-16 rounded bg-surface-2 animate-pulse"})]})]},`skel-${t}`))})}export{ae as default};
|
|
5
|
-
//# sourceMappingURL=approvals-
|
|
5
|
+
//# sourceMappingURL=approvals-CY-_Lg4Y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approvals-4gNB4E5r.js","sources":["../../src/components/approvals/approval-card.tsx","../../src/hooks/use-approvals.ts","../../src/routes/approvals.tsx"],"sourcesContent":["/**\n * ApprovalCard — one HITL approval, rendered as a card.\n *\n * The /approvals route uses cards (not table rows) on purpose:\n * * approvals are time-sensitive and few — visual urgency matters\n * * each row's `input` is a free-form record that's hard to squeeze\n * into a single cell. The card body has room for a JSON preview.\n * * Allow / Deny are 1-click decisions; we want big tap targets\n * even on desktop, which doesn't fit cleanly into a TableCell.\n *\n * Layout:\n * ┌─ tool name · platform · age ─────────────────┐\n * │ thread id (monospaced) │\n * │ │\n * │ <pre>input json (truncated to ~12 lines)</pre>│\n * │ │\n * │ [ Deny ] [ Allow ] │\n * └──────────────────────────────────────────────┘\n *\n * The buttons are disabled while a resolution is in flight (so a\n * second click can't double-fire). Async failure surfaces via the\n * parent's toast; the card stays put.\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { Check, X, AlertTriangle } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { cn } from '@/lib/utils'\nimport type { Approval, ApprovalBehavior } from '@/types/api'\n\nexport interface ApprovalCardProps {\n approval: Approval\n /** Async resolve callback. The card calls this with the behavior\n * + the current reqId; parent handles toast + mutation state.\n * The card disables its buttons while the promise is in flight. */\n onResolve: (behavior: ApprovalBehavior) => Promise<void> | void\n /** When true, both action buttons are disabled. Parent flips this\n * on while its mutation is in flight. */\n busy?: boolean\n /** Optional className for the outer card. */\n className?: string\n}\n\nexport function ApprovalCard({\n approval,\n onResolve,\n busy = false,\n className,\n}: ApprovalCardProps): JSX.Element {\n const { t } = useTranslation('approvals')\n\n const aged = formatAge(approval.ageMs)\n const inputPreview = previewJson(approval.input, 12)\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3',\n 'rounded-md border bg-surface p-4',\n // Cards older than 90s carry a soft danger border to draw\n // the operator's eye to stale requests.\n approval.ageMs > 90_000 ? 'border-danger/60' : 'border-border',\n className,\n )}\n >\n <header className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{approval.toolName}</span>\n <Badge variant=\"secondary\">{approval.platform}</Badge>\n {approval.autoAllow && (\n <Badge variant=\"info\" title={t('autoAllowedTitle')}>\n {t('autoAllowedTag')}\n </Badge>\n )}\n <span className=\"ml-auto inline-flex items-center gap-1 text-xs text-text-dim\">\n {approval.ageMs > 90_000 && <AlertTriangle className=\"h-3 w-3 text-danger\" />}\n {aged}\n </span>\n </header>\n\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"text-text-muted\">{t('threadLabel')}</div>\n <code\n className=\"rounded bg-surface-2 px-1.5 py-0.5 font-mono text-xs text-text-dim line-clamp-1\"\n title={approval.threadId}\n >\n {approval.threadId}\n </code>\n </div>\n\n <pre\n className={cn(\n 'max-h-48 overflow-auto rounded-md',\n 'bg-surface-2 px-2 py-2',\n 'font-mono text-xs leading-5 text-text-dim',\n 'whitespace-pre-wrap break-words',\n )}\n >\n {inputPreview}\n </pre>\n\n <footer className=\"flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n disabled={busy}\n onClick={() => void onResolve('deny')}\n >\n <X className=\"h-4 w-4\" />\n {t('deny')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={busy}\n onClick={() => void onResolve('allow')}\n >\n <Check className=\"h-4 w-4\" />\n {t('allow')}\n </Button>\n </footer>\n </div>\n )\n}\n\n/** Human-readable age string (\"12s\", \"4m\", \"2h\"). Tracks the\n * bus's ageMs at render time; SSE invalidation keeps it fresh. */\nfunction formatAge(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n const s = Math.floor(ms / 1000)\n if (s < 60) return `${s}s`\n const m = Math.floor(s / 60)\n if (m < 60) return `${m}m`\n const h = Math.floor(m / 60)\n return `${h}h`\n}\n\n/** Pretty-print the tool input JSON with a line cap. Falls back to\n * `String(value)` if JSON.stringify throws (e.g. circular). */\nfunction previewJson(value: unknown, maxLines: number): string {\n let text: string\n try {\n text = JSON.stringify(value, null, 2)\n } catch {\n text = String(value)\n }\n const lines = text.split('\\n')\n if (lines.length <= maxLines) return text\n return `${lines.slice(0, maxLines).join('\\n')}\\n… +${lines.length - maxLines} more`\n}\n","/**\n * useApprovals — react-query wrappers for the HITL approval queue.\n *\n * useApprovals() — list pending + bus metrics\n * useResolveApproval() — allow / deny a specific reqId\n *\n * SSE: the route subscribes to the `approval` SSE event and\n * invalidates this query on any phase change, so a `requested` from\n * another tab (or `resolved` we don't initiate) shows up live\n * without a poll.\n *\n * No background poll — approvals are short-lived, the SSE channel\n * is the live source, and the v1 admin's 3 s poll caused enough\n * jitter that we'd rather rely on SSE plus an explicit refresh\n * button.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListApprovalsResponse, ResolveApprovalBody, ResolveApprovalResponse } from '@/types/api'\n\nexport const approvalsKeys = {\n all: ['approvals'] as const,\n list: ['approvals', 'list'] as const,\n}\n\nexport function useApprovals() {\n return useQuery<ListApprovalsResponse>({\n queryKey: approvalsKeys.list,\n queryFn: () => api.listApprovals(),\n })\n}\n\nexport function useInvalidateApprovals() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: approvalsKeys.all })\n}\n\nexport function useResolveApproval() {\n const qc = useQueryClient()\n return useMutation<\n ResolveApprovalResponse,\n Error,\n { reqId: string; body: ResolveApprovalBody }\n >({\n mutationFn: ({ reqId, body }) => api.resolveApproval(reqId, body),\n onSuccess: () => qc.invalidateQueries({ queryKey: approvalsKeys.all }),\n })\n}\n","/**\n * /approvals — Human-in-the-loop tool approval queue.\n *\n * Cards (one per pending request) instead of a DataTable: approvals\n * are short-lived, time-sensitive, and each one wants a JSON-preview\n * block that doesn't fit cleanly in a row. Allow / Deny are 1-click\n * decisions — no ConfirmDialog (the user already weighed the call\n * when they clicked).\n *\n * SSE: the `approval` event invalidates the list on every requested /\n * resolved transition, so a request from another tab (or a backend\n * resolve we didn't initiate) flips off the screen instantly.\n *\n * KPI strip:\n * pending | totalAllowed | totalDenied | totalTimedOut\n *\n * Empty state is the desired steady-state — the friendly empty card\n * matches \"all caught up\", not \"broken\".\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, RefreshCcw, ShieldCheck } from 'lucide-react'\n\nimport { Topbar } from '@/components/shell/topbar'\nimport { Button } from '@/components/ui/button'\nimport { ApprovalCard } from '@/components/approvals/approval-card'\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n useApprovals,\n useInvalidateApprovals,\n useResolveApproval,\n} from '@/hooks/use-approvals'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport { describeError } from '@/lib/api/errors'\nimport type { ApprovalBehavior } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function ApprovalsRoute(): JSX.Element {\n const { t } = useTranslation(['approvals', 'common'])\n const invalidate = useInvalidateApprovals()\n\n const { data, isLoading, isFetching, refetch } = useApprovals()\n const pending = data?.pending ?? []\n const metrics = data?.metrics\n\n const live = useEventStream({\n approval: () => invalidate(),\n })\n\n const resolve = useResolveApproval()\n /** Tracks the reqId currently being resolved so the card can\n * disable its buttons. Multiple cards in flight is fine (we\n * bake one key per card), but each card stays inert until its\n * own promise lands. */\n const [resolvingId, setResolvingId] = useState<string | null>(null)\n\n async function onResolve(reqId: string, behavior: ApprovalBehavior): Promise<void> {\n setResolvingId(reqId)\n try {\n await resolve.mutateAsync({ reqId, body: { behavior } })\n toast.success(\n behavior === 'allow' ? t('toast.allowedShort') : t('toast.deniedShort'),\n )\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n } finally {\n setResolvingId((id) => (id === reqId ? null : id))\n }\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <main className=\"mx-auto flex w-full max-w-5xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 pb-safe\">\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('pageTitle')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('subtitle')}</p>\n </header>\n\n {/* Metrics strip */}\n {metrics && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('stats.pending')} value={metrics.pending} tone=\"info\" />\n <StatCard label={t('stats.totalAllowed')} value={metrics.totalAllowed} tone=\"success\" />\n <StatCard label={t('stats.totalDenied')} value={metrics.totalDenied} tone=\"danger\" />\n <StatCard label={t('stats.totalTimedOut')} value={metrics.totalTimedOut} tone=\"warning\" />\n </div>\n )}\n\n {/* List */}\n {isLoading ? (\n <SkeletonList />\n ) : pending.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck />}\n title={t('empty.title')}\n description={t('empty.description')}\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {pending.map((p) => (\n <ApprovalCard\n key={p.reqId}\n approval={p}\n busy={resolvingId === p.reqId}\n onResolve={(behavior) => onResolve(p.reqId, behavior)}\n />\n ))}\n </div>\n )}\n </main>\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\nfunction SkeletonList(): JSX.Element {\n return (\n <div className=\"flex flex-col gap-3\">\n {Array.from({ length: 2 }).map((_, i) => (\n <div\n key={`skel-${i}`}\n className=\"flex flex-col gap-3 rounded-md border border-border bg-surface p-4\"\n >\n <div className=\"h-4 w-1/3 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-1/2 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-24 w-full rounded bg-surface-2 animate-pulse\" />\n <div className=\"ml-auto flex gap-2\">\n <div className=\"h-8 w-16 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-8 w-16 rounded bg-surface-2 animate-pulse\" />\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],"names":["ApprovalCard","approval","onResolve","busy","className","t","useTranslation","aged","formatAge","inputPreview","previewJson","jsxs","cn","jsx","Badge","AlertTriangle","Button","X","Check","ms","s","m","value","maxLines","text","lines","approvalsKeys","useApprovals","useQuery","api","useInvalidateApprovals","qc","useQueryClient","useResolveApproval","useMutation","reqId","body","LIVE_STATUS_CLASS","ApprovalsRoute","invalidate","data","isLoading","isFetching","refetch","pending","metrics","live","useEventStream","resolve","resolvingId","setResolvingId","useState","behavior","toast","err","message","describeError","id","Topbar","Loader2","RefreshCcw","StatCard","SkeletonList","EmptyState","ShieldCheck","p","TONE_STYLES","label","tone","_","i"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"approvals-CY-_Lg4Y.js","sources":["../../src/components/approvals/approval-card.tsx","../../src/hooks/use-approvals.ts","../../src/routes/approvals.tsx"],"sourcesContent":["/**\n * ApprovalCard — one HITL approval, rendered as a card.\n *\n * The /approvals route uses cards (not table rows) on purpose:\n * * approvals are time-sensitive and few — visual urgency matters\n * * each row's `input` is a free-form record that's hard to squeeze\n * into a single cell. The card body has room for a JSON preview.\n * * Allow / Deny are 1-click decisions; we want big tap targets\n * even on desktop, which doesn't fit cleanly into a TableCell.\n *\n * Layout:\n * ┌─ tool name · platform · age ─────────────────┐\n * │ thread id (monospaced) │\n * │ │\n * │ <pre>input json (truncated to ~12 lines)</pre>│\n * │ │\n * │ [ Deny ] [ Allow ] │\n * └──────────────────────────────────────────────┘\n *\n * The buttons are disabled while a resolution is in flight (so a\n * second click can't double-fire). Async failure surfaces via the\n * parent's toast; the card stays put.\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { Check, X, AlertTriangle } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { cn } from '@/lib/utils'\nimport type { Approval, ApprovalBehavior } from '@/types/api'\n\nexport interface ApprovalCardProps {\n approval: Approval\n /** Async resolve callback. The card calls this with the behavior\n * + the current reqId; parent handles toast + mutation state.\n * The card disables its buttons while the promise is in flight. */\n onResolve: (behavior: ApprovalBehavior) => Promise<void> | void\n /** When true, both action buttons are disabled. Parent flips this\n * on while its mutation is in flight. */\n busy?: boolean\n /** Optional className for the outer card. */\n className?: string\n}\n\nexport function ApprovalCard({\n approval,\n onResolve,\n busy = false,\n className,\n}: ApprovalCardProps): JSX.Element {\n const { t } = useTranslation('approvals')\n\n const aged = formatAge(approval.ageMs)\n const inputPreview = previewJson(approval.input, 12)\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-3',\n 'rounded-md border bg-surface p-4',\n // Cards older than 90s carry a soft danger border to draw\n // the operator's eye to stale requests.\n approval.ageMs > 90_000 ? 'border-danger/60' : 'border-border',\n className,\n )}\n >\n <header className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium text-text\">{approval.toolName}</span>\n <Badge variant=\"secondary\">{approval.platform}</Badge>\n {approval.autoAllow && (\n <Badge variant=\"info\" title={t('autoAllowedTitle')}>\n {t('autoAllowedTag')}\n </Badge>\n )}\n <span className=\"ml-auto inline-flex items-center gap-1 text-xs text-text-dim\">\n {approval.ageMs > 90_000 && <AlertTriangle className=\"h-3 w-3 text-danger\" />}\n {aged}\n </span>\n </header>\n\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"text-text-muted\">{t('threadLabel')}</div>\n <code\n className=\"rounded bg-surface-2 px-1.5 py-0.5 font-mono text-xs text-text-dim line-clamp-1\"\n title={approval.threadId}\n >\n {approval.threadId}\n </code>\n </div>\n\n <pre\n className={cn(\n 'max-h-48 overflow-auto rounded-md',\n 'bg-surface-2 px-2 py-2',\n 'font-mono text-xs leading-5 text-text-dim',\n 'whitespace-pre-wrap break-words',\n )}\n >\n {inputPreview}\n </pre>\n\n <footer className=\"flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n disabled={busy}\n onClick={() => void onResolve('deny')}\n >\n <X className=\"h-4 w-4\" />\n {t('deny')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={busy}\n onClick={() => void onResolve('allow')}\n >\n <Check className=\"h-4 w-4\" />\n {t('allow')}\n </Button>\n </footer>\n </div>\n )\n}\n\n/** Human-readable age string (\"12s\", \"4m\", \"2h\"). Tracks the\n * bus's ageMs at render time; SSE invalidation keeps it fresh. */\nfunction formatAge(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n const s = Math.floor(ms / 1000)\n if (s < 60) return `${s}s`\n const m = Math.floor(s / 60)\n if (m < 60) return `${m}m`\n const h = Math.floor(m / 60)\n return `${h}h`\n}\n\n/** Pretty-print the tool input JSON with a line cap. Falls back to\n * `String(value)` if JSON.stringify throws (e.g. circular). */\nfunction previewJson(value: unknown, maxLines: number): string {\n let text: string\n try {\n text = JSON.stringify(value, null, 2)\n } catch {\n text = String(value)\n }\n const lines = text.split('\\n')\n if (lines.length <= maxLines) return text\n return `${lines.slice(0, maxLines).join('\\n')}\\n… +${lines.length - maxLines} more`\n}\n","/**\n * useApprovals — react-query wrappers for the HITL approval queue.\n *\n * useApprovals() — list pending + bus metrics\n * useResolveApproval() — allow / deny a specific reqId\n *\n * SSE: the route subscribes to the `approval` SSE event and\n * invalidates this query on any phase change, so a `requested` from\n * another tab (or `resolved` we don't initiate) shows up live\n * without a poll.\n *\n * No background poll — approvals are short-lived, the SSE channel\n * is the live source, and the v1 admin's 3 s poll caused enough\n * jitter that we'd rather rely on SSE plus an explicit refresh\n * button.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListApprovalsResponse, ResolveApprovalBody, ResolveApprovalResponse } from '@/types/api'\n\nexport const approvalsKeys = {\n all: ['approvals'] as const,\n list: ['approvals', 'list'] as const,\n}\n\nexport function useApprovals() {\n return useQuery<ListApprovalsResponse>({\n queryKey: approvalsKeys.list,\n queryFn: () => api.listApprovals(),\n })\n}\n\nexport function useInvalidateApprovals() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: approvalsKeys.all })\n}\n\nexport function useResolveApproval() {\n const qc = useQueryClient()\n return useMutation<\n ResolveApprovalResponse,\n Error,\n { reqId: string; body: ResolveApprovalBody }\n >({\n mutationFn: ({ reqId, body }) => api.resolveApproval(reqId, body),\n onSuccess: () => qc.invalidateQueries({ queryKey: approvalsKeys.all }),\n })\n}\n","/**\n * /approvals — Human-in-the-loop tool approval queue.\n *\n * Cards (one per pending request) instead of a DataTable: approvals\n * are short-lived, time-sensitive, and each one wants a JSON-preview\n * block that doesn't fit cleanly in a row. Allow / Deny are 1-click\n * decisions — no ConfirmDialog (the user already weighed the call\n * when they clicked).\n *\n * SSE: the `approval` event invalidates the list on every requested /\n * resolved transition, so a request from another tab (or a backend\n * resolve we didn't initiate) flips off the screen instantly.\n *\n * KPI strip:\n * pending | totalAllowed | totalDenied | totalTimedOut\n *\n * Empty state is the desired steady-state — the friendly empty card\n * matches \"all caught up\", not \"broken\".\n */\n\nimport { useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Loader2, RefreshCcw, ShieldCheck } from 'lucide-react'\n\nimport { Topbar } from '@/components/shell/topbar'\nimport { Button } from '@/components/ui/button'\nimport { ApprovalCard } from '@/components/approvals/approval-card'\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n useApprovals,\n useInvalidateApprovals,\n useResolveApproval,\n} from '@/hooks/use-approvals'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport { describeError } from '@/lib/api/errors'\nimport type { ApprovalBehavior } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function ApprovalsRoute(): JSX.Element {\n const { t } = useTranslation(['approvals', 'common'])\n const invalidate = useInvalidateApprovals()\n\n const { data, isLoading, isFetching, refetch } = useApprovals()\n const pending = data?.pending ?? []\n const metrics = data?.metrics\n\n const live = useEventStream({\n approval: () => invalidate(),\n })\n\n const resolve = useResolveApproval()\n /** Tracks the reqId currently being resolved so the card can\n * disable its buttons. Multiple cards in flight is fine (we\n * bake one key per card), but each card stays inert until its\n * own promise lands. */\n const [resolvingId, setResolvingId] = useState<string | null>(null)\n\n async function onResolve(reqId: string, behavior: ApprovalBehavior): Promise<void> {\n setResolvingId(reqId)\n try {\n await resolve.mutateAsync({ reqId, body: { behavior } })\n toast.success(\n behavior === 'allow' ? t('toast.allowedShort') : t('toast.deniedShort'),\n )\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n } finally {\n setResolvingId((id) => (id === reqId ? null : id))\n }\n }\n\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <main className=\"mx-auto flex w-full max-w-5xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 pb-safe\">\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('pageTitle')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('subtitle')}</p>\n </header>\n\n {/* Metrics strip */}\n {metrics && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('stats.pending')} value={metrics.pending} tone=\"info\" />\n <StatCard label={t('stats.totalAllowed')} value={metrics.totalAllowed} tone=\"success\" />\n <StatCard label={t('stats.totalDenied')} value={metrics.totalDenied} tone=\"danger\" />\n <StatCard label={t('stats.totalTimedOut')} value={metrics.totalTimedOut} tone=\"warning\" />\n </div>\n )}\n\n {/* List */}\n {isLoading ? (\n <SkeletonList />\n ) : pending.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck />}\n title={t('empty.title')}\n description={t('empty.description')}\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {pending.map((p) => (\n <ApprovalCard\n key={p.reqId}\n approval={p}\n busy={resolvingId === p.reqId}\n onResolve={(behavior) => onResolve(p.reqId, behavior)}\n />\n ))}\n </div>\n )}\n </main>\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\nfunction SkeletonList(): JSX.Element {\n return (\n <div className=\"flex flex-col gap-3\">\n {Array.from({ length: 2 }).map((_, i) => (\n <div\n key={`skel-${i}`}\n className=\"flex flex-col gap-3 rounded-md border border-border bg-surface p-4\"\n >\n <div className=\"h-4 w-1/3 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-3 w-1/2 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-24 w-full rounded bg-surface-2 animate-pulse\" />\n <div className=\"ml-auto flex gap-2\">\n <div className=\"h-8 w-16 rounded bg-surface-2 animate-pulse\" />\n <div className=\"h-8 w-16 rounded bg-surface-2 animate-pulse\" />\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],"names":["ApprovalCard","approval","onResolve","busy","className","t","useTranslation","aged","formatAge","inputPreview","previewJson","jsxs","cn","jsx","Badge","AlertTriangle","Button","X","Check","ms","s","m","value","maxLines","text","lines","approvalsKeys","useApprovals","useQuery","api","useInvalidateApprovals","qc","useQueryClient","useResolveApproval","useMutation","reqId","body","LIVE_STATUS_CLASS","ApprovalsRoute","invalidate","data","isLoading","isFetching","refetch","pending","metrics","live","useEventStream","resolve","resolvingId","setResolvingId","useState","behavior","toast","err","message","describeError","id","Topbar","Loader2","RefreshCcw","StatCard","SkeletonList","EmptyState","ShieldCheck","p","TONE_STYLES","label","tone","_","i"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{n as o}from"./index-
|
|
1
|
+
import{n as o}from"./index-CqwhfPlr.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 r=o("ArrowDown",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);export{r as A};
|
|
7
|
-
//# sourceMappingURL=arrow-down-
|
|
7
|
+
//# sourceMappingURL=arrow-down-BkZ50IzL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrow-down-
|
|
1
|
+
{"version":3,"file":"arrow-down-BkZ50IzL.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-down.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 ArrowDown = createLucideIcon(\"ArrowDown\", [\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }],\n [\"path\", { d: \"m19 12-7 7-7-7\", key: \"1idqje\" }]\n]);\n\nexport { ArrowDown as default };\n//# sourceMappingURL=arrow-down.js.map\n"],"names":["ArrowDown","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAYC,EAAiB,YAAa,CAC9C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAQ,CAAE,CACjD,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{n as r}from"./index-
|
|
1
|
+
import{n as r}from"./index-CqwhfPlr.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=r("ArrowUp",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]);export{a as A};
|
|
7
|
-
//# sourceMappingURL=arrow-up-
|
|
7
|
+
//# sourceMappingURL=arrow-up-NWC5K6Jw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrow-up-
|
|
1
|
+
{"version":3,"file":"arrow-up-NWC5K6Jw.js","sources":["../../node_modules/lucide-react/dist/esm/icons/arrow-up.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 ArrowUp = createLucideIcon(\"ArrowUp\", [\n [\"path\", { d: \"m5 12 7-7 7 7\", key: \"hav0vg\" }],\n [\"path\", { d: \"M12 19V5\", key: \"x0mq9r\" }]\n]);\n\nexport { ArrowUp as default };\n//# sourceMappingURL=arrow-up.js.map\n"],"names":["ArrowUp","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAUC,EAAiB,UAAW,CAC1C,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,QAAQ,CAAE,EAC9C,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{n as u,u as j,j as s,k as o,B as d,l as m}from"./index-
|
|
1
|
+
import{n as u,u as j,j as s,k as o,B as d,l as m}from"./index-CqwhfPlr.js";import{T as f,a as k,b as x,c as r,d as p,e as n}from"./table-BNqo2xb8.js";import{d as g,e as b}from"./use-background-tasks-CY2gWPBZ.js";import{L as N}from"./loader-circle-U-jPjmeD.js";import{R as v}from"./refresh-ccw-CBiHL1tY.js";import{C as w}from"./circle-x-THl-PO3_.js";import"./react-Cb2sDjhD.js";import"./useQuery-Ds6-WURB.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 y=u("Hourglass",[["path",{d:"M5 22h14",key:"ehvnwv"}],["path",{d:"M5 2h14",key:"pdyrp9"}],["path",{d:"M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22",key:"1d314k"}],["path",{d:"M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2",key:"1vvvr6"}]]);function H(){const{t:e}=j(["tasks","common"]),t=g(),i=b();async function h(a){if(confirm(e("asks.cancelConfirm",{id:a.slice(0,8)})))try{await i.mutateAsync(a),m.success(e("asks.cancelledToast"))}catch(l){m.error(l?.message??String(l))}}const c=t.data?.pending??[];return s.jsxs("div",{className:"mx-auto flex max-w-6xl flex-col gap-4 p-4",children:[s.jsxs("header",{className:"flex items-center gap-3",children:[s.jsx(y,{className:"h-5 w-5 text-text-dim"}),s.jsx("h1",{className:"text-xl font-semibold",children:e("asks.title")}),s.jsx(o,{variant:"info",children:c.length}),s.jsxs(d,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>void t.refetch(),disabled:t.isFetching,"aria-label":e("actions.refresh",{ns:"common"}),children:[t.isFetching?s.jsx(N,{className:"h-4 w-4 animate-spin"}):s.jsx(v,{className:"h-4 w-4"}),s.jsx("span",{className:"hidden sm:inline",children:e("asks.refresh")})]})]}),s.jsx("p",{className:"text-sm text-text-dim",children:e("asks.subtitle")}),t.isLoading?s.jsx("div",{className:"h-32 rounded-md bg-surface-2 animate-pulse"}):c.length===0?s.jsx("section",{className:"rounded-md border border-border bg-surface p-6 text-center text-sm text-text-dim",children:e("asks.empty")}):s.jsx("section",{className:"rounded-md border border-border bg-surface",children:s.jsxs(f,{children:[s.jsx(k,{children:s.jsxs(x,{children:[s.jsx(r,{children:e("asks.col.reqId")}),s.jsx(r,{children:e("asks.col.thread")}),s.jsx(r,{children:e("asks.col.question")}),s.jsx(r,{children:e("asks.col.choices")}),s.jsx(r,{children:e("asks.col.age")}),s.jsx(r,{children:e("asks.col.actions")})]})}),s.jsx(p,{children:c.map(a=>s.jsxs(x,{children:[s.jsxs(n,{className:"font-mono text-[11px]",children:[a.reqId.slice(0,8),"…"]}),s.jsxs(n,{className:"font-mono text-[11px]",children:[a.platform,":",a.threadId]}),s.jsx(n,{className:"max-w-md break-words",children:a.question}),s.jsx(n,{children:s.jsx(o,{variant:"outline",children:a.choices})}),s.jsx(n,{className:"text-xs text-text-dim",children:C(a.ageMs,e)}),s.jsx(n,{children:s.jsxs(d,{variant:"ghost",size:"sm",onClick:()=>void h(a.reqId),disabled:i.isPending,className:"text-danger hover:text-danger",children:[s.jsx(w,{className:"h-4 w-4"}),e("asks.cancel")]})})]},a.reqId))})]})})]})}function C(e,t){return e<1e3?t("asks.justNow"):e<6e4?t("asks.seconds",{count:Math.floor(e/1e3)}):e<36e5?t("asks.minutes",{count:Math.floor(e/6e4)}):t("asks.hours",{count:Math.floor(e/36e5)})}export{H as default};
|
|
7
|
-
//# sourceMappingURL=asks-
|
|
7
|
+
//# sourceMappingURL=asks-VzAmpsEh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asks-
|
|
1
|
+
{"version":3,"file":"asks-VzAmpsEh.js","sources":["../../node_modules/lucide-react/dist/esm/icons/hourglass.js","../../src/routes/tasks/asks.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 Hourglass = createLucideIcon(\"Hourglass\", [\n [\"path\", { d: \"M5 22h14\", key: \"ehvnwv\" }],\n [\"path\", { d: \"M5 2h14\", key: \"pdyrp9\" }],\n [\n \"path\",\n {\n d: \"M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22\",\n key: \"1d314k\"\n }\n ],\n [\n \"path\",\n { d: \"M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2\", key: \"1vvvr6\" }\n ]\n]);\n\nexport { Hourglass as default };\n//# sourceMappingURL=hourglass.js.map\n","/**\n * /tasks/asks — admin view of pending ask_user (P1).\n */\n\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Hourglass, Loader2, RefreshCcw, XCircle } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Table, TableBody, TableCell, TableHead, TableHeader, TableRow,\n} from '@/components/ui/table'\nimport {\n useAsksList, useAskCancel,\n} from '@/hooks/use-background-tasks'\n\nexport default function TasksAsksRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const listQuery = useAsksList()\n const cancel = useAskCancel()\n\n async function onCancel(reqId: string): Promise<void> {\n if (!confirm(t('asks.cancelConfirm', { id: reqId.slice(0, 8) }))) return\n try {\n await cancel.mutateAsync(reqId)\n toast.success(t('asks.cancelledToast'))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n const rows = listQuery.data?.pending ?? []\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4 p-4\">\n <header className=\"flex items-center gap-3\">\n <Hourglass className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('asks.title')}</h1>\n <Badge variant=\"info\">{rows.length}</Badge>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void listQuery.refetch()}\n disabled={listQuery.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {listQuery.isFetching\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('asks.refresh')}</span>\n </Button>\n </header>\n <p className=\"text-sm text-text-dim\">{t('asks.subtitle')}</p>\n\n {listQuery.isLoading ? (\n <div className=\"h-32 rounded-md bg-surface-2 animate-pulse\" />\n ) : rows.length === 0 ? (\n <section className=\"rounded-md border border-border bg-surface p-6 text-center text-sm text-text-dim\">\n {t('asks.empty')}\n </section>\n ) : (\n <section className=\"rounded-md border border-border bg-surface\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t('asks.col.reqId')}</TableHead>\n <TableHead>{t('asks.col.thread')}</TableHead>\n <TableHead>{t('asks.col.question')}</TableHead>\n <TableHead>{t('asks.col.choices')}</TableHead>\n <TableHead>{t('asks.col.age')}</TableHead>\n <TableHead>{t('asks.col.actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {rows.map((r) => (\n <TableRow key={r.reqId}>\n <TableCell className=\"font-mono text-[11px]\">{r.reqId.slice(0, 8)}…</TableCell>\n <TableCell className=\"font-mono text-[11px]\">{r.platform}:{r.threadId}</TableCell>\n <TableCell className=\"max-w-md break-words\">{r.question}</TableCell>\n <TableCell><Badge variant=\"outline\">{r.choices}</Badge></TableCell>\n <TableCell className=\"text-xs text-text-dim\">{fmtAge(r.ageMs, t)}</TableCell>\n <TableCell>\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onCancel(r.reqId)}\n disabled={cancel.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <XCircle className=\"h-4 w-4\" />\n {t('asks.cancel')}\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </section>\n )}\n </div>\n )\n}\n\nfunction fmtAge(ms: number, t: (key: string, opts?: Record<string, unknown>) => string): string {\n if (ms < 1_000) return t('asks.justNow')\n if (ms < 60_000) return t('asks.seconds', { count: Math.floor(ms / 1_000) })\n if (ms < 3_600_000) return t('asks.minutes', { count: Math.floor(ms / 60_000) })\n return t('asks.hours', { count: Math.floor(ms / 3_600_000) })\n}\n"],"names":["Hourglass","createLucideIcon","TasksAsksRoute","t","useTranslation","listQuery","useAsksList","cancel","useAskCancel","onCancel","reqId","toast","err","rows","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","Table","TableHeader","TableRow","TableHead","TableBody","r","TableCell","XCircle","fmtAge","ms"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as A,e as O,j as t,k as F,B as I,L as P,I as k,c as B}from"./index-
|
|
2
|
-
//# sourceMappingURL=audit-
|
|
1
|
+
import{u as A,e as O,j as t,k as F,B as I,L as P,I as k,c as B}from"./index-CqwhfPlr.js";import{r as i}from"./react-Cb2sDjhD.js";import{D as _}from"./data-table-B80M8zdu.js";import{E as U}from"./empty-state-CrPnUC6d.js";import{b as $}from"./use-observability-BOepIjX5.js";import{L as q}from"./loader-circle-U-jPjmeD.js";import{R as z}from"./refresh-ccw-CBiHL1tY.js";import{A as H}from"./activity-Cckc7fGG.js";import"./table-BNqo2xb8.js";import"./arrow-up-NWC5K6Jw.js";import"./arrow-down-BkZ50IzL.js";import"./useQuery-Ds6-WURB.js";const G=300;function nt(){const{t:e}=A(["observability","common"]),[s,d]=O(),c=Math.max(1,Number(s.get("days"))||7),n=s.get("agent")??"",l=s.get("platform")??"",r=s.get("user")??"",o=s.get("intent")??"",[u,j]=i.useState(n),[x,b]=i.useState(l),[f,w]=i.useState(r),[h,C]=i.useState(o);i.useEffect(()=>{j(n)},[n]),i.useEffect(()=>{b(l)},[l]),i.useEffect(()=>{w(r)},[r]),i.useEffect(()=>{C(o)},[o]),i.useEffect(()=>{const a=window.setTimeout(()=>{R({agent:u||null,platform:x||null,user:f||null,intent:h||null})},G);return()=>window.clearTimeout(a)},[u,x,f,h]);const E=i.useMemo(()=>({days:c,limit:200,...n?{agent:n}:{},...l?{platform:l}:{},...r?{user:r}:{},...o?{intent:o}:{}}),[c,n,l,r,o]),{data:v,isLoading:S,isFetching:y,refetch:M}=$(E),L=v?.invocations??[],p=v?.stats;function R(a){const g=new URLSearchParams(s);for(const[D,N]of Object.entries(a))N==null||N===""?g.delete(D):g.set(D,N);d(g,{replace:!0})}const T=i.useMemo(()=>[{id:"ts",header:e("audit.col.ts"),cell:a=>t.jsx("span",{className:"text-text-dim text-xs tabular-nums",children:J(a.ts)}),headClassName:"w-32"},{id:"agent",header:e("audit.col.agent"),cell:a=>t.jsx("span",{className:"font-medium",children:a.agent}),headClassName:"w-32"},{id:"platform",header:e("audit.col.platform"),cell:a=>t.jsx("span",{className:"text-text-dim",children:a.platform}),headClassName:"w-24",hideOnMobile:!0},{id:"user",header:e("audit.col.user"),cell:a=>t.jsx("span",{className:"font-mono text-xs text-text-dim line-clamp-1",children:a.user_id}),headClassName:"w-32",hideOnMobile:!0},{id:"intent",header:e("audit.col.intent"),cell:a=>t.jsx("span",{className:"text-text-dim line-clamp-1",children:a.intent||"—"}),asCardTitle:!0},{id:"duration",header:e("audit.col.duration"),cell:a=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:[Math.round(a.duration_ms),"ms"]}),headClassName:"w-20"},{id:"cost",header:e("audit.col.cost"),cell:a=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["$",a.cost.toFixed(4)]}),headClassName:"w-24",hideOnMobile:!0},{id:"outcome",header:e("audit.col.outcome"),cell:a=>t.jsx(F,{variant:a.success?"success":"danger",title:a.error??"",children:a.success?e("audit.outcome.ok"):e("audit.outcome.fail")}),headClassName:"w-20"}],[e]);return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsx("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("audit.title")}),t.jsxs(I,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>M(),disabled:y,"aria-label":e("actions.refresh",{ns:"common"}),children:[y?t.jsx(q,{className:"h-4 w-4 animate-spin"}):t.jsx(z,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]})}),p&&t.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm",children:[t.jsxs("span",{className:"text-text-dim",children:[e("audit.stats.total"),": ",t.jsx("span",{className:"tabular-nums font-medium text-text",children:p.total})]}),t.jsxs("span",{className:"text-text-dim",children:[e("audit.stats.totalCost"),": ",t.jsxs("span",{className:"tabular-nums font-medium text-text",children:["$",p.totalCost.toFixed(4)]})]})]}),t.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[t.jsx(m,{id:"agent",label:e("audit.filter.agent"),value:u,onChange:j}),t.jsx(m,{id:"platform",label:e("audit.filter.platform"),value:x,onChange:b}),t.jsx(m,{id:"user",label:e("audit.filter.user"),value:f,onChange:w}),t.jsx(m,{id:"intent",label:e("audit.filter.intent"),value:h,onChange:C})]}),t.jsx(_,{columns:T,rows:L,getRowId:a=>String(a.id),loading:S,emptyState:t.jsx(U,{icon:t.jsx(H,{}),title:e("audit.empty.title"),description:e("audit.empty.description")})})]})}function m({id:e,label:s,value:d,onChange:c}){return t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(P,{htmlFor:e,className:"text-xs text-text-dim",children:s}),t.jsx(k,{id:e,value:d,onChange:n=>c(n.target.value),className:B("h-9")})]})}function J(e){try{const s=new Date(e);return Number.isNaN(s.getTime())?e:s.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return e}}export{nt as default};
|
|
2
|
+
//# sourceMappingURL=audit-fOn2LH4D.js.map
|