agim-cli 1.2.39 → 1.2.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/onboarding.d.ts +11 -0
- package/dist/core/onboarding.d.ts.map +1 -1
- package/dist/core/onboarding.js.map +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +27 -10
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts.map +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +148 -48
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -1
- package/dist/plugins/messengers/dingtalk/types.d.ts +24 -0
- package/dist/plugins/messengers/dingtalk/types.d.ts.map +1 -1
- package/dist/web/public/assets/{a2a-C7lYvkA4.js → a2a-Dvz7ig4m.js} +2 -2
- package/dist/web/public/assets/{a2a-C7lYvkA4.js.map → a2a-Dvz7ig4m.js.map} +1 -1
- package/dist/web/public/assets/{activity-DFB1UVF1.js → activity-BJqk7b-v.js} +2 -2
- package/dist/web/public/assets/{activity-DFB1UVF1.js.map → activity-BJqk7b-v.js.map} +1 -1
- package/dist/web/public/assets/{admins-BgmlFiRu.js → admins-DeiNQcMh.js} +2 -2
- package/dist/web/public/assets/{admins-BgmlFiRu.js.map → admins-DeiNQcMh.js.map} +1 -1
- package/dist/web/public/assets/{agents-D9GBT8Zl.js → agents-DJGdXKLv.js} +2 -2
- package/dist/web/public/assets/{agents-D9GBT8Zl.js.map → agents-DJGdXKLv.js.map} +1 -1
- package/dist/web/public/assets/{approvals-Be45xKtz.js → approvals-BOJ9et5G.js} +2 -2
- package/dist/web/public/assets/{approvals-Be45xKtz.js.map → approvals-BOJ9et5G.js.map} +1 -1
- package/dist/web/public/assets/{audit-BNx_EkjC.js → audit-Dnnevx6v.js} +2 -2
- package/dist/web/public/assets/{audit-BNx_EkjC.js.map → audit-Dnnevx6v.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-uQw6SA4h.js → bgjobs-BZAxNFpA.js} +2 -2
- package/dist/web/public/assets/{bgjobs-uQw6SA4h.js.map → bgjobs-BZAxNFpA.js.map} +1 -1
- package/dist/web/public/assets/{brain-CY9GRk9W.js → brain-fC59o4ZL.js} +2 -2
- package/dist/web/public/assets/{brain-CY9GRk9W.js.map → brain-fC59o4ZL.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-6msjfYUU.js → briefcase-DJRv77W6.js} +2 -2
- package/dist/web/public/assets/{briefcase-6msjfYUU.js.map → briefcase-DJRv77W6.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-DECkw7Jd.js → chevron-right-DzyVDoQs.js} +2 -2
- package/dist/web/public/assets/{chevron-right-DECkw7Jd.js.map → chevron-right-DzyVDoQs.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-BL5BCLn_.js → circle-check-B7B_CkmJ.js} +2 -2
- package/dist/web/public/assets/{circle-check-BL5BCLn_.js.map → circle-check-B7B_CkmJ.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-DtKj0bvZ.js → circle-check-big-dmFsJv6U.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-DtKj0bvZ.js.map → circle-check-big-dmFsJv6U.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-Dv0fneWH.js → circle-x-epC-av6L.js} +2 -2
- package/dist/web/public/assets/{circle-x-Dv0fneWH.js.map → circle-x-epC-av6L.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-QaqXnzLc.js → confirm-dialog-BEzhDlk7.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-QaqXnzLc.js.map → confirm-dialog-BEzhDlk7.js.map} +1 -1
- package/dist/web/public/assets/{data-table-BRHemHNS.js → data-table-B_BxQrSj.js} +2 -2
- package/dist/web/public/assets/{data-table-BRHemHNS.js.map → data-table-B_BxQrSj.js.map} +1 -1
- package/dist/web/public/assets/{dialog-DzCAOdn8.js → dialog-BAZNQtMt.js} +2 -2
- package/dist/web/public/assets/{dialog-DzCAOdn8.js.map → dialog-BAZNQtMt.js.map} +1 -1
- package/dist/web/public/assets/{download-DGggXcuj.js → download-C08F-eA4.js} +2 -2
- package/dist/web/public/assets/{download-DGggXcuj.js.map → download-C08F-eA4.js.map} +1 -1
- package/dist/web/public/assets/{email-DZXu4PeQ.js → email-qzOnhITw.js} +2 -2
- package/dist/web/public/assets/{email-DZXu4PeQ.js.map → email-qzOnhITw.js.map} +1 -1
- package/dist/web/public/assets/{empty-state--qSLu4iL.js → empty-state-BKs1qKHx.js} +2 -2
- package/dist/web/public/assets/{empty-state--qSLu4iL.js.map → empty-state-BKs1qKHx.js.map} +1 -1
- package/dist/web/public/assets/{external-link-SkbgGADx.js → external-link-HML--jya.js} +2 -2
- package/dist/web/public/assets/{external-link-SkbgGADx.js.map → external-link-HML--jya.js.map} +1 -1
- package/dist/web/public/assets/{eye-Du4m0dYr.js → eye-C20O3zvh.js} +2 -2
- package/dist/web/public/assets/{eye-Du4m0dYr.js.map → eye-C20O3zvh.js.map} +1 -1
- package/dist/web/public/assets/{facts-cmX647ty.js → facts-B7VlqoVs.js} +2 -2
- package/dist/web/public/assets/{facts-cmX647ty.js.map → facts-B7VlqoVs.js.map} +1 -1
- package/dist/web/public/assets/{health-Co_2jH5V.js → health-IF_VcgWW.js} +2 -2
- package/dist/web/public/assets/{health-Co_2jH5V.js.map → health-IF_VcgWW.js.map} +1 -1
- package/dist/web/public/assets/{hot-BAX3WV0p.js → hot-D-aKQ8y2.js} +2 -2
- package/dist/web/public/assets/{hot-BAX3WV0p.js.map → hot-D-aKQ8y2.js.map} +1 -1
- package/dist/web/public/assets/{index-BAK3HT1o.js → index-B48azMO-.js} +4 -4
- package/dist/web/public/assets/{index-BAK3HT1o.js.map → index-B48azMO-.js.map} +1 -1
- package/dist/web/public/assets/index-Cvacw7Jg.css +1 -0
- package/dist/web/public/assets/{installed-vEt64SE3.js → installed-CkiQRc89.js} +2 -2
- package/dist/web/public/assets/{installed-vEt64SE3.js.map → installed-CkiQRc89.js.map} +1 -1
- package/dist/web/public/assets/{jobs-CmSWAbse.js → jobs-g1Wl8_zd.js} +2 -2
- package/dist/web/public/assets/{jobs-CmSWAbse.js.map → jobs-g1Wl8_zd.js.map} +1 -1
- package/dist/web/public/assets/{layout-DF92UGuZ.js → layout-CS9s-Q0a.js} +2 -2
- package/dist/web/public/assets/{layout-DF92UGuZ.js.map → layout-CS9s-Q0a.js.map} +1 -1
- package/dist/web/public/assets/{layout-BgbibVU6.js → layout-ChcpcCB8.js} +2 -2
- package/dist/web/public/assets/{layout-BgbibVU6.js.map → layout-ChcpcCB8.js.map} +1 -1
- package/dist/web/public/assets/{layout-Cbf_CCBN.js → layout-CjLzz--E.js} +2 -2
- package/dist/web/public/assets/{layout-Cbf_CCBN.js.map → layout-CjLzz--E.js.map} +1 -1
- package/dist/web/public/assets/{layout-Bl6t0Q6D.js → layout-D_CUXsIR.js} +2 -2
- package/dist/web/public/assets/{layout-Bl6t0Q6D.js.map → layout-D_CUXsIR.js.map} +1 -1
- package/dist/web/public/assets/{layout-DKUTeV-p.js → layout-fTZD9lJN.js} +2 -2
- package/dist/web/public/assets/{layout-DKUTeV-p.js.map → layout-fTZD9lJN.js.map} +1 -1
- package/dist/web/public/assets/{loader-circle-CXl24wsB.js → loader-circle-DBf4xFjo.js} +2 -2
- package/dist/web/public/assets/{loader-circle-CXl24wsB.js.map → loader-circle-DBf4xFjo.js.map} +1 -1
- package/dist/web/public/assets/{map-pin-CVRwkuru.js → map-pin-BYR0Sf5r.js} +2 -2
- package/dist/web/public/assets/{map-pin-CVRwkuru.js.map → map-pin-BYR0Sf5r.js.map} +1 -1
- package/dist/web/public/assets/{memos-k6FW9dd4.js → memos-ChfapnyG.js} +2 -2
- package/dist/web/public/assets/{memos-k6FW9dd4.js.map → memos-ChfapnyG.js.map} +1 -1
- package/dist/web/public/assets/messengers-zBIYakPW.js +7 -0
- package/dist/web/public/assets/messengers-zBIYakPW.js.map +1 -0
- package/dist/web/public/assets/{network-BLcJyt3y.js → network-CEqTiog6.js} +2 -2
- package/dist/web/public/assets/{network-BLcJyt3y.js.map → network-CEqTiog6.js.map} +1 -1
- package/dist/web/public/assets/{outbox-X2aiMbdq.js → outbox-D4IQcACJ.js} +2 -2
- package/dist/web/public/assets/{outbox-X2aiMbdq.js.map → outbox-D4IQcACJ.js.map} +1 -1
- package/dist/web/public/assets/{pagination-BD7XfwcX.js → pagination-R9mql8VB.js} +2 -2
- package/dist/web/public/assets/{pagination-BD7XfwcX.js.map → pagination-R9mql8VB.js.map} +1 -1
- package/dist/web/public/assets/{persona-CiMN6Pne.js → persona-Cj_C5frK.js} +2 -2
- package/dist/web/public/assets/{persona-CiMN6Pne.js.map → persona-Cj_C5frK.js.map} +1 -1
- package/dist/web/public/assets/{play-DTK7F9m6.js → play-CTWqoMcj.js} +2 -2
- package/dist/web/public/assets/{play-DTK7F9m6.js.map → play-CTWqoMcj.js.map} +1 -1
- package/dist/web/public/assets/{policy-awgRqM5Z.js → policy-BKEZ2ziu.js} +2 -2
- package/dist/web/public/assets/{policy-awgRqM5Z.js.map → policy-BKEZ2ziu.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-ChTs-DiT.js → refresh-ccw-Clj5sQNF.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-ChTs-DiT.js.map → refresh-ccw-Clj5sQNF.js.map} +1 -1
- package/dist/web/public/assets/{reminders-DZDyIu_n.js → reminders-C5bVkLgj.js} +2 -2
- package/dist/web/public/assets/{reminders-DZDyIu_n.js.map → reminders-C5bVkLgj.js.map} +1 -1
- package/dist/web/public/assets/{save-Bd0yyWyF.js → save-CAFra1jb.js} +2 -2
- package/dist/web/public/assets/{save-Bd0yyWyF.js.map → save-CAFra1jb.js.map} +1 -1
- package/dist/web/public/assets/{schedules-Bbq9N-Sz.js → schedules-KQCD7978.js} +2 -2
- package/dist/web/public/assets/{schedules-Bbq9N-Sz.js.map → schedules-KQCD7978.js.map} +1 -1
- package/dist/web/public/assets/{search-CUZFSMD0.js → search-bDqizeZv.js} +2 -2
- package/dist/web/public/assets/{search-CUZFSMD0.js.map → search-bDqizeZv.js.map} +1 -1
- package/dist/web/public/assets/{service-CPV-yW7V.js → service-DTeMmX2u.js} +2 -2
- package/dist/web/public/assets/{service-CPV-yW7V.js.map → service-DTeMmX2u.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-DHLuTCYi.js → status-badge-_3Ve0Jef.js} +2 -2
- package/dist/web/public/assets/{status-badge-DHLuTCYi.js.map → status-badge-_3Ve0Jef.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-dR1OyViz.js → subtasks-DROeZcfT.js} +2 -2
- package/dist/web/public/assets/{subtasks-dR1OyViz.js.map → subtasks-DROeZcfT.js.map} +1 -1
- package/dist/web/public/assets/{table-CTNMqGvo.js → table-CZwKizat.js} +2 -2
- package/dist/web/public/assets/{table-CTNMqGvo.js.map → table-CZwKizat.js.map} +1 -1
- package/dist/web/public/assets/{topn-Dk9JxsaD.js → topn-DpErN6N8.js} +2 -2
- package/dist/web/public/assets/{topn-Dk9JxsaD.js.map → topn-DpErN6N8.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-CSId-EFx.js → trash-2-BkZrVFdH.js} +2 -2
- package/dist/web/public/assets/{trash-2-CSId-EFx.js.map → trash-2-BkZrVFdH.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-B5fLcSLE.js → use-memory-CElm89Hg.js} +2 -2
- package/dist/web/public/assets/{use-memory-B5fLcSLE.js.map → use-memory-CElm89Hg.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-CUbSm1kG.js → use-observability-D8qHfj0S.js} +2 -2
- package/dist/web/public/assets/{use-observability-CUbSm1kG.js.map → use-observability-D8qHfj0S.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-CtTPlLXz.js → use-settings-DgU8YmGj.js} +2 -2
- package/dist/web/public/assets/{use-settings-CtTPlLXz.js.map → use-settings-DgU8YmGj.js.map} +1 -1
- package/dist/web/public/assets/{use-skills-DdmwXWK7.js → use-skills-Cp_ok0Uq.js} +2 -2
- package/dist/web/public/assets/{use-skills-DdmwXWK7.js.map → use-skills-Cp_ok0Uq.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-C_zPgOcX.js → use-workspace-Dc6rNi5d.js} +2 -2
- package/dist/web/public/assets/{use-workspace-C_zPgOcX.js.map → use-workspace-Dc6rNi5d.js.map} +1 -1
- package/dist/web/public/assets/{useQuery-CBD2h35Q.js → useQuery-BjFqOBV3.js} +2 -2
- package/dist/web/public/assets/{useQuery-CBD2h35Q.js.map → useQuery-BjFqOBV3.js.map} +1 -1
- package/dist/web/public/assets/{vector-vwq7t-U5.js → vector-Bb3l7TOa.js} +2 -2
- package/dist/web/public/assets/{vector-vwq7t-U5.js.map → vector-Bb3l7TOa.js.map} +1 -1
- package/dist/web/public/assets/{viewer-SR8OwQK3.js → viewer-BeyW50lw.js} +2 -2
- package/dist/web/public/assets/{viewer-SR8OwQK3.js.map → viewer-BeyW50lw.js.map} +1 -1
- package/dist/web/public/assets/{workspace-VRwymXux.js → workspace-Du8va-tD.js} +2 -2
- package/dist/web/public/assets/{workspace-VRwymXux.js.map → workspace-Du8va-tD.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-5N_hYIVk.js → workspaces-BjgDtEnF.js} +2 -2
- package/dist/web/public/assets/{workspaces-5N_hYIVk.js.map → workspaces-BjgDtEnF.js.map} +1 -1
- package/dist/web/public/assets/{x-De56D6Eb.js → x-CHe1y-sG.js} +2 -2
- package/dist/web/public/assets/{x-De56D6Eb.js.map → x-CHe1y-sG.js.map} +1 -1
- package/dist/web/public/index.html +2 -2
- package/dist/web/server.js +27 -0
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/assets/index-CDYTPZH0.css +0 -1
- package/dist/web/public/assets/messengers-iXrlzy93.js +0 -7
- package/dist/web/public/assets/messengers-iXrlzy93.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-CPV-yW7V.js","sources":["../../node_modules/lucide-react/dist/esm/icons/square.js","../../src/routes/settings/service.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 Square = createLucideIcon(\"Square\", [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }]\n]);\n\nexport { Square as default };\n//# sourceMappingURL=square.js.map\n","/**\n * /settings/service — operator-facing process control: see the\n * running agim daemon's mode/pid/uptime + start, stop, or restart it.\n *\n * R8 (this round) added a dedicated \"Ports\" card at the top covering\n * webPort + acpPort. They live in `~/.agim/config.json` (PUT /api/config),\n * and take effect on the next service restart — handled by the\n * Start/Restart buttons immediately below.\n *\n * Stop and restart go through ConfirmDialog because they\n * permanently interrupt every messenger adapter + in-flight job;\n * Start is one-click since it's safe to invoke even when already\n * running (backend short-circuits to alreadyRunning:true).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Loader2, Network, Play, RefreshCcw, RotateCcw, Save, Square, X,\n} from 'lucide-react'\n\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useConfig,\n useRestartService,\n useServiceStatus,\n useStartService,\n useStopService,\n useUpdateConfig,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { ServiceMode } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nconst MODE_VARIANT: Record<ServiceMode, 'success' | 'info' | 'warning' | 'default'> = {\n systemd: 'success',\n background: 'info',\n foreground: 'warning',\n none: 'default',\n}\n\nconst DEFAULT_WEB_PORT = 3000\nconst DEFAULT_ACP_PORT = 9090\n\nexport default function SettingsServiceRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const status = useServiceStatus()\n const data = status.data\n const isRunning = data && data.mode !== 'none'\n\n const start = useStartService()\n const stop = useStopService()\n const restart = useRestartService()\n\n const [confirmStop, setConfirmStop] = useState(false)\n const [confirmRestart, setConfirmRestart] = useState(false)\n\n async function onStart(): Promise<void> {\n try {\n await start.mutateAsync()\n toast.success(t('service.toast.started'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n async function onConfirmStop(): Promise<void> {\n try {\n await stop.mutateAsync()\n toast.success(t('service.toast.stopped'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n throw err\n }\n }\n async function onConfirmRestart(): Promise<void> {\n try {\n await restart.mutateAsync()\n toast.success(t('service.toast.restarted'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n throw err\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-3xl 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('service.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => status.refetch()}\n disabled={status.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {status.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('service.subtitle')}</p>\n </header>\n\n <PortsCard />\n\n {status.isLoading ? (\n <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n ) : data ? (\n <div className=\"rounded-md border border-border bg-surface p-4\">\n <dl className=\"grid grid-cols-[max-content_1fr] gap-x-4 gap-y-2 text-sm\">\n <dt className=\"text-text-dim\">{t('service.modeLabel')}</dt>\n <dd>\n <Badge variant={MODE_VARIANT[data.mode]}>\n {t(`service.mode.${data.mode}`)}\n </Badge>\n </dd>\n {data.pid != null && (\n <>\n <dt className=\"text-text-dim\">{t('service.pidLabel')}</dt>\n <dd className=\"tabular-nums font-mono\">{data.pid}</dd>\n </>\n )}\n {data.uptime && (\n <>\n <dt className=\"text-text-dim\">{t('service.uptimeLabel')}</dt>\n <dd className=\"tabular-nums\">{data.uptime}</dd>\n </>\n )}\n {data.web && (\n <>\n <dt className=\"text-text-dim\">{t('service.webLabel')}</dt>\n <dd className=\"font-mono text-xs\">{data.web.bind}:{data.web.port}</dd>\n </>\n )}\n <dt className=\"text-text-dim\">{t('service.bootPhaseLabel')}</dt>\n <dd>\n <code className=\"rounded bg-surface-2 px-1.5 py-0.5 text-xs\">{data.bootPhase}</code>\n </dd>\n </dl>\n\n {/* Action buttons */}\n <div className=\"mt-4 flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={isRunning || start.isPending}\n onClick={() => void onStart()}\n >\n {start.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Play className=\"h-4 w-4\" />}\n {t('service.actions.start')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={!isRunning || restart.isPending}\n onClick={() => setConfirmRestart(true)}\n >\n <RotateCcw className={cn('h-4 w-4', restart.isPending && 'animate-spin')} />\n {t('service.actions.restart')}\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n disabled={!isRunning || stop.isPending}\n onClick={() => setConfirmStop(true)}\n >\n <Square className=\"h-4 w-4\" />\n {t('service.actions.stop')}\n </Button>\n </div>\n </div>\n ) : null}\n\n <ConfirmDialog\n open={confirmStop}\n onOpenChange={setConfirmStop}\n title={t('service.actions.confirmStop')}\n description={t('service.actions.confirmStopDesc')}\n intent=\"danger\"\n confirmLabel={t('service.actions.stop')}\n onConfirm={onConfirmStop}\n />\n <ConfirmDialog\n open={confirmRestart}\n onOpenChange={setConfirmRestart}\n title={t('service.actions.confirmRestart')}\n description={t('service.actions.confirmRestartDesc')}\n intent=\"danger\"\n confirmLabel={t('service.actions.restart')}\n onConfirm={onConfirmRestart}\n />\n </div>\n )\n}\n\n/* ─────────────── Ports card (webPort + acpPort) ─────────────── */\n\n/** Validate a port string. Empty = \"use the default\", which we\n * represent on the wire as `undefined` (omitted field). Non-empty\n * must parse to 1..65535. */\nfunction parsePort(s: string): { ok: true; value: number | undefined } | { ok: false } {\n const trimmed = s.trim()\n if (!trimmed) return { ok: true, value: undefined }\n const n = Number.parseInt(trimmed, 10)\n if (!Number.isFinite(n) || n < 1 || n > 65535) return { ok: false }\n return { ok: true, value: n }\n}\n\nfunction PortsCard(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const updateCfg = useUpdateConfig()\n\n const cfg = cfgQuery.data\n const currentWeb = cfg?.webPort\n const currentAcp = cfg?.acpPort\n\n const [webDraft, setWebDraft] = useState<string>('')\n const [acpDraft, setAcpDraft] = useState<string>('')\n // Tracks the cfg snapshot we last synced from, so post-save refetch\n // re-hydrates the drafts cleanly (and so local edits don't get\n // clobbered by background refetches).\n const [syncedAt, setSyncedAt] = useState<number>(0)\n\n useEffect(() => {\n if (!cfg) return\n if (cfgQuery.dataUpdatedAt === syncedAt) return\n setWebDraft(currentWeb != null ? String(currentWeb) : '')\n setAcpDraft(currentAcp != null ? String(currentAcp) : '')\n setSyncedAt(cfgQuery.dataUpdatedAt)\n }, [cfg, cfgQuery.dataUpdatedAt, currentWeb, currentAcp, syncedAt])\n\n const webParsed = parsePort(webDraft)\n const acpParsed = parsePort(acpDraft)\n const webInvalid = !webParsed.ok\n const acpInvalid = !acpParsed.ok\n\n const isDirty = useMemo(() => {\n if (!cfg) return false\n const nextWeb = webParsed.ok ? webParsed.value : undefined\n const nextAcp = acpParsed.ok ? acpParsed.value : undefined\n return nextWeb !== currentWeb || nextAcp !== currentAcp\n }, [cfg, webParsed, acpParsed, currentWeb, currentAcp])\n\n function onDiscard(): void {\n setWebDraft(currentWeb != null ? String(currentWeb) : '')\n setAcpDraft(currentAcp != null ? String(currentAcp) : '')\n }\n\n async function onSave(): Promise<void> {\n if (!cfg || webInvalid || acpInvalid) return\n try {\n await updateCfg.mutateAsync({\n ...cfg,\n webPort: webParsed.ok ? webParsed.value : undefined,\n acpPort: acpParsed.ok ? acpParsed.value : undefined,\n })\n toast.success(t('service.ports.toast.saved'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n if (cfgQuery.isLoading) {\n return <div className=\"h-32 rounded-md bg-surface-2 animate-pulse\" />\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('service.ports.title')}</h2>\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('service.ports.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-3 px-4 py-3 sm:grid-cols-2\">\n <PortField\n id=\"web-port\"\n label={t('service.ports.webPort')}\n hint={t('service.ports.webPortHint', { default: DEFAULT_WEB_PORT })}\n value={webDraft}\n onChange={setWebDraft}\n invalid={webInvalid}\n placeholder={String(DEFAULT_WEB_PORT)}\n />\n {/* R15 — acpPort hidden when remote-agent feature is off (same\n gate as the ACP card in /settings/agents). Server already\n strips acpPort from GET /api/config and drops it from\n incoming PUT in the off state. */}\n {cfg?.features?.remoteAgent ? (\n <PortField\n id=\"acp-port\"\n label={t('service.ports.acpPort')}\n hint={t('service.ports.acpPortHint', { default: DEFAULT_ACP_PORT })}\n value={acpDraft}\n onChange={setAcpDraft}\n invalid={acpInvalid}\n placeholder={String(DEFAULT_ACP_PORT)}\n />\n ) : null}\n </div>\n\n {isDirty && (\n <div className=\"flex items-center gap-2 border-t border-border px-4 py-3\">\n <Badge variant=\"warning\">{t('service.ports.restartRequired')}</Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={onDiscard}\n disabled={updateCfg.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('service.ports.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateCfg.isPending || webInvalid || acpInvalid}\n >\n {updateCfg.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateCfg.isPending ? t('service.ports.saving') : t('service.ports.save')}\n </Button>\n </div>\n )}\n </section>\n )\n}\n\ninterface PortFieldProps {\n id: string\n label: string\n hint: string\n value: string\n onChange: (v: string) => void\n invalid: boolean\n placeholder: string\n}\n\nfunction PortField({\n id, label, hint, value, onChange, invalid, placeholder,\n}: PortFieldProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor={id} className=\"text-xs font-medium\">{label}</Label>\n <Input\n id={id}\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={65535}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n aria-invalid={invalid}\n className={cn('font-mono', invalid && 'border-danger focus:ring-danger')}\n />\n <p className={cn('text-[11px]', invalid ? 'text-danger' : 'text-text-dim')}>\n {invalid ? t('service.ports.invalidPort') : hint}\n </p>\n </div>\n )\n}\n"],"names":["Square","createLucideIcon","MODE_VARIANT","DEFAULT_WEB_PORT","DEFAULT_ACP_PORT","SettingsServiceRoute","t","useTranslation","status","useServiceStatus","data","isRunning","start","useStartService","stop","useStopService","restart","useRestartService","confirmStop","setConfirmStop","useState","confirmRestart","setConfirmRestart","onStart","toast","err","describeError","onConfirmStop","onConfirmRestart","jsxs","jsx","Button","Loader2","RefreshCcw","PortsCard","Badge","Fragment","Play","RotateCcw","cn","ConfirmDialog","parsePort","trimmed","n","cfgQuery","useConfig","updateCfg","useUpdateConfig","cfg","currentWeb","currentAcp","webDraft","setWebDraft","acpDraft","setAcpDraft","syncedAt","setSyncedAt","useEffect","webParsed","acpParsed","webInvalid","acpInvalid","isDirty","useMemo","nextWeb","nextAcp","onDiscard","onSave","Network","PortField","X","Save","id","label","hint","value","onChange","invalid","placeholder","Label","Input","e"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"service-DTeMmX2u.js","sources":["../../node_modules/lucide-react/dist/esm/icons/square.js","../../src/routes/settings/service.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 Square = createLucideIcon(\"Square\", [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }]\n]);\n\nexport { Square as default };\n//# sourceMappingURL=square.js.map\n","/**\n * /settings/service — operator-facing process control: see the\n * running agim daemon's mode/pid/uptime + start, stop, or restart it.\n *\n * R8 (this round) added a dedicated \"Ports\" card at the top covering\n * webPort + acpPort. They live in `~/.agim/config.json` (PUT /api/config),\n * and take effect on the next service restart — handled by the\n * Start/Restart buttons immediately below.\n *\n * Stop and restart go through ConfirmDialog because they\n * permanently interrupt every messenger adapter + in-flight job;\n * Start is one-click since it's safe to invoke even when already\n * running (backend short-circuits to alreadyRunning:true).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n Loader2, Network, Play, RefreshCcw, RotateCcw, Save, Square, X,\n} from 'lucide-react'\n\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useConfig,\n useRestartService,\n useServiceStatus,\n useStartService,\n useStopService,\n useUpdateConfig,\n} from '@/hooks/use-settings'\nimport { describeError } from '@/lib/api/errors'\nimport type { ServiceMode } from '@/types/api'\nimport { cn } from '@/lib/utils'\n\nconst MODE_VARIANT: Record<ServiceMode, 'success' | 'info' | 'warning' | 'default'> = {\n systemd: 'success',\n background: 'info',\n foreground: 'warning',\n none: 'default',\n}\n\nconst DEFAULT_WEB_PORT = 3000\nconst DEFAULT_ACP_PORT = 9090\n\nexport default function SettingsServiceRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const status = useServiceStatus()\n const data = status.data\n const isRunning = data && data.mode !== 'none'\n\n const start = useStartService()\n const stop = useStopService()\n const restart = useRestartService()\n\n const [confirmStop, setConfirmStop] = useState(false)\n const [confirmRestart, setConfirmRestart] = useState(false)\n\n async function onStart(): Promise<void> {\n try {\n await start.mutateAsync()\n toast.success(t('service.toast.started'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n async function onConfirmStop(): Promise<void> {\n try {\n await stop.mutateAsync()\n toast.success(t('service.toast.stopped'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n throw err\n }\n }\n async function onConfirmRestart(): Promise<void> {\n try {\n await restart.mutateAsync()\n toast.success(t('service.toast.restarted'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n throw err\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-3xl 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('service.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => status.refetch()}\n disabled={status.isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {status.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('service.subtitle')}</p>\n </header>\n\n <PortsCard />\n\n {status.isLoading ? (\n <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n ) : data ? (\n <div className=\"rounded-md border border-border bg-surface p-4\">\n <dl className=\"grid grid-cols-[max-content_1fr] gap-x-4 gap-y-2 text-sm\">\n <dt className=\"text-text-dim\">{t('service.modeLabel')}</dt>\n <dd>\n <Badge variant={MODE_VARIANT[data.mode]}>\n {t(`service.mode.${data.mode}`)}\n </Badge>\n </dd>\n {data.pid != null && (\n <>\n <dt className=\"text-text-dim\">{t('service.pidLabel')}</dt>\n <dd className=\"tabular-nums font-mono\">{data.pid}</dd>\n </>\n )}\n {data.uptime && (\n <>\n <dt className=\"text-text-dim\">{t('service.uptimeLabel')}</dt>\n <dd className=\"tabular-nums\">{data.uptime}</dd>\n </>\n )}\n {data.web && (\n <>\n <dt className=\"text-text-dim\">{t('service.webLabel')}</dt>\n <dd className=\"font-mono text-xs\">{data.web.bind}:{data.web.port}</dd>\n </>\n )}\n <dt className=\"text-text-dim\">{t('service.bootPhaseLabel')}</dt>\n <dd>\n <code className=\"rounded bg-surface-2 px-1.5 py-0.5 text-xs\">{data.bootPhase}</code>\n </dd>\n </dl>\n\n {/* Action buttons */}\n <div className=\"mt-4 flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n disabled={isRunning || start.isPending}\n onClick={() => void onStart()}\n >\n {start.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Play className=\"h-4 w-4\" />}\n {t('service.actions.start')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={!isRunning || restart.isPending}\n onClick={() => setConfirmRestart(true)}\n >\n <RotateCcw className={cn('h-4 w-4', restart.isPending && 'animate-spin')} />\n {t('service.actions.restart')}\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n disabled={!isRunning || stop.isPending}\n onClick={() => setConfirmStop(true)}\n >\n <Square className=\"h-4 w-4\" />\n {t('service.actions.stop')}\n </Button>\n </div>\n </div>\n ) : null}\n\n <ConfirmDialog\n open={confirmStop}\n onOpenChange={setConfirmStop}\n title={t('service.actions.confirmStop')}\n description={t('service.actions.confirmStopDesc')}\n intent=\"danger\"\n confirmLabel={t('service.actions.stop')}\n onConfirm={onConfirmStop}\n />\n <ConfirmDialog\n open={confirmRestart}\n onOpenChange={setConfirmRestart}\n title={t('service.actions.confirmRestart')}\n description={t('service.actions.confirmRestartDesc')}\n intent=\"danger\"\n confirmLabel={t('service.actions.restart')}\n onConfirm={onConfirmRestart}\n />\n </div>\n )\n}\n\n/* ─────────────── Ports card (webPort + acpPort) ─────────────── */\n\n/** Validate a port string. Empty = \"use the default\", which we\n * represent on the wire as `undefined` (omitted field). Non-empty\n * must parse to 1..65535. */\nfunction parsePort(s: string): { ok: true; value: number | undefined } | { ok: false } {\n const trimmed = s.trim()\n if (!trimmed) return { ok: true, value: undefined }\n const n = Number.parseInt(trimmed, 10)\n if (!Number.isFinite(n) || n < 1 || n > 65535) return { ok: false }\n return { ok: true, value: n }\n}\n\nfunction PortsCard(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const cfgQuery = useConfig()\n const updateCfg = useUpdateConfig()\n\n const cfg = cfgQuery.data\n const currentWeb = cfg?.webPort\n const currentAcp = cfg?.acpPort\n\n const [webDraft, setWebDraft] = useState<string>('')\n const [acpDraft, setAcpDraft] = useState<string>('')\n // Tracks the cfg snapshot we last synced from, so post-save refetch\n // re-hydrates the drafts cleanly (and so local edits don't get\n // clobbered by background refetches).\n const [syncedAt, setSyncedAt] = useState<number>(0)\n\n useEffect(() => {\n if (!cfg) return\n if (cfgQuery.dataUpdatedAt === syncedAt) return\n setWebDraft(currentWeb != null ? String(currentWeb) : '')\n setAcpDraft(currentAcp != null ? String(currentAcp) : '')\n setSyncedAt(cfgQuery.dataUpdatedAt)\n }, [cfg, cfgQuery.dataUpdatedAt, currentWeb, currentAcp, syncedAt])\n\n const webParsed = parsePort(webDraft)\n const acpParsed = parsePort(acpDraft)\n const webInvalid = !webParsed.ok\n const acpInvalid = !acpParsed.ok\n\n const isDirty = useMemo(() => {\n if (!cfg) return false\n const nextWeb = webParsed.ok ? webParsed.value : undefined\n const nextAcp = acpParsed.ok ? acpParsed.value : undefined\n return nextWeb !== currentWeb || nextAcp !== currentAcp\n }, [cfg, webParsed, acpParsed, currentWeb, currentAcp])\n\n function onDiscard(): void {\n setWebDraft(currentWeb != null ? String(currentWeb) : '')\n setAcpDraft(currentAcp != null ? String(currentAcp) : '')\n }\n\n async function onSave(): Promise<void> {\n if (!cfg || webInvalid || acpInvalid) return\n try {\n await updateCfg.mutateAsync({\n ...cfg,\n webPort: webParsed.ok ? webParsed.value : undefined,\n acpPort: acpParsed.ok ? acpParsed.value : undefined,\n })\n toast.success(t('service.ports.toast.saved'))\n } catch (err) {\n toast.error(describeError(err, t).message)\n }\n }\n\n if (cfgQuery.isLoading) {\n return <div className=\"h-32 rounded-md bg-surface-2 animate-pulse\" />\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('service.ports.title')}</h2>\n </header>\n <p className=\"px-4 pt-2 text-xs text-text-dim\">{t('service.ports.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-3 px-4 py-3 sm:grid-cols-2\">\n <PortField\n id=\"web-port\"\n label={t('service.ports.webPort')}\n hint={t('service.ports.webPortHint', { default: DEFAULT_WEB_PORT })}\n value={webDraft}\n onChange={setWebDraft}\n invalid={webInvalid}\n placeholder={String(DEFAULT_WEB_PORT)}\n />\n {/* R15 — acpPort hidden when remote-agent feature is off (same\n gate as the ACP card in /settings/agents). Server already\n strips acpPort from GET /api/config and drops it from\n incoming PUT in the off state. */}\n {cfg?.features?.remoteAgent ? (\n <PortField\n id=\"acp-port\"\n label={t('service.ports.acpPort')}\n hint={t('service.ports.acpPortHint', { default: DEFAULT_ACP_PORT })}\n value={acpDraft}\n onChange={setAcpDraft}\n invalid={acpInvalid}\n placeholder={String(DEFAULT_ACP_PORT)}\n />\n ) : null}\n </div>\n\n {isDirty && (\n <div className=\"flex items-center gap-2 border-t border-border px-4 py-3\">\n <Badge variant=\"warning\">{t('service.ports.restartRequired')}</Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={onDiscard}\n disabled={updateCfg.isPending}\n >\n <X className=\"h-4 w-4\" />\n {t('service.ports.discard')}\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={updateCfg.isPending || webInvalid || acpInvalid}\n >\n {updateCfg.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <Save className=\"h-4 w-4\" />}\n {updateCfg.isPending ? t('service.ports.saving') : t('service.ports.save')}\n </Button>\n </div>\n )}\n </section>\n )\n}\n\ninterface PortFieldProps {\n id: string\n label: string\n hint: string\n value: string\n onChange: (v: string) => void\n invalid: boolean\n placeholder: string\n}\n\nfunction PortField({\n id, label, hint, value, onChange, invalid, placeholder,\n}: PortFieldProps): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor={id} className=\"text-xs font-medium\">{label}</Label>\n <Input\n id={id}\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={65535}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n aria-invalid={invalid}\n className={cn('font-mono', invalid && 'border-danger focus:ring-danger')}\n />\n <p className={cn('text-[11px]', invalid ? 'text-danger' : 'text-text-dim')}>\n {invalid ? t('service.ports.invalidPort') : hint}\n </p>\n </div>\n )\n}\n"],"names":["Square","createLucideIcon","MODE_VARIANT","DEFAULT_WEB_PORT","DEFAULT_ACP_PORT","SettingsServiceRoute","t","useTranslation","status","useServiceStatus","data","isRunning","start","useStartService","stop","useStopService","restart","useRestartService","confirmStop","setConfirmStop","useState","confirmRestart","setConfirmRestart","onStart","toast","err","describeError","onConfirmStop","onConfirmRestart","jsxs","jsx","Button","Loader2","RefreshCcw","PortsCard","Badge","Fragment","Play","RotateCcw","cn","ConfirmDialog","parsePort","trimmed","n","cfgQuery","useConfig","updateCfg","useUpdateConfig","cfg","currentWeb","currentAcp","webDraft","setWebDraft","acpDraft","setAcpDraft","syncedAt","setSyncedAt","useEffect","webParsed","acpParsed","webInvalid","acpInvalid","isDirty","useMemo","nextWeb","nextAcp","onDiscard","onSave","Network","PortField","X","Save","id","label","hint","value","onChange","invalid","placeholder","Label","Input","e"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Q as r,B as c}from"./index-
|
|
2
|
-
//# sourceMappingURL=status-badge-
|
|
1
|
+
import{Q as r,B as c}from"./index-B48azMO-.js";const i={succeeded:"success",completed:"success",done:"success",approved:"success",allowed:"success",delivered:"success",active:"success",running:"info",in_progress:"info",pending:"info",queued:"info",scheduled:"info",open:"info",paused:"warning",awaiting:"warning",timeout:"warning",expired:"warning",failed:"danger",error:"danger",denied:"danger",rejected:"danger",cancelled:"danger",canceled:"danger",finished:"default",closed:"default",archived:"default"};function o({status:e,variant:n,children:d,...s}){const a=n??i[e.toLowerCase()]??"default";return r.jsx(c,{variant:a,...s,children:d??e})}o.displayName="StatusBadge";export{o as S};
|
|
2
|
+
//# sourceMappingURL=status-badge-_3Ve0Jef.js.map
|
package/dist/web/public/assets/{status-badge-DHLuTCYi.js.map → status-badge-_3Ve0Jef.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-badge-
|
|
1
|
+
{"version":3,"file":"status-badge-_3Ve0Jef.js","sources":["../../src/components/common/status-badge.tsx"],"sourcesContent":["/**\n * StatusBadge — domain status string → Badge variant + label.\n *\n * Single source of truth for the color mapping across the 4 M2 pages\n * (jobs / approvals / reminders / memos) plus the M3 observability\n * page. Without this every page would invent its own (job status\n * \"running\" mapped to \"warning\" on tasks.html, \"info\" on approvals.\n * html, \"secondary\" on observability — the kind of drift the v2\n * rewrite is supposed to eliminate).\n *\n * The label slot is intentionally a child rather than a prop: callers\n * pass i18n'd strings via `<StatusBadge status=\"running\">{t('jobs.\n * status.running')}</StatusBadge>` so the badge stays language-aware\n * without needing useTranslation here.\n *\n * Unknown status falls back to `default` variant (neutral gray pill)\n * so a backend that introduces a new state doesn't crash the page.\n */\n\nimport * as React from 'react'\nimport { Badge, type BadgeProps } from '@/components/ui/badge'\n\n/**\n * Status palette shared across domain entities. The mapping is\n * deliberately broad — both \"succeeded\" and \"completed\" land on\n * success; both \"running\" and \"in_progress\" land on info, etc. —\n * because the backend hasn't been canonicalised yet (memory.ts uses\n * one set, jobs.ts another).\n */\nconst STATUS_VARIANT: Record<string, BadgeProps['variant']> = {\n // Success-family\n succeeded: 'success',\n completed: 'success',\n done: 'success',\n approved: 'success',\n allowed: 'success',\n delivered: 'success',\n active: 'success',\n\n // In-flight\n running: 'info',\n in_progress:'info',\n pending: 'info',\n queued: 'info',\n scheduled: 'info',\n open: 'info',\n\n // Warnings (operator may need to look)\n paused: 'warning',\n awaiting: 'warning',\n timeout: 'warning',\n expired: 'warning',\n\n // Failed / errored\n failed: 'danger',\n error: 'danger',\n denied: 'danger',\n rejected: 'danger',\n cancelled: 'danger',\n canceled: 'danger',\n\n // Terminal-neutral\n finished: 'default',\n closed: 'default',\n archived: 'default',\n}\n\nexport interface StatusBadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {\n status: string\n children?: React.ReactNode\n /** Force-override the auto-mapped variant. */\n variant?: BadgeProps['variant']\n}\n\nfunction StatusBadge({\n status,\n variant,\n children,\n ...rest\n}: StatusBadgeProps): JSX.Element {\n const resolved = variant ?? STATUS_VARIANT[status.toLowerCase()] ?? 'default'\n return (\n <Badge variant={resolved} {...rest}>\n {children ?? status}\n </Badge>\n )\n}\nStatusBadge.displayName = 'StatusBadge'\n\nexport { StatusBadge, STATUS_VARIANT }\n"],"names":["STATUS_VARIANT","StatusBadge","status","variant","children","rest","resolved","Badge"],"mappings":"+CA6BA,MAAMA,EAAwD,CAE5D,UAAY,UACZ,UAAY,UACZ,KAAY,UACZ,SAAY,UACZ,QAAY,UACZ,UAAY,UACZ,OAAY,UAGZ,QAAY,OACZ,YAAY,OACZ,QAAY,OACZ,OAAY,OACZ,UAAY,OACZ,KAAY,OAGZ,OAAY,UACZ,SAAY,UACZ,QAAY,UACZ,QAAY,UAGZ,OAAY,SACZ,MAAY,SACZ,OAAY,SACZ,SAAY,SACZ,UAAY,SACZ,SAAY,SAGZ,SAAY,UACZ,OAAY,UACZ,SAAY,SACd,EASA,SAASC,EAAY,CACnB,OAAAC,EACA,QAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EAAkC,CAChC,MAAMC,EAAWH,GAAWH,EAAeE,EAAO,YAAA,CAAa,GAAK,UACpE,aACGK,EAAA,CAAM,QAASD,EAAW,GAAGD,EAC3B,YAAYH,EACf,CAEJ,CACAD,EAAY,YAAc"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{x as g,aa as b,q as k,ac as N,ab as j,Q as s,r as y,c as w,L as S,I as v}from"./index-
|
|
1
|
+
import{x as g,aa as b,q as k,ac as N,ab as j,Q as s,r as y,c as w,L as S,I as v}from"./index-B48azMO-.js";import{e as C}from"./react-C9F3QeMB.js";import{D as L}from"./data-table-B_BxQrSj.js";import{E as T}from"./empty-state-BKs1qKHx.js";import{S as I}from"./status-badge-_3Ve0Jef.js";import{u as A}from"./useQuery-BjFqOBV3.js";import{u as D}from"./use-event-stream-BGeFcayX.js";import{L as M}from"./loader-circle-DBf4xFjo.js";import{R as E}from"./refresh-ccw-Clj5sQNF.js";import"./table-CZwKizat.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=g("ListTree",[["path",{d:"M21 12h-8",key:"1bmf0i"}],["path",{d:"M21 6H8",key:"1pqkrb"}],["path",{d:"M21 18h-8",key:"1tm79t"}],["path",{d:"M3 6v4c0 1.1.9 2 2 2h3",key:"1ywdgy"}],["path",{d:"M3 10v6c0 1.1.9 2 2 2h3",key:"2wc746"}]]),m={all:["subtasks"],list:e=>["subtasks","list",e]};function q(e){return A({queryKey:m.list(e),queryFn:()=>k.listSubtasks(e)})}function F(){const e=b();return()=>e.invalidateQueries({queryKey:m.all})}const Q={connected:"text-success",connecting:"text-text-dim",reconnecting:"text-warning",closed:"text-text-muted"};function J(){const{t:e}=N(["tasks","common"]),[a,n]=j(),r=F(),i=a.get("agent")??"",{data:d,isLoading:u,isFetching:c,refetch:x}=q(i?{agent:i}:{}),h=d?.subtasks??[],o=D({job:()=>r()});function p(t){const l=new URLSearchParams(a);t?l.set("agent",t):l.delete("agent"),n(l,{replace:!0})}const f=C.useMemo(()=>[{id:"id",header:e("subtasks.col.id"),cell:t=>s.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",t.id]}),headClassName:"w-16"},{id:"agent",header:e("subtasks.col.agent"),cell:t=>s.jsx("span",{className:"font-medium",children:t.agent}),headClassName:"w-32"},{id:"prompt",header:e("subtasks.col.prompt"),cell:t=>s.jsx("span",{className:"line-clamp-2 text-text-dim",children:t.prompt}),asCardTitle:!0},{id:"status",header:e("subtasks.col.status"),cell:t=>s.jsx(I,{status:t.status,children:e(`subtasks.status.${t.status}`,{defaultValue:t.status})}),headClassName:"w-32"},{id:"parent",header:e("subtasks.col.parent"),cell:t=>s.jsxs("span",{className:"text-text-dim",children:[s.jsx("span",{className:"font-medium text-text",children:t.parentAgent}),s.jsx("span",{className:"text-text-muted",children:" / "}),s.jsx("span",{title:t.parentSessionId,children:t.parentSessionId.slice(0,8)})]}),headClassName:"w-40"},{id:"platform",header:e("subtasks.col.platform"),cell:t=>s.jsx("span",{className:"text-text-dim",children:t.platform}),headClassName:"w-28",hideOnMobile:!0},{id:"createdAt",header:e("subtasks.col.createdAt"),cell:t=>s.jsx("span",{className:"text-text-dim",children:$(t.createdAt)}),headClassName:"w-40",hideOnMobile:!0}],[e]);return s.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[s.jsxs("header",{className:"flex flex-col gap-1",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.jsx("h1",{className:"text-xl font-semibold",children:e("subtasks.title")}),s.jsx("span",{className:y("text-xs font-medium tabular-nums",Q[o]),children:e(`jobs.live.${o}`)}),s.jsxs(w,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>x(),disabled:c,"aria-label":e("actions.refresh",{ns:"common"}),children:[c?s.jsx(M,{className:"h-4 w-4 animate-spin"}):s.jsx(E,{className:"h-4 w-4"}),s.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),s.jsx("p",{className:"text-sm text-text-dim",children:e("subtasks.subtitle")})]}),s.jsx("div",{className:"flex flex-wrap items-end gap-2",children:s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(S,{htmlFor:"agent-filter",className:"text-xs text-text-dim",children:e("subtasks.filter.agent")}),s.jsx(v,{id:"agent-filter",value:i,onChange:t=>p(t.target.value),placeholder:e("subtasks.filter.agentAny"),className:"w-48"})]})}),s.jsx(L,{columns:f,rows:h,getRowId:t=>`${t.parentSessionId}:${t.id}`,loading:u,emptyState:s.jsx(T,{icon:s.jsx(R,{}),title:e("subtasks.empty.title"),description:e("subtasks.empty.description")})})]})}function $(e){try{const a=new Date(e);if(Number.isNaN(a.getTime()))return e;const n=new Date;return a.toDateString()===n.toDateString()?a.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit"}):a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}export{J as default};
|
|
7
|
-
//# sourceMappingURL=subtasks-
|
|
7
|
+
//# sourceMappingURL=subtasks-DROeZcfT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtasks-dR1OyViz.js","sources":["../../node_modules/lucide-react/dist/esm/icons/list-tree.js","../../src/hooks/use-subtasks.ts","../../src/routes/tasks/subtasks.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 ListTree = createLucideIcon(\"ListTree\", [\n [\"path\", { d: \"M21 12h-8\", key: \"1bmf0i\" }],\n [\"path\", { d: \"M21 6H8\", key: \"1pqkrb\" }],\n [\"path\", { d: \"M21 18h-8\", key: \"1tm79t\" }],\n [\"path\", { d: \"M3 6v4c0 1.1.9 2 2 2h3\", key: \"1ywdgy\" }],\n [\"path\", { d: \"M3 10v6c0 1.1.9 2 2 2h3\", key: \"2wc746\" }]\n]);\n\nexport { ListTree as default };\n//# sourceMappingURL=list-tree.js.map\n","/**\n * useSubtasks — react-query wrapper for /api/subtasks.\n *\n * Subtasks are a flattened view of session.subtasks across every\n * conversation file in ~/.agim/sessions/. The endpoint is read-only\n * — no cancel / re-run mutation surface (yet). Live refresh rides on\n * the same SSE 'job' event (subtask state changes piggy-back on the\n * parent job's lifecycle).\n */\n\nimport { useQueryClient, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListSubtasksQuery, ListSubtasksResponse } from '@/types/api'\n\nexport const subtasksKeys = {\n all: ['subtasks'] as const,\n list: (q: ListSubtasksQuery) => ['subtasks', 'list', q] as const,\n}\n\nexport function useSubtasks(query: ListSubtasksQuery) {\n return useQuery<ListSubtasksResponse>({\n queryKey: subtasksKeys.list(query),\n queryFn: () => api.listSubtasks(query),\n })\n}\n\nexport function useInvalidateSubtasks() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: subtasksKeys.all })\n}\n","/**\n * /tasks/subtasks — flattened view of per-conversation child tasks\n * spawned by parent agents.\n *\n * Read-only: the backend doesn't expose cancel / re-run for subtasks\n * separately from the parent session. The page mirrors the columns\n * of /tasks/jobs but adds parent context (agent + platform) and\n * drops the duration / cost columns (which session.subtasks doesn't\n * track per-subtask).\n *\n * SSE: subscribes to the same `job` event as /tasks/jobs — subtask\n * status changes piggy-back on the parent job lifecycle in the\n * backend's event-bus.\n */\n\nimport { useMemo } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Loader2, ListTree, RefreshCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport { useSubtasks, useInvalidateSubtasks } from '@/hooks/use-subtasks'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Subtask } 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 SubtasksRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidate = useInvalidateSubtasks()\n const agent = params.get('agent') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useSubtasks(\n agent ? { agent } : {},\n )\n const subtasks = data?.subtasks ?? []\n\n const live = useEventStream({\n job: () => invalidate(),\n })\n\n function setAgentFilter(v: string): void {\n const next = new URLSearchParams(params)\n if (!v) next.delete('agent')\n else next.set('agent', v)\n setParams(next, { replace: true })\n }\n\n const columns: DataTableColumn<Subtask>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('subtasks.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'agent',\n header: t('subtasks.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('subtasks.col.prompt'),\n cell: (r) => <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>,\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('subtasks.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`subtasks.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'parent',\n header: t('subtasks.col.parent'),\n cell: (r) => (\n <span className=\"text-text-dim\">\n <span className=\"font-medium text-text\">{r.parentAgent}</span>\n <span className=\"text-text-muted\"> / </span>\n <span title={r.parentSessionId}>{r.parentSessionId.slice(0, 8)}</span>\n </span>\n ),\n headClassName: 'w-40',\n },\n {\n id: 'platform',\n header: t('subtasks.col.platform'),\n cell: (r) => <span className=\"text-text-dim\">{r.platform}</span>,\n headClassName: 'w-28',\n hideOnMobile: true,\n },\n {\n id: 'createdAt',\n header: t('subtasks.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.createdAt)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('subtasks.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('subtasks.subtitle')}</p>\n </header>\n\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"agent-filter\" className=\"text-xs text-text-dim\">\n {t('subtasks.filter.agent')}\n </Label>\n <Input\n id=\"agent-filter\"\n value={agent}\n onChange={(e) => setAgentFilter(e.target.value)}\n placeholder={t('subtasks.filter.agentAny')}\n className=\"w-48\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={subtasks}\n getRowId={(r) => `${r.parentSessionId}:${r.id}`}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<ListTree />}\n title={t('subtasks.empty.title')}\n description={t('subtasks.empty.description')}\n />\n }\n />\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["ListTree","createLucideIcon","subtasksKeys","q","useSubtasks","query","useQuery","api","useInvalidateSubtasks","qc","useQueryClient","LIVE_STATUS_CLASS","SubtasksRoute","t","useTranslation","params","setParams","useSearchParams","invalidate","agent","data","isLoading","isFetching","refetch","subtasks","live","useEventStream","setAgentFilter","v","next","columns","useMemo","r","jsxs","jsx","StatusBadge","formatTime","cn","Button","Loader2","RefreshCcw","Label","Input","e","DataTable","EmptyState","iso","d","now"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"subtasks-DROeZcfT.js","sources":["../../node_modules/lucide-react/dist/esm/icons/list-tree.js","../../src/hooks/use-subtasks.ts","../../src/routes/tasks/subtasks.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 ListTree = createLucideIcon(\"ListTree\", [\n [\"path\", { d: \"M21 12h-8\", key: \"1bmf0i\" }],\n [\"path\", { d: \"M21 6H8\", key: \"1pqkrb\" }],\n [\"path\", { d: \"M21 18h-8\", key: \"1tm79t\" }],\n [\"path\", { d: \"M3 6v4c0 1.1.9 2 2 2h3\", key: \"1ywdgy\" }],\n [\"path\", { d: \"M3 10v6c0 1.1.9 2 2 2h3\", key: \"2wc746\" }]\n]);\n\nexport { ListTree as default };\n//# sourceMappingURL=list-tree.js.map\n","/**\n * useSubtasks — react-query wrapper for /api/subtasks.\n *\n * Subtasks are a flattened view of session.subtasks across every\n * conversation file in ~/.agim/sessions/. The endpoint is read-only\n * — no cancel / re-run mutation surface (yet). Live refresh rides on\n * the same SSE 'job' event (subtask state changes piggy-back on the\n * parent job's lifecycle).\n */\n\nimport { useQueryClient, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { ListSubtasksQuery, ListSubtasksResponse } from '@/types/api'\n\nexport const subtasksKeys = {\n all: ['subtasks'] as const,\n list: (q: ListSubtasksQuery) => ['subtasks', 'list', q] as const,\n}\n\nexport function useSubtasks(query: ListSubtasksQuery) {\n return useQuery<ListSubtasksResponse>({\n queryKey: subtasksKeys.list(query),\n queryFn: () => api.listSubtasks(query),\n })\n}\n\nexport function useInvalidateSubtasks() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: subtasksKeys.all })\n}\n","/**\n * /tasks/subtasks — flattened view of per-conversation child tasks\n * spawned by parent agents.\n *\n * Read-only: the backend doesn't expose cancel / re-run for subtasks\n * separately from the parent session. The page mirrors the columns\n * of /tasks/jobs but adds parent context (agent + platform) and\n * drops the duration / cost columns (which session.subtasks doesn't\n * track per-subtask).\n *\n * SSE: subscribes to the same `job` event as /tasks/jobs — subtask\n * status changes piggy-back on the parent job lifecycle in the\n * backend's event-bus.\n */\n\nimport { useMemo } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Loader2, ListTree, RefreshCcw } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport { useSubtasks, useInvalidateSubtasks } from '@/hooks/use-subtasks'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Subtask } 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 SubtasksRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidate = useInvalidateSubtasks()\n const agent = params.get('agent') ?? ''\n\n const { data, isLoading, isFetching, refetch } = useSubtasks(\n agent ? { agent } : {},\n )\n const subtasks = data?.subtasks ?? []\n\n const live = useEventStream({\n job: () => invalidate(),\n })\n\n function setAgentFilter(v: string): void {\n const next = new URLSearchParams(params)\n if (!v) next.delete('agent')\n else next.set('agent', v)\n setParams(next, { replace: true })\n }\n\n const columns: DataTableColumn<Subtask>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('subtasks.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n },\n {\n id: 'agent',\n header: t('subtasks.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('subtasks.col.prompt'),\n cell: (r) => <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>,\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('subtasks.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`subtasks.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'parent',\n header: t('subtasks.col.parent'),\n cell: (r) => (\n <span className=\"text-text-dim\">\n <span className=\"font-medium text-text\">{r.parentAgent}</span>\n <span className=\"text-text-muted\"> / </span>\n <span title={r.parentSessionId}>{r.parentSessionId.slice(0, 8)}</span>\n </span>\n ),\n headClassName: 'w-40',\n },\n {\n id: 'platform',\n header: t('subtasks.col.platform'),\n cell: (r) => <span className=\"text-text-dim\">{r.platform}</span>,\n headClassName: 'w-28',\n hideOnMobile: true,\n },\n {\n id: 'createdAt',\n header: t('subtasks.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.createdAt)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('subtasks.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('subtasks.subtitle')}</p>\n </header>\n\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"agent-filter\" className=\"text-xs text-text-dim\">\n {t('subtasks.filter.agent')}\n </Label>\n <Input\n id=\"agent-filter\"\n value={agent}\n onChange={(e) => setAgentFilter(e.target.value)}\n placeholder={t('subtasks.filter.agentAny')}\n className=\"w-48\"\n />\n </div>\n </div>\n\n <DataTable\n columns={columns}\n rows={subtasks}\n getRowId={(r) => `${r.parentSessionId}:${r.id}`}\n loading={isLoading}\n emptyState={\n <EmptyState\n icon={<ListTree />}\n title={t('subtasks.empty.title')}\n description={t('subtasks.empty.description')}\n />\n }\n />\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n"],"names":["ListTree","createLucideIcon","subtasksKeys","q","useSubtasks","query","useQuery","api","useInvalidateSubtasks","qc","useQueryClient","LIVE_STATUS_CLASS","SubtasksRoute","t","useTranslation","params","setParams","useSearchParams","invalidate","agent","data","isLoading","isFetching","refetch","subtasks","live","useEventStream","setAgentFilter","v","next","columns","useMemo","r","jsxs","jsx","StatusBadge","formatTime","cn","Button","Loader2","RefreshCcw","Label","Input","e","DataTable","EmptyState","iso","d","now"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Q as s,r as t}from"./index-
|
|
2
|
-
//# sourceMappingURL=table-
|
|
1
|
+
import{Q as s,r as t}from"./index-B48azMO-.js";import{e as o}from"./react-C9F3QeMB.js";const l=o.forwardRef(({className:e,...a},r)=>s.jsx("div",{className:"w-full overflow-x-auto",children:s.jsx("table",{ref:r,className:t("w-full caption-bottom text-sm",e),...a})}));l.displayName="Table";const d=o.forwardRef(({className:e,...a},r)=>s.jsx("thead",{ref:r,className:t("[&_tr]:border-b [&_tr]:border-border bg-surface-2",e),...a}));d.displayName="TableHeader";const b=o.forwardRef(({className:e,...a},r)=>s.jsx("tbody",{ref:r,className:t("[&_tr:last-child]:border-0",e),...a}));b.displayName="TableBody";const c=o.forwardRef(({className:e,...a},r)=>s.jsx("tfoot",{ref:r,className:t("border-t border-border bg-surface-2 font-medium [&>tr]:last:border-b-0",e),...a}));c.displayName="TableFooter";const m=o.forwardRef(({className:e,...a},r)=>s.jsx("tr",{ref:r,className:t("border-b border-border transition-colors","hover:bg-surface-hover data-[state=selected]:bg-accent-bg",e),...a}));m.displayName="TableRow";const i=o.forwardRef(({className:e,...a},r)=>s.jsx("th",{ref:r,className:t("h-10 px-4 text-left align-middle","text-xs font-semibold uppercase tracking-wide text-text-dim","[&:has([role=checkbox])]:pr-0",e),...a}));i.displayName="TableHead";const f=o.forwardRef(({className:e,...a},r)=>s.jsx("td",{ref:r,className:t("p-3 align-middle [&:has([role=checkbox])]:pr-0",e),...a}));f.displayName="TableCell";const x=o.forwardRef(({className:e,...a},r)=>s.jsx("caption",{ref:r,className:t("mt-4 text-sm text-text-dim",e),...a}));x.displayName="TableCaption";export{l as T,b as a,f as b,i as c,d,m as e};
|
|
2
|
+
//# sourceMappingURL=table-CZwKizat.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-
|
|
1
|
+
{"version":3,"file":"table-CZwKizat.js","sources":["../../src/components/ui/table.tsx"],"sourcesContent":["/**\n * Table — accessible HTML table primitives. No 3rd-party dep; the\n * sortable / paginated / virtualised DataTable that wraps this lives\n * at components/common/data-table.tsx (PR-8).\n *\n * Mobile fallback strategy: the DataTable wrapper detects `< md` and\n * renders cards instead of rows. The primitives here keep a `min-w`\n * + overflow-x-auto wrapper as the fallback fallback (degrade to\n * horizontal scroll) so even raw `<Table>` usage is usable on phone.\n */\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\n\nconst Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(\n ({ className, ...props }, ref) => (\n <div className=\"w-full overflow-x-auto\">\n <table\n ref={ref}\n className={cn('w-full caption-bottom text-sm', className)}\n {...props}\n />\n </div>\n ),\n)\nTable.displayName = 'Table'\n\nconst TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <thead ref={ref} className={cn('[&_tr]:border-b [&_tr]:border-border bg-surface-2', className)} {...props} />\n ),\n)\nTableHeader.displayName = 'TableHeader'\n\nconst TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />\n ),\n)\nTableBody.displayName = 'TableBody'\n\nconst TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n 'border-t border-border bg-surface-2 font-medium [&>tr]:last:border-b-0',\n className,\n )}\n {...props}\n />\n ),\n)\nTableFooter.displayName = 'TableFooter'\n\nconst TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(\n ({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n 'border-b border-border transition-colors',\n 'hover:bg-surface-hover data-[state=selected]:bg-accent-bg',\n className,\n )}\n {...props}\n />\n ),\n)\nTableRow.displayName = 'TableRow'\n\nconst TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n 'h-10 px-4 text-left align-middle',\n 'text-xs font-semibold uppercase tracking-wide text-text-dim',\n '[&:has([role=checkbox])]:pr-0',\n className,\n )}\n {...props}\n />\n ),\n)\nTableHead.displayName = 'TableHead'\n\nconst TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn('p-3 align-middle [&:has([role=checkbox])]:pr-0', className)}\n {...props}\n />\n ),\n)\nTableCell.displayName = 'TableCell'\n\nconst TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(\n ({ className, ...props }, ref) => (\n <caption ref={ref} className={cn('mt-4 text-sm text-text-dim', className)} {...props} />\n ),\n)\nTableCaption.displayName = 'TableCaption'\n\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }\n"],"names":["Table","React.forwardRef","className","props","ref","jsx","cn","TableHeader","TableBody","TableFooter","TableRow","TableHead","TableCell","TableCaption"],"mappings":"uFAcA,MAAMA,EAAQC,EAAAA,WACZ,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,MAAC,MAAA,CAAI,UAAU,yBACb,SAAAA,EAAAA,IAAC,QAAA,CACC,IAAAD,EACA,UAAWE,EAAG,gCAAiCJ,CAAS,EACvD,GAAGC,CAAA,CAAA,CACN,CACF,CAEJ,EACAH,EAAM,YAAc,QAEpB,MAAMO,EAAcN,EAAAA,WAClB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,QAAA,CAAM,IAAAD,EAAU,UAAWE,EAAG,oDAAqDJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE/G,EACAI,EAAY,YAAc,cAE1B,MAAMC,EAAYP,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,QAAA,CAAM,IAAAD,EAAU,UAAWE,EAAG,6BAA8BJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAExF,EACAK,EAAU,YAAc,YAExB,MAAMC,EAAcR,EAAAA,WAClB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,QAAA,CACC,IAAAD,EACA,UAAWE,EACT,yEACAJ,CAAA,EAED,GAAGC,CAAA,CAAA,CAGV,EACAM,EAAY,YAAc,cAE1B,MAAMC,EAAWT,EAAAA,WACf,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CACC,IAAAD,EACA,UAAWE,EACT,2CACA,4DACAJ,CAAA,EAED,GAAGC,CAAA,CAAA,CAGV,EACAO,EAAS,YAAc,WAEvB,MAAMC,EAAYV,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CACC,IAAAD,EACA,UAAWE,EACT,mCACA,8DACA,gCACAJ,CAAA,EAED,GAAGC,CAAA,CAAA,CAGV,EACAQ,EAAU,YAAc,YAExB,MAAMC,EAAYX,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CACC,IAAAD,EACA,UAAWE,EAAG,iDAAkDJ,CAAS,EACxE,GAAGC,CAAA,CAAA,CAGV,EACAS,EAAU,YAAc,YAExB,MAAMC,EAAeZ,EAAAA,WACnB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,UAAA,CAAQ,IAAAD,EAAU,UAAWE,EAAG,6BAA8BJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE1F,EACAU,EAAa,YAAc"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{x as S,ac as w,ab as M,Q as e,c as L,L as p,S as j,l as u,m as f,j as b,k as N}from"./index-
|
|
1
|
+
import{x as S,ac as w,ab as M,Q as e,c as L,L as p,S as j,l as u,m as f,j as b,k as N}from"./index-B48azMO-.js";import{E as R}from"./empty-state-BKs1qKHx.js";import{T as V,d as $,e as g,c as t,a as E,b as c}from"./table-CZwKizat.js";import{b as F}from"./use-observability-D8qHfj0S.js";import{L as I}from"./loader-circle-DBf4xFjo.js";import{R as P}from"./refresh-ccw-Clj5sQNF.js";import"./react-C9F3QeMB.js";import"./useQuery-BjFqOBV3.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const z=S("ChartColumn",[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]),B=["user","agent","platform","intent"],H=["cost","calls","errors","avg_latency"];function J(){const{t:a}=w(["observability","common"]),[n,y]=M(),v=Math.max(1,Number(n.get("days"))||7),r=n.get("dim")??"agent",i=n.get("by")??"cost";function m(s){const l=new URLSearchParams(n);for(const[x,h]of Object.entries(s))h==null?l.delete(x):l.set(x,h);y(l,{replace:!0})}const{data:k,isLoading:C,isFetching:o,refetch:T}=F({dim:r,by:i,days:v,limit:20}),d=k?.items??[];return e.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[e.jsx("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:a("topn.title")}),e.jsxs(L,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>T(),disabled:o,"aria-label":a("actions.refresh",{ns:"common"}),children:[o?e.jsx(I,{className:"h-4 w-4 animate-spin"}):e.jsx(P,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:a("actions.refresh",{ns:"common"})})]})]})}),e.jsxs("div",{className:"flex flex-wrap items-end gap-2",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(p,{htmlFor:"dim",className:"text-xs text-text-dim",children:a("topn.filter.dim")}),e.jsxs(j,{value:r,onValueChange:s=>m({dim:s==="agent"?null:s}),children:[e.jsx(u,{id:"dim",className:"w-32",children:e.jsx(f,{})}),e.jsx(b,{children:B.map(s=>e.jsx(N,{value:s,children:a(`topn.dim.${s}`)},s))})]})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(p,{htmlFor:"by",className:"text-xs text-text-dim",children:a("topn.filter.metric")}),e.jsxs(j,{value:i,onValueChange:s=>m({by:s==="cost"?null:s}),children:[e.jsx(u,{id:"by",className:"w-36",children:e.jsx(f,{})}),e.jsx(b,{children:H.map(s=>e.jsx(N,{value:s,children:a(`topn.metric.${s}`)},s))})]})]})]}),C?e.jsx("div",{className:"h-48 w-full rounded-md bg-surface-2 animate-pulse"}):d.length===0?e.jsx(R,{icon:e.jsx(z,{}),title:a("topn.empty.title"),description:a("topn.empty.description")}):e.jsxs(V,{children:[e.jsx($,{children:e.jsxs(g,{children:[e.jsx(t,{className:"w-12",children:a("topn.col.rank")}),e.jsx(t,{children:a("topn.col.key")}),e.jsx(t,{className:"w-24",children:a("topn.col.calls")}),e.jsx(t,{className:"w-24",children:a("topn.col.cost")}),e.jsx(t,{className:"w-24",children:a("topn.col.errors")}),e.jsx(t,{className:"w-32",children:a("topn.col.avgLatencyMs")})]})}),e.jsx(E,{children:d.map((s,l)=>e.jsxs(g,{children:[e.jsx(c,{className:"tabular-nums text-text-dim",children:l+1}),e.jsx(c,{className:"font-medium",children:s.key}),e.jsx(c,{className:"tabular-nums",children:s.calls}),e.jsxs(c,{className:"tabular-nums",children:["$",s.cost.toFixed(4)]}),e.jsx(c,{className:"tabular-nums",children:e.jsx("span",{className:s.errors>0?"text-danger":"text-text-dim",children:s.errors})}),e.jsxs(c,{className:"tabular-nums",children:[Math.round(s.avgLatencyMs),"ms"]})]},`${s.key}-${l}`))})]})]})}export{J as default};
|
|
7
|
-
//# sourceMappingURL=topn-
|
|
7
|
+
//# sourceMappingURL=topn-DpErN6N8.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topn-Dk9JxsaD.js","sources":["../../node_modules/lucide-react/dist/esm/icons/chart-column.js","../../src/routes/observability/topn.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 ChartColumn = createLucideIcon(\"ChartColumn\", [\n [\"path\", { d: \"M3 3v16a2 2 0 0 0 2 2h16\", key: \"c24i48\" }],\n [\"path\", { d: \"M18 17V9\", key: \"2bz60n\" }],\n [\"path\", { d: \"M13 17V5\", key: \"1frdt8\" }],\n [\"path\", { d: \"M8 17v-3\", key: \"17ska0\" }]\n]);\n\nexport { ChartColumn as default };\n//# sourceMappingURL=chart-column.js.map\n","/**\n * /observability/topn — leaderboard grouped by a dimension, sorted\n * by a metric. Dim + metric live in URL state alongside the\n * layout's ?days= so the URL fully describes the view.\n */\n\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { BarChart3, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useTopN } from '@/hooks/use-observability'\nimport type { TopNDim, TopNMetric } from '@/types/api'\n\nconst DIMS: TopNDim[] = ['user', 'agent', 'platform', 'intent']\nconst METRICS: TopNMetric[] = ['cost', 'calls', 'errors', 'avg_latency']\n\nexport default function ObservabilityTopNRoute(): JSX.Element {\n const { t } = useTranslation(['observability', 'common'])\n const [params, setParams] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n const dim = (params.get('dim') as TopNDim | null) ?? 'agent'\n const by = (params.get('by') as TopNMetric | null) ?? 'cost'\n\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null) next.delete(k)\n else next.set(k, v)\n }\n setParams(next, { replace: true })\n }\n\n const { data, isLoading, isFetching, refetch } = useTopN({ dim, by, days, limit: 20 })\n const items = data?.items ?? []\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('topn.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n </header>\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"dim\" className=\"text-xs text-text-dim\">{t('topn.filter.dim')}</Label>\n <Select value={dim} onValueChange={(v) => patchParams({ dim: v === 'agent' ? null : v })}>\n <SelectTrigger id=\"dim\" className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DIMS.map((d) => (\n <SelectItem key={d} value={d}>{t(`topn.dim.${d}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"by\" className=\"text-xs text-text-dim\">{t('topn.filter.metric')}</Label>\n <Select value={by} onValueChange={(v) => patchParams({ by: v === 'cost' ? null : v })}>\n <SelectTrigger id=\"by\" className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {METRICS.map((m) => (\n <SelectItem key={m} value={m}>{t(`topn.metric.${m}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<BarChart3 />}\n title={t('topn.empty.title')}\n description={t('topn.empty.description')}\n />\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-12\">{t('topn.col.rank')}</TableHead>\n <TableHead>{t('topn.col.key')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.calls')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.cost')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.errors')}</TableHead>\n <TableHead className=\"w-32\">{t('topn.col.avgLatencyMs')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {items.map((row, i) => (\n <TableRow key={`${row.key}-${i}`}>\n <TableCell className=\"tabular-nums text-text-dim\">{i + 1}</TableCell>\n <TableCell className=\"font-medium\">{row.key}</TableCell>\n <TableCell className=\"tabular-nums\">{row.calls}</TableCell>\n <TableCell className=\"tabular-nums\">${row.cost.toFixed(4)}</TableCell>\n <TableCell className=\"tabular-nums\">\n <span className={row.errors > 0 ? 'text-danger' : 'text-text-dim'}>{row.errors}</span>\n </TableCell>\n <TableCell className=\"tabular-nums\">{Math.round(row.avgLatencyMs)}ms</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </div>\n )\n}\n"],"names":["ChartColumn","createLucideIcon","DIMS","METRICS","ObservabilityTopNRoute","t","useTranslation","params","setParams","useSearchParams","days","dim","by","patchParams","patch","next","k","v","data","isLoading","isFetching","refetch","useTopN","items","jsxs","jsx","Button","Loader2","RefreshCcw","Label","Select","SelectTrigger","SelectValue","SelectContent","d","SelectItem","m","EmptyState","BarChart3","Table","TableHeader","TableRow","TableHead","TableBody","row","i","TableCell"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"topn-DpErN6N8.js","sources":["../../node_modules/lucide-react/dist/esm/icons/chart-column.js","../../src/routes/observability/topn.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 ChartColumn = createLucideIcon(\"ChartColumn\", [\n [\"path\", { d: \"M3 3v16a2 2 0 0 0 2 2h16\", key: \"c24i48\" }],\n [\"path\", { d: \"M18 17V9\", key: \"2bz60n\" }],\n [\"path\", { d: \"M13 17V5\", key: \"1frdt8\" }],\n [\"path\", { d: \"M8 17v-3\", key: \"17ska0\" }]\n]);\n\nexport { ChartColumn as default };\n//# sourceMappingURL=chart-column.js.map\n","/**\n * /observability/topn — leaderboard grouped by a dimension, sorted\n * by a metric. Dim + metric live in URL state alongside the\n * layout's ?days= so the URL fully describes the view.\n */\n\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { BarChart3, Loader2, RefreshCcw } from 'lucide-react'\n\nimport { EmptyState } from '@/components/common/empty-state'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { useTopN } from '@/hooks/use-observability'\nimport type { TopNDim, TopNMetric } from '@/types/api'\n\nconst DIMS: TopNDim[] = ['user', 'agent', 'platform', 'intent']\nconst METRICS: TopNMetric[] = ['cost', 'calls', 'errors', 'avg_latency']\n\nexport default function ObservabilityTopNRoute(): JSX.Element {\n const { t } = useTranslation(['observability', 'common'])\n const [params, setParams] = useSearchParams()\n const days = Math.max(1, Number(params.get('days')) || 7)\n const dim = (params.get('dim') as TopNDim | null) ?? 'agent'\n const by = (params.get('by') as TopNMetric | null) ?? 'cost'\n\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null) next.delete(k)\n else next.set(k, v)\n }\n setParams(next, { replace: true })\n }\n\n const { data, isLoading, isFetching, refetch } = useTopN({ dim, by, days, limit: 20 })\n const items = data?.items ?? []\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('topn.title')}</h1>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n </header>\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"dim\" className=\"text-xs text-text-dim\">{t('topn.filter.dim')}</Label>\n <Select value={dim} onValueChange={(v) => patchParams({ dim: v === 'agent' ? null : v })}>\n <SelectTrigger id=\"dim\" className=\"w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DIMS.map((d) => (\n <SelectItem key={d} value={d}>{t(`topn.dim.${d}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"by\" className=\"text-xs text-text-dim\">{t('topn.filter.metric')}</Label>\n <Select value={by} onValueChange={(v) => patchParams({ by: v === 'cost' ? null : v })}>\n <SelectTrigger id=\"by\" className=\"w-36\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {METRICS.map((m) => (\n <SelectItem key={m} value={m}>{t(`topn.metric.${m}`)}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {isLoading ? (\n <div className=\"h-48 w-full rounded-md bg-surface-2 animate-pulse\" />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<BarChart3 />}\n title={t('topn.empty.title')}\n description={t('topn.empty.description')}\n />\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-12\">{t('topn.col.rank')}</TableHead>\n <TableHead>{t('topn.col.key')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.calls')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.cost')}</TableHead>\n <TableHead className=\"w-24\">{t('topn.col.errors')}</TableHead>\n <TableHead className=\"w-32\">{t('topn.col.avgLatencyMs')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {items.map((row, i) => (\n <TableRow key={`${row.key}-${i}`}>\n <TableCell className=\"tabular-nums text-text-dim\">{i + 1}</TableCell>\n <TableCell className=\"font-medium\">{row.key}</TableCell>\n <TableCell className=\"tabular-nums\">{row.calls}</TableCell>\n <TableCell className=\"tabular-nums\">${row.cost.toFixed(4)}</TableCell>\n <TableCell className=\"tabular-nums\">\n <span className={row.errors > 0 ? 'text-danger' : 'text-text-dim'}>{row.errors}</span>\n </TableCell>\n <TableCell className=\"tabular-nums\">{Math.round(row.avgLatencyMs)}ms</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </div>\n )\n}\n"],"names":["ChartColumn","createLucideIcon","DIMS","METRICS","ObservabilityTopNRoute","t","useTranslation","params","setParams","useSearchParams","days","dim","by","patchParams","patch","next","k","v","data","isLoading","isFetching","refetch","useTopN","items","jsxs","jsx","Button","Loader2","RefreshCcw","Label","Select","SelectTrigger","SelectValue","SelectContent","d","SelectItem","m","EmptyState","BarChart3","Table","TableHeader","TableRow","TableHead","TableBody","row","i","TableCell"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{x as e}from"./index-
|
|
1
|
+
import{x as e}from"./index-B48azMO-.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 t=e("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);export{t as T};
|
|
7
|
-
//# sourceMappingURL=trash-2-
|
|
7
|
+
//# sourceMappingURL=trash-2-BkZrVFdH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trash-2-
|
|
1
|
+
{"version":3,"file":"trash-2-BkZrVFdH.js","sources":["../../node_modules/lucide-react/dist/esm/icons/trash-2.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 Trash2 = createLucideIcon(\"Trash2\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }],\n [\"line\", { x1: \"10\", x2: \"10\", y1: \"11\", y2: \"17\", key: \"1uufr5\" }],\n [\"line\", { x1: \"14\", x2: \"14\", y1: \"11\", y2: \"17\", key: \"xtxkd\" }]\n]);\n\nexport { Trash2 as default };\n//# sourceMappingURL=trash-2.js.map\n"],"names":["Trash2","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAASC,EAAiB,SAAU,CACxC,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAQ,CAAE,EACxC,CAAC,OAAQ,CAAE,EAAG,wCAAyC,IAAK,QAAQ,CAAE,EACtE,CAAC,OAAQ,CAAE,EAAG,qCAAsC,IAAK,QAAQ,CAAE,EACnE,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,IAAK,QAAQ,CAAE,EAClE,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,IAAK,OAAO,CAAE,CACnE,CAAC","x_google_ignoreList":[0]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u}from"./useQuery-
|
|
2
|
-
//# sourceMappingURL=use-memory-
|
|
1
|
+
import{u}from"./useQuery-BjFqOBV3.js";import{aa as t,a9 as o,q as n,a as i}from"./index-B48azMO-.js";const r={all:["memory"],users:["memory","users"],facts:e=>["memory","facts",e],persona:e=>["memory","persona",e],consolidate:["memory","consolidate"]};function y(){return u({queryKey:r.users,queryFn:()=>n.listMemoryUsers()})}function m(e,a={}){return u({queryKey:r.facts(e),queryFn:()=>n.listMemoryFacts(e),enabled:a.enabled!==!1&&!!e.user_key})}function d(){const e=t();return o({mutationFn:({id:a,user_key:s})=>n.deleteMemoryFactById(a,{user_key:s}),onSuccess:()=>e.invalidateQueries({queryKey:r.all})})}function f(){const e=t();return o({mutationFn:({user_key:a,body:s})=>n.deleteMemoryFacts({user_key:a},s),onSuccess:()=>e.invalidateQueries({queryKey:r.all})})}function q(e,a={}){return u({queryKey:r.persona(e),queryFn:async()=>{try{return await n.getMemoryPersona({user_key:e})}catch(s){if(s instanceof i&&s.status===404)return null;throw s}},enabled:a.enabled!==!1&&!!e})}function F(){const e=t();return o({mutationFn:({user_key:a,body:s})=>n.updateMemoryPersona({user_key:a},s),onSuccess:(a,s)=>{e.invalidateQueries({queryKey:r.persona(s.user_key)}),e.invalidateQueries({queryKey:r.users})}})}function K(){const e=t();return o({mutationFn:a=>n.deleteMemoryPersona({user_key:a}),onSuccess:(a,s)=>{e.invalidateQueries({queryKey:r.persona(s)}),e.invalidateQueries({queryKey:r.users})}})}function M(e={}){return u({queryKey:r.consolidate,queryFn:()=>n.getMemoryConsolidateStatus(),refetchInterval:3e3,refetchIntervalInBackground:!1,enabled:e.enabled!==!1})}function p(){const e=t();return o({mutationFn:()=>n.consolidateMemory(),onSuccess:()=>{e.invalidateQueries({queryKey:r.consolidate}),e.invalidateQueries({queryKey:r.all})}})}export{M as a,d as b,K as c,m as d,q as e,y as f,p as g,F as h,r as m,f as u};
|
|
2
|
+
//# sourceMappingURL=use-memory-CElm89Hg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-memory-
|
|
1
|
+
{"version":3,"file":"use-memory-CElm89Hg.js","sources":["../../src/hooks/use-memory.ts"],"sourcesContent":["/**\n * useMemory — react-query wrappers for the agent long-term memory.\n *\n * useMemoryUsers() — pick list of users that have\n * facts in the bank\n * useMemoryFacts(query) — pageable facts for one user\n * useDeleteFactById() — single-row delete\n * useBulkDeleteFacts() — multi / category / threshold\n *\n * No SSE channel; memory mutations are operator-driven and the\n * react-query 30s staleTime is enough. Mutations invalidate the\n * full ['memory'] tree so adjacent views (e.g. the user summary's\n * fact_count) stay in sync.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport { ApiClientError } from '@/lib/api/client'\nimport type {\n ConsolidateMemoryResponse,\n ConsolidateStatusResponse,\n DeleteMemoryFactsBody,\n DeleteMemoryFactsResponse,\n ListMemoryFactsQuery,\n ListMemoryFactsResponse,\n ListMemoryUsersResponse,\n OkResponse,\n Persona,\n UpdatePersonaBody,\n} from '@/types/api'\n\nexport const memoryKeys = {\n all: ['memory'] as const,\n users: ['memory', 'users'] as const,\n facts: (q: ListMemoryFactsQuery) => ['memory', 'facts', q] as const,\n persona: (user_key: string) => ['memory', 'persona', user_key] as const,\n consolidate: ['memory', 'consolidate'] as const,\n}\n\nexport function useMemoryUsers() {\n return useQuery<ListMemoryUsersResponse>({\n queryKey: memoryKeys.users,\n queryFn: () => api.listMemoryUsers(),\n })\n}\n\nexport function useMemoryFacts(query: ListMemoryFactsQuery, opts: { enabled?: boolean } = {}) {\n return useQuery<ListMemoryFactsResponse>({\n queryKey: memoryKeys.facts(query),\n queryFn: () => api.listMemoryFacts(query),\n // Caller passes enabled=false until a user_key is chosen so the\n // hook doesn't fire with an empty key.\n enabled: opts.enabled !== false && Boolean(query.user_key),\n })\n}\n\nexport function useInvalidateMemory() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: memoryKeys.all })\n}\n\nexport function useDeleteFactById() {\n const qc = useQueryClient()\n return useMutation<\n OkResponse & { id: number },\n Error,\n { id: number; user_key: string }\n >({\n mutationFn: ({ id, user_key }) => api.deleteMemoryFactById(id, { user_key }),\n onSuccess: () => qc.invalidateQueries({ queryKey: memoryKeys.all }),\n })\n}\n\nexport function useBulkDeleteFacts() {\n const qc = useQueryClient()\n return useMutation<\n DeleteMemoryFactsResponse,\n Error,\n { user_key: string; body: DeleteMemoryFactsBody }\n >({\n mutationFn: ({ user_key, body }) => api.deleteMemoryFacts({ user_key }, body),\n onSuccess: () => qc.invalidateQueries({ queryKey: memoryKeys.all }),\n })\n}\n\n/* ─────────────── Persona ─────────────── */\n\n/** Fetch the persona for a user. The backend returns 404 when the\n * user has no persona yet — we map that to `data: null` so the\n * route can render the \"not set yet\" state without a try/catch. */\nexport function useMemoryPersona(user_key: string, opts: { enabled?: boolean } = {}) {\n return useQuery<Persona | null>({\n queryKey: memoryKeys.persona(user_key),\n queryFn: async () => {\n try {\n return await api.getMemoryPersona({ user_key })\n } catch (err) {\n if (err instanceof ApiClientError && err.status === 404) return null\n throw err\n }\n },\n enabled: opts.enabled !== false && Boolean(user_key),\n })\n}\n\nexport function useUpdatePersona() {\n const qc = useQueryClient()\n return useMutation<\n { ok: boolean },\n Error,\n { user_key: string; body: UpdatePersonaBody }\n >({\n mutationFn: ({ user_key, body }) => api.updateMemoryPersona({ user_key }, body),\n onSuccess: (_data, vars) => {\n qc.invalidateQueries({ queryKey: memoryKeys.persona(vars.user_key) })\n qc.invalidateQueries({ queryKey: memoryKeys.users })\n },\n })\n}\n\nexport function useDeletePersona() {\n const qc = useQueryClient()\n return useMutation<{ ok: boolean }, Error, string>({\n mutationFn: (user_key) => api.deleteMemoryPersona({ user_key }),\n onSuccess: (_data, user_key) => {\n qc.invalidateQueries({ queryKey: memoryKeys.persona(user_key) })\n qc.invalidateQueries({ queryKey: memoryKeys.users })\n },\n })\n}\n\n/* ─────────────── Consolidate ─────────────── */\n\n/** Status of the in-flight + recent consolidation jobs. Polls while\n * the page is open since consolidate runs asynchronously and we\n * want the operator to see when it completes without manual\n * refresh. */\nexport function useConsolidateStatus(opts: { enabled?: boolean } = {}) {\n return useQuery<ConsolidateStatusResponse>({\n queryKey: memoryKeys.consolidate,\n queryFn: () => api.getMemoryConsolidateStatus(),\n refetchInterval: 3000,\n refetchIntervalInBackground: false,\n enabled: opts.enabled !== false,\n })\n}\n\nexport function useTriggerConsolidate() {\n const qc = useQueryClient()\n return useMutation<ConsolidateMemoryResponse, Error, void>({\n mutationFn: () => api.consolidateMemory(),\n onSuccess: () => {\n qc.invalidateQueries({ queryKey: memoryKeys.consolidate })\n qc.invalidateQueries({ queryKey: memoryKeys.all })\n },\n })\n}\n"],"names":["memoryKeys","q","user_key","useMemoryUsers","useQuery","api","useMemoryFacts","query","opts","useDeleteFactById","qc","useQueryClient","useMutation","id","useBulkDeleteFacts","body","useMemoryPersona","err","ApiClientError","useUpdatePersona","_data","vars","useDeletePersona","useConsolidateStatus","useTriggerConsolidate"],"mappings":"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"}
|
package/dist/web/public/assets/{use-observability-CUbSm1kG.js → use-observability-D8qHfj0S.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as a}from"./useQuery-
|
|
2
|
-
//# sourceMappingURL=use-observability-
|
|
1
|
+
import{u as a}from"./useQuery-BjFqOBV3.js";import{q as i}from"./index-B48azMO-.js";const n={all:["observability"],health:e=>["observability","health",e],topN:(e,t,r,u)=>["observability","topn",e,t,r,u],audit:e=>["observability","audit",e]};function o(e){return a({queryKey:n.health(e),queryFn:()=>i.getHealthSummary({days:e}),refetchInterval:3e4,refetchIntervalInBackground:!1})}function s(e){const t=e.days??7,r=e.limit??10;return a({queryKey:n.topN(e.dim,e.by,t,r),queryFn:()=>i.getHealthTopN({dim:e.dim,by:e.by,days:t,limit:r}),refetchInterval:6e4,refetchIntervalInBackground:!1})}function c(e){return a({queryKey:n.audit(e),queryFn:()=>i.getAudit(e),refetchInterval:1e4,refetchIntervalInBackground:!1})}export{o as a,s as b,c as u};
|
|
2
|
+
//# sourceMappingURL=use-observability-D8qHfj0S.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-observability-
|
|
1
|
+
{"version":3,"file":"use-observability-D8qHfj0S.js","sources":["../../src/hooks/use-observability.ts"],"sourcesContent":["/**\n * useObservability — react-query wrappers for the operational\n * dashboard.\n *\n * useHealthSummary({ days }) — totals + byDay roll-up\n * useTopN({ dim, by, days, limit }) — leaderboard by dimension\n * useAudit(query) — recent invocations\n *\n * All three are read-only; observability stays a passive view.\n * Refetch intervals are tuned to match operator expectations:\n * health summary every 30s (background sweep latency); audit\n * every 10s (fresher); TopN every 60s (the leaderboard moves\n * slowly enough).\n */\n\nimport { useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type {\n AuditResponse,\n HealthSummary,\n ListAuditQuery,\n TopNDim,\n TopNMetric,\n TopNResponse,\n} from '@/types/api'\n\nexport const observabilityKeys = {\n all: ['observability'] as const,\n health: (days: number) => ['observability', 'health', days] as const,\n topN: (dim: TopNDim, by: TopNMetric, days: number, limit: number) =>\n ['observability', 'topn', dim, by, days, limit] as const,\n audit: (q: ListAuditQuery) => ['observability', 'audit', q] as const,\n}\n\nexport function useHealthSummary(days: number) {\n return useQuery<HealthSummary>({\n queryKey: observabilityKeys.health(days),\n queryFn: () => api.getHealthSummary({ days }),\n refetchInterval: 30_000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useTopN(opts: { dim: TopNDim; by: TopNMetric; days?: number; limit?: number }) {\n const days = opts.days ?? 7\n const limit = opts.limit ?? 10\n return useQuery<TopNResponse>({\n queryKey: observabilityKeys.topN(opts.dim, opts.by, days, limit),\n queryFn: () => api.getHealthTopN({ dim: opts.dim, by: opts.by, days, limit }),\n refetchInterval: 60_000,\n refetchIntervalInBackground: false,\n })\n}\n\nexport function useAudit(query: ListAuditQuery) {\n return useQuery<AuditResponse>({\n queryKey: observabilityKeys.audit(query),\n queryFn: () => api.getAudit(query),\n refetchInterval: 10_000,\n refetchIntervalInBackground: false,\n })\n}\n"],"names":["observabilityKeys","days","dim","by","limit","q","useHealthSummary","useQuery","api","useTopN","opts","useAudit","query"],"mappings":"mFA0BO,MAAMA,EAAoB,CAC/B,IAAS,CAAC,eAAe,EACzB,OAAUC,GAAiB,CAAC,gBAAiB,SAAUA,CAAI,EAC3D,KAAS,CAACC,EAAcC,EAAgBF,EAAcG,IACpD,CAAC,gBAAiB,OAAQF,EAAKC,EAAIF,EAAMG,CAAK,EAChD,MAAUC,GAAsB,CAAC,gBAAiB,QAASA,CAAC,CAC9D,EAEO,SAASC,EAAiBL,EAAc,CAC7C,OAAOM,EAAwB,CAC7B,SAAUP,EAAkB,OAAOC,CAAI,EACvC,QAAS,IAAMO,EAAI,iBAAiB,CAAE,KAAAP,EAAM,EAC5C,gBAAiB,IACjB,4BAA6B,EAAA,CAC9B,CACH,CAEO,SAASQ,EAAQC,EAAuE,CAC7F,MAAMT,EAAOS,EAAK,MAAQ,EACpBN,EAAQM,EAAK,OAAS,GAC5B,OAAOH,EAAuB,CAC5B,SAAUP,EAAkB,KAAKU,EAAK,IAAKA,EAAK,GAAIT,EAAMG,CAAK,EAC/D,QAAS,IAAMI,EAAI,cAAc,CAAE,IAAKE,EAAK,IAAK,GAAIA,EAAK,GAAI,KAAAT,EAAM,MAAAG,EAAO,EAC5E,gBAAiB,IACjB,4BAA6B,EAAA,CAC9B,CACH,CAEO,SAASO,EAASC,EAAuB,CAC9C,OAAOL,EAAwB,CAC7B,SAAUP,EAAkB,MAAMY,CAAK,EACvC,QAAS,IAAMJ,EAAI,SAASI,CAAK,EACjC,gBAAiB,IACjB,4BAA6B,EAAA,CAC9B,CACH"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as i}from"./useQuery-
|
|
2
|
-
//# sourceMappingURL=use-settings-
|
|
1
|
+
import{u as i}from"./useQuery-BjFqOBV3.js";import{aa as u,a9 as s,q as n}from"./index-B48azMO-.js";const r={all:["settings"],env:e=>["settings","env",e],service:["settings","service"],admins:["settings","admins"],config:["settings","config"],workspaces:["settings","workspaces"]};function l(e={}){const t=!!e.reveal;return i({queryKey:r.env(t),queryFn:()=>n.getEnv({reveal:t})})}function v(){const e=u();return s({mutationFn:t=>n.updateEnv(t),onSuccess:()=>e.invalidateQueries({queryKey:["settings","env"]})})}function f(){return i({queryKey:r.service,queryFn:()=>n.getServiceStatus(),refetchInterval:5e3,refetchIntervalInBackground:!1})}function a(e,t){return s({mutationFn:e,onSuccess:()=>t.invalidateQueries({queryKey:r.service})})}function y(){const e=u();return a(()=>n.startService(),e)}function m(){const e=u();return a(()=>n.stopService(),e)}function q(){const e=u();return a(()=>n.restartService(),e)}function d(){return i({queryKey:r.admins,queryFn:()=>n.listAdminAllowlist()})}function g(){const e=u();return s({mutationFn:t=>n.addAdminAllowlist(t),onSuccess:()=>e.invalidateQueries({queryKey:r.admins})})}function p(){const e=u();return s({mutationFn:t=>n.removeAdminAllowlist(t),onSuccess:()=>e.invalidateQueries({queryKey:r.admins})})}function S(){return i({queryKey:r.config,queryFn:()=>n.getConfig()})}function F(){const e=u();return s({mutationFn:t=>n.updateConfig(t),onSuccess:()=>e.invalidateQueries({queryKey:r.config})})}function A(){return i({queryKey:r.workspaces,queryFn:()=>n.listWorkspacesFull()})}function K(){const e=u();return s({mutationFn:t=>n.upsertWorkspace(t),onSuccess:()=>e.invalidateQueries({queryKey:r.workspaces})})}function w(){return s({mutationFn:()=>n.startWechatQr()})}function Q(e){return i({queryKey:["settings","wechat-qr",e??""],queryFn:()=>n.getWechatQrStatus({token:e}),enabled:!!e,refetchInterval:2e3,refetchIntervalInBackground:!1})}function h(){return s({mutationFn:e=>n.testAcpAgent(e)})}function k(){return s({mutationFn:e=>n.discoverAcpAgents(e)})}function W(){return s({mutationFn:()=>n.testEmail()})}function E(){return i({queryKey:["settings","viewer-tunnel"],queryFn:()=>n.getViewerTunnel()})}export{d as a,S as b,k as c,l as d,p as e,q as f,f as g,y as h,w as i,m as j,h as k,W as l,F as m,v as n,K as o,E as p,Q as q,A as r,g as u};
|
|
2
|
+
//# sourceMappingURL=use-settings-DgU8YmGj.js.map
|
package/dist/web/public/assets/{use-settings-CtTPlLXz.js.map → use-settings-DgU8YmGj.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-settings-CtTPlLXz.js","sources":["../../src/hooks/use-settings.ts"],"sourcesContent":["/**\n * useSettings — react-query wrappers for the env editor + service\n * control surfaces.\n *\n * useEnv({ reveal }) — env file values (masked when\n * reveal is false)\n * useUpdateEnv() — bulk update\n * useServiceStatus() — pid / mode / uptime\n * useStart/Stop/Restart() — service lifecycle\n *\n * Service status polls every 5s while the page is foreground so\n * the operator sees restart progress live.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type {\n ACPDiscoverBody,\n ACPDiscoverResponse,\n ACPTestBody,\n ACPTestResponse,\n EmailTestResponse,\n ViewerTunnelStatusResponse,\n AddAdminBody,\n AdminAllowlistResponse,\n AdminMutationResponse,\n AppConfig,\n EnvResponse,\n RemoveAdminBody,\n ServiceActionResponse,\n ServiceStatus,\n UpdateEnvBody,\n WechatQrStartResponse,\n WechatQrStatusResponse,\n WorkspaceConfig,\n} from '@/types/api'\n\nexport const settingsKeys = {\n all: ['settings'] as const,\n env: (reveal: boolean) => ['settings', 'env', reveal] as const,\n service: ['settings', 'service'] as const,\n admins: ['settings', 'admins'] as const,\n config: ['settings', 'config'] as const,\n workspaces: ['settings', 'workspaces'] as const,\n}\n\nexport function useEnv(opts: { reveal?: boolean } = {}) {\n const reveal = !!opts.reveal\n return useQuery<EnvResponse>({\n queryKey: settingsKeys.env(reveal),\n queryFn: () => api.getEnv({ reveal }),\n })\n}\n\nexport function useUpdateEnv() {\n const qc = useQueryClient()\n return useMutation<EnvResponse, Error, UpdateEnvBody>({\n mutationFn: (body) => api.updateEnv(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: ['settings', 'env'] }),\n })\n}\n\nexport function useServiceStatus() {\n return useQuery<ServiceStatus>({\n queryKey: settingsKeys.service,\n queryFn: () => api.getServiceStatus(),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nfunction makeServiceMutation(\n fn: () => Promise<ServiceActionResponse>,\n qc: ReturnType<typeof useQueryClient>,\n) {\n return useMutation<ServiceActionResponse, Error, void>({\n mutationFn: fn,\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.service }),\n })\n}\n\nexport function useStartService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.startService(), qc)\n}\n\nexport function useStopService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.stopService(), qc)\n}\n\nexport function useRestartService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.restartService(), qc)\n}\n\n/* ─────────────── Admin allowlist ─────────────── */\n\nexport function useAdminAllowlist() {\n return useQuery<AdminAllowlistResponse>({\n queryKey: settingsKeys.admins,\n queryFn: () => api.listAdminAllowlist(),\n })\n}\n\nexport function useAddAdmin() {\n const qc = useQueryClient()\n return useMutation<AdminMutationResponse, Error, AddAdminBody>({\n mutationFn: (body) => api.addAdminAllowlist(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.admins }),\n })\n}\n\nexport function useRemoveAdmin() {\n const qc = useQueryClient()\n return useMutation<AdminMutationResponse, Error, RemoveAdminBody>({\n mutationFn: (body) => api.removeAdminAllowlist(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.admins }),\n })\n}\n\n/* ─────────────── App config ─────────────── */\n\nexport function useConfig() {\n return useQuery<AppConfig>({\n queryKey: settingsKeys.config,\n queryFn: () => api.getConfig(),\n })\n}\n\nexport function useUpdateConfig() {\n const qc = useQueryClient()\n return useMutation<AppConfig, Error, Partial<AppConfig>>({\n mutationFn: (body) => api.updateConfig(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.config }),\n })\n}\n\n/* ─────────────── Workspaces ─────────────── */\n\nexport function useWorkspaces() {\n return useQuery<{ workspaces: WorkspaceConfig[] }>({\n queryKey: settingsKeys.workspaces,\n queryFn: () => api.listWorkspacesFull(),\n })\n}\n\nexport function useUpsertWorkspace() {\n const qc = useQueryClient()\n return useMutation<\n { ok: boolean; workspace: WorkspaceConfig },\n Error,\n WorkspaceConfig\n >({\n mutationFn: (body) => api.upsertWorkspace(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.workspaces }),\n })\n}\n\n/* ─────────────── WeChat QR ─────────────── */\n\nexport function useStartWechatQr() {\n return useMutation<WechatQrStartResponse, Error, void>({\n mutationFn: () => api.startWechatQr(),\n })\n}\n\n/** Poll the QR status every 2s while the modal is open. Caller\n * passes `token` once it has it from the start mutation; passing\n * null disables the polling. On status='confirmed' the backend\n * persists wechat-ilink → re-fetch config to update the toggle. */\nexport function useWechatQrStatus(token: string | null) {\n return useQuery<WechatQrStatusResponse>({\n queryKey: ['settings', 'wechat-qr', token ?? ''],\n queryFn: () => api.getWechatQrStatus({ token: token as string }),\n enabled: Boolean(token),\n refetchInterval: 2000,\n refetchIntervalInBackground: false,\n })\n}\n\n/** Probe a single ACP endpoint by fetching its manifest. Used by\n * the \"Test\" buttons in /settings/agents to validate an entry\n * before saving it to config. Errors flow back as ApiError. */\nexport function useTestAcp() {\n return useMutation<ACPTestResponse, Error, ACPTestBody>({\n mutationFn: (body) => api.testAcpAgent(body),\n })\n}\n\n/** Probe a `<baseUrl>/.well-known/acp` doc for an agent list. Used\n * by the \"Discover\" form in /settings/agents to bulk-import. The\n * caller still has to PUT /api/config { acpAgents } to persist. */\nexport function useDiscoverAcp() {\n return useMutation<ACPDiscoverResponse, Error, ACPDiscoverBody>({\n mutationFn: (body) => api.discoverAcpAgents(body),\n })\n}\n\n/** Verify SMTP creds in the running env. Doesn't actually send mail —\n * just `nodemailer.verify()`. Returns `{ ok, message }` on success or\n * throws ApiError otherwise (the route catches + toasts the message). */\nexport function useTestEmail() {\n return useMutation<EmailTestResponse, Error, void>({\n mutationFn: () => api.testEmail(),\n })\n}\n\n/** Live viewer config + cloudflared tunnel state. Used by the Viewer\n * card on /settings/viewer to render the \"Tunnel: running / URL: X /\n * binary: …\" panel. Operators click a manual Refresh button to\n * re-fetch — no auto-polling because tunnel state is essentially\n * static between operator actions (start / stop / link expiry). */\nexport function useViewerTunnel() {\n return useQuery<ViewerTunnelStatusResponse>({\n queryKey: ['settings', 'viewer-tunnel'],\n queryFn: () => api.getViewerTunnel(),\n })\n}\n"],"names":["settingsKeys","reveal","useEnv","opts","useQuery","api","useUpdateEnv","qc","useQueryClient","useMutation","body","useServiceStatus","makeServiceMutation","fn","useStartService","useStopService","useRestartService","useAdminAllowlist","useAddAdmin","useRemoveAdmin","useConfig","useUpdateConfig","useWorkspaces","useUpsertWorkspace","useStartWechatQr","useWechatQrStatus","token","useTestAcp","useDiscoverAcp","useTestEmail","useViewerTunnel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-settings-DgU8YmGj.js","sources":["../../src/hooks/use-settings.ts"],"sourcesContent":["/**\n * useSettings — react-query wrappers for the env editor + service\n * control surfaces.\n *\n * useEnv({ reveal }) — env file values (masked when\n * reveal is false)\n * useUpdateEnv() — bulk update\n * useServiceStatus() — pid / mode / uptime\n * useStart/Stop/Restart() — service lifecycle\n *\n * Service status polls every 5s while the page is foreground so\n * the operator sees restart progress live.\n */\n\nimport { useQueryClient, useQuery, useMutation } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type {\n ACPDiscoverBody,\n ACPDiscoverResponse,\n ACPTestBody,\n ACPTestResponse,\n EmailTestResponse,\n ViewerTunnelStatusResponse,\n AddAdminBody,\n AdminAllowlistResponse,\n AdminMutationResponse,\n AppConfig,\n EnvResponse,\n RemoveAdminBody,\n ServiceActionResponse,\n ServiceStatus,\n UpdateEnvBody,\n WechatQrStartResponse,\n WechatQrStatusResponse,\n WorkspaceConfig,\n} from '@/types/api'\n\nexport const settingsKeys = {\n all: ['settings'] as const,\n env: (reveal: boolean) => ['settings', 'env', reveal] as const,\n service: ['settings', 'service'] as const,\n admins: ['settings', 'admins'] as const,\n config: ['settings', 'config'] as const,\n workspaces: ['settings', 'workspaces'] as const,\n}\n\nexport function useEnv(opts: { reveal?: boolean } = {}) {\n const reveal = !!opts.reveal\n return useQuery<EnvResponse>({\n queryKey: settingsKeys.env(reveal),\n queryFn: () => api.getEnv({ reveal }),\n })\n}\n\nexport function useUpdateEnv() {\n const qc = useQueryClient()\n return useMutation<EnvResponse, Error, UpdateEnvBody>({\n mutationFn: (body) => api.updateEnv(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: ['settings', 'env'] }),\n })\n}\n\nexport function useServiceStatus() {\n return useQuery<ServiceStatus>({\n queryKey: settingsKeys.service,\n queryFn: () => api.getServiceStatus(),\n refetchInterval: 5000,\n refetchIntervalInBackground: false,\n })\n}\n\nfunction makeServiceMutation(\n fn: () => Promise<ServiceActionResponse>,\n qc: ReturnType<typeof useQueryClient>,\n) {\n return useMutation<ServiceActionResponse, Error, void>({\n mutationFn: fn,\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.service }),\n })\n}\n\nexport function useStartService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.startService(), qc)\n}\n\nexport function useStopService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.stopService(), qc)\n}\n\nexport function useRestartService() {\n const qc = useQueryClient()\n return makeServiceMutation(() => api.restartService(), qc)\n}\n\n/* ─────────────── Admin allowlist ─────────────── */\n\nexport function useAdminAllowlist() {\n return useQuery<AdminAllowlistResponse>({\n queryKey: settingsKeys.admins,\n queryFn: () => api.listAdminAllowlist(),\n })\n}\n\nexport function useAddAdmin() {\n const qc = useQueryClient()\n return useMutation<AdminMutationResponse, Error, AddAdminBody>({\n mutationFn: (body) => api.addAdminAllowlist(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.admins }),\n })\n}\n\nexport function useRemoveAdmin() {\n const qc = useQueryClient()\n return useMutation<AdminMutationResponse, Error, RemoveAdminBody>({\n mutationFn: (body) => api.removeAdminAllowlist(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.admins }),\n })\n}\n\n/* ─────────────── App config ─────────────── */\n\nexport function useConfig() {\n return useQuery<AppConfig>({\n queryKey: settingsKeys.config,\n queryFn: () => api.getConfig(),\n })\n}\n\nexport function useUpdateConfig() {\n const qc = useQueryClient()\n return useMutation<AppConfig, Error, Partial<AppConfig>>({\n mutationFn: (body) => api.updateConfig(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.config }),\n })\n}\n\n/* ─────────────── Workspaces ─────────────── */\n\nexport function useWorkspaces() {\n return useQuery<{ workspaces: WorkspaceConfig[] }>({\n queryKey: settingsKeys.workspaces,\n queryFn: () => api.listWorkspacesFull(),\n })\n}\n\nexport function useUpsertWorkspace() {\n const qc = useQueryClient()\n return useMutation<\n { ok: boolean; workspace: WorkspaceConfig },\n Error,\n WorkspaceConfig\n >({\n mutationFn: (body) => api.upsertWorkspace(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: settingsKeys.workspaces }),\n })\n}\n\n/* ─────────────── WeChat QR ─────────────── */\n\nexport function useStartWechatQr() {\n return useMutation<WechatQrStartResponse, Error, void>({\n mutationFn: () => api.startWechatQr(),\n })\n}\n\n/** Poll the QR status every 2s while the modal is open. Caller\n * passes `token` once it has it from the start mutation; passing\n * null disables the polling. On status='confirmed' the backend\n * persists wechat-ilink → re-fetch config to update the toggle. */\nexport function useWechatQrStatus(token: string | null) {\n return useQuery<WechatQrStatusResponse>({\n queryKey: ['settings', 'wechat-qr', token ?? ''],\n queryFn: () => api.getWechatQrStatus({ token: token as string }),\n enabled: Boolean(token),\n refetchInterval: 2000,\n refetchIntervalInBackground: false,\n })\n}\n\n/** Probe a single ACP endpoint by fetching its manifest. Used by\n * the \"Test\" buttons in /settings/agents to validate an entry\n * before saving it to config. Errors flow back as ApiError. */\nexport function useTestAcp() {\n return useMutation<ACPTestResponse, Error, ACPTestBody>({\n mutationFn: (body) => api.testAcpAgent(body),\n })\n}\n\n/** Probe a `<baseUrl>/.well-known/acp` doc for an agent list. Used\n * by the \"Discover\" form in /settings/agents to bulk-import. The\n * caller still has to PUT /api/config { acpAgents } to persist. */\nexport function useDiscoverAcp() {\n return useMutation<ACPDiscoverResponse, Error, ACPDiscoverBody>({\n mutationFn: (body) => api.discoverAcpAgents(body),\n })\n}\n\n/** Verify SMTP creds in the running env. Doesn't actually send mail —\n * just `nodemailer.verify()`. Returns `{ ok, message }` on success or\n * throws ApiError otherwise (the route catches + toasts the message). */\nexport function useTestEmail() {\n return useMutation<EmailTestResponse, Error, void>({\n mutationFn: () => api.testEmail(),\n })\n}\n\n/** Live viewer config + cloudflared tunnel state. Used by the Viewer\n * card on /settings/viewer to render the \"Tunnel: running / URL: X /\n * binary: …\" panel. Operators click a manual Refresh button to\n * re-fetch — no auto-polling because tunnel state is essentially\n * static between operator actions (start / stop / link expiry). */\nexport function useViewerTunnel() {\n return useQuery<ViewerTunnelStatusResponse>({\n queryKey: ['settings', 'viewer-tunnel'],\n queryFn: () => api.getViewerTunnel(),\n })\n}\n"],"names":["settingsKeys","reveal","useEnv","opts","useQuery","api","useUpdateEnv","qc","useQueryClient","useMutation","body","useServiceStatus","makeServiceMutation","fn","useStartService","useStopService","useRestartService","useAdminAllowlist","useAddAdmin","useRemoveAdmin","useConfig","useUpdateConfig","useWorkspaces","useUpsertWorkspace","useStartWechatQr","useWechatQrStatus","token","useTestAcp","useDiscoverAcp","useTestEmail","useViewerTunnel"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as l}from"./useQuery-
|
|
2
|
-
//# sourceMappingURL=use-skills-
|
|
1
|
+
import{u as l}from"./useQuery-BjFqOBV3.js";import{q as t}from"./index-B48azMO-.js";const s={all:["skills"],list:["skills","list"],detail:e=>["skills","detail",e],remoteHot:["skills","remote","hot"]};function r(){return l({queryKey:s.list,queryFn:()=>t.listSkills()})}function u(e){return l({queryKey:s.detail(e??""),queryFn:()=>t.getSkillDetail(e),enabled:!!e})}function a(){return l({queryKey:s.remoteHot,queryFn:()=>t.getSkillsRemoteHot(),staleTime:6e4})}export{r as a,a as b,u};
|
|
2
|
+
//# sourceMappingURL=use-skills-Cp_ok0Uq.js.map
|