agent-relay-server 0.121.0 → 0.121.1
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/docs/openapi.json +1 -1
- package/package.json +5 -4
- package/public/assets/{MessageBubble-BaPGFJxq.js → MessageBubble-CLqxCG9b.js} +2 -2
- package/public/assets/{MessageBubble-BaPGFJxq.js.map → MessageBubble-CLqxCG9b.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-BXCVfmln.js → PlanGraphPanel-BkkToFEb.js} +2 -2
- package/public/assets/{PlanGraphPanel-BXCVfmln.js.map → PlanGraphPanel-BkkToFEb.js.map} +1 -1
- package/public/assets/{activity-D_shwAZt.js → activity-D-ocGQGs.js} +2 -2
- package/public/assets/{activity-D_shwAZt.js.map → activity-D-ocGQGs.js.map} +1 -1
- package/public/assets/{agent-profiles-BrfVz5IV.js → agent-profiles-CRPgYTyb.js} +2 -2
- package/public/assets/{agent-profiles-BrfVz5IV.js.map → agent-profiles-CRPgYTyb.js.map} +1 -1
- package/public/assets/{agents-B5w-Z9Ic.js → agents-Chw5E_2q.js} +2 -2
- package/public/assets/{agents-B5w-Z9Ic.js.map → agents-Chw5E_2q.js.map} +1 -1
- package/public/assets/{analytics-Bm3D12UN.js → analytics-BmNDG0hR.js} +2 -2
- package/public/assets/{analytics-Bm3D12UN.js.map → analytics-BmNDG0hR.js.map} +1 -1
- package/public/assets/{automation-DOTL8BFs.js → automation-D7g90kTv.js} +2 -2
- package/public/assets/{automation-DOTL8BFs.js.map → automation-D7g90kTv.js.map} +1 -1
- package/public/assets/{branch-state-badge-BlqeJZ5-.js → branch-state-badge-Bv7DhLBZ.js} +2 -2
- package/public/assets/{branch-state-badge-BlqeJZ5-.js.map → branch-state-badge-Bv7DhLBZ.js.map} +1 -1
- package/public/assets/{channels-BoiKfK6Q.js → channels-CLwPeEPi.js} +2 -2
- package/public/assets/{channels-BoiKfK6Q.js.map → channels-CLwPeEPi.js.map} +1 -1
- package/public/assets/{chat-PeU3iOaa.js → chat-Cgj7VKzc.js} +2 -2
- package/public/assets/{chat-PeU3iOaa.js.map → chat-Cgj7VKzc.js.map} +1 -1
- package/public/assets/{connectors-BvV8Hee2.js → connectors-Br6fiTny.js} +2 -2
- package/public/assets/{connectors-BvV8Hee2.js.map → connectors-Br6fiTny.js.map} +1 -1
- package/public/assets/{formatted-body-C1FgzlT1.js → formatted-body-CmkuD23M.js} +3 -3
- package/public/assets/{formatted-body-C1FgzlT1.js.map → formatted-body-CmkuD23M.js.map} +1 -1
- package/public/assets/{formatted-body-impl-BTpU1xH4.js → formatted-body-impl-DbdFmbwW.js} +2 -2
- package/public/assets/{formatted-body-impl-BTpU1xH4.js.map → formatted-body-impl-DbdFmbwW.js.map} +1 -1
- package/public/assets/{index-DZEahmyc.js → index-D9OogaB5.js} +6 -6
- package/public/assets/{index-DZEahmyc.js.map → index-D9OogaB5.js.map} +1 -1
- package/public/assets/{insights-BqmgSpQm.js → insights-qvaPqWCV.js} +2 -2
- package/public/assets/{insights-BqmgSpQm.js.map → insights-qvaPqWCV.js.map} +1 -1
- package/public/assets/{integrations-CuT92zQi.js → integrations-DYEGSqq_.js} +2 -2
- package/public/assets/{integrations-CuT92zQi.js.map → integrations-DYEGSqq_.js.map} +1 -1
- package/public/assets/{maintenance-lM7FeXVC.js → maintenance-C0HIEB-J.js} +2 -2
- package/public/assets/{maintenance-lM7FeXVC.js.map → maintenance-C0HIEB-J.js.map} +1 -1
- package/public/assets/{managed-agents-DaPNv3yY.js → managed-agents-DdS7aI38.js} +2 -2
- package/public/assets/{managed-agents-DaPNv3yY.js.map → managed-agents-DdS7aI38.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-Wia3Ho1s.js → markdown-preview-impl-BnXMH1z1.js} +2 -2
- package/public/assets/{markdown-preview-impl-Wia3Ho1s.js.map → markdown-preview-impl-BnXMH1z1.js.map} +1 -1
- package/public/assets/{memory-B1v_zD-M.js → memory-CSwx7bz8.js} +2 -2
- package/public/assets/{memory-B1v_zD-M.js.map → memory-CSwx7bz8.js.map} +1 -1
- package/public/assets/{messages-BNOx3yK6.js → messages-Be9CmvDv.js} +2 -2
- package/public/assets/{messages-BNOx3yK6.js.map → messages-Be9CmvDv.js.map} +1 -1
- package/public/assets/{orchestrators-DWFy4asl.js → orchestrators-BgtvvHvo.js} +2 -2
- package/public/assets/{orchestrators-DWFy4asl.js.map → orchestrators-BgtvvHvo.js.map} +1 -1
- package/public/assets/{overview-C_12cFPM.js → overview-BvhbPWtF.js} +2 -2
- package/public/assets/{overview-C_12cFPM.js.map → overview-BvhbPWtF.js.map} +1 -1
- package/public/assets/{pairs-DIc7gX83.js → pairs-CpXSOMx0.js} +2 -2
- package/public/assets/{pairs-DIc7gX83.js.map → pairs-CpXSOMx0.js.map} +1 -1
- package/public/assets/{projects-DPjvJUzT.js → projects-DdPNPFJI.js} +2 -2
- package/public/assets/{projects-DPjvJUzT.js.map → projects-DdPNPFJI.js.map} +1 -1
- package/public/assets/{prompt-settings-CtumNgG8.js → prompt-settings-BpZse7-X.js} +2 -2
- package/public/assets/{prompt-settings-CtumNgG8.js.map → prompt-settings-BpZse7-X.js.map} +1 -1
- package/public/assets/{registry-DzUhgMq9.js → registry-pb1gTZEg.js} +2 -2
- package/public/assets/{registry-DzUhgMq9.js.map → registry-pb1gTZEg.js.map} +1 -1
- package/public/assets/{security-BJ3_u0uY.js → security-BgcX1n9D.js} +2 -2
- package/public/assets/{security-BJ3_u0uY.js.map → security-BgcX1n9D.js.map} +1 -1
- package/public/assets/{select-AWvlctyQ.js → select-DZPVpKPv.js} +2 -2
- package/public/assets/{select-AWvlctyQ.js.map → select-DZPVpKPv.js.map} +1 -1
- package/public/assets/{settings-5ofqi-bN.js → settings-hd5kzdRB.js} +2 -2
- package/public/assets/{settings-5ofqi-bN.js.map → settings-hd5kzdRB.js.map} +1 -1
- package/public/assets/store-DKTLubBT.js +9 -0
- package/public/assets/store-DKTLubBT.js.map +1 -0
- package/public/assets/{tasks-BEE9bBf7.js → tasks-C5d2LU5E.js} +2 -2
- package/public/assets/{tasks-BEE9bBf7.js.map → tasks-C5d2LU5E.js.map} +1 -1
- package/public/assets/{teams-C27H_Gwo.js → teams-B8f2pGJe.js} +2 -2
- package/public/assets/{teams-C27H_Gwo.js.map → teams-B8f2pGJe.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-WD2TboA7.js → terminal-viewer-impl-CxAscH0U.js} +2 -2
- package/public/assets/{terminal-viewer-impl-WD2TboA7.js.map → terminal-viewer-impl-CxAscH0U.js.map} +1 -1
- package/public/assets/types-uVOXgvMT.js.map +1 -1
- package/public/assets/{work-queue-CtmPK2hK.js → work-queue-9imc7aNK.js} +2 -2
- package/public/assets/{work-queue-CtmPK2hK.js.map → work-queue-9imc7aNK.js.map} +1 -1
- package/public/assets/{workspaces-B26EKv_H.js → workspaces-CLYc3yF3.js} +2 -2
- package/public/assets/{workspaces-B26EKv_H.js.map → workspaces-CLYc3yF3.js.map} +1 -1
- package/public/index.html +3 -3
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +4 -0
- package/src/agent-issue-repo.ts +10 -3
- package/src/agent-lifecycle-events.ts +23 -1
- package/src/agent-ref.ts +18 -3
- package/src/bus-outbox.ts +44 -1
- package/src/bus.ts +28 -5
- package/src/channel-target.ts +4 -0
- package/src/cli/steward.ts +15 -14
- package/src/commands-db.ts +63 -9
- package/src/config.ts +50 -0
- package/src/db/claim-sql.ts +16 -0
- package/src/db/continuations.ts +44 -3
- package/src/db/message-reads.ts +34 -4
- package/src/db/messages.ts +128 -4
- package/src/db/pairs.ts +1 -0
- package/src/db/schema.ts +6 -0
- package/src/gate-resolver.ts +124 -0
- package/src/lifecycle-manager.ts +41 -10
- package/src/lifecycle-signal-registry.ts +87 -0
- package/src/maintenance/constants.ts +5 -1
- package/src/maintenance/jobs.ts +28 -2
- package/src/maintenance/workspaces.ts +75 -44
- package/src/managed-policy-escalation.ts +68 -3
- package/src/mcp/tools-spawn.ts +16 -6
- package/src/mcp-plan-tools.ts +2 -3
- package/src/notification-settings.ts +11 -0
- package/src/notification-types.ts +4 -0
- package/src/operator-alarm.ts +37 -0
- package/src/routes/agents.ts +4 -0
- package/src/routes/orchestrator-proxy.ts +13 -1
- package/src/routes/orchestrator.ts +4 -0
- package/src/security.ts +20 -0
- package/src/self-resume.ts +185 -21
- package/src/server.ts +2 -0
- package/src/services/plan-graph.ts +42 -12
- package/src/services/register-agent.ts +5 -1
- package/src/services/send-message.ts +36 -0
- package/src/services/spawn-agent.ts +21 -2
- package/src/services/task-semantic-events.ts +17 -1
- package/src/spawn-command.ts +3 -0
- package/src/spawn-targets.ts +26 -1
- package/src/sse.ts +13 -5
- package/src/workspace-auto-merge.ts +90 -34
- package/src/workspace-escalation.ts +52 -3
- package/src/workspace-human-escalation.ts +68 -0
- package/src/workspace-orphans.ts +11 -6
- package/src/workspace-phase.ts +22 -1
- package/public/assets/store-D5et8685.js +0 -9
- package/public/assets/store-D5et8685.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{L as t,hr as n,nr as r,rr as i,yt as a}from"./lucide-react-DuhlF2Sj.js";import{u as o}from"./types-uVOXgvMT.js";import{K as s}from"./display-exQDWum3.js";import{t as c}from"./badge-DCIT3Irj.js";import{t as l}from"./button-CzdTkRIf.js";import{t as u}from"./input-B6Q0NWCS.js";import{yt as d}from"./index-
|
|
2
|
-
//# sourceMappingURL=insights-
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{L as t,hr as n,nr as r,rr as i,yt as a}from"./lucide-react-DuhlF2Sj.js";import{u as o}from"./types-uVOXgvMT.js";import{K as s}from"./display-exQDWum3.js";import{t as c}from"./badge-DCIT3Irj.js";import{t as l}from"./button-CzdTkRIf.js";import{t as u}from"./input-B6Q0NWCS.js";import{yt as d}from"./index-D9OogaB5.js";import{o as f,r as p,s as m,t as h}from"./card-C3BGuVC6.js";var g=e(n(),1),_=r(),v={enabled:!0,contextRatio:{enabled:!0},introspection:{enabled:!0,minTurns:4,minContextRemaining:.15}};function y(e){return!e||Object.keys(e).length===0?`—`:Object.entries(e).map(([e,t])=>`${e}: ${typeof t==`number`?Math.round(t*1e3)/1e3:String(t)}`).join(` `)}function b(){let[e,n]=(0,g.useState)(v),[r,b]=(0,g.useState)(0),[x,S]=(0,g.useState)([]),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)([]),[D,O]=(0,g.useState)(``),[k,A]=(0,g.useState)(``),[j,M]=(0,g.useState)(!1),[N,P]=(0,g.useState)(null),[F,I]=(0,g.useState)(()=>Date.now());async function L(){P(null);try{let e=new URLSearchParams;D&&e.set(`project`,D),k&&e.set(`signal`,k);let t=e.toString(),[r,a]=await Promise.all([i(`GET`,`/insights/config`),i(`GET`,`/insights/observations${t?`?${t}`:``}`)]);n(r.value),b(r.version),S(a.observations),w(a.stats),E(a.projects),I(Date.now())}catch(e){P(o(e))}}(0,g.useEffect)(()=>{L()},[D,k]);async function R(t){M(!0),P(null);let r=e;n(t);try{let e=await i(`PUT`,`/insights/config`,{value:t,updatedBy:`dashboard`});n(e.value),b(e.version)}catch(e){n(r),P(o(e))}finally{M(!1)}}let z=(0,g.useMemo)(()=>[...new Set(C.map(e=>e.signal))].sort(),[C]),B=(0,g.useMemo)(()=>C.filter(e=>e.project===null),[C]),V=(0,g.useMemo)(()=>C.filter(e=>e.project!==null),[C]);return(0,_.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(a,{className:`size-5 text-primary`}),(0,_.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Insights`}),(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`continuous self-improvement · epic #183`})]}),(0,_.jsxs)(l,{variant:`outline`,size:`sm`,onClick:()=>void L(),children:[(0,_.jsx)(t,{className:`size-4`}),` Refresh`]})]}),N&&(0,_.jsx)(`div`,{className:`rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:N}),(0,_.jsxs)(h,{children:[(0,_.jsx)(f,{children:(0,_.jsxs)(m,{className:`flex items-center justify-between`,children:[(0,_.jsx)(`span`,{children:`Features`}),(0,_.jsxs)(`span`,{className:`text-xs font-normal text-muted-foreground`,children:[`config v`,r,` · saved by `,e&&`dashboard`]})]})}),(0,_.jsxs)(p,{className:`space-y-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`div`,{className:`text-sm font-medium`,children:`Insights enabled`}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Master switch. When off, no signals are recorded regardless of the toggles below.`})]}),(0,_.jsx)(d,{checked:e.enabled,disabled:j,onCheckedChange:t=>void R({...e,enabled:t})})]}),(0,_.jsxs)(`div`,{className:`flex items-center justify-between border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`Context-gathering ratio `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#184)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Server-side: read/search vs. action before first substantive move, per session.`})]}),(0,_.jsx)(d,{checked:e.contextRatio.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,contextRatio:{enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`End-of-session introspection `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#185)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Agent-authored 3-field artifact at session end. Gated below.`})]}),(0,_.jsx)(d,{checked:e.introspection.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,introspection:{...e.introspection,enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-4`,children:[(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min turns`,(0,_.jsx)(u,{type:`number`,className:`h-7 w-20`,value:e.introspection.minTurns,disabled:j||!e.enabled||!e.introspection.enabled,onChange:t=>n({...e,introspection:{...e.introspection,minTurns:Number(t.target.value)}}),onBlur:()=>void R(e)})]}),(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min context remaining (0–1)`,(0,_.jsx)(u,{type:`number`,step:`0.05`,min:`0`,max:`1`,className:`h-7 w-24`,value:e.introspection.minContextRemaining,disabled:j||!e.enabled||!e.introspection.enabled,onChange:t=>n({...e,introspection:{...e.introspection,minContextRemaining:Number(t.target.value)}}),onBlur:()=>void R(e)})]})]})]})]})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(f,{children:(0,_.jsx)(m,{children:`Signals`})}),(0,_.jsx)(p,{children:B.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations yet — they appear after sessions end with Insights enabled.`}):(0,_.jsx)(`div`,{className:`space-y-4`,children:B.map(e=>(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`mb-1 flex items-center gap-2`,children:[(0,_.jsx)(c,{variant:`secondary`,children:e.signal}),(0,_.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[e.count,` obs · `,e.avgRatio===null?`no ratio`:`avg ratio ${e.avgRatio.toFixed(2)}`,` · `,s(F,e.lastAt)]})]}),(0,_.jsx)(`div`,{className:`flex flex-wrap gap-2 pl-2`,children:V.filter(t=>t.signal===e.signal).map(t=>(0,_.jsxs)(`span`,{className:`rounded border border-border px-2 py-0.5 text-xs text-muted-foreground`,children:[t.project,`: `,t.count,t.avgRatio===null?``:` · ${t.avgRatio.toFixed(2)}`]},`${e.signal}-${t.project}`))})]},e.signal))})})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(f,{children:(0,_.jsxs)(m,{className:`flex flex-wrap items-center gap-3`,children:[(0,_.jsx)(`span`,{children:`Observations`}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:D,onChange:e=>O(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all projects`}),T.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:k,onChange:e=>A(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all signals`}),z.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]})]})}),(0,_.jsx)(p,{children:x.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations match.`}):(0,_.jsx)(`div`,{className:`overflow-x-auto`,children:(0,_.jsxs)(`table`,{className:`w-full min-w-[680px] text-left text-xs`,children:[(0,_.jsx)(`thead`,{className:`text-muted-foreground`,children:(0,_.jsxs)(`tr`,{className:`border-b border-border`,children:[(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`when`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`project`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`signal`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`src`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`value`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`outcome`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`session`})]})}),(0,_.jsx)(`tbody`,{children:x.map(e=>(0,_.jsxs)(`tr`,{className:`border-b border-border/50`,children:[(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:s(F,e.createdAt)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:e.project}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:(0,_.jsx)(c,{variant:`outline`,children:e.signal})}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.source}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono`,children:y(e.value)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono text-muted-foreground`,children:y(e.outcome)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.agentId??e.sessionId.slice(0,12)})]},e.id))})]})})})]})]})}export{b as InsightsView};
|
|
2
|
+
//# sourceMappingURL=insights-qvaPqWCV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insights-BqmgSpQm.js","names":[],"sources":["../../dashboard/src/components/views/insights.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { errMessage } from 'agent-relay-sdk/types'\nimport { api } from '@/lib/api'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { timeAgo } from '@/lib/display'\nimport { Lightbulb, RefreshCw } from 'lucide-react'\n\n// Insights — continuous self-improvement module (epic #183, docs/self-improvement.md).\n// v0: feature toggles + a raw per-project/global view of the observations the relay\n// collects. No charts, no alerting — the data earns those once a week proves it's real.\n\ninterface InsightsConfig {\n enabled: boolean\n contextRatio: { enabled: boolean }\n introspection: { enabled: boolean; minTurns: number; minContextRemaining: number }\n}\n\ninterface ConfigEntry {\n value: InsightsConfig\n version: number\n updatedAt: string\n updatedBy?: string\n}\n\ninterface Observation {\n id: number\n sessionId: string\n agentId?: string\n project: string\n signal: string\n value: Record<string, unknown>\n outcome?: Record<string, unknown>\n source: 'server' | 'agent'\n createdAt: number\n}\n\ninterface Stat {\n signal: string\n project: string | null\n count: number\n avgRatio: number | null\n lastAt: number | null\n}\n\ninterface ObservationsResponse {\n observations: Observation[]\n stats: Stat[]\n projects: string[]\n}\n\nconst DEFAULT_CONFIG: InsightsConfig = {\n enabled: true,\n contextRatio: { enabled: true },\n introspection: { enabled: true, minTurns: 4, minContextRemaining: 0.15 },\n}\n\nfunction compactJson(value: Record<string, unknown> | undefined): string {\n if (!value || Object.keys(value).length === 0) return '—'\n return Object.entries(value)\n .map(([k, v]) => `${k}: ${typeof v === 'number' ? Math.round(v * 1000) / 1000 : String(v)}`)\n .join(' ')\n}\n\nexport function InsightsView() {\n const [config, setConfig] = useState<InsightsConfig>(DEFAULT_CONFIG)\n const [version, setVersion] = useState(0)\n const [observations, setObservations] = useState<Observation[]>([])\n const [stats, setStats] = useState<Stat[]>([])\n const [projects, setProjects] = useState<string[]>([])\n const [projectFilter, setProjectFilter] = useState<string>('')\n const [signalFilter, setSignalFilter] = useState<string>('')\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [now, setNow] = useState(() => Date.now())\n\n async function refresh() {\n setError(null)\n try {\n const params = new URLSearchParams()\n if (projectFilter) params.set('project', projectFilter)\n if (signalFilter) params.set('signal', signalFilter)\n const query = params.toString()\n const [cfg, obs] = await Promise.all([\n api<ConfigEntry>('GET', '/insights/config'),\n api<ObservationsResponse>('GET', `/insights/observations${query ? `?${query}` : ''}`),\n ])\n setConfig(cfg.value)\n setVersion(cfg.version)\n setObservations(obs.observations)\n setStats(obs.stats)\n setProjects(obs.projects)\n setNow(Date.now())\n } catch (e) {\n setError(errMessage(e))\n }\n }\n\n // Mount + filter-change: synchronize the view with the relay's stored data.\n useEffect(() => {\n void refresh()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [projectFilter, signalFilter])\n\n async function saveConfig(next: InsightsConfig) {\n setSaving(true)\n setError(null)\n const previous = config\n setConfig(next) // optimistic\n try {\n const entry = await api<ConfigEntry>('PUT', '/insights/config', { value: next, updatedBy: 'dashboard' })\n setConfig(entry.value)\n setVersion(entry.version)\n } catch (e) {\n setConfig(previous) // revert on failure\n setError(errMessage(e))\n } finally {\n setSaving(false)\n }\n }\n\n const signals = useMemo(() => {\n const set = new Set<string>(stats.map((s) => s.signal))\n return [...set].sort()\n }, [stats])\n\n const globalStats = useMemo(() => stats.filter((s) => s.project === null), [stats])\n const projectStats = useMemo(() => stats.filter((s) => s.project !== null), [stats])\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Lightbulb className=\"size-5 text-primary\" />\n <h1 className=\"text-lg font-semibold\">Insights</h1>\n <span className=\"text-xs text-muted-foreground\">continuous self-improvement · epic #183</span>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void refresh()}>\n <RefreshCw className=\"size-4\" /> Refresh\n </Button>\n </div>\n\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">{error}</div>\n )}\n\n {/* Feature toggles */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Features</span>\n <span className=\"text-xs font-normal text-muted-foreground\">config v{version} · saved by {config && 'dashboard'}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">Insights enabled</div>\n <div className=\"text-xs text-muted-foreground\">Master switch. When off, no signals are recorded regardless of the toggles below.</div>\n </div>\n <Switch checked={config.enabled} disabled={saving} onCheckedChange={(v) => void saveConfig({ ...config, enabled: v })} />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border pt-3\">\n <div>\n <div className=\"text-sm font-medium\">Context-gathering ratio <span className=\"text-xs text-muted-foreground\">(#184)</span></div>\n <div className=\"text-xs text-muted-foreground\">Server-side: read/search vs. action before first substantive move, per session.</div>\n </div>\n <Switch checked={config.contextRatio.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, contextRatio: { enabled: v } })} />\n </div>\n\n <div className=\"border-t border-border pt-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">End-of-session introspection <span className=\"text-xs text-muted-foreground\">(#185)</span></div>\n <div className=\"text-xs text-muted-foreground\">Agent-authored 3-field artifact at session end. Gated below.</div>\n </div>\n <Switch checked={config.introspection.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, introspection: { ...config.introspection, enabled: v } })} />\n </div>\n <div className=\"mt-3 flex flex-wrap gap-4\">\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min turns\n <Input type=\"number\" className=\"h-7 w-20\" value={config.introspection.minTurns}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minTurns: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min context remaining (0–1)\n <Input type=\"number\" step=\"0.05\" min=\"0\" max=\"1\" className=\"h-7 w-24\" value={config.introspection.minContextRemaining}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minContextRemaining: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Stats rollup */}\n <Card>\n <CardHeader>\n <CardTitle>Signals</CardTitle>\n </CardHeader>\n <CardContent>\n {globalStats.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations yet — they appear after sessions end with Insights enabled.</div>\n ) : (\n <div className=\"space-y-4\">\n {globalStats.map((g) => (\n <div key={g.signal}>\n <div className=\"mb-1 flex items-center gap-2\">\n <Badge variant=\"secondary\">{g.signal}</Badge>\n <span className=\"text-xs text-muted-foreground\">\n {g.count} obs · {g.avgRatio !== null ? `avg ratio ${g.avgRatio.toFixed(2)}` : 'no ratio'} · {timeAgo(now, g.lastAt)}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2 pl-2\">\n {projectStats.filter((p) => p.signal === g.signal).map((p) => (\n <span key={`${g.signal}-${p.project}`} className=\"rounded border border-border px-2 py-0.5 text-xs text-muted-foreground\">\n {p.project}: {p.count}{p.avgRatio !== null ? ` · ${p.avgRatio.toFixed(2)}` : ''}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Raw observations */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-3\">\n <span>Observations</span>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={projectFilter} onChange={(e) => setProjectFilter(e.target.value)}>\n <option value=\"\">all projects</option>\n {projects.map((p) => <option key={p} value={p}>{p}</option>)}\n </select>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={signalFilter} onChange={(e) => setSignalFilter(e.target.value)}>\n <option value=\"\">all signals</option>\n {signals.map((s) => <option key={s} value={s}>{s}</option>)}\n </select>\n </CardTitle>\n </CardHeader>\n <CardContent>\n {observations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations match.</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[680px] text-left text-xs\">\n <thead className=\"text-muted-foreground\">\n <tr className=\"border-b border-border\">\n <th className=\"py-1 pr-3 font-medium\">when</th>\n <th className=\"py-1 pr-3 font-medium\">project</th>\n <th className=\"py-1 pr-3 font-medium\">signal</th>\n <th className=\"py-1 pr-3 font-medium\">src</th>\n <th className=\"py-1 pr-3 font-medium\">value</th>\n <th className=\"py-1 pr-3 font-medium\">outcome</th>\n <th className=\"py-1 pr-3 font-medium\">session</th>\n </tr>\n </thead>\n <tbody>\n {observations.map((o) => (\n <tr key={o.id} className=\"border-b border-border/50\">\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{timeAgo(now, o.createdAt)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\">{o.project}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\"><Badge variant=\"outline\">{o.signal}</Badge></td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.source}</td>\n <td className=\"py-1 pr-3 font-mono\">{compactJson(o.value)}</td>\n <td className=\"py-1 pr-3 font-mono text-muted-foreground\">{compactJson(o.outcome)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.agentId ?? o.sessionId.slice(0, 12)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"insights-qvaPqWCV.js","names":[],"sources":["../../dashboard/src/components/views/insights.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { errMessage } from 'agent-relay-sdk/types'\nimport { api } from '@/lib/api'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { timeAgo } from '@/lib/display'\nimport { Lightbulb, RefreshCw } from 'lucide-react'\n\n// Insights — continuous self-improvement module (epic #183, docs/self-improvement.md).\n// v0: feature toggles + a raw per-project/global view of the observations the relay\n// collects. No charts, no alerting — the data earns those once a week proves it's real.\n\ninterface InsightsConfig {\n enabled: boolean\n contextRatio: { enabled: boolean }\n introspection: { enabled: boolean; minTurns: number; minContextRemaining: number }\n}\n\ninterface ConfigEntry {\n value: InsightsConfig\n version: number\n updatedAt: string\n updatedBy?: string\n}\n\ninterface Observation {\n id: number\n sessionId: string\n agentId?: string\n project: string\n signal: string\n value: Record<string, unknown>\n outcome?: Record<string, unknown>\n source: 'server' | 'agent'\n createdAt: number\n}\n\ninterface Stat {\n signal: string\n project: string | null\n count: number\n avgRatio: number | null\n lastAt: number | null\n}\n\ninterface ObservationsResponse {\n observations: Observation[]\n stats: Stat[]\n projects: string[]\n}\n\nconst DEFAULT_CONFIG: InsightsConfig = {\n enabled: true,\n contextRatio: { enabled: true },\n introspection: { enabled: true, minTurns: 4, minContextRemaining: 0.15 },\n}\n\nfunction compactJson(value: Record<string, unknown> | undefined): string {\n if (!value || Object.keys(value).length === 0) return '—'\n return Object.entries(value)\n .map(([k, v]) => `${k}: ${typeof v === 'number' ? Math.round(v * 1000) / 1000 : String(v)}`)\n .join(' ')\n}\n\nexport function InsightsView() {\n const [config, setConfig] = useState<InsightsConfig>(DEFAULT_CONFIG)\n const [version, setVersion] = useState(0)\n const [observations, setObservations] = useState<Observation[]>([])\n const [stats, setStats] = useState<Stat[]>([])\n const [projects, setProjects] = useState<string[]>([])\n const [projectFilter, setProjectFilter] = useState<string>('')\n const [signalFilter, setSignalFilter] = useState<string>('')\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [now, setNow] = useState(() => Date.now())\n\n async function refresh() {\n setError(null)\n try {\n const params = new URLSearchParams()\n if (projectFilter) params.set('project', projectFilter)\n if (signalFilter) params.set('signal', signalFilter)\n const query = params.toString()\n const [cfg, obs] = await Promise.all([\n api<ConfigEntry>('GET', '/insights/config'),\n api<ObservationsResponse>('GET', `/insights/observations${query ? `?${query}` : ''}`),\n ])\n setConfig(cfg.value)\n setVersion(cfg.version)\n setObservations(obs.observations)\n setStats(obs.stats)\n setProjects(obs.projects)\n setNow(Date.now())\n } catch (e) {\n setError(errMessage(e))\n }\n }\n\n // Mount + filter-change: synchronize the view with the relay's stored data.\n useEffect(() => {\n void refresh()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [projectFilter, signalFilter])\n\n async function saveConfig(next: InsightsConfig) {\n setSaving(true)\n setError(null)\n const previous = config\n setConfig(next) // optimistic\n try {\n const entry = await api<ConfigEntry>('PUT', '/insights/config', { value: next, updatedBy: 'dashboard' })\n setConfig(entry.value)\n setVersion(entry.version)\n } catch (e) {\n setConfig(previous) // revert on failure\n setError(errMessage(e))\n } finally {\n setSaving(false)\n }\n }\n\n const signals = useMemo(() => {\n const set = new Set<string>(stats.map((s) => s.signal))\n return [...set].sort()\n }, [stats])\n\n const globalStats = useMemo(() => stats.filter((s) => s.project === null), [stats])\n const projectStats = useMemo(() => stats.filter((s) => s.project !== null), [stats])\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Lightbulb className=\"size-5 text-primary\" />\n <h1 className=\"text-lg font-semibold\">Insights</h1>\n <span className=\"text-xs text-muted-foreground\">continuous self-improvement · epic #183</span>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void refresh()}>\n <RefreshCw className=\"size-4\" /> Refresh\n </Button>\n </div>\n\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">{error}</div>\n )}\n\n {/* Feature toggles */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Features</span>\n <span className=\"text-xs font-normal text-muted-foreground\">config v{version} · saved by {config && 'dashboard'}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">Insights enabled</div>\n <div className=\"text-xs text-muted-foreground\">Master switch. When off, no signals are recorded regardless of the toggles below.</div>\n </div>\n <Switch checked={config.enabled} disabled={saving} onCheckedChange={(v) => void saveConfig({ ...config, enabled: v })} />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border pt-3\">\n <div>\n <div className=\"text-sm font-medium\">Context-gathering ratio <span className=\"text-xs text-muted-foreground\">(#184)</span></div>\n <div className=\"text-xs text-muted-foreground\">Server-side: read/search vs. action before first substantive move, per session.</div>\n </div>\n <Switch checked={config.contextRatio.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, contextRatio: { enabled: v } })} />\n </div>\n\n <div className=\"border-t border-border pt-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">End-of-session introspection <span className=\"text-xs text-muted-foreground\">(#185)</span></div>\n <div className=\"text-xs text-muted-foreground\">Agent-authored 3-field artifact at session end. Gated below.</div>\n </div>\n <Switch checked={config.introspection.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, introspection: { ...config.introspection, enabled: v } })} />\n </div>\n <div className=\"mt-3 flex flex-wrap gap-4\">\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min turns\n <Input type=\"number\" className=\"h-7 w-20\" value={config.introspection.minTurns}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minTurns: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min context remaining (0–1)\n <Input type=\"number\" step=\"0.05\" min=\"0\" max=\"1\" className=\"h-7 w-24\" value={config.introspection.minContextRemaining}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minContextRemaining: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Stats rollup */}\n <Card>\n <CardHeader>\n <CardTitle>Signals</CardTitle>\n </CardHeader>\n <CardContent>\n {globalStats.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations yet — they appear after sessions end with Insights enabled.</div>\n ) : (\n <div className=\"space-y-4\">\n {globalStats.map((g) => (\n <div key={g.signal}>\n <div className=\"mb-1 flex items-center gap-2\">\n <Badge variant=\"secondary\">{g.signal}</Badge>\n <span className=\"text-xs text-muted-foreground\">\n {g.count} obs · {g.avgRatio !== null ? `avg ratio ${g.avgRatio.toFixed(2)}` : 'no ratio'} · {timeAgo(now, g.lastAt)}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2 pl-2\">\n {projectStats.filter((p) => p.signal === g.signal).map((p) => (\n <span key={`${g.signal}-${p.project}`} className=\"rounded border border-border px-2 py-0.5 text-xs text-muted-foreground\">\n {p.project}: {p.count}{p.avgRatio !== null ? ` · ${p.avgRatio.toFixed(2)}` : ''}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Raw observations */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-3\">\n <span>Observations</span>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={projectFilter} onChange={(e) => setProjectFilter(e.target.value)}>\n <option value=\"\">all projects</option>\n {projects.map((p) => <option key={p} value={p}>{p}</option>)}\n </select>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={signalFilter} onChange={(e) => setSignalFilter(e.target.value)}>\n <option value=\"\">all signals</option>\n {signals.map((s) => <option key={s} value={s}>{s}</option>)}\n </select>\n </CardTitle>\n </CardHeader>\n <CardContent>\n {observations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations match.</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[680px] text-left text-xs\">\n <thead className=\"text-muted-foreground\">\n <tr className=\"border-b border-border\">\n <th className=\"py-1 pr-3 font-medium\">when</th>\n <th className=\"py-1 pr-3 font-medium\">project</th>\n <th className=\"py-1 pr-3 font-medium\">signal</th>\n <th className=\"py-1 pr-3 font-medium\">src</th>\n <th className=\"py-1 pr-3 font-medium\">value</th>\n <th className=\"py-1 pr-3 font-medium\">outcome</th>\n <th className=\"py-1 pr-3 font-medium\">session</th>\n </tr>\n </thead>\n <tbody>\n {observations.map((o) => (\n <tr key={o.id} className=\"border-b border-border/50\">\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{timeAgo(now, o.createdAt)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\">{o.project}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\"><Badge variant=\"outline\">{o.signal}</Badge></td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.source}</td>\n <td className=\"py-1 pr-3 font-mono\">{compactJson(o.value)}</td>\n <td className=\"py-1 pr-3 font-mono text-muted-foreground\">{compactJson(o.outcome)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.agentId ?? o.sessionId.slice(0, 12)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{$n as e,Gn as t,H as n,Jt as r,bn as i,ht as a,nr as o,tt as s,vn as c}from"./lucide-react-DuhlF2Sj.js";import{t as l}from"./store-
|
|
2
|
-
//# sourceMappingURL=integrations-
|
|
1
|
+
import{$n as e,Gn as t,H as n,Jt as r,bn as i,ht as a,nr as o,tt as s,vn as c}from"./lucide-react-DuhlF2Sj.js";import{t as l}from"./store-DKTLubBT.js";import{J as u,b as d}from"./display-exQDWum3.js";import{t as f}from"./badge-DCIT3Irj.js";import{t as p}from"./button-CzdTkRIf.js";import{o as m,r as h,s as g,t as _}from"./card-C3BGuVC6.js";var v=o(),y={PlugZap:n,AlertCircle:i,Activity:e,Eye:r,CircleCheck:c};function b(){let e=l(e=>e.integrations),r=l(e=>e.channels),i=l(e=>e.set),o=l(e=>e.switchView),c=e.reduce((e,t)=>e+(t.taskStats?.waitingTasks||0),0),b=new Set(r.map(e=>e.type)),x=e.filter(e=>b.has(e.name)).length;function S(e){i({taskSourceFilter:e}),o(`tasks`)}return(0,v.jsxs)(`div`,{className:`space-y-6`,children:[x>0&&(0,v.jsxs)(`div`,{className:`flex items-center gap-3 px-3 py-2.5 rounded-lg border border-blue-500/20 bg-blue-500/5 text-sm`,children:[(0,v.jsx)(s,{className:`w-4 h-4 text-blue-400 shrink-0`}),(0,v.jsxs)(`span`,{className:`text-muted-foreground flex-1`,children:[(0,v.jsx)(`span`,{className:`text-foreground font-medium`,children:x}),` integration`,x===1?``:`s`,` have active channels — view them in Channels for live status and routing detail.`]}),(0,v.jsxs)(p,{variant:`ghost`,size:`sm`,className:`h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 shrink-0`,onClick:()=>void o(`channels`),children:[`Channels`,(0,v.jsx)(t,{className:`w-3 h-3`})]})]}),(0,v.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,v.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,v.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Integrations`}),(0,v.jsxs)(f,{variant:`outline`,className:`text-xs`,children:[e.length,` total`]}),c>0&&(0,v.jsxs)(f,{className:`bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs`,children:[c,` waiting`]})]})}),e.length===0?(0,v.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-16 text-center`,children:[(0,v.jsx)(n,{className:`w-10 h-10 text-zinc-600 mb-3`}),(0,v.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No integrations configured`})]}):(0,v.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:e.map(e=>{let t=d(e),r=y[e.icon||t.icon]||y[t.icon]||n,i=e.taskStats||{};return(0,v.jsxs)(_,{className:`flex flex-col border-l-2`,style:{borderLeftColor:e.accentColor||void 0},children:[(0,v.jsxs)(m,{children:[(0,v.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,v.jsxs)(`div`,{className:`min-w-0`,children:[(0,v.jsx)(g,{className:`text-sm font-medium truncate`,children:e.displayName||e.name}),e.description&&(0,v.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-2`,children:e.description})]}),(0,v.jsxs)(`div`,{className:`flex items-center gap-1.5 shrink-0`,children:[(0,v.jsx)(r,{className:`w-3.5 h-3.5 ${u(t.tone)}`}),(0,v.jsx)(`span`,{className:`text-xs ${u(t.tone)}`,children:t.label})]})]}),(0,v.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-1`,children:[e.configured&&(0,v.jsx)(f,{variant:`outline`,className:`text-xs text-emerald-400 border-emerald-500/30`,children:`configured`}),e.observed&&(0,v.jsx)(f,{variant:`outline`,className:`text-xs text-blue-400 border-blue-500/30`,children:`observed`}),!e.enabled&&(0,v.jsx)(f,{variant:`outline`,className:`text-xs text-red-400 border-red-500/30`,children:`disabled`}),e.type&&(0,v.jsx)(f,{variant:`secondary`,className:`text-xs`,children:e.type}),e.tags?.map(e=>(0,v.jsxs)(f,{variant:`outline`,className:`text-xs text-zinc-400`,children:[`#`,e]},e))]})]}),(0,v.jsxs)(h,{className:`flex-1 space-y-3`,children:[(0,v.jsxs)(`div`,{className:`grid grid-cols-4 gap-2 text-center`,children:[(0,v.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,v.jsx)(`p`,{className:`text-base font-semibold tabular-nums`,children:i.tasks??0}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`tasks`})]}),(0,v.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,v.jsx)(`p`,{className:`text-base font-semibold tabular-nums text-blue-400`,children:i.openTasks??0}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`open`})]}),(0,v.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,v.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.waitingTasks??0)>0?`text-yellow-400`:``}`,children:i.waitingTasks??0}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`waiting`})]}),(0,v.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,v.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.failedTasks??0)>0?`text-red-400`:``}`,children:i.failedTasks??0}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`failed`})]})]}),(e.scopes?.length>0||e.targets?.length>0||e.channels?.length>0)&&(0,v.jsxs)(`div`,{className:`space-y-1.5`,children:[e.scopes?.length>0&&(0,v.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.scopes.map(e=>(0,v.jsx)(f,{variant:`outline`,className:`text-xs text-zinc-400`,children:e},e))}),e.targets?.length>0&&(0,v.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.targets.map(e=>(0,v.jsx)(f,{variant:`secondary`,className:`text-xs`,children:e},e))}),e.channels?.length>0&&(0,v.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.channels.map(e=>(0,v.jsxs)(f,{className:`text-xs bg-blue-500/10 text-blue-400 border-blue-500/20`,children:[`#`,e]},e))})]})]}),(i.tasks??0)>0&&(0,v.jsx)(`div`,{className:`px-4 pb-4`,children:(0,v.jsxs)(p,{variant:`outline`,size:`sm`,className:`w-full gap-1.5`,onClick:()=>S(i.source||e.name),children:[(0,v.jsx)(a,{className:`w-3.5 h-3.5`}),`Show tasks`]})})]},e.name)})})]})}export{b as IntegrationsView};
|
|
2
|
+
//# sourceMappingURL=integrations-DYEGSqq_.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integrations-CuT92zQi.js","names":[],"sources":["../../dashboard/src/components/views/integrations.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { integrationPresence, toneToColor } from '@/lib/display'\nimport { PlugZap, AlertCircle, Activity, Eye, CircleCheck, ListChecks, MessagesSquare, ArrowRight } from 'lucide-react'\n\nconst PRESENCE_ICONS: Record<string, typeof PlugZap> = {\n PlugZap, AlertCircle, Activity, Eye, CircleCheck,\n}\n\nexport function IntegrationsView() {\n const integrations = useRelayStore((s) => s.integrations)\n const channels = useRelayStore((s) => s.channels)\n const set = useRelayStore((s) => s.set)\n const switchView = useRelayStore((s) => s.switchView)\n\n const waitingCount = integrations.reduce((sum, i) => sum + (i.taskStats?.waitingTasks || 0), 0)\n const activeChannelTypes = new Set(channels.map((c) => c.type))\n const channelBackedCount = integrations.filter((i) => activeChannelTypes.has(i.name)).length\n\n function showTasks(source: string) {\n set({ taskSourceFilter: source })\n switchView('tasks')\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Channel integrations cross-link */}\n {channelBackedCount > 0 && (\n <div className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg border border-blue-500/20 bg-blue-500/5 text-sm\">\n <MessagesSquare className=\"w-4 h-4 text-blue-400 shrink-0\" />\n <span className=\"text-muted-foreground flex-1\">\n <span className=\"text-foreground font-medium\">{channelBackedCount}</span> integration{channelBackedCount !== 1 ? 's' : ''} have active channels — view them in Channels for live status and routing detail.\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 shrink-0\"\n onClick={() => void switchView('channels')}\n >\n Channels\n <ArrowRight className=\"w-3 h-3\" />\n </Button>\n </div>\n )}\n\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-lg font-semibold\">Integrations</h1>\n <Badge variant=\"outline\" className=\"text-xs\">\n {integrations.length} total\n </Badge>\n {waitingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs\">\n {waitingCount} waiting\n </Badge>\n )}\n </div>\n </div>\n\n {integrations.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <PlugZap className=\"w-10 h-10 text-zinc-600 mb-3\" />\n <p className=\"text-muted-foreground text-sm\">No integrations configured</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {integrations.map((integration) => {\n const presence = integrationPresence(integration)\n const PresenceIcon = PRESENCE_ICONS[integration.icon || presence.icon] || PRESENCE_ICONS[presence.icon] || PlugZap\n const stats = integration.taskStats || {}\n\n return (\n <Card key={integration.name} className=\"flex flex-col border-l-2\" style={{ borderLeftColor: integration.accentColor || undefined }}>\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{integration.displayName || integration.name}</CardTitle>\n {integration.description && <p className=\"mt-1 text-xs text-muted-foreground line-clamp-2\">{integration.description}</p>}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <PresenceIcon className={`w-3.5 h-3.5 ${toneToColor(presence.tone)}`} />\n <span className={`text-xs ${toneToColor(presence.tone)}`}>{presence.label}</span>\n </div>\n </div>\n\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {integration.configured && (\n <Badge variant=\"outline\" className=\"text-xs text-emerald-400 border-emerald-500/30\">\n configured\n </Badge>\n )}\n {integration.observed && (\n <Badge variant=\"outline\" className=\"text-xs text-blue-400 border-blue-500/30\">\n observed\n </Badge>\n )}\n {!integration.enabled && (\n <Badge variant=\"outline\" className=\"text-xs text-red-400 border-red-500/30\">\n disabled\n </Badge>\n )}\n {integration.type && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {integration.type}\n </Badge>\n )}\n {integration.tags?.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs text-zinc-400\">\n #{tag}\n </Badge>\n ))}\n </div>\n </CardHeader>\n\n <CardContent className=\"flex-1 space-y-3\">\n {/* Mini stats */}\n <div className=\"grid grid-cols-4 gap-2 text-center\">\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums\">{stats.tasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">tasks</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums text-blue-400\">{stats.openTasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">open</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.waitingTasks ?? 0) > 0 ? 'text-yellow-400' : ''}`}>\n {stats.waitingTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">waiting</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.failedTasks ?? 0) > 0 ? 'text-red-400' : ''}`}>\n {stats.failedTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">failed</p>\n </div>\n </div>\n\n {/* Scopes / Targets / Channels */}\n {(integration.scopes?.length > 0 || integration.targets?.length > 0 || integration.channels?.length > 0) && (\n <div className=\"space-y-1.5\">\n {integration.scopes?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.scopes.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-xs text-zinc-400\">\n {s}\n </Badge>\n ))}\n </div>\n )}\n {integration.targets?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.targets.map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-xs\">\n {t}\n </Badge>\n ))}\n </div>\n )}\n {integration.channels?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.channels.map((c) => (\n <Badge key={c} className=\"text-xs bg-blue-500/10 text-blue-400 border-blue-500/20\">\n #{c}\n </Badge>\n ))}\n </div>\n )}\n </div>\n )}\n </CardContent>\n\n {(stats.tasks ?? 0) > 0 && (\n <div className=\"px-4 pb-4\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full gap-1.5\"\n onClick={() => showTasks(stats.source || integration.name)}\n >\n <ListChecks className=\"w-3.5 h-3.5\" />\n Show tasks\n </Button>\n </div>\n )}\n </Card>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integrations-DYEGSqq_.js","names":[],"sources":["../../dashboard/src/components/views/integrations.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { integrationPresence, toneToColor } from '@/lib/display'\nimport { PlugZap, AlertCircle, Activity, Eye, CircleCheck, ListChecks, MessagesSquare, ArrowRight } from 'lucide-react'\n\nconst PRESENCE_ICONS: Record<string, typeof PlugZap> = {\n PlugZap, AlertCircle, Activity, Eye, CircleCheck,\n}\n\nexport function IntegrationsView() {\n const integrations = useRelayStore((s) => s.integrations)\n const channels = useRelayStore((s) => s.channels)\n const set = useRelayStore((s) => s.set)\n const switchView = useRelayStore((s) => s.switchView)\n\n const waitingCount = integrations.reduce((sum, i) => sum + (i.taskStats?.waitingTasks || 0), 0)\n const activeChannelTypes = new Set(channels.map((c) => c.type))\n const channelBackedCount = integrations.filter((i) => activeChannelTypes.has(i.name)).length\n\n function showTasks(source: string) {\n set({ taskSourceFilter: source })\n switchView('tasks')\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Channel integrations cross-link */}\n {channelBackedCount > 0 && (\n <div className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg border border-blue-500/20 bg-blue-500/5 text-sm\">\n <MessagesSquare className=\"w-4 h-4 text-blue-400 shrink-0\" />\n <span className=\"text-muted-foreground flex-1\">\n <span className=\"text-foreground font-medium\">{channelBackedCount}</span> integration{channelBackedCount !== 1 ? 's' : ''} have active channels — view them in Channels for live status and routing detail.\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 text-xs gap-1 text-blue-400 hover:text-blue-300 shrink-0\"\n onClick={() => void switchView('channels')}\n >\n Channels\n <ArrowRight className=\"w-3 h-3\" />\n </Button>\n </div>\n )}\n\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-lg font-semibold\">Integrations</h1>\n <Badge variant=\"outline\" className=\"text-xs\">\n {integrations.length} total\n </Badge>\n {waitingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs\">\n {waitingCount} waiting\n </Badge>\n )}\n </div>\n </div>\n\n {integrations.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <PlugZap className=\"w-10 h-10 text-zinc-600 mb-3\" />\n <p className=\"text-muted-foreground text-sm\">No integrations configured</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {integrations.map((integration) => {\n const presence = integrationPresence(integration)\n const PresenceIcon = PRESENCE_ICONS[integration.icon || presence.icon] || PRESENCE_ICONS[presence.icon] || PlugZap\n const stats = integration.taskStats || {}\n\n return (\n <Card key={integration.name} className=\"flex flex-col border-l-2\" style={{ borderLeftColor: integration.accentColor || undefined }}>\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{integration.displayName || integration.name}</CardTitle>\n {integration.description && <p className=\"mt-1 text-xs text-muted-foreground line-clamp-2\">{integration.description}</p>}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <PresenceIcon className={`w-3.5 h-3.5 ${toneToColor(presence.tone)}`} />\n <span className={`text-xs ${toneToColor(presence.tone)}`}>{presence.label}</span>\n </div>\n </div>\n\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {integration.configured && (\n <Badge variant=\"outline\" className=\"text-xs text-emerald-400 border-emerald-500/30\">\n configured\n </Badge>\n )}\n {integration.observed && (\n <Badge variant=\"outline\" className=\"text-xs text-blue-400 border-blue-500/30\">\n observed\n </Badge>\n )}\n {!integration.enabled && (\n <Badge variant=\"outline\" className=\"text-xs text-red-400 border-red-500/30\">\n disabled\n </Badge>\n )}\n {integration.type && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {integration.type}\n </Badge>\n )}\n {integration.tags?.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs text-zinc-400\">\n #{tag}\n </Badge>\n ))}\n </div>\n </CardHeader>\n\n <CardContent className=\"flex-1 space-y-3\">\n {/* Mini stats */}\n <div className=\"grid grid-cols-4 gap-2 text-center\">\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums\">{stats.tasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">tasks</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums text-blue-400\">{stats.openTasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">open</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.waitingTasks ?? 0) > 0 ? 'text-yellow-400' : ''}`}>\n {stats.waitingTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">waiting</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.failedTasks ?? 0) > 0 ? 'text-red-400' : ''}`}>\n {stats.failedTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">failed</p>\n </div>\n </div>\n\n {/* Scopes / Targets / Channels */}\n {(integration.scopes?.length > 0 || integration.targets?.length > 0 || integration.channels?.length > 0) && (\n <div className=\"space-y-1.5\">\n {integration.scopes?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.scopes.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-xs text-zinc-400\">\n {s}\n </Badge>\n ))}\n </div>\n )}\n {integration.targets?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.targets.map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-xs\">\n {t}\n </Badge>\n ))}\n </div>\n )}\n {integration.channels?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.channels.map((c) => (\n <Badge key={c} className=\"text-xs bg-blue-500/10 text-blue-400 border-blue-500/20\">\n #{c}\n </Badge>\n ))}\n </div>\n )}\n </div>\n )}\n </CardContent>\n\n {(stats.tasks ?? 0) > 0 && (\n <div className=\"px-4 pb-4\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full gap-1.5\"\n onClick={() => showTasks(stats.source || integration.name)}\n >\n <ListChecks className=\"w-3.5 h-3.5\" />\n Show tasks\n </Button>\n </div>\n )}\n </Card>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,L as n,U as r,er as i,h as a,hr as o,ln as s,nr as c,o as l,vn as u}from"./lucide-react-DuhlF2Sj.js";import{p as d,t as f}from"./store-
|
|
2
|
-
//# sourceMappingURL=maintenance-
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,L as n,U as r,er as i,h as a,hr as o,ln as s,nr as c,o as l,vn as u}from"./lucide-react-DuhlF2Sj.js";import{p as d,t as f}from"./store-DKTLubBT.js";import{K as p,h as m}from"./display-exQDWum3.js";import{t as h}from"./badge-DCIT3Irj.js";import{t as g}from"./button-CzdTkRIf.js";import{G as _}from"./index-D9OogaB5.js";var v=e(o(),1),y=c(),b={succeeded:`bg-emerald-500/10 text-emerald-400 border-emerald-500/30`,running:`bg-blue-500/10 text-blue-400 border-blue-500/30`,failed:`bg-red-500/10 text-red-400 border-red-500/30`,idle:`bg-zinc-500/10 text-zinc-400 border-zinc-500/30`,disabled:`bg-zinc-500/10 text-zinc-500 border-zinc-500/20`};function x(){let e=d(),t=f(e=>e.maintenanceJobs),r=f(e=>e.fetchMaintenanceJobs),i=f(e=>e.runMaintenanceJob),a=(0,v.useMemo)(()=>({failed:t.filter(e=>e.lastStatus===`failed`).length,running:t.filter(e=>e.running||e.lastStatus===`running`).length,dueSoon:t.filter(t=>t.nextRunAt&&t.nextRunAt<=e+300*1e3).length}),[t,e]);return(0,y.jsxs)(`div`,{className:`space-y-4`,children:[(0,y.jsxs)(`div`,{className:`flex items-center justify-between flex-wrap gap-2`,children:[(0,y.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,y.jsx)(l,{className:`h-5 w-5 text-muted-foreground`}),(0,y.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Maintenance`}),(0,y.jsx)(h,{variant:`secondary`,children:t.length}),a.running>0&&(0,y.jsxs)(h,{className:`border border-blue-500/30 bg-blue-500/10 text-blue-400`,children:[a.running,` running`]}),a.failed>0&&(0,y.jsxs)(h,{variant:`destructive`,children:[a.failed,` failing`]}),a.dueSoon>0&&(0,y.jsxs)(h,{className:`border border-yellow-500/30 bg-yellow-500/10 text-yellow-400`,children:[a.dueSoon,` due soon`]})]}),(0,y.jsxs)(g,{size:`sm`,variant:`outline`,onClick:()=>void r(),children:[(0,y.jsx)(n,{className:`h-3.5 w-3.5`}),` Refresh`]})]}),(0,y.jsx)(_,{className:`h-[calc(100dvh-10rem)]`,children:t.length===0?(0,y.jsx)(`div`,{className:`rounded-md border border-border px-3 py-12 text-center text-sm text-muted-foreground`,children:`No maintenance jobs registered`}):(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`div`,{className:`hidden overflow-x-auto rounded-md border border-border md:block`,children:(0,y.jsxs)(`table`,{className:`w-full min-w-[980px] text-sm`,children:[(0,y.jsx)(`thead`,{className:`bg-muted/40 text-xs text-muted-foreground`,children:(0,y.jsxs)(`tr`,{children:[(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Job`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Status`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Last run`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Next run`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Duration`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-left font-medium`,children:`Result`}),(0,y.jsx)(`th`,{className:`px-3 py-2 text-right font-medium`,children:`Action`})]})}),(0,y.jsx)(`tbody`,{children:t.map(t=>(0,y.jsx)(T,{job:t,now:e,onRun:()=>void i(t.id)},t.id))})]})}),(0,y.jsx)(`div`,{className:`space-y-3 md:hidden`,children:t.map(t=>(0,y.jsx)(w,{job:t,now:e,onRun:()=>void i(t.id)},t.id))})]})})]})}function S(e){return e.running?`running`:e.enabled?e.lastStatus:`disabled`}function C({status:e}){return(0,y.jsxs)(h,{variant:`outline`,className:i(`border`,b[e]||b.idle),children:[E(e),e]})}function w({job:e,now:t,onRun:n}){let i=S(e);return(0,y.jsxs)(`div`,{className:`rounded-md border border-border p-3`,children:[(0,y.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,y.jsxs)(`div`,{className:`min-w-0`,children:[(0,y.jsx)(`div`,{className:`font-medium`,children:e.title}),(0,y.jsx)(`div`,{className:`mt-0.5 text-xs text-muted-foreground`,children:e.description}),(0,y.jsx)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground/80`,children:e.id})]}),(0,y.jsx)(C,{status:i})]}),e.consecutiveFailures>0&&(0,y.jsxs)(`div`,{className:`mt-2 text-xs text-red-400`,children:[e.consecutiveFailures,` failure`,e.consecutiveFailures===1?``:`s`]}),(0,y.jsxs)(`dl`,{className:`mt-3 grid grid-cols-3 gap-2 text-xs`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{className:`text-muted-foreground`,children:`Last run`}),(0,y.jsx)(`dd`,{children:e.lastRunAt?(0,y.jsx)(`span`,{title:m(e.lastRunAt),children:p(t,e.lastRunAt)}):`never`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{className:`text-muted-foreground`,children:`Next run`}),(0,y.jsx)(`dd`,{children:e.nextRunAt?(0,y.jsx)(`span`,{title:m(e.nextRunAt),children:O(t,e.nextRunAt)}):`-`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{className:`text-muted-foreground`,children:`Duration`}),(0,y.jsx)(`dd`,{children:e.lastDurationMs===void 0?`-`:`${e.lastDurationMs}ms`})]})]}),(0,y.jsxs)(`div`,{className:`mt-3`,children:[(0,y.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Result`}),e.lastError?(0,y.jsx)(`div`,{className:`mt-0.5 text-xs text-red-400 line-clamp-3`,children:e.lastError}):(0,y.jsx)(`div`,{className:`mt-0.5 font-mono text-[11px] text-muted-foreground line-clamp-3`,children:D(e)})]}),(0,y.jsx)(`div`,{className:`mt-3 flex justify-end`,children:(0,y.jsxs)(g,{size:`sm`,variant:`outline`,disabled:!e.enabled||e.running,onClick:n,children:[(0,y.jsx)(r,{className:`h-3.5 w-3.5`}),` Run`]})})]})}function T({job:e,now:t,onRun:n}){let i=S(e);return(0,y.jsxs)(`tr`,{className:`border-t border-border align-top`,children:[(0,y.jsxs)(`td`,{className:`px-3 py-3`,children:[(0,y.jsx)(`div`,{className:`font-medium`,children:e.title}),(0,y.jsx)(`div`,{className:`mt-0.5 max-w-md text-xs text-muted-foreground`,children:e.description}),(0,y.jsx)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground/80`,children:e.id})]}),(0,y.jsxs)(`td`,{className:`px-3 py-3`,children:[(0,y.jsx)(C,{status:i}),e.consecutiveFailures>0&&(0,y.jsxs)(`div`,{className:`mt-1 text-xs text-red-400`,children:[e.consecutiveFailures,` failure`,e.consecutiveFailures===1?``:`s`]})]}),(0,y.jsx)(`td`,{className:`px-3 py-3 text-xs text-muted-foreground`,children:e.lastRunAt?(0,y.jsx)(`span`,{title:m(e.lastRunAt),children:p(t,e.lastRunAt)}):`never`}),(0,y.jsx)(`td`,{className:`px-3 py-3 text-xs text-muted-foreground`,children:e.nextRunAt?(0,y.jsx)(`span`,{title:m(e.nextRunAt),children:O(t,e.nextRunAt)}):`-`}),(0,y.jsx)(`td`,{className:`px-3 py-3 text-xs text-muted-foreground`,children:e.lastDurationMs===void 0?`-`:`${e.lastDurationMs}ms`}),(0,y.jsx)(`td`,{className:`px-3 py-3`,children:e.lastError?(0,y.jsx)(`div`,{className:`max-w-sm text-xs text-red-400 line-clamp-3`,children:e.lastError}):(0,y.jsx)(`div`,{className:`max-w-sm font-mono text-[11px] text-muted-foreground line-clamp-3`,children:D(e)})}),(0,y.jsx)(`td`,{className:`px-3 py-3 text-right`,children:(0,y.jsxs)(g,{size:`sm`,variant:`outline`,disabled:!e.enabled||e.running,onClick:n,children:[(0,y.jsx)(r,{className:`h-3.5 w-3.5`}),` Run`]})})]})}function E(e){return e===`succeeded`?(0,y.jsx)(u,{className:`mr-1 h-3 w-3`}):e===`running`?(0,y.jsx)(t,{className:`mr-1 h-3 w-3`}):e===`failed`?(0,y.jsx)(a,{className:`mr-1 h-3 w-3`}):(0,y.jsx)(s,{className:`mr-1 h-3 w-3`})}function D(e){if(!e.lastResult)return`-`;let t=Object.entries(e.lastResult).filter(([,e])=>Array.isArray(e)?e.length>0:e!=null&&e!==0).map(([e,t])=>`${e}: ${Array.isArray(t)?t.length:String(t)}`);return t.length?t.join(`, `):`no changes`}function O(e,t){if(t<=e)return`due now`;let n=Math.max(0,(t-e)/1e3);return n<60?`in ${Math.ceil(n)}s`:n<3600?`in ${Math.ceil(n/60)}m`:n<86400?`in ${Math.ceil(n/3600)}h`:`in ${Math.ceil(n/86400)}d`}export{x as MaintenanceView};
|
|
2
|
+
//# sourceMappingURL=maintenance-C0HIEB-J.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maintenance-lM7FeXVC.js","names":[],"sources":["../../dashboard/src/components/views/maintenance.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { Activity, AlertTriangle, CheckCircle2, Clock3, Play, RefreshCw, Wrench } from 'lucide-react'\nimport { useRelayStore, useNow } from '@/store'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { cn } from '@/lib/utils'\nimport { fmtTime, timeAgo } from '@/lib/display'\nimport type { MaintenanceJob } from '@/types'\n\nconst STATUS_CLASS: Record<string, string> = {\n succeeded: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30',\n running: 'bg-blue-500/10 text-blue-400 border-blue-500/30',\n failed: 'bg-red-500/10 text-red-400 border-red-500/30',\n idle: 'bg-zinc-500/10 text-zinc-400 border-zinc-500/30',\n disabled: 'bg-zinc-500/10 text-zinc-500 border-zinc-500/20',\n}\n\nexport function MaintenanceView() {\n const now = useNow()\n const jobs = useRelayStore((s) => s.maintenanceJobs)\n const fetchMaintenanceJobs = useRelayStore((s) => s.fetchMaintenanceJobs)\n const runMaintenanceJob = useRelayStore((s) => s.runMaintenanceJob)\n\n const summary = useMemo(() => {\n const failed = jobs.filter((job) => job.lastStatus === 'failed').length\n const running = jobs.filter((job) => job.running || job.lastStatus === 'running').length\n const dueSoon = jobs.filter((job) => job.nextRunAt && job.nextRunAt <= now + 5 * 60 * 1000).length\n return { failed, running, dueSoon }\n }, [jobs, now])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <Wrench className=\"h-5 w-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Maintenance</h2>\n <Badge variant=\"secondary\">{jobs.length}</Badge>\n {summary.running > 0 && <Badge className=\"border border-blue-500/30 bg-blue-500/10 text-blue-400\">{summary.running} running</Badge>}\n {summary.failed > 0 && <Badge variant=\"destructive\">{summary.failed} failing</Badge>}\n {summary.dueSoon > 0 && <Badge className=\"border border-yellow-500/30 bg-yellow-500/10 text-yellow-400\">{summary.dueSoon} due soon</Badge>}\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => void fetchMaintenanceJobs()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Refresh\n </Button>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-10rem)]\">\n {jobs.length === 0 ? (\n <div className=\"rounded-md border border-border px-3 py-12 text-center text-sm text-muted-foreground\">No maintenance jobs registered</div>\n ) : (\n <>\n {/* Desktop / wide: full table */}\n <div className=\"hidden overflow-x-auto rounded-md border border-border md:block\">\n <table className=\"w-full min-w-[980px] text-sm\">\n <thead className=\"bg-muted/40 text-xs text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2 text-left font-medium\">Job</th>\n <th className=\"px-3 py-2 text-left font-medium\">Status</th>\n <th className=\"px-3 py-2 text-left font-medium\">Last run</th>\n <th className=\"px-3 py-2 text-left font-medium\">Next run</th>\n <th className=\"px-3 py-2 text-left font-medium\">Duration</th>\n <th className=\"px-3 py-2 text-left font-medium\">Result</th>\n <th className=\"px-3 py-2 text-right font-medium\">Action</th>\n </tr>\n </thead>\n <tbody>\n {jobs.map((job) => (\n <MaintenanceRow\n key={job.id}\n job={job}\n now={now}\n onRun={() => void runMaintenanceJob(job.id)}\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {/* Mobile / narrow: stacked cards so every field is visible without horizontal scroll */}\n <div className=\"space-y-3 md:hidden\">\n {jobs.map((job) => (\n <MaintenanceCard\n key={job.id}\n job={job}\n now={now}\n onRun={() => void runMaintenanceJob(job.id)}\n />\n ))}\n </div>\n </>\n )}\n </ScrollArea>\n </div>\n )\n}\n\nfunction jobStatus(job: MaintenanceJob): string {\n return job.running ? 'running' : job.enabled ? job.lastStatus : 'disabled'\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n return (\n <Badge variant=\"outline\" className={cn('border', STATUS_CLASS[status] || STATUS_CLASS.idle)}>\n {statusIcon(status)}\n {status}\n </Badge>\n )\n}\n\nfunction MaintenanceCard({ job, now, onRun }: { job: MaintenanceJob; now: number; onRun: () => void }) {\n const status = jobStatus(job)\n return (\n <div className=\"rounded-md border border-border p-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"font-medium\">{job.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{job.description}</div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground/80\">{job.id}</div>\n </div>\n <StatusBadge status={status} />\n </div>\n\n {job.consecutiveFailures > 0 && (\n <div className=\"mt-2 text-xs text-red-400\">{job.consecutiveFailures} failure{job.consecutiveFailures === 1 ? '' : 's'}</div>\n )}\n\n <dl className=\"mt-3 grid grid-cols-3 gap-2 text-xs\">\n <div>\n <dt className=\"text-muted-foreground\">Last run</dt>\n <dd>{job.lastRunAt ? <span title={fmtTime(job.lastRunAt)}>{timeAgo(now, job.lastRunAt)}</span> : 'never'}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">Next run</dt>\n <dd>{job.nextRunAt ? <span title={fmtTime(job.nextRunAt)}>{nextRunText(now, job.nextRunAt)}</span> : '-'}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">Duration</dt>\n <dd>{job.lastDurationMs !== undefined ? `${job.lastDurationMs}ms` : '-'}</dd>\n </div>\n </dl>\n\n <div className=\"mt-3\">\n <div className=\"text-xs text-muted-foreground\">Result</div>\n {job.lastError ? (\n <div className=\"mt-0.5 text-xs text-red-400 line-clamp-3\">{job.lastError}</div>\n ) : (\n <div className=\"mt-0.5 font-mono text-[11px] text-muted-foreground line-clamp-3\">{resultSummary(job)}</div>\n )}\n </div>\n\n <div className=\"mt-3 flex justify-end\">\n <Button size=\"sm\" variant=\"outline\" disabled={!job.enabled || job.running} onClick={onRun}>\n <Play className=\"h-3.5 w-3.5\" /> Run\n </Button>\n </div>\n </div>\n )\n}\n\nfunction MaintenanceRow({ job, now, onRun }: { job: MaintenanceJob; now: number; onRun: () => void }) {\n const status = jobStatus(job)\n return (\n <tr className=\"border-t border-border align-top\">\n <td className=\"px-3 py-3\">\n <div className=\"font-medium\">{job.title}</div>\n <div className=\"mt-0.5 max-w-md text-xs text-muted-foreground\">{job.description}</div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground/80\">{job.id}</div>\n </td>\n <td className=\"px-3 py-3\">\n <StatusBadge status={status} />\n {job.consecutiveFailures > 0 && (\n <div className=\"mt-1 text-xs text-red-400\">{job.consecutiveFailures} failure{job.consecutiveFailures === 1 ? '' : 's'}</div>\n )}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.lastRunAt ? (\n <span title={fmtTime(job.lastRunAt)}>{timeAgo(now, job.lastRunAt)}</span>\n ) : 'never'}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.nextRunAt ? (\n <span title={fmtTime(job.nextRunAt)}>{nextRunText(now, job.nextRunAt)}</span>\n ) : '-'}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.lastDurationMs !== undefined ? `${job.lastDurationMs}ms` : '-'}\n </td>\n <td className=\"px-3 py-3\">\n {job.lastError ? (\n <div className=\"max-w-sm text-xs text-red-400 line-clamp-3\">{job.lastError}</div>\n ) : (\n <div className=\"max-w-sm font-mono text-[11px] text-muted-foreground line-clamp-3\">{resultSummary(job)}</div>\n )}\n </td>\n <td className=\"px-3 py-3 text-right\">\n <Button size=\"sm\" variant=\"outline\" disabled={!job.enabled || job.running} onClick={onRun}>\n <Play className=\"h-3.5 w-3.5\" /> Run\n </Button>\n </td>\n </tr>\n )\n}\n\nfunction statusIcon(status: string) {\n if (status === 'succeeded') return <CheckCircle2 className=\"mr-1 h-3 w-3\" />\n if (status === 'running') return <Activity className=\"mr-1 h-3 w-3\" />\n if (status === 'failed') return <AlertTriangle className=\"mr-1 h-3 w-3\" />\n return <Clock3 className=\"mr-1 h-3 w-3\" />\n}\n\nfunction resultSummary(job: MaintenanceJob): string {\n if (!job.lastResult) return '-'\n const entries = Object.entries(job.lastResult)\n .filter(([, value]) => Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== 0)\n .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.length : String(value)}`)\n return entries.length ? entries.join(', ') : 'no changes'\n}\n\nfunction nextRunText(now: number, nextRunAt: number): string {\n if (nextRunAt <= now) return 'due now'\n const diff = Math.max(0, (nextRunAt - now) / 1000)\n if (diff < 60) return `in ${Math.ceil(diff)}s`\n if (diff < 3600) return `in ${Math.ceil(diff / 60)}m`\n if (diff < 86400) return `in ${Math.ceil(diff / 3600)}h`\n return `in ${Math.ceil(diff / 86400)}d`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"maintenance-C0HIEB-J.js","names":[],"sources":["../../dashboard/src/components/views/maintenance.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { Activity, AlertTriangle, CheckCircle2, Clock3, Play, RefreshCw, Wrench } from 'lucide-react'\nimport { useRelayStore, useNow } from '@/store'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { cn } from '@/lib/utils'\nimport { fmtTime, timeAgo } from '@/lib/display'\nimport type { MaintenanceJob } from '@/types'\n\nconst STATUS_CLASS: Record<string, string> = {\n succeeded: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30',\n running: 'bg-blue-500/10 text-blue-400 border-blue-500/30',\n failed: 'bg-red-500/10 text-red-400 border-red-500/30',\n idle: 'bg-zinc-500/10 text-zinc-400 border-zinc-500/30',\n disabled: 'bg-zinc-500/10 text-zinc-500 border-zinc-500/20',\n}\n\nexport function MaintenanceView() {\n const now = useNow()\n const jobs = useRelayStore((s) => s.maintenanceJobs)\n const fetchMaintenanceJobs = useRelayStore((s) => s.fetchMaintenanceJobs)\n const runMaintenanceJob = useRelayStore((s) => s.runMaintenanceJob)\n\n const summary = useMemo(() => {\n const failed = jobs.filter((job) => job.lastStatus === 'failed').length\n const running = jobs.filter((job) => job.running || job.lastStatus === 'running').length\n const dueSoon = jobs.filter((job) => job.nextRunAt && job.nextRunAt <= now + 5 * 60 * 1000).length\n return { failed, running, dueSoon }\n }, [jobs, now])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between flex-wrap gap-2\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <Wrench className=\"h-5 w-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Maintenance</h2>\n <Badge variant=\"secondary\">{jobs.length}</Badge>\n {summary.running > 0 && <Badge className=\"border border-blue-500/30 bg-blue-500/10 text-blue-400\">{summary.running} running</Badge>}\n {summary.failed > 0 && <Badge variant=\"destructive\">{summary.failed} failing</Badge>}\n {summary.dueSoon > 0 && <Badge className=\"border border-yellow-500/30 bg-yellow-500/10 text-yellow-400\">{summary.dueSoon} due soon</Badge>}\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => void fetchMaintenanceJobs()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Refresh\n </Button>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-10rem)]\">\n {jobs.length === 0 ? (\n <div className=\"rounded-md border border-border px-3 py-12 text-center text-sm text-muted-foreground\">No maintenance jobs registered</div>\n ) : (\n <>\n {/* Desktop / wide: full table */}\n <div className=\"hidden overflow-x-auto rounded-md border border-border md:block\">\n <table className=\"w-full min-w-[980px] text-sm\">\n <thead className=\"bg-muted/40 text-xs text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2 text-left font-medium\">Job</th>\n <th className=\"px-3 py-2 text-left font-medium\">Status</th>\n <th className=\"px-3 py-2 text-left font-medium\">Last run</th>\n <th className=\"px-3 py-2 text-left font-medium\">Next run</th>\n <th className=\"px-3 py-2 text-left font-medium\">Duration</th>\n <th className=\"px-3 py-2 text-left font-medium\">Result</th>\n <th className=\"px-3 py-2 text-right font-medium\">Action</th>\n </tr>\n </thead>\n <tbody>\n {jobs.map((job) => (\n <MaintenanceRow\n key={job.id}\n job={job}\n now={now}\n onRun={() => void runMaintenanceJob(job.id)}\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {/* Mobile / narrow: stacked cards so every field is visible without horizontal scroll */}\n <div className=\"space-y-3 md:hidden\">\n {jobs.map((job) => (\n <MaintenanceCard\n key={job.id}\n job={job}\n now={now}\n onRun={() => void runMaintenanceJob(job.id)}\n />\n ))}\n </div>\n </>\n )}\n </ScrollArea>\n </div>\n )\n}\n\nfunction jobStatus(job: MaintenanceJob): string {\n return job.running ? 'running' : job.enabled ? job.lastStatus : 'disabled'\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n return (\n <Badge variant=\"outline\" className={cn('border', STATUS_CLASS[status] || STATUS_CLASS.idle)}>\n {statusIcon(status)}\n {status}\n </Badge>\n )\n}\n\nfunction MaintenanceCard({ job, now, onRun }: { job: MaintenanceJob; now: number; onRun: () => void }) {\n const status = jobStatus(job)\n return (\n <div className=\"rounded-md border border-border p-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"font-medium\">{job.title}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{job.description}</div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground/80\">{job.id}</div>\n </div>\n <StatusBadge status={status} />\n </div>\n\n {job.consecutiveFailures > 0 && (\n <div className=\"mt-2 text-xs text-red-400\">{job.consecutiveFailures} failure{job.consecutiveFailures === 1 ? '' : 's'}</div>\n )}\n\n <dl className=\"mt-3 grid grid-cols-3 gap-2 text-xs\">\n <div>\n <dt className=\"text-muted-foreground\">Last run</dt>\n <dd>{job.lastRunAt ? <span title={fmtTime(job.lastRunAt)}>{timeAgo(now, job.lastRunAt)}</span> : 'never'}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">Next run</dt>\n <dd>{job.nextRunAt ? <span title={fmtTime(job.nextRunAt)}>{nextRunText(now, job.nextRunAt)}</span> : '-'}</dd>\n </div>\n <div>\n <dt className=\"text-muted-foreground\">Duration</dt>\n <dd>{job.lastDurationMs !== undefined ? `${job.lastDurationMs}ms` : '-'}</dd>\n </div>\n </dl>\n\n <div className=\"mt-3\">\n <div className=\"text-xs text-muted-foreground\">Result</div>\n {job.lastError ? (\n <div className=\"mt-0.5 text-xs text-red-400 line-clamp-3\">{job.lastError}</div>\n ) : (\n <div className=\"mt-0.5 font-mono text-[11px] text-muted-foreground line-clamp-3\">{resultSummary(job)}</div>\n )}\n </div>\n\n <div className=\"mt-3 flex justify-end\">\n <Button size=\"sm\" variant=\"outline\" disabled={!job.enabled || job.running} onClick={onRun}>\n <Play className=\"h-3.5 w-3.5\" /> Run\n </Button>\n </div>\n </div>\n )\n}\n\nfunction MaintenanceRow({ job, now, onRun }: { job: MaintenanceJob; now: number; onRun: () => void }) {\n const status = jobStatus(job)\n return (\n <tr className=\"border-t border-border align-top\">\n <td className=\"px-3 py-3\">\n <div className=\"font-medium\">{job.title}</div>\n <div className=\"mt-0.5 max-w-md text-xs text-muted-foreground\">{job.description}</div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground/80\">{job.id}</div>\n </td>\n <td className=\"px-3 py-3\">\n <StatusBadge status={status} />\n {job.consecutiveFailures > 0 && (\n <div className=\"mt-1 text-xs text-red-400\">{job.consecutiveFailures} failure{job.consecutiveFailures === 1 ? '' : 's'}</div>\n )}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.lastRunAt ? (\n <span title={fmtTime(job.lastRunAt)}>{timeAgo(now, job.lastRunAt)}</span>\n ) : 'never'}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.nextRunAt ? (\n <span title={fmtTime(job.nextRunAt)}>{nextRunText(now, job.nextRunAt)}</span>\n ) : '-'}\n </td>\n <td className=\"px-3 py-3 text-xs text-muted-foreground\">\n {job.lastDurationMs !== undefined ? `${job.lastDurationMs}ms` : '-'}\n </td>\n <td className=\"px-3 py-3\">\n {job.lastError ? (\n <div className=\"max-w-sm text-xs text-red-400 line-clamp-3\">{job.lastError}</div>\n ) : (\n <div className=\"max-w-sm font-mono text-[11px] text-muted-foreground line-clamp-3\">{resultSummary(job)}</div>\n )}\n </td>\n <td className=\"px-3 py-3 text-right\">\n <Button size=\"sm\" variant=\"outline\" disabled={!job.enabled || job.running} onClick={onRun}>\n <Play className=\"h-3.5 w-3.5\" /> Run\n </Button>\n </td>\n </tr>\n )\n}\n\nfunction statusIcon(status: string) {\n if (status === 'succeeded') return <CheckCircle2 className=\"mr-1 h-3 w-3\" />\n if (status === 'running') return <Activity className=\"mr-1 h-3 w-3\" />\n if (status === 'failed') return <AlertTriangle className=\"mr-1 h-3 w-3\" />\n return <Clock3 className=\"mr-1 h-3 w-3\" />\n}\n\nfunction resultSummary(job: MaintenanceJob): string {\n if (!job.lastResult) return '-'\n const entries = Object.entries(job.lastResult)\n .filter(([, value]) => Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== 0)\n .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.length : String(value)}`)\n return entries.length ? entries.join(', ') : 'no changes'\n}\n\nfunction nextRunText(now: number, nextRunAt: number): string {\n if (nextRunAt <= now) return 'due now'\n const diff = Math.max(0, (nextRunAt - now) / 1000)\n if (diff < 60) return `in ${Math.ceil(diff)}s`\n if (diff < 3600) return `in ${Math.ceil(diff / 60)}m`\n if (diff < 86400) return `in ${Math.ceil(diff / 3600)}h`\n return `in ${Math.ceil(diff / 86400)}d`\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,D as n,G as r,N as i,U as a,Ut as o,V as s,_ as c,b as l,er as u,g as d,h as f,hr as p,nr as m,rr as h,y as g}from"./lucide-react-DuhlF2Sj.js";import{p as _,t as v}from"./store-
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,D as n,G as r,N as i,U as a,Ut as o,V as s,_ as c,b as l,er as u,g as d,h as f,hr as p,nr as m,rr as h,y as g}from"./lucide-react-DuhlF2Sj.js";import{p as _,t as v}from"./store-DKTLubBT.js";import{d as y}from"./types-uVOXgvMT.js";import{K as b,h as x,q as S}from"./display-exQDWum3.js";import{t as C}from"./badge-DCIT3Irj.js";import{t as w}from"./button-CzdTkRIf.js";import{t as T}from"./copy-button-B3o1jpLu.js";import{$ as E,Q as D,et as O}from"./index-D9OogaB5.js";var k=e(p(),1),A=m(),j={running:`bg-emerald-500/15 text-emerald-400 border-emerald-500/30`,starting:`bg-blue-500/15 text-blue-400 border-blue-500/30`,stopping:`bg-yellow-500/15 text-yellow-400 border-yellow-500/30`,backoff:`bg-red-500/15 text-red-400 border-red-500/30`,failed:`bg-red-500/15 text-red-400 border-red-500/30`,stopped:`bg-muted text-muted-foreground border-border`};function M({status:e}){return(0,A.jsx)(`span`,{className:u(`inline-flex items-center rounded border px-2 py-0.5 text-xs font-medium`,j[e]),children:e})}var N={running:`bg-emerald-500/20 text-emerald-400`,starting:`bg-blue-500/20 text-blue-400`,stopping:`bg-yellow-500/20 text-yellow-400`,stopped:`bg-zinc-500/20 text-zinc-400`,backoff:`bg-red-500/20 text-red-400`,failed:`bg-red-500/20 text-red-400`};function P({item:e,agent:r,orchestrators:i,now:a,onClose:s,initialDiagnostics:c}){let[l,u]=(0,k.useState)(c??null),[d,p]=(0,k.useState)(!1),[m,_]=(0,k.useState)(null);(0,k.useEffect)(()=>{if(c){u(c);return}let t=!1;return p(!0),_(null),h(`GET`,`/spawn-policy/`+encodeURIComponent(e.policy.name)+`/diagnostics?limit=80`).then(e=>{t||u(e)}).catch(e=>{t||(u(null),_(e.message))}).finally(()=>{t||p(!1)}),()=>{t=!0}},[e.policy.name,e.state.updatedAt,c]);let v=i.find(t=>t.id===e.policy.orchestratorId),y=(0,k.useMemo)(()=>F(e,v),[e,v]),S=l?.timeline??[],O=L(S,r),j=l?.crashReport??null,P=I(e,y),R=r?D(a,r):null;return(0,A.jsxs)(`section`,{className:`rounded-md border border-border bg-card p-3 space-y-3`,children:[(0,A.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:[(0,A.jsxs)(`div`,{className:`min-w-0`,children:[(0,A.jsxs)(`h2`,{className:`flex items-center gap-1.5 text-sm font-semibold`,children:[(0,A.jsx)(g,{className:`h-4 w-4 text-muted-foreground`}),e.policy.label||e.policy.name,` Diagnostics`]}),(0,A.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Spawn config, live attachments, recent lifecycle, and logs.`})]}),(0,A.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,A.jsx)(T,{value:()=>z(e,r,v,y,S,j,O),label:`Copy Bundle`,showText:!0,size:`sm`,variant:`outline`,className:`h-8 text-xs`}),(0,A.jsx)(w,{variant:`outline`,size:`sm`,onClick:s,children:`Close`})]})]}),m&&(0,A.jsx)(`div`,{className:`rounded border border-red-500/20 bg-red-500/5 px-2 py-1.5 text-xs text-red-300`,children:m}),d&&!l&&(0,A.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Loading diagnostics...`}),(0,A.jsxs)(`div`,{className:`grid gap-3 lg:grid-cols-2`,children:[(0,A.jsx)(B,{title:`Spawn Command`,icon:(0,A.jsx)(o,{className:`h-3.5 w-3.5`}),children:(0,A.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-3 gap-y-1 text-xs`,children:[(0,A.jsx)(V,{label:`Provider`,value:e.policy.provider}),e.policy.model&&(0,A.jsx)(V,{label:`Model`,value:e.policy.model}),e.policy.effort&&(0,A.jsx)(V,{label:`Effort`,value:e.policy.effort}),(0,A.jsx)(V,{label:`Approval`,value:e.policy.permissionMode}),(0,A.jsx)(V,{label:`Mode`,value:e.policy.mode}),e.policy.profile&&(0,A.jsx)(V,{label:`Profile`,value:e.policy.profile}),e.policy.rig&&(0,A.jsx)(V,{label:`Rig`,value:e.policy.rig}),(0,A.jsx)(V,{label:`CWD`,value:e.policy.cwd,className:`col-span-2`,mono:!0}),e.policy.providerArgs.length>0&&(0,A.jsx)(V,{label:`Provider Args`,value:e.policy.providerArgs.join(` `),className:`col-span-2`,mono:!0}),e.policy.tags.length>0&&(0,A.jsx)(H,{label:`Tags`,values:e.policy.tags}),e.policy.capabilities.length>0&&(0,A.jsx)(H,{label:`Caps`,values:e.policy.capabilities})]})}),(0,A.jsx)(B,{title:`Runtime`,icon:(0,A.jsx)(n,{className:`h-3.5 w-3.5`}),children:(0,A.jsxs)(`div`,{className:`space-y-2 text-xs`,children:[(0,A.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,A.jsx)(`span`,{className:`text-muted-foreground`,children:`Lifecycle`}),(0,A.jsx)(M,{status:e.state.status}),(0,A.jsx)(C,{className:N[e.state.status]||`bg-zinc-500/20 text-zinc-400`,children:e.state.status})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-3 gap-y-1`,children:[(0,A.jsx)(V,{label:`Orchestrator`,value:v?`${v.hostname} (${v.id})`:e.policy.orchestratorId}),v?.version&&(0,A.jsx)(V,{label:`Orch Version`,value:v.version}),y?.pid&&(0,A.jsx)(V,{label:`PID`,value:String(y.pid),mono:!0}),y?.supervisor&&(0,A.jsx)(V,{label:`Supervisor`,value:y.supervisor}),y?.systemdUnit&&(0,A.jsx)(V,{label:`Systemd`,value:y.systemdUnit,mono:!0,className:`col-span-2`}),y?.sessionName&&(0,A.jsx)(V,{label:`Session`,value:y.sessionName,mono:!0}),y?.terminalSession&&(0,A.jsx)(V,{label:`Terminal`,value:y.terminalAvailable?`${y.terminalSession} (available)`:`${y.terminalSession} (not attachable)`,mono:!0}),y?.spawnRequestId&&(0,A.jsx)(V,{label:`Spawn ID`,value:y.spawnRequestId,mono:!0,className:`col-span-2`}),y?.startedAt&&(0,A.jsx)(V,{label:`Started`,value:x(y.startedAt)}),e.state.restartCount!==void 0&&(0,A.jsx)(V,{label:`Restarts`,value:String(e.state.restartCount)}),e.state.consecutiveFailures!==void 0&&(0,A.jsx)(V,{label:`Failures`,value:String(e.state.consecutiveFailures)}),e.state.backoffUntil&&(0,A.jsx)(V,{label:`Backoff`,value:e.state.backoffUntil>a?b(a,e.state.backoffUntil):`expired`})]}),R&&(0,A.jsxs)(`div`,{className:`rounded border border-yellow-500/20 bg-yellow-500/5 px-2 py-1.5 text-yellow-100/80`,children:[`Stuck busy: `,R.kind,` stale for `,b(a,a-R.staleForMs)]}),e.state.lastError&&(0,A.jsx)(U,{title:`Last Error`,body:e.state.lastError})]})})]}),(O||j)&&(0,A.jsx)(B,{title:`Post-Mortem`,icon:(0,A.jsx)(f,{className:`h-3.5 w-3.5`}),children:(0,A.jsxs)(`div`,{className:`space-y-2 text-xs`,children:[j&&(0,A.jsxs)(`div`,{className:`rounded border border-red-500/20 bg-red-500/5 px-2 py-1.5`,children:[(0,A.jsx)(`div`,{className:`font-medium text-red-200`,children:j.diagnosis.summary}),(0,A.jsxs)(`div`,{className:`mt-0.5 text-red-200/70`,children:[`Cause `,j.diagnosis.cause,` · `,j.diagnosis.confidence]})]}),O&&(0,A.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-3 gap-y-1`,children:[(0,A.jsx)(V,{label:`Exit`,value:O.lastError,className:`col-span-2`}),O.detectedAt&&(0,A.jsx)(V,{label:`Detected`,value:b(a,O.detectedAt)}),typeof O.runtimeMs==`number`&&(0,A.jsx)(V,{label:`Runtime`,value:`${Math.max(0,Math.round(O.runtimeMs/1e3))}s`}),O.systemd?.unit&&(0,A.jsx)(V,{label:`Unit`,value:O.systemd.unit,mono:!0,className:`col-span-2`}),O.systemd?.result&&(0,A.jsx)(V,{label:`Systemd Result`,value:O.systemd.result}),O.logFile&&(0,A.jsx)(V,{label:`Log`,value:O.logFile,mono:!0,className:`col-span-2`})]}),O?.logTail?.length?(0,A.jsx)(`pre`,{className:`max-h-32 overflow-auto whitespace-pre-wrap break-words rounded border border-border bg-zinc-950 p-2 text-[11px] leading-4 text-zinc-100`,children:O.logTail.slice(-8).join(`
|
|
2
2
|
`)}):null]})}),(0,A.jsx)(B,{title:`Recent Events (${S.length})`,icon:(0,A.jsx)(t,{className:`h-3.5 w-3.5`}),children:S.length===0?(0,A.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`No recent lifecycle events or command outcomes.`}):(0,A.jsx)(`div`,{className:`space-y-1`,children:S.slice(0,12).map((e,t)=>(0,A.jsxs)(`div`,{className:`grid grid-cols-[5.5rem_5rem_1fr] gap-2 text-xs`,children:[(0,A.jsx)(`span`,{className:`text-muted-foreground tabular-nums`,children:b(a,e.ts)}),(0,A.jsx)(C,{variant:`outline`,className:`h-5 justify-center text-[10px]`,children:e.source}),(0,A.jsxs)(`div`,{className:`min-w-0`,children:[(0,A.jsx)(`div`,{className:`truncate font-medium`,title:e.title,children:e.title}),e.detail&&(0,A.jsx)(`div`,{className:`break-words text-muted-foreground`,children:e.detail.length>160?e.detail.slice(0,160)+`...`:e.detail}),typeof e.metadata?.id==`string`&&(0,A.jsxs)(`div`,{className:`font-mono text-[10px] text-muted-foreground`,children:[`command `,e.metadata.id]})]})]},`${e.source}-${e.ts}-${e.kind}-${t}`))})}),v&&P&&(0,A.jsx)(B,{title:`Log Tail`,icon:(0,A.jsx)(o,{className:`h-3.5 w-3.5`}),children:(0,A.jsx)(E,{orchestratorId:v.id,session:P,lines:120})})]})}function F(e,t){return t?.managedAgents.find(t=>t.policyName===e.policy.name||e.state.agentId&&t.agentId===e.state.agentId||e.state.spawnRequestId&&t.spawnRequestId===e.state.spawnRequestId||e.state.tmuxSession&&(t.sessionName===e.state.tmuxSession||t.tmuxSession===e.state.tmuxSession))}function I(e,t){return t?.terminalSession||t?.sessionName||t?.tmuxSession||e.state.tmuxSession}function L(e,t){let n=R(t?.meta?.lastExit);if(n)return n;for(let t of e){let e=R(t.metadata?.lastExit);if(e)return e}return null}function R(e){if(!y(e)||typeof e.lastError!=`string`)return null;let t=y(e.systemd)?e.systemd:void 0;return{lastError:e.lastError,detectedAt:typeof e.detectedAt==`number`?e.detectedAt:void 0,runtimeMs:typeof e.runtimeMs==`number`?e.runtimeMs:void 0,logFile:typeof e.logFile==`string`?e.logFile:void 0,logBytes:typeof e.logBytes==`number`?e.logBytes:void 0,logEmpty:typeof e.logEmpty==`boolean`?e.logEmpty:void 0,logTail:Array.isArray(e.logTail)?e.logTail.filter(e=>typeof e==`string`):void 0,systemd:t?{unit:typeof t.unit==`string`?t.unit:void 0,activeState:typeof t.activeState==`string`?t.activeState:void 0,subState:typeof t.subState==`string`?t.subState:void 0,result:typeof t.result==`string`?t.result:void 0}:void 0,unavailable:Array.isArray(e.unavailable)?e.unavailable.filter(e=>typeof e==`string`):void 0}}function z(e,t,n,r,i,a,o){let s=[`# Managed Agent Diagnostics`,`Policy: ${e.policy.name}`,`Lifecycle: ${e.state.status}`,`Provider: ${e.policy.provider}`,`CWD: ${e.policy.cwd}`,`Approval: ${e.policy.permissionMode}`];if(e.policy.model&&s.push(`Model: ${e.policy.model}`),e.policy.effort&&s.push(`Effort: ${e.policy.effort}`),e.policy.profile&&s.push(`Profile: ${e.policy.profile}`),e.policy.tags.length&&s.push(`Tags: ${e.policy.tags.join(`, `)}`),e.policy.capabilities.length&&s.push(`Caps: ${e.policy.capabilities.join(`, `)}`),t&&s.push(`Agent: ${t.id} (${t.status})`),n&&s.push(`Orchestrator: ${n.hostname} (${n.id})`,`Orchestrator status: ${n.status}`),r&&(s.push(``,`## Runtime`),r.pid&&s.push(`PID: ${r.pid}`),r.supervisor&&s.push(`Supervisor: ${r.supervisor}`),r.systemdUnit&&s.push(`Systemd: ${r.systemdUnit}`),r.sessionName&&s.push(`Session: ${r.sessionName}`),r.terminalSession&&s.push(`Terminal: ${r.terminalSession} (${r.terminalAvailable?`available`:`not attachable`})`),r.spawnRequestId&&s.push(`Spawn request: ${r.spawnRequestId}`)),(e.state.lastError||a||o)&&(s.push(``,`## Post-Mortem`),e.state.lastError&&s.push(`Last error: ${e.state.lastError}`),a&&s.push(`Crash: ${a.diagnosis.cause}/${a.diagnosis.confidence} - ${a.diagnosis.summary}`),o?.lastError&&s.push(`Exit: ${o.lastError}`),o?.logTail?.length&&s.push(``,`Log tail:`,...o.logTail.slice(-8))),i.length){s.push(``,`## Recent Events`);for(let e of i.slice(0,12)){let t=typeof e.metadata?.id==`string`?` (${e.metadata.id})`:``;s.push(`- ${new Date(S(e.ts)).toISOString()} [${e.source}] ${e.title}${t}${e.detail?`: ${e.detail}`:``}`)}}return s.join(`
|
|
3
3
|
`)}function B({title:e,icon:t,children:n}){return(0,A.jsxs)(`div`,{className:`rounded-md border border-border p-2.5`,children:[(0,A.jsxs)(`h3`,{className:`mb-2 flex items-center gap-1.5 text-xs font-medium text-muted-foreground`,children:[t,e]}),n]})}function V({label:e,value:t,className:n=``,mono:r=!1}){return(0,A.jsxs)(`div`,{className:`min-w-0 ${n}`,children:[(0,A.jsx)(`span`,{className:`text-muted-foreground`,children:e}),(0,A.jsx)(`div`,{className:`truncate ${r?`font-mono`:``}`,title:t,children:t})]})}function H({label:e,values:t}){return(0,A.jsxs)(`div`,{className:`col-span-2`,children:[(0,A.jsx)(`span`,{className:`text-muted-foreground`,children:e}),(0,A.jsx)(`div`,{className:`mt-0.5 flex flex-wrap gap-1`,children:t.map(e=>(0,A.jsx)(C,{variant:`outline`,className:`text-[10px]`,children:e},e))})]})}function U({title:e,body:t}){return(0,A.jsxs)(`div`,{className:`rounded border border-red-500/20 bg-red-500/5 px-2 py-1.5`,children:[(0,A.jsx)(`span`,{className:`text-muted-foreground`,children:e}),(0,A.jsx)(`div`,{className:`mt-0.5 break-words text-red-300/80`,children:t})]})}function W(e,t){let n=t?.meta?.tmuxSession;return typeof n==`string`&&n.trim()?n:e.state.tmuxSession}function G(e,t){return W(e,t)?!!t?.providerCapabilities?.terminal?.live?.read:!1}function K(e,t){return G(e,t)?!!t?.providerCapabilities?.terminal?.live?.write:!1}function q(){let e=v(e=>e.managedPolicies),t=v(e=>e.agentsById),n=v(e=>e.orchestrators),u=v(e=>e.fetchManagedPolicies),f=v(e=>e.fetchOrchestrators),p=v(e=>e.apiCall),m=v(e=>e.openPolicyCreate),h=v(e=>e.openPolicyEdit),y=v(e=>e.deletePolicy),b=_(),[S,C]=(0,k.useState)(null),[T,D]=(0,k.useState)(null),[j,N]=(0,k.useState)(null);(0,k.useEffect)(()=>{Promise.all([u(),f()])},[]);async function F(e,t){await p(`POST`,`/spawn-policy/${encodeURIComponent(e)}/${t}`,{surface:{component:`managed-agents`}}),await u()}let I=j?e.find(e=>e.policy.name===j)??null:null;return(0,A.jsxs)(`div`,{className:`space-y-4`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h1`,{className:`text-2xl font-semibold`,children:`Managed Agents`}),(0,A.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Spawn policies, lifecycle state, and headless session logs.`})]}),(0,A.jsxs)(w,{onClick:m,size:`sm`,children:[(0,A.jsx)(s,{className:`h-4 w-4 mr-1`}),`Create Policy`]})]}),e.length===0&&(0,A.jsx)(`div`,{className:`rounded-md border border-border px-3 py-8 text-center text-sm text-muted-foreground`,children:`No managed agents configured`}),(0,A.jsx)(`div`,{className:`grid gap-3 sm:grid-cols-2 lg:grid-cols-3`,children:e.map(e=>{let n=e.state.agentId?t[e.state.agentId]:void 0,s=W(e,n);return(0,A.jsxs)(`div`,{className:`rounded-md border border-border bg-card p-3 space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,A.jsxs)(`div`,{className:`min-w-0`,children:[(0,A.jsx)(`div`,{className:`font-medium text-sm truncate`,children:e.policy.label||e.policy.name}),(0,A.jsxs)(`div`,{className:`text-xs text-muted-foreground truncate`,children:[e.policy.mode,` · `,e.policy.cwd]})]}),(0,A.jsx)(M,{status:e.state.status})]}),(0,A.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-1 text-xs`,children:[(0,A.jsx)(`div`,{className:`text-muted-foreground`,children:`Provider`}),(0,A.jsx)(`div`,{children:e.policy.provider}),(0,A.jsx)(`div`,{className:`text-muted-foreground`,children:`Agent`}),(0,A.jsx)(`div`,{className:`font-mono truncate`,children:e.state.agentId||`-`}),(0,A.jsx)(`div`,{className:`text-muted-foreground`,children:`Restarts`}),(0,A.jsx)(`div`,{children:e.state.restartCount}),(e.state.backoffUntil||e.state.lastError)&&(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(`div`,{className:`text-muted-foreground`,children:e.state.backoffUntil?`Backoff`:`Error`}),(0,A.jsx)(`div`,{className:`truncate`,children:e.state.backoffUntil?x(e.state.backoffUntil):e.state.lastError})]})]}),(0,A.jsxs)(`div`,{className:`flex flex-wrap gap-1 pt-1 border-t border-border`,children:[(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>F(e.policy.name,`start`),title:`Start`,children:(0,A.jsx)(a,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>F(e.policy.name,`stop`),title:`Stop`,children:(0,A.jsx)(l,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>F(e.policy.name,`restart`),title:`Restart`,children:(0,A.jsx)(i,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>C(e),disabled:!e.state.tmuxSession,title:`Logs`,children:(0,A.jsx)(o,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>s&&D({item:e,session:s}),disabled:!G(e,n),title:`Terminal`,children:(0,A.jsx)(c,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:j===e.policy.name?`secondary`:`outline`,className:`h-7 w-7`,onClick:()=>N(t=>t===e.policy.name?null:e.policy.name),title:`Diagnostics`,children:(0,A.jsx)(g,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>h(e.policy),title:`Edit`,children:(0,A.jsx)(r,{className:`h-3.5 w-3.5`})}),(0,A.jsx)(w,{size:`icon`,variant:`outline`,className:`h-7 w-7`,onClick:()=>y(e.policy.name),title:`Delete`,children:(0,A.jsx)(d,{className:`h-3.5 w-3.5`})})]})]},e.policy.name)})}),I&&(0,A.jsx)(P,{item:I,agent:I.state.agentId?t[I.state.agentId]:void 0,orchestrators:n,now:b,onClose:()=>N(null)}),S?.state.tmuxSession&&(0,A.jsxs)(`div`,{className:`space-y-2`,children:[(0,A.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,A.jsxs)(`h2`,{className:`text-lg font-semibold`,children:[S.policy.name,` Logs`]}),(0,A.jsx)(w,{variant:`outline`,size:`sm`,onClick:()=>C(null),children:`Close`})]}),(0,A.jsx)(E,{orchestratorId:S.policy.orchestratorId,session:S.state.tmuxSession})]}),(0,A.jsx)(O,{open:!!T,onOpenChange:e=>{e||D(null)},orchestratorId:T?.item.policy.orchestratorId??``,session:T?.session??``,interactive:T?K(T.item,T.item.state.agentId?t[T.item.state.agentId]:void 0):!1,canWrite:T?K(T.item,T.item.state.agentId?t[T.item.state.agentId]:void 0):!1})]})}export{q as ManagedAgentsView};
|
|
4
|
-
//# sourceMappingURL=managed-agents-
|
|
4
|
+
//# sourceMappingURL=managed-agents-DdS7aI38.js.map
|