agent-relay-server 0.110.0 → 0.111.0
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 +2 -2
- package/public/assets/{MessageBubble-CmqJMGYF.js → MessageBubble-WYqSyKPM.js} +2 -2
- package/public/assets/{MessageBubble-CmqJMGYF.js.map → MessageBubble-WYqSyKPM.js.map} +1 -1
- package/public/assets/PlanGraphPanel-Dvu17jGe.js +2 -0
- package/public/assets/PlanGraphPanel-Dvu17jGe.js.map +1 -0
- package/public/assets/{activity-DyqKrJe_.js → activity-wAN_upn7.js} +2 -2
- package/public/assets/{activity-DyqKrJe_.js.map → activity-wAN_upn7.js.map} +1 -1
- package/public/assets/{agent-profiles-DRQ5vbPo.js → agent-profiles-D8WLdTCs.js} +2 -2
- package/public/assets/{agent-profiles-DRQ5vbPo.js.map → agent-profiles-D8WLdTCs.js.map} +1 -1
- package/public/assets/{agents-BJ9sm23O.js → agents-C5FajNPw.js} +2 -2
- package/public/assets/{agents-BJ9sm23O.js.map → agents-C5FajNPw.js.map} +1 -1
- package/public/assets/{automation-CJ2-uiYt.js → automation-ShdXg0pX.js} +2 -2
- package/public/assets/{automation-CJ2-uiYt.js.map → automation-ShdXg0pX.js.map} +1 -1
- package/public/assets/{chat-D0VtHShz.js → chat-aRCk0pLJ.js} +2 -2
- package/public/assets/{chat-D0VtHShz.js.map → chat-aRCk0pLJ.js.map} +1 -1
- package/public/assets/{formatted-body-impl-ChCxpVtI.js → formatted-body-impl-DZc7C4-2.js} +2 -2
- package/public/assets/{formatted-body-impl-ChCxpVtI.js.map → formatted-body-impl-DZc7C4-2.js.map} +1 -1
- package/public/assets/{index-BIRtwnUI.js → index-DXEYz_JV.js} +5 -5
- package/public/assets/{index-BIRtwnUI.js.map → index-DXEYz_JV.js.map} +1 -1
- package/public/assets/{insights-BGuB8DWZ.js → insights-FzTX2wNh.js} +2 -2
- package/public/assets/{insights-BGuB8DWZ.js.map → insights-FzTX2wNh.js.map} +1 -1
- package/public/assets/{maintenance-BFyuZuv5.js → maintenance-C8Uw8XiI.js} +2 -2
- package/public/assets/{maintenance-BFyuZuv5.js.map → maintenance-C8Uw8XiI.js.map} +1 -1
- package/public/assets/{managed-agents-BIXZUkrA.js → managed-agents-DVbJ2hqh.js} +2 -2
- package/public/assets/{managed-agents-BIXZUkrA.js.map → managed-agents-DVbJ2hqh.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-DTI--VmH.js → markdown-preview-impl-C5D-B-9S.js} +2 -2
- package/public/assets/{markdown-preview-impl-DTI--VmH.js.map → markdown-preview-impl-C5D-B-9S.js.map} +1 -1
- package/public/assets/{memory-OoM2E30h.js → memory-Bp-D_V80.js} +2 -2
- package/public/assets/{memory-OoM2E30h.js.map → memory-Bp-D_V80.js.map} +1 -1
- package/public/assets/{messages-BHvC3SNR.js → messages-DE1QSeHI.js} +2 -2
- package/public/assets/{messages-BHvC3SNR.js.map → messages-DE1QSeHI.js.map} +1 -1
- package/public/assets/{orchestrators-9pzQqf6-.js → orchestrators-B0u2lQfw.js} +2 -2
- package/public/assets/{orchestrators-9pzQqf6-.js.map → orchestrators-B0u2lQfw.js.map} +1 -1
- package/public/assets/{overview-L8iYOYmR.js → overview-DpaEvvLT.js} +2 -2
- package/public/assets/{overview-L8iYOYmR.js.map → overview-DpaEvvLT.js.map} +1 -1
- package/public/assets/{pairs-BCejxa6_.js → pairs-DRp_qAu8.js} +2 -2
- package/public/assets/{pairs-BCejxa6_.js.map → pairs-DRp_qAu8.js.map} +1 -1
- package/public/assets/{prompt-settings-D9y9hhSy.js → prompt-settings-CNoBiymk.js} +2 -2
- package/public/assets/{prompt-settings-D9y9hhSy.js.map → prompt-settings-CNoBiymk.js.map} +1 -1
- package/public/assets/{registry-BwBg64Vj.js → registry-0A4QFMWC.js} +2 -2
- package/public/assets/{registry-BwBg64Vj.js.map → registry-0A4QFMWC.js.map} +1 -1
- package/public/assets/{security-upd2zf8l.js → security-C9P6yiQ3.js} +2 -2
- package/public/assets/{security-upd2zf8l.js.map → security-C9P6yiQ3.js.map} +1 -1
- package/public/assets/{select-Cu55Vi-R.js → select-B1PVUj6D.js} +2 -2
- package/public/assets/{select-Cu55Vi-R.js.map → select-B1PVUj6D.js.map} +1 -1
- package/public/assets/{settings-Dk5iNqCZ.js → settings-TnHlB9-t.js} +2 -2
- package/public/assets/{settings-Dk5iNqCZ.js.map → settings-TnHlB9-t.js.map} +1 -1
- package/public/assets/{tasks-BoDuvHnZ.js → tasks-1oK_ggFC.js} +2 -2
- package/public/assets/{tasks-BoDuvHnZ.js.map → tasks-1oK_ggFC.js.map} +1 -1
- package/public/assets/{teams-C6Pn-gpw.js → teams-BBb0ZYiF.js} +2 -2
- package/public/assets/{teams-C6Pn-gpw.js.map → teams-BBb0ZYiF.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-afW96xEF.js → terminal-viewer-impl-DzvaRjkp.js} +2 -2
- package/public/assets/{terminal-viewer-impl-afW96xEF.js.map → terminal-viewer-impl-DzvaRjkp.js.map} +1 -1
- package/public/assets/{user-avatar-tSPnqEk5.js → user-avatar-X1pfizLv.js} +2 -2
- package/public/assets/{user-avatar-tSPnqEk5.js.map → user-avatar-X1pfizLv.js.map} +1 -1
- package/public/assets/{work-queue-DP3UdDwC.js → work-queue-DQMbkSD8.js} +2 -2
- package/public/assets/{work-queue-DP3UdDwC.js.map → work-queue-DQMbkSD8.js.map} +1 -1
- package/public/assets/{workspaces-Dt2xndG4.js → workspaces-BNLP4IlV.js} +2 -2
- package/public/assets/{workspaces-Dt2xndG4.js.map → workspaces-BNLP4IlV.js.map} +1 -1
- package/public/index.html +1 -1
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/src/db/agents.ts +3 -0
- package/src/db/notification-subscriptions.ts +15 -0
- package/src/db/task-entity.ts +2 -0
- package/src/mcp-notification-subscription-tools.ts +2 -1
- package/src/notification-rules.ts +17 -1
- package/src/notification-types.ts +18 -0
- package/src/reviewer-pipeline.ts +13 -0
- package/src/routes/commands.ts +14 -0
- package/src/routes/tasks.ts +1 -0
- package/src/services/spawn-agent.ts +2 -0
- package/src/services/task-entity.ts +20 -6
- package/src/services/task-lifecycle.ts +36 -7
- package/src/services/task-semantic-events.ts +241 -13
- package/src/workspace-auto-merge.ts +17 -0
- package/public/assets/PlanGraphPanel-K6aFJmdd.js +0 -2
- package/public/assets/PlanGraphPanel-K6aFJmdd.js.map +0 -1
|
@@ -33,6 +33,7 @@ import { getLifecycleManager } from "./lifecycle-manager";
|
|
|
33
33
|
import { routeNotification } from "./notification-router";
|
|
34
34
|
import { renderTemplate } from "./prompt-resolver";
|
|
35
35
|
import { isAwaitingReviewerApproval } from "./reviewer-pipeline";
|
|
36
|
+
import { emitWorkspaceTaskSemanticNotifications } from "./services/task-lifecycle";
|
|
36
37
|
import { ensureRepoSteward } from "./steward";
|
|
37
38
|
import { requestWorkspaceMerge } from "./workspace-merge";
|
|
38
39
|
import { workspaceActiveClaim } from "./workspace-claim";
|
|
@@ -186,6 +187,13 @@ function escalateNoProgressMerge(ws: WorkspaceRecord): void {
|
|
|
186
187
|
if (getStewardConfig().enabled) {
|
|
187
188
|
wakeRepoSteward(ws, `auto-merge backed off after ${MAX_NO_PROGRESS_MERGE_ATTEMPTS} no-progress attempts (${mergeError})`);
|
|
188
189
|
}
|
|
190
|
+
emitWorkspaceTaskSemanticNotifications({
|
|
191
|
+
workspace: ws,
|
|
192
|
+
transition: "land-conflict",
|
|
193
|
+
actor: "workspace-auto-merge",
|
|
194
|
+
occurrenceKey: `workspace-merge-backoff:${ws.id}:${mergeNoProgressCount(ws.metadata)}:${lastEscalated || "first"}`,
|
|
195
|
+
outcome: { reason: mergeError, attempts: MAX_NO_PROGRESS_MERGE_ATTEMPTS },
|
|
196
|
+
});
|
|
189
197
|
// Emit the owner-facing `landed-failure` wake — the SAME actionable notice the live
|
|
190
198
|
// merge_planned→failed settle fires (routes/commands.ts → notifyBranchLandFailed). The
|
|
191
199
|
// loop-breaker stops dispatching once a lane hits the no-progress cap, so without this
|
|
@@ -307,6 +315,15 @@ async function landCandidates(
|
|
|
307
315
|
const woke = wakeRepoSteward(ws, p.conflict === true ? "conflict" : "merge state unknown");
|
|
308
316
|
if (woke) wokeStewards.push(woke);
|
|
309
317
|
}
|
|
318
|
+
if (p.conflict === true) {
|
|
319
|
+
emitWorkspaceTaskSemanticNotifications({
|
|
320
|
+
workspace: ws,
|
|
321
|
+
transition: "land-conflict",
|
|
322
|
+
actor: "workspace-auto-merge",
|
|
323
|
+
occurrenceKey: `workspace-conflict:${ws.id}:${p.baseRef ?? ws.baseRef ?? "base"}:${p.ahead ?? "?"}:${p.behind ?? "?"}`,
|
|
324
|
+
outcome: { reason: "conflict", ahead: p.ahead, behind: p.behind, baseRef: p.baseRef },
|
|
325
|
+
});
|
|
326
|
+
}
|
|
310
327
|
continue;
|
|
311
328
|
}
|
|
312
329
|
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$n as t,Cn as n,Zn as r,bn as i,fr as a,jt as o}from"./lucide-react-DmbfpRvJ.js";import{i as s,r as c,t as l}from"./store-DDWg67Pg.js";import{_ as u,f as d}from"./index-BIRtwnUI.js";var f=e(a(),1),p=`(max-width: 767px)`;function m(e){if(typeof window>`u`)return()=>{};let t=window.matchMedia(p);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)}function h(){return(0,f.useSyncExternalStore)(m,()=>typeof window<`u`?window.matchMedia(p).matches:!1,()=>!1)}var g=t(),_=196,v=84,y=52,b=16,x=14,S=[`landed`,`in-progress`,`pending`,`blocked`],C={landed:{label:`landed`,dot:`bg-emerald-400`,accent:`border-l-emerald-400`,text:`text-emerald-300`,wire:`#34d399`},"in-progress":{label:`in progress`,dot:`bg-sky-400`,accent:`border-l-sky-400`,text:`text-sky-300`,wire:`#38bdf8`},pending:{label:`pending`,dot:`bg-amber-400`,accent:`border-l-amber-400`,text:`text-amber-300`,wire:`#fbbf24`},blocked:{label:`blocked`,dot:`bg-red-400`,accent:`border-l-red-400`,text:`text-red-300`,wire:`#f87171`}};function w(e){return e?e.label||(e.policyName?`policy:${e.policyName}`:e.agentId||``):``}function T(e){let t=new Map(e.nodes.map(e=>[e.id,e])),n=new Map(e.nodes.map((e,t)=>[e.id,t])),r=new Map,i=new Map(e.nodes.map(e=>[e.id,0]));for(let n of e.edges)!t.has(n.from)||!t.has(n.to)||(r.set(n.from,[...r.get(n.from)??[],n.to]),i.set(n.to,(i.get(n.to)??0)+1));let a=new Map(e.nodes.map(e=>[e.id,0])),o=e.nodes.filter(e=>(i.get(e.id)??0)===0).map(e=>e.id),s=new Set;for(;o.length;){let e=o.shift();s.add(e);let t=a.get(e)??0;for(let n of r.get(e)??[])a.set(n,Math.max(a.get(n)??0,t+1)),i.set(n,(i.get(n)??0)-1),(i.get(n)??0)===0&&o.push(n)}let c=Math.max(0,...Array.from(a.values()))+1;for(let t of e.nodes)s.has(t.id)||a.set(t.id,c++);let l=new Map;for(let t of e.nodes){let e=a.get(t.id)??0;l.set(e,[...l.get(e)??[],t])}let u=[...l.entries()].sort(([e],[t])=>e-t),d=Math.max(1,...u.map(([,e])=>e.length)),f=v+b,p=[];u.forEach(([e,t],r)=>{let i=[...t].sort((e,t)=>(e.lane||``).localeCompare(t.lane||``)||(n.get(e.id)??0)-(n.get(t.id)??0)),a=(d-i.length)*f/2;i.forEach((t,n)=>{p.push({node:t,layer:e,x:x+r*(_+y),y:x+a+n*f})})});let m=u.length;return{nodes:p,width:Math.max(320,x*2+m*_+Math.max(0,m-1)*y),height:Math.max(v+x*2,x*2+d*v+Math.max(0,d-1)*b)}}function E(e,t){let n=e.x+_,r=e.y+v/2,i=t.x,a=t.y+v/2,o=n+Math.max(20,(i-n)/2);return`M ${n} ${r} C ${o} ${r}, ${o} ${a}, ${i} ${a}`}function D({threadId:e,teamId:t,channel:a}){let p=t?s(t,a):e?c(e,a):``,m=l(e=>t?e.plansByTeam[p]:p?e.plansByThread[p]:null),y=l(e=>e.fetchPlan),b=l(e=>e.planCollapsed),x=l(e=>e.setPlanCollapsed),D=l(e=>e.issueRefsById),O=l(e=>e.deliverableTasks),k=l(e=>e.openTaskDetailById),A=h(),j=b??A;(0,f.useEffect)(()=>{if(t){y({teamId:t,channel:a});return}e&&y({threadId:e,channel:a})},[a,y,t,e]);let M=(0,f.useMemo)(()=>m?T(m):null,[m]),N=(0,f.useMemo)(()=>new Map(M?.nodes.map(e=>[e.node.id,e])??[]),[M]),P=(0,f.useMemo)(()=>{if(!m)return[];let e=new Map;for(let t of m.nodes)e.set(t.status,(e.get(t.status)??0)+1);return S.filter(t=>e.has(t)).map(t=>({status:t,count:e.get(t)??0}))},[m]);if(!m||!M)return null;let F=m.nodes.length,I=P.find(e=>e.status===`landed`)?.count??0,L=`${F} node${F===1?``:`s`}${I>0?` · ${I} landed`:``}`;return(0,g.jsxs)(`section`,{className:`shrink-0 border-b border-border bg-card/45 px-3 py-2`,children:[(0,g.jsxs)(`button`,{type:`button`,onClick:()=>x(!j),"aria-expanded":!j,"aria-label":j?`Expand plan graph`:`Collapse plan graph`,className:r(`flex w-full min-w-0 items-center gap-2 text-left`,!j&&`mb-2`),children:[(0,g.jsx)(`span`,{className:`flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted/60`,children:(0,g.jsx)(o,{className:`h-3 w-3 text-muted-foreground`})}),(0,g.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,g.jsx)(`div`,{className:`truncate text-[13px] font-semibold leading-tight text-foreground`,children:m.title||`Plan`}),(0,g.jsx)(`div`,{className:`truncate text-[11px] leading-tight text-muted-foreground`,children:j?L:m.objective||L})]}),P.length>0&&(0,g.jsx)(`div`,{className:`hidden shrink-0 items-center gap-2.5 sm:flex`,children:P.map(({status:e,count:t})=>(0,g.jsxs)(`span`,{className:`flex items-center gap-1 text-[10px] text-muted-foreground`,children:[(0,g.jsx)(`span`,{className:r(`h-1.5 w-1.5 rounded-full`,C[e].dot)}),(0,g.jsx)(`span`,{className:r(`font-medium tabular-nums`,C[e].text),children:t}),(0,g.jsx)(`span`,{children:C[e].label})]},e))}),(0,g.jsxs)(`span`,{className:`shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground`,children:[`v`,m.version]}),(0,g.jsx)(`span`,{className:`flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted/60 hover:text-foreground`,children:j?(0,g.jsx)(n,{className:`h-3.5 w-3.5`}):(0,g.jsx)(i,{className:`h-3.5 w-3.5`})})]}),j?null:m.nodes.length===0?(0,g.jsx)(`div`,{className:`rounded-md border border-dashed border-border px-3 py-3 text-center text-xs text-muted-foreground`,children:`No nodes yet — the plan graph fills in as the team is composed.`}):(0,g.jsx)(`div`,{className:`max-h-[min(46vh,360px)] overflow-auto`,children:(0,g.jsxs)(`div`,{className:`relative`,style:{width:M.width,height:M.height},children:[(0,g.jsxs)(`svg`,{className:`pointer-events-none absolute inset-0`,width:M.width,height:M.height,"aria-hidden":`true`,children:[(0,g.jsx)(`defs`,{children:S.map(e=>(0,g.jsx)(`marker`,{id:`plan-arrow-${e}`,viewBox:`0 0 8 8`,refX:`6.5`,refY:`4`,markerWidth:`6`,markerHeight:`6`,orient:`auto-start-reverse`,children:(0,g.jsx)(`path`,{d:`M0 0 L8 4 L0 8 z`,fill:C[e].wire})},e))}),m.edges.map(e=>{let t=N.get(e.from),n=N.get(e.to);if(!t||!n)return null;let r=C[t.node.status];return(0,g.jsx)(`path`,{d:E(t,n),stroke:r.wire,strokeOpacity:.7,strokeWidth:2,fill:`none`,strokeLinecap:`round`,markerEnd:`url(#plan-arrow-${t.node.status})`},`${e.from}->${e.to}`)})]}),M.nodes.map(({node:e,x:t,y:n})=>{let i=C[e.status],a=w(e.ownerRef),o=e.refs?.issueId?D[e.refs.issueId]:null,s=e.refs?.taskId?parseInt(e.refs.taskId,10):null,c=s==null?void 0:O.find(e=>e.id===s)?.title;return(0,g.jsxs)(`article`,{className:r(`group absolute flex flex-col justify-between rounded-md border border-l-[3px] bg-background/95 p-2`,`shadow-sm transition-all hover:-translate-y-px hover:border-border hover:shadow-md hover:bg-background`,i.accent),style:{left:t,top:n,width:_,height:v},title:e.scopeBlurb||e.label,children:[(0,g.jsx)(`div`,{className:`truncate text-xs font-semibold leading-tight text-foreground`,children:e.label}),(e.scopeBlurb||e.id)&&(0,g.jsx)(`div`,{className:`truncate text-[10px] leading-tight text-muted-foreground`,children:e.scopeBlurb||e.id}),(o||s!=null)&&(0,g.jsxs)(`div`,{className:`flex min-w-0 flex-wrap gap-1`,children:[o&&(0,g.jsx)(u,{issueRef:o,compact:!0,className:`max-w-full`}),s!=null&&(0,g.jsx)(d,{id:s,title:c,onClick:()=>k(s),className:`max-w-full`})]}),(0,g.jsxs)(`div`,{className:`flex min-w-0 items-center justify-between gap-1.5`,children:[(0,g.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5`,children:[(0,g.jsx)(`span`,{className:r(`h-1.5 w-1.5 shrink-0 rounded-full`,i.dot)}),(0,g.jsx)(`span`,{className:r(`text-[10px] font-medium`,i.text),children:i.label})]}),(0,g.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5`,children:[a&&(0,g.jsx)(`span`,{className:`truncate text-[10px] text-muted-foreground`,children:a}),e.lane&&(0,g.jsx)(`span`,{className:`shrink-0 rounded-sm bg-muted/70 px-1 py-px text-[9px] font-medium uppercase tracking-wide text-muted-foreground`,children:e.lane})]})]})]},e.id)})]})})]})}function O({agentId:e}){let t=l(e=>e.deliverableTasks),n=l(e=>e.openTaskDetailById),r=t.filter(t=>t.createdBy===e);return r.length===0?null:(0,g.jsxs)(`section`,{className:`shrink-0 border-b border-border bg-card/45 px-3 py-2`,children:[(0,g.jsxs)(`div`,{className:`mb-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground`,children:[`Tasks from this session (`,r.length,`)`]}),(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:r.map(e=>(0,g.jsx)(d,{id:e.id,title:e.title,status:e.status,onClick:()=>n(e.id)},e.id))})]})}export{O as n,D as t};
|
|
2
|
-
//# sourceMappingURL=PlanGraphPanel-K6aFJmdd.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PlanGraphPanel-K6aFJmdd.js","names":[],"sources":["../../dashboard/src/components/chat/hooks/useIsMobile.ts","../../dashboard/src/components/chat/PlanGraphPanel.tsx"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\n// Reactive narrow-viewport flag. Subscribes to the same `max-width: 767px`\n// breakpoint the chat single-pane layout uses, via useSyncExternalStore — an\n// external-store subscription, not effect-driven derived state — so it stays\n// correct across resize/rotate without a useEffect.\nconst QUERY = '(max-width: 767px)'\n\nfunction subscribe(cb: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n const mql = window.matchMedia(QUERY)\n mql.addEventListener('change', cb)\n return () => mql.removeEventListener('change', cb)\n}\n\nexport function useIsMobile(): boolean {\n return useSyncExternalStore(\n subscribe,\n () => (typeof window !== 'undefined' ? window.matchMedia(QUERY).matches : false),\n () => false,\n )\n}\n","import { useEffect, useMemo } from 'react'\nimport { ChevronDown, ChevronUp, GitBranch } from 'lucide-react'\nimport { useRelayStore } from '@/store'\nimport type { Plan, PlanNode, PlanOwnerRef, PlanStatus } from '@/types'\nimport { cn } from '@/lib/utils'\nimport { planLookupKey, planTeamLookupKey } from '@/store/slices/plans'\nimport { IssueRefChip } from '@/components/shared/issue-ref-chip'\nimport { TaskChip } from '@/components/shared/task-chip'\nimport { useIsMobile } from './hooks/useIsMobile'\n\n// Left-to-right DAG: dependency depth flows along x (sequential gates), nodes\n// that share a depth stack along y (parallel lanes). This keeps the panel SHORT\n// — it's an operator overlay above the chat, not a full view — and lets the\n// gate-vs-lane structure read at a glance. Height is capped + scrollable below.\nconst NODE_W = 196\nconst NODE_H = 84\nconst COL_GAP = 52\nconst ROW_GAP = 16\nconst PAD = 14\n\nconst STATUS_ORDER: PlanStatus[] = ['landed', 'in-progress', 'pending', 'blocked']\n\nconst STATUS_STYLE: Record<\n PlanStatus,\n { label: string; dot: string; accent: string; text: string; wire: string }\n> = {\n landed: { label: 'landed', dot: 'bg-emerald-400', accent: 'border-l-emerald-400', text: 'text-emerald-300', wire: '#34d399' },\n 'in-progress': { label: 'in progress', dot: 'bg-sky-400', accent: 'border-l-sky-400', text: 'text-sky-300', wire: '#38bdf8' },\n pending: { label: 'pending', dot: 'bg-amber-400', accent: 'border-l-amber-400', text: 'text-amber-300', wire: '#fbbf24' },\n blocked: { label: 'blocked', dot: 'bg-red-400', accent: 'border-l-red-400', text: 'text-red-300', wire: '#f87171' },\n}\n\ninterface LayoutNode {\n node: PlanNode\n x: number\n y: number\n layer: number\n}\n\nfunction ownerLabel(owner?: PlanOwnerRef): string {\n if (!owner) return ''\n return owner.label || (owner.policyName ? `policy:${owner.policyName}` : owner.agentId || '')\n}\n\nfunction layerPlan(plan: Plan): { nodes: LayoutNode[]; width: number; height: number } {\n const nodeById = new Map(plan.nodes.map((node) => [node.id, node]))\n const indexById = new Map(plan.nodes.map((node, index) => [node.id, index]))\n const outgoing = new Map<string, string[]>()\n const indegree = new Map(plan.nodes.map((node) => [node.id, 0]))\n for (const edge of plan.edges) {\n if (!nodeById.has(edge.from) || !nodeById.has(edge.to)) continue\n outgoing.set(edge.from, [...(outgoing.get(edge.from) ?? []), edge.to])\n indegree.set(edge.to, (indegree.get(edge.to) ?? 0) + 1)\n }\n\n const layerById = new Map(plan.nodes.map((node) => [node.id, 0]))\n const queue = plan.nodes\n .filter((node) => (indegree.get(node.id) ?? 0) === 0)\n .map((node) => node.id)\n const visited = new Set<string>()\n\n while (queue.length) {\n const id = queue.shift()!\n visited.add(id)\n const fromLayer = layerById.get(id) ?? 0\n for (const to of outgoing.get(id) ?? []) {\n layerById.set(to, Math.max(layerById.get(to) ?? 0, fromLayer + 1))\n indegree.set(to, (indegree.get(to) ?? 0) - 1)\n if ((indegree.get(to) ?? 0) === 0) queue.push(to)\n }\n }\n\n let fallbackLayer = Math.max(0, ...Array.from(layerById.values())) + 1\n for (const node of plan.nodes) {\n if (visited.has(node.id)) continue\n layerById.set(node.id, fallbackLayer++)\n }\n\n const layers = new Map<number, PlanNode[]>()\n for (const node of plan.nodes) {\n const layer = layerById.get(node.id) ?? 0\n layers.set(layer, [...(layers.get(layer) ?? []), node])\n }\n\n const orderedLayers = [...layers.entries()].sort(([a], [b]) => a - b)\n const maxRows = Math.max(1, ...orderedLayers.map(([, nodes]) => nodes.length))\n const rowPitch = NODE_H + ROW_GAP\n\n const layoutNodes: LayoutNode[] = []\n orderedLayers.forEach(([layer, nodes], col) => {\n const ordered = [...nodes].sort((a, b) => {\n const lane = (a.lane || '').localeCompare(b.lane || '')\n return lane || ((indexById.get(a.id) ?? 0) - (indexById.get(b.id) ?? 0))\n })\n // Center each column vertically against the tallest column so the spine\n // runs through the middle and the parallel fan reads as a fan.\n const offset = ((maxRows - ordered.length) * rowPitch) / 2\n ordered.forEach((node, row) => {\n layoutNodes.push({\n node,\n layer,\n x: PAD + col * (NODE_W + COL_GAP),\n y: PAD + offset + row * rowPitch,\n })\n })\n })\n\n const cols = orderedLayers.length\n return {\n nodes: layoutNodes,\n width: Math.max(320, PAD * 2 + cols * NODE_W + Math.max(0, cols - 1) * COL_GAP),\n height: Math.max(NODE_H + PAD * 2, PAD * 2 + maxRows * NODE_H + Math.max(0, maxRows - 1) * ROW_GAP),\n }\n}\n\nfunction edgePath(from: LayoutNode, to: LayoutNode): string {\n const x1 = from.x + NODE_W\n const y1 = from.y + NODE_H / 2\n const x2 = to.x\n const y2 = to.y + NODE_H / 2\n const midX = x1 + Math.max(20, (x2 - x1) / 2)\n return `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`\n}\n\nexport function PlanGraphPanel({ threadId, teamId, channel }: { threadId?: string | number | null; teamId?: string | null; channel?: string }) {\n const key = teamId ? planTeamLookupKey(teamId, channel) : threadId ? planLookupKey(threadId, channel) : ''\n const plan = useRelayStore((s) => teamId ? s.plansByTeam[key] : key ? s.plansByThread[key] : null)\n const fetchPlan = useRelayStore((s) => s.fetchPlan)\n const planCollapsed = useRelayStore((s) => s.planCollapsed)\n const setPlanCollapsed = useRelayStore((s) => s.setPlanCollapsed)\n const issueRefsById = useRelayStore((s) => s.issueRefsById)\n const deliverableTasks = useRelayStore((s) => s.deliverableTasks)\n const openTaskDetailById = useRelayStore((s) => s.openTaskDetailById)\n const isMobile = useIsMobile()\n // null = no manual toggle yet → follow the viewport default. The graph\n // dominates a phone screen, so it starts collapsed there and expanded on\n // desktop; an explicit user toggle (persisted) overrides the default.\n const collapsed = planCollapsed ?? isMobile\n\n useEffect(() => {\n if (teamId) {\n void fetchPlan({ teamId, channel })\n return\n }\n if (threadId) void fetchPlan({ threadId, channel })\n }, [channel, fetchPlan, teamId, threadId])\n\n const layout = useMemo(() => plan ? layerPlan(plan) : null, [plan])\n const nodeById = useMemo(() => new Map(layout?.nodes.map((node) => [node.node.id, node]) ?? []), [layout])\n\n const legend = useMemo(() => {\n if (!plan) return []\n const counts = new Map<PlanStatus, number>()\n for (const node of plan.nodes) counts.set(node.status, (counts.get(node.status) ?? 0) + 1)\n return STATUS_ORDER.filter((status) => counts.has(status)).map((status) => ({\n status,\n count: counts.get(status) ?? 0,\n }))\n }, [plan])\n\n if (!plan || !layout) return null\n\n const nodeCount = plan.nodes.length\n const landedCount = legend.find((entry) => entry.status === 'landed')?.count ?? 0\n // Thin summary for the collapsed bar (the legend dots are hidden on mobile),\n // e.g. \"5 nodes · 4 landed\".\n const summary = `${nodeCount} node${nodeCount === 1 ? '' : 's'}${landedCount > 0 ? ` · ${landedCount} landed` : ''}`\n\n return (\n <section className=\"shrink-0 border-b border-border bg-card/45 px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => setPlanCollapsed(!collapsed)}\n aria-expanded={!collapsed}\n aria-label={collapsed ? 'Expand plan graph' : 'Collapse plan graph'}\n className={cn(\n 'flex w-full min-w-0 items-center gap-2 text-left',\n !collapsed && 'mb-2',\n )}\n >\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded bg-muted/60\">\n <GitBranch className=\"h-3 w-3 text-muted-foreground\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-[13px] font-semibold leading-tight text-foreground\">{plan.title || 'Plan'}</div>\n <div className=\"truncate text-[11px] leading-tight text-muted-foreground\">\n {collapsed ? summary : (plan.objective || summary)}\n </div>\n </div>\n {legend.length > 0 && (\n <div className=\"hidden shrink-0 items-center gap-2.5 sm:flex\">\n {legend.map(({ status, count }) => (\n <span key={status} className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <span className={cn('h-1.5 w-1.5 rounded-full', STATUS_STYLE[status].dot)} />\n <span className={cn('font-medium tabular-nums', STATUS_STYLE[status].text)}>{count}</span>\n <span>{STATUS_STYLE[status].label}</span>\n </span>\n ))}\n </div>\n )}\n <span className=\"shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-muted-foreground\">\n v{plan.version}\n </span>\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted/60 hover:text-foreground\">\n {collapsed ? <ChevronDown className=\"h-3.5 w-3.5\" /> : <ChevronUp className=\"h-3.5 w-3.5\" />}\n </span>\n </button>\n {collapsed ? null : plan.nodes.length === 0 ? (\n <div className=\"rounded-md border border-dashed border-border px-3 py-3 text-center text-xs text-muted-foreground\">\n No nodes yet — the plan graph fills in as the team is composed.\n </div>\n ) : (\n <div className=\"max-h-[min(46vh,360px)] overflow-auto\">\n <div className=\"relative\" style={{ width: layout.width, height: layout.height }}>\n <svg className=\"pointer-events-none absolute inset-0\" width={layout.width} height={layout.height} aria-hidden=\"true\">\n <defs>\n {STATUS_ORDER.map((status) => (\n <marker\n key={status}\n id={`plan-arrow-${status}`}\n viewBox=\"0 0 8 8\"\n refX=\"6.5\"\n refY=\"4\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n >\n <path d=\"M0 0 L8 4 L0 8 z\" fill={STATUS_STYLE[status].wire} />\n </marker>\n ))}\n </defs>\n {plan.edges.map((edge) => {\n const from = nodeById.get(edge.from)\n const to = nodeById.get(edge.to)\n if (!from || !to) return null\n const wire = STATUS_STYLE[from.node.status]\n return (\n <path\n key={`${edge.from}->${edge.to}`}\n d={edgePath(from, to)}\n stroke={wire.wire}\n strokeOpacity={0.7}\n strokeWidth={2}\n fill=\"none\"\n strokeLinecap=\"round\"\n markerEnd={`url(#plan-arrow-${from.node.status})`}\n />\n )\n })}\n </svg>\n {layout.nodes.map(({ node, x, y }) => {\n const status = STATUS_STYLE[node.status]\n const owner = ownerLabel(node.ownerRef)\n const issueRef = node.refs?.issueId ? issueRefsById[node.refs.issueId] : null\n const taskNumId = node.refs?.taskId ? parseInt(node.refs.taskId, 10) : null\n const taskTitle = taskNumId != null ? deliverableTasks.find((t) => t.id === taskNumId)?.title : undefined\n return (\n <article\n key={node.id}\n className={cn(\n 'group absolute flex flex-col justify-between rounded-md border border-l-[3px] bg-background/95 p-2',\n 'shadow-sm transition-all hover:-translate-y-px hover:border-border hover:shadow-md hover:bg-background',\n status.accent,\n )}\n style={{ left: x, top: y, width: NODE_W, height: NODE_H }}\n title={node.scopeBlurb || node.label}\n >\n <div className=\"truncate text-xs font-semibold leading-tight text-foreground\">{node.label}</div>\n {(node.scopeBlurb || node.id) && (\n <div className=\"truncate text-[10px] leading-tight text-muted-foreground\">{node.scopeBlurb || node.id}</div>\n )}\n {(issueRef || taskNumId != null) && (\n <div className=\"flex min-w-0 flex-wrap gap-1\">\n {issueRef && <IssueRefChip issueRef={issueRef} compact className=\"max-w-full\" />}\n {taskNumId != null && (\n <TaskChip id={taskNumId} title={taskTitle} onClick={() => openTaskDetailById(taskNumId)} className=\"max-w-full\" />\n )}\n </div>\n )}\n <div className=\"flex min-w-0 items-center justify-between gap-1.5\">\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <span className={cn('h-1.5 w-1.5 shrink-0 rounded-full', status.dot)} />\n <span className={cn('text-[10px] font-medium', status.text)}>{status.label}</span>\n </div>\n <div className=\"flex min-w-0 items-center gap-1.5\">\n {owner && <span className=\"truncate text-[10px] text-muted-foreground\">{owner}</span>}\n {node.lane && (\n <span className=\"shrink-0 rounded-sm bg-muted/70 px-1 py-px text-[9px] font-medium uppercase tracking-wide text-muted-foreground\">\n {node.lane}\n </span>\n )}\n </div>\n </div>\n </article>\n )\n })}\n </div>\n </div>\n )}\n </section>\n )\n}\n\n// Tasks created/triggered from a session (#856). Client-side filter on createdBy until\n// the backend exposes a dedicated /api/tasks?createdBy= filter (backend follow-up needed).\nexport function SessionTasksPanel({ agentId }: { agentId: string }) {\n const deliverableTasks = useRelayStore((s) => s.deliverableTasks)\n const openTaskDetailById = useRelayStore((s) => s.openTaskDetailById)\n const sessionTasks = deliverableTasks.filter((t) => t.createdBy === agentId)\n if (sessionTasks.length === 0) return null\n return (\n <section className=\"shrink-0 border-b border-border bg-card/45 px-3 py-2\">\n <div className=\"mb-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground\">\n Tasks from this session ({sessionTasks.length})\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {sessionTasks.map((task) => (\n <TaskChip\n key={task.id}\n id={task.id}\n title={task.title}\n status={task.status}\n onClick={() => openTaskDetailById(task.id)}\n />\n ))}\n </div>\n </section>\n )\n}\n"],"mappings":"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"}
|