agent-relay-server 0.127.0 → 0.127.2
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-D2cnxyTy.js → MessageBubble-DnXnkt4a.js} +2 -2
- package/public/assets/{MessageBubble-D2cnxyTy.js.map → MessageBubble-DnXnkt4a.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-Cnxt-x7R.js → PlanGraphPanel-D6CPEpQD.js} +2 -2
- package/public/assets/{PlanGraphPanel-Cnxt-x7R.js.map → PlanGraphPanel-D6CPEpQD.js.map} +1 -1
- package/public/assets/{activity-BEm1BQB1.js → activity-ZPwHcPLK.js} +2 -2
- package/public/assets/{activity-BEm1BQB1.js.map → activity-ZPwHcPLK.js.map} +1 -1
- package/public/assets/{agent-profiles-C8V_oCiM.js → agent-profiles-CT0E9LV1.js} +2 -2
- package/public/assets/{agent-profiles-C8V_oCiM.js.map → agent-profiles-CT0E9LV1.js.map} +1 -1
- package/public/assets/{agents-D8mc9X1j.js → agents-Dt5TncjC.js} +2 -2
- package/public/assets/{agents-D8mc9X1j.js.map → agents-Dt5TncjC.js.map} +1 -1
- package/public/assets/{automation-BEhJZkNQ.js → automation-yzUJbvT2.js} +2 -2
- package/public/assets/{automation-BEhJZkNQ.js.map → automation-yzUJbvT2.js.map} +1 -1
- package/public/assets/chat-DhYX9BDG.js +2 -0
- package/public/assets/chat-DhYX9BDG.js.map +1 -0
- package/public/assets/{formatted-body-Rv9RDPsQ.js → formatted-body-D5-1aiyB.js} +3 -3
- package/public/assets/{formatted-body-Rv9RDPsQ.js.map → formatted-body-D5-1aiyB.js.map} +1 -1
- package/public/assets/{formatted-body-impl-XFU4tPeT.js → formatted-body-impl-Do5NbJUA.js} +2 -2
- package/public/assets/{formatted-body-impl-XFU4tPeT.js.map → formatted-body-impl-Do5NbJUA.js.map} +1 -1
- package/public/assets/{index-Bhy_jnX4.js → index-BdNafiPz.js} +6 -6
- package/public/assets/{index-Bhy_jnX4.js.map → index-BdNafiPz.js.map} +1 -1
- package/public/assets/{insights-DpXPAEwH.js → insights-i6AEZT_a.js} +2 -2
- package/public/assets/{insights-DpXPAEwH.js.map → insights-i6AEZT_a.js.map} +1 -1
- package/public/assets/{maintenance-BrkqfGwx.js → maintenance-CJ6wikpg.js} +2 -2
- package/public/assets/{maintenance-BrkqfGwx.js.map → maintenance-CJ6wikpg.js.map} +1 -1
- package/public/assets/{managed-agents-CLANxOAN.js → managed-agents-JZn0xNJR.js} +3 -3
- package/public/assets/managed-agents-JZn0xNJR.js.map +1 -0
- package/public/assets/{markdown-preview-impl-CcZFkjn-.js → markdown-preview-impl-BsvAkpR4.js} +2 -2
- package/public/assets/{markdown-preview-impl-CcZFkjn-.js.map → markdown-preview-impl-BsvAkpR4.js.map} +1 -1
- package/public/assets/{memory-BoQw8q-i.js → memory-BE9IwCdC.js} +2 -2
- package/public/assets/{memory-BoQw8q-i.js.map → memory-BE9IwCdC.js.map} +1 -1
- package/public/assets/{messages-DfKNuph2.js → messages-vXgdc3H4.js} +2 -2
- package/public/assets/{messages-DfKNuph2.js.map → messages-vXgdc3H4.js.map} +1 -1
- package/public/assets/{orchestrators-sQh8e7-V.js → orchestrators-CribhLg-.js} +2 -2
- package/public/assets/{orchestrators-sQh8e7-V.js.map → orchestrators-CribhLg-.js.map} +1 -1
- package/public/assets/{overview-B0z8ZNtp.js → overview-q3O9K9VK.js} +2 -2
- package/public/assets/{overview-B0z8ZNtp.js.map → overview-q3O9K9VK.js.map} +1 -1
- package/public/assets/{pairs-B3FhGmn-.js → pairs-BNOnd0IE.js} +2 -2
- package/public/assets/{pairs-B3FhGmn-.js.map → pairs-BNOnd0IE.js.map} +1 -1
- package/public/assets/{prompt-settings-CCj_s008.js → prompt-settings-Bdz_xCgD.js} +2 -2
- package/public/assets/{prompt-settings-CCj_s008.js.map → prompt-settings-Bdz_xCgD.js.map} +1 -1
- package/public/assets/{registry-mD_y06Ru.js → registry-DPcyGypi.js} +2 -2
- package/public/assets/{registry-mD_y06Ru.js.map → registry-DPcyGypi.js.map} +1 -1
- package/public/assets/{security-CTSA9niL.js → security-Z3l3u-Pl.js} +2 -2
- package/public/assets/{security-CTSA9niL.js.map → security-Z3l3u-Pl.js.map} +1 -1
- package/public/assets/{select-gEQEHCIf.js → select-BX_lW49D.js} +2 -2
- package/public/assets/{select-gEQEHCIf.js.map → select-BX_lW49D.js.map} +1 -1
- package/public/assets/{settings-ByAR-TYj.js → settings-Y381jZt7.js} +2 -2
- package/public/assets/{settings-ByAR-TYj.js.map → settings-Y381jZt7.js.map} +1 -1
- package/public/assets/{tasks-CZyJX881.js → tasks-Di6d0_Ch.js} +2 -2
- package/public/assets/{tasks-CZyJX881.js.map → tasks-Di6d0_Ch.js.map} +1 -1
- package/public/assets/{teams-BrL4sEL7.js → teams-DJv4l-_l.js} +2 -2
- package/public/assets/{teams-BrL4sEL7.js.map → teams-DJv4l-_l.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-LjIph8ql.js → terminal-viewer-impl-3zBLpRel.js} +2 -2
- package/public/assets/{terminal-viewer-impl-LjIph8ql.js.map → terminal-viewer-impl-3zBLpRel.js.map} +1 -1
- package/public/assets/{work-queue-CSu5kRsw.js → work-queue-D73-hP0c.js} +2 -2
- package/public/assets/{work-queue-CSu5kRsw.js.map → work-queue-D73-hP0c.js.map} +1 -1
- package/public/index.html +2 -2
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/mcp-outbox.ts +13 -1
- package/runner/src/provisioning.ts +121 -0
- package/runner/src/runner-core.ts +1 -1
- package/src/routes/agent-sessions.ts +4 -1
- package/src/routes/agents.ts +3 -0
- package/src/services/task-entity.ts +32 -1
- package/src/workspace-actions.ts +4 -2
- package/public/assets/chat-BAH9bEPx.js +0 -2
- package/public/assets/chat-BAH9bEPx.js.map +0 -1
- package/public/assets/managed-agents-CLANxOAN.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,gt as t,jn as n,rr as r,yn as i}from"./lucide-react-NXHPIMsX.js";import{p as a,t as o}from"./store-D-Frk_EC.js";import{K as s,ct as c,d as l}from"./display-aTnwsqQh.js";import{t as u}from"./badge-BCvp7LK3.js";import{t as d}from"./button-DyHjsHY3.js";import{At as f,G as p,wt as m}from"./index-
|
|
2
|
-
//# sourceMappingURL=work-queue-
|
|
1
|
+
import{a as e,gt as t,jn as n,rr as r,yn as i}from"./lucide-react-NXHPIMsX.js";import{p as a,t as o}from"./store-D-Frk_EC.js";import{K as s,ct as c,d as l}from"./display-aTnwsqQh.js";import{t as u}from"./badge-BCvp7LK3.js";import{t as d}from"./button-DyHjsHY3.js";import{At as f,G as p,wt as m}from"./index-BdNafiPz.js";import{r as h,t as g}from"./card-BoqYxpVW.js";var _=r(),v={open:`bg-blue-500/10 text-blue-400 border-blue-500/20`,blocked:`bg-yellow-500/10 text-yellow-400 border-yellow-500/20`,claimed:`bg-emerald-500/10 text-emerald-400 border-emerald-500/20`,in_progress:`bg-purple-500/10 text-purple-400 border-purple-500/20`};function y(){let e=a(),n=o(e=>e.agentsById),r=o(e=>e.compose),i=o(e=>e.set),s=o(e=>e.doClaimTask),c=o(e=>e.doClaim),d=o(e=>e.openTaskEvents),h=o(e=>e.showError),g=o(e=>e.openConfirm),v=o(e=>e.doDeleteMessage),y=o(e=>e.doUpdateTaskStatus),x=m(),S=f(),C=S.filter(e=>e.claimable).length;function w(e){if(!r.from){h(`Validation`,`Select a "Claim as" agent first.`);return}e.sourceType===`task`&&e.task?s(e.task.id):e.sourceType===`message`&&e.message&&c(e.message.id)}function T(e){g(`Cancel Item`,`Cancel "${e.title||(e.sourceType===`task`?`T${e.id}`:`Message #${e.id}`)}"? This cannot be undone.`,()=>{e.sourceType===`task`&&e.task?y(e.task,`canceled`):e.sourceType===`message`&&e.message&&v(e.message.id)})}function E(e){e.task&&d(e.task)}return(0,_.jsxs)(`div`,{className:`space-y-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between flex-wrap gap-2`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(t,{className:`w-5 h-5 text-muted-foreground`}),(0,_.jsx)(`h2`,{className:`text-lg font-semibold`,children:`Work Queue`}),C>0&&(0,_.jsxs)(u,{className:`bg-orange-500/20 text-orange-400 border-orange-500/30 border`,children:[C,` claimable`]})]}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`label`,{className:`text-xs text-muted-foreground shrink-0`,children:`Claim as`}),(0,_.jsxs)(`select`,{className:`rounded-md border border-input bg-background px-3 py-1.5 text-sm`,value:r.from,onChange:e=>i({compose:{...r,from:e.target.value}}),children:[(0,_.jsx)(`option`,{value:``,children:`Select agent...`}),x.map(e=>(0,_.jsx)(`option`,{value:e.id,children:l(e)},e.id))]})]})]}),(0,_.jsx)(p,{className:`h-[calc(100dvh-11rem)]`,children:(0,_.jsxs)(`div`,{className:`space-y-2 pr-2`,children:[S.length===0&&(0,_.jsx)(`div`,{className:`text-center text-muted-foreground py-16 text-sm`,children:`Work queue is empty`}),S.map(t=>(0,_.jsx)(b,{item:t,now:e,agentName:e=>n[e]?l(n[e]):e.slice(-10),onClaim:()=>w(t),onCancel:()=>T(t),onEvents:t.task?()=>E(t):void 0},t.id))]})})]})}function b({item:t,now:r,agentName:a,onClaim:o,onCancel:l,onEvents:f}){let p=c[t.severity]||c.info,m=v[t.status]||`bg-zinc-500/10 text-zinc-400 border-zinc-500/20`;return(0,_.jsx)(g,{className:t.claimable?`ring-1 ring-orange-500/30`:``,children:(0,_.jsx)(h,{className:`p-3`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap mb-1`,children:[(0,_.jsx)(`span`,{className:`font-medium text-sm truncate`,children:t.title}),(0,_.jsx)(u,{variant:`outline`,className:`text-xs px-1.5 py-0 border ${p}`,children:t.severity}),(0,_.jsx)(u,{variant:`outline`,className:`text-xs px-1.5 py-0 border ${m}`,children:t.status}),t.sourceType===`message`&&(0,_.jsx)(u,{variant:`outline`,className:`text-xs px-1.5 py-0 border border-zinc-500/20 text-zinc-400`,children:`msg`})]}),t.body&&(0,_.jsx)(`p`,{className:`text-xs text-muted-foreground line-clamp-2 mb-2`,children:t.body}),(0,_.jsxs)(`div`,{className:`flex items-center gap-3 text-xs text-muted-foreground flex-wrap`,children:[t.owner&&(0,_.jsxs)(`span`,{title:`Owner`,children:[(0,_.jsx)(i,{className:`w-3 h-3 inline mr-1`}),a(t.owner)]}),t.source&&(0,_.jsx)(`span`,{className:`font-mono`,children:t.source}),(0,_.jsxs)(`span`,{title:String(t.updatedAt),children:[(0,_.jsx)(n,{className:`w-3 h-3 inline mr-1`}),s(r,t.updatedAt)]})]})]}),(0,_.jsxs)(`div`,{className:`flex flex-col gap-1 shrink-0`,children:[t.claimable&&(0,_.jsxs)(d,{size:`sm`,className:`h-7 text-xs bg-orange-600 hover:bg-orange-700 text-white`,onClick:o,children:[(0,_.jsx)(i,{className:`w-3.5 h-3.5 mr-1`}),` Claim`]}),f&&(0,_.jsx)(d,{size:`sm`,variant:`outline`,className:`h-7 text-xs`,onClick:f,children:`Events`}),(0,_.jsxs)(d,{size:`sm`,variant:`outline`,className:`h-7 text-xs text-red-400 hover:text-red-300 hover:bg-red-500/10 border-red-500/20`,onClick:l,children:[(0,_.jsx)(e,{className:`w-3.5 h-3.5 mr-1`}),` Cancel`]})]})]})})})}export{y as WorkQueueView};
|
|
2
|
+
//# sourceMappingURL=work-queue-D73-hP0c.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-queue-CSu5kRsw.js","names":[],"sources":["../../dashboard/src/components/views/work-queue.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { useWorkQueueItems, useComposeAgents } from '@/hooks/use-selectors'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { ListChecks, CheckCircle2, Calendar, X } from 'lucide-react'\nimport { displayName, timeAgo } from '@/lib/display'\nimport { SEVERITY_COLORS } from '@/lib/constants'\nimport type { WorkQueueItem } from '@/types'\n\nconst STATUS_COLORS: Record<string, string> = {\n open: 'bg-blue-500/10 text-blue-400 border-blue-500/20',\n blocked: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20',\n claimed: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20',\n in_progress: 'bg-purple-500/10 text-purple-400 border-purple-500/20',\n}\n\nexport function WorkQueueView() {\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const compose = useRelayStore((s) => s.compose)\n const set = useRelayStore((s) => s.set)\n const doClaimTask = useRelayStore((s) => s.doClaimTask)\n const doClaim = useRelayStore((s) => s.doClaim)\n const openTaskEvents = useRelayStore((s) => s.openTaskEvents)\n const showError = useRelayStore((s) => s.showError)\n const openConfirm = useRelayStore((s) => s.openConfirm)\n const doDeleteMessage = useRelayStore((s) => s.doDeleteMessage)\n const doUpdateTaskStatus = useRelayStore((s) => s.doUpdateTaskStatus)\n\n const composeAgents = useComposeAgents()\n const items = useWorkQueueItems()\n\n const claimableCount = items.filter((i) => i.claimable).length\n\n function handleClaim(item: WorkQueueItem) {\n if (!compose.from) { showError('Validation', 'Select a \"Claim as\" agent first.'); return }\n if (item.sourceType === 'task' && item.task) doClaimTask(item.task.id)\n else if (item.sourceType === 'message' && item.message) doClaim(item.message.id)\n }\n\n function handleCancel(item: WorkQueueItem) {\n const label = item.title || (item.sourceType === 'task' ? `T${item.id}` : `Message #${item.id}`)\n openConfirm('Cancel Item', `Cancel \"${label}\"? This cannot be undone.`, () => {\n if (item.sourceType === 'task' && item.task) doUpdateTaskStatus(item.task, 'canceled')\n else if (item.sourceType === 'message' && item.message) doDeleteMessage(item.message.id)\n })\n }\n\n function handleEvents(item: WorkQueueItem) {\n if (item.task) openTaskEvents(item.task)\n }\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\">\n <ListChecks className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Work Queue</h2>\n {claimableCount > 0 && (\n <Badge className=\"bg-orange-500/20 text-orange-400 border-orange-500/30 border\">\n {claimableCount} claimable\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-muted-foreground shrink-0\">Claim as</label>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={compose.from}\n onChange={(e) => set({ compose: { ...compose, from: e.target.value } })}\n >\n <option value=\"\">Select agent...</option>\n {composeAgents.map((a) => <option key={a.id} value={a.id}>{displayName(a)}</option>)}\n </select>\n </div>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-11rem)]\">\n <div className=\"space-y-2 pr-2\">\n {items.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">Work queue is empty</div>\n )}\n {items.map((item) => (\n <WorkQueueCard\n key={item.id}\n item={item}\n now={now}\n agentName={(id) => agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)}\n onClaim={() => handleClaim(item)}\n onCancel={() => handleCancel(item)}\n onEvents={item.task ? () => handleEvents(item) : undefined}\n />\n ))}\n </div>\n </ScrollArea>\n </div>\n )\n}\n\nfunction WorkQueueCard({\n item, now, agentName, onClaim, onCancel, onEvents,\n}: {\n item: WorkQueueItem\n now: number\n agentName: (id: string) => string\n onClaim: () => void\n onCancel: () => void\n onEvents?: () => void\n}) {\n const severityClass = SEVERITY_COLORS[item.severity] || SEVERITY_COLORS.info\n const statusClass = STATUS_COLORS[item.status] || 'bg-zinc-500/10 text-zinc-400 border-zinc-500/20'\n\n return (\n <Card className={item.claimable ? 'ring-1 ring-orange-500/30' : ''}>\n <CardContent className=\"p-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap mb-1\">\n <span className=\"font-medium text-sm truncate\">{item.title}</span>\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 border ${severityClass}`}>{item.severity}</Badge>\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 border ${statusClass}`}>{item.status}</Badge>\n {item.sourceType === 'message' && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 border border-zinc-500/20 text-zinc-400\">msg</Badge>\n )}\n </div>\n {item.body && (\n <p className=\"text-xs text-muted-foreground line-clamp-2 mb-2\">{item.body}</p>\n )}\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground flex-wrap\">\n {item.owner && (\n <span title=\"Owner\">\n <CheckCircle2 className=\"w-3 h-3 inline mr-1\" />{agentName(item.owner)}\n </span>\n )}\n {item.source && (\n <span className=\"font-mono\">{item.source}</span>\n )}\n <span title={String(item.updatedAt)}>\n <Calendar className=\"w-3 h-3 inline mr-1\" />{timeAgo(now, item.updatedAt)}\n </span>\n </div>\n </div>\n <div className=\"flex flex-col gap-1 shrink-0\">\n {item.claimable && (\n <Button size=\"sm\" className=\"h-7 text-xs bg-orange-600 hover:bg-orange-700 text-white\" onClick={onClaim}>\n <CheckCircle2 className=\"w-3.5 h-3.5 mr-1\" /> Claim\n </Button>\n )}\n {onEvents && (\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\" onClick={onEvents}>\n Events\n </Button>\n )}\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300 hover:bg-red-500/10 border-red-500/20\" onClick={onCancel}>\n <X className=\"w-3.5 h-3.5 mr-1\" /> Cancel\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"work-queue-D73-hP0c.js","names":[],"sources":["../../dashboard/src/components/views/work-queue.tsx"],"sourcesContent":["import { useRelayStore, useNow } from '@/store'\nimport { useWorkQueueItems, useComposeAgents } from '@/hooks/use-selectors'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { ListChecks, CheckCircle2, Calendar, X } from 'lucide-react'\nimport { displayName, timeAgo } from '@/lib/display'\nimport { SEVERITY_COLORS } from '@/lib/constants'\nimport type { WorkQueueItem } from '@/types'\n\nconst STATUS_COLORS: Record<string, string> = {\n open: 'bg-blue-500/10 text-blue-400 border-blue-500/20',\n blocked: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20',\n claimed: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20',\n in_progress: 'bg-purple-500/10 text-purple-400 border-purple-500/20',\n}\n\nexport function WorkQueueView() {\n const now = useNow()\n const agentsById = useRelayStore((s) => s.agentsById)\n const compose = useRelayStore((s) => s.compose)\n const set = useRelayStore((s) => s.set)\n const doClaimTask = useRelayStore((s) => s.doClaimTask)\n const doClaim = useRelayStore((s) => s.doClaim)\n const openTaskEvents = useRelayStore((s) => s.openTaskEvents)\n const showError = useRelayStore((s) => s.showError)\n const openConfirm = useRelayStore((s) => s.openConfirm)\n const doDeleteMessage = useRelayStore((s) => s.doDeleteMessage)\n const doUpdateTaskStatus = useRelayStore((s) => s.doUpdateTaskStatus)\n\n const composeAgents = useComposeAgents()\n const items = useWorkQueueItems()\n\n const claimableCount = items.filter((i) => i.claimable).length\n\n function handleClaim(item: WorkQueueItem) {\n if (!compose.from) { showError('Validation', 'Select a \"Claim as\" agent first.'); return }\n if (item.sourceType === 'task' && item.task) doClaimTask(item.task.id)\n else if (item.sourceType === 'message' && item.message) doClaim(item.message.id)\n }\n\n function handleCancel(item: WorkQueueItem) {\n const label = item.title || (item.sourceType === 'task' ? `T${item.id}` : `Message #${item.id}`)\n openConfirm('Cancel Item', `Cancel \"${label}\"? This cannot be undone.`, () => {\n if (item.sourceType === 'task' && item.task) doUpdateTaskStatus(item.task, 'canceled')\n else if (item.sourceType === 'message' && item.message) doDeleteMessage(item.message.id)\n })\n }\n\n function handleEvents(item: WorkQueueItem) {\n if (item.task) openTaskEvents(item.task)\n }\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\">\n <ListChecks className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Work Queue</h2>\n {claimableCount > 0 && (\n <Badge className=\"bg-orange-500/20 text-orange-400 border-orange-500/30 border\">\n {claimableCount} claimable\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-muted-foreground shrink-0\">Claim as</label>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={compose.from}\n onChange={(e) => set({ compose: { ...compose, from: e.target.value } })}\n >\n <option value=\"\">Select agent...</option>\n {composeAgents.map((a) => <option key={a.id} value={a.id}>{displayName(a)}</option>)}\n </select>\n </div>\n </div>\n\n <ScrollArea className=\"h-[calc(100dvh-11rem)]\">\n <div className=\"space-y-2 pr-2\">\n {items.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">Work queue is empty</div>\n )}\n {items.map((item) => (\n <WorkQueueCard\n key={item.id}\n item={item}\n now={now}\n agentName={(id) => agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)}\n onClaim={() => handleClaim(item)}\n onCancel={() => handleCancel(item)}\n onEvents={item.task ? () => handleEvents(item) : undefined}\n />\n ))}\n </div>\n </ScrollArea>\n </div>\n )\n}\n\nfunction WorkQueueCard({\n item, now, agentName, onClaim, onCancel, onEvents,\n}: {\n item: WorkQueueItem\n now: number\n agentName: (id: string) => string\n onClaim: () => void\n onCancel: () => void\n onEvents?: () => void\n}) {\n const severityClass = SEVERITY_COLORS[item.severity] || SEVERITY_COLORS.info\n const statusClass = STATUS_COLORS[item.status] || 'bg-zinc-500/10 text-zinc-400 border-zinc-500/20'\n\n return (\n <Card className={item.claimable ? 'ring-1 ring-orange-500/30' : ''}>\n <CardContent className=\"p-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap mb-1\">\n <span className=\"font-medium text-sm truncate\">{item.title}</span>\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 border ${severityClass}`}>{item.severity}</Badge>\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 border ${statusClass}`}>{item.status}</Badge>\n {item.sourceType === 'message' && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 border border-zinc-500/20 text-zinc-400\">msg</Badge>\n )}\n </div>\n {item.body && (\n <p className=\"text-xs text-muted-foreground line-clamp-2 mb-2\">{item.body}</p>\n )}\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground flex-wrap\">\n {item.owner && (\n <span title=\"Owner\">\n <CheckCircle2 className=\"w-3 h-3 inline mr-1\" />{agentName(item.owner)}\n </span>\n )}\n {item.source && (\n <span className=\"font-mono\">{item.source}</span>\n )}\n <span title={String(item.updatedAt)}>\n <Calendar className=\"w-3 h-3 inline mr-1\" />{timeAgo(now, item.updatedAt)}\n </span>\n </div>\n </div>\n <div className=\"flex flex-col gap-1 shrink-0\">\n {item.claimable && (\n <Button size=\"sm\" className=\"h-7 text-xs bg-orange-600 hover:bg-orange-700 text-white\" onClick={onClaim}>\n <CheckCircle2 className=\"w-3.5 h-3.5 mr-1\" /> Claim\n </Button>\n )}\n {onEvents && (\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs\" onClick={onEvents}>\n Events\n </Button>\n )}\n <Button size=\"sm\" variant=\"outline\" className=\"h-7 text-xs text-red-400 hover:text-red-300 hover:bg-red-500/10 border-red-500/20\" onClick={onCancel}>\n <X className=\"w-3.5 h-3.5 mr-1\" /> Cancel\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":"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"}
|
package/public/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%2309090b'/%3E%3Ccircle cx='16' cy='16' r='4.5' fill='%2358a6ff'/%3E%3Ccircle cx='6' cy='8' r='2.5' fill='%233fb950'/%3E%3Ccircle cx='26' cy='8' r='2.5' fill='%233fb950'/%3E%3Ccircle cx='6' cy='24' r='2.5' fill='%233fb950'/%3E%3Ccircle cx='26' cy='24' r='2.5' fill='%233fb950'/%3E%3Cline x1='8' y1='9.5' x2='13' y2='14' stroke='%2330363d' stroke-width='1.5'/%3E%3Cline x1='24' y1='9.5' x2='19' y2='14' stroke='%2330363d' stroke-width='1.5'/%3E%3Cline x1='8' y1='22.5' x2='13' y2='18' stroke='%2330363d' stroke-width='1.5'/%3E%3Cline x1='24' y1='22.5' x2='19' y2='18' stroke='%2330363d' stroke-width='1.5'/%3E%3C/svg%3E">
|
|
13
13
|
<link rel="manifest" href="manifest.webmanifest">
|
|
14
14
|
<link rel="apple-touch-icon" href="icons/agent-relay-192.png">
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-BdNafiPz.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/chunk-CilyBKbf.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-C_JMBXql.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/lucide-react-NXHPIMsX.js">
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<link rel="modulepreload" crossorigin href="./assets/agent-type-icon-BmBR-9CH.js">
|
|
37
37
|
<link rel="modulepreload" crossorigin href="./assets/button-DyHjsHY3.js">
|
|
38
38
|
<link rel="modulepreload" crossorigin href="./assets/copy-button-C67FUG3E.js">
|
|
39
|
-
<link rel="modulepreload" crossorigin href="./assets/formatted-body-
|
|
39
|
+
<link rel="modulepreload" crossorigin href="./assets/formatted-body-D5-1aiyB.js">
|
|
40
40
|
<link rel="modulepreload" crossorigin href="./assets/task-chip-CeujtXYT.js">
|
|
41
41
|
<link rel="modulepreload" crossorigin href="./assets/badge-BCvp7LK3.js">
|
|
42
42
|
<link rel="modulepreload" crossorigin href="./assets/input-Rc4oWv4q.js">
|
package/runner/src/mcp-outbox.ts
CHANGED
|
@@ -67,7 +67,12 @@ export async function deliverRunnerOutboxEvent(input: RunnerOutboxDelivery): Pro
|
|
|
67
67
|
}
|
|
68
68
|
logger.warn("outbox", `dropping event with unknown kind: ${record.kind}`);
|
|
69
69
|
} catch (error) {
|
|
70
|
-
if (isHttpStatusError(error, 409))
|
|
70
|
+
if (isHttpStatusError(error, 409)) {
|
|
71
|
+
if (record.kind === "session-message-batch") {
|
|
72
|
+
logger.error("outbox", `relay reported duplicate session batch; acking row seq=${record.seq} batchKey=${record.idempotencyKey} itemKeys=${sessionBatchItemKeys(record).join(",")} error=${errMessage(error)}`);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
71
76
|
if (isHttpAuthError(error)) input.recoverRuntimeTokenAfterAuthFailure("outbox");
|
|
72
77
|
throw error;
|
|
73
78
|
}
|
|
@@ -89,6 +94,13 @@ function isDeterministicValidationError(error: unknown): boolean {
|
|
|
89
94
|
return status === 400 || status === 413 || status === 422;
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
function sessionBatchItemKeys(record: OutboxRecord): string[] {
|
|
98
|
+
const messages = Array.isArray((record.payload as { messages?: unknown }).messages)
|
|
99
|
+
? (record.payload as { messages: SendMessageInput[] }).messages
|
|
100
|
+
: [];
|
|
101
|
+
return messages.map((message, index) => message.idempotencyKey ?? `${record.idempotencyKey}:${index}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
export async function deliverBufferedMcpCall(input: {
|
|
93
105
|
record: OutboxRecord;
|
|
94
106
|
relayUrl: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
4
|
import { sanitizeFsName } from "agent-relay-sdk/fs-name";
|
|
@@ -355,6 +356,126 @@ export function writeCodexHooksJson(codexHome: string, hooks: ProvisioningHookSe
|
|
|
355
356
|
return;
|
|
356
357
|
}
|
|
357
358
|
writeFileSync(join(codexHome, "hooks.json"), JSON.stringify({ hooks }, null, 2), { mode: 0o600 });
|
|
359
|
+
writeCodexHookTrustState(codexHome, hooks);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const CODEX_HOOK_EVENT_STATE_KEYS: Record<string, string> = {
|
|
363
|
+
PreToolUse: "pre_tool_use",
|
|
364
|
+
PermissionRequest: "permission_request",
|
|
365
|
+
PostToolUse: "post_tool_use",
|
|
366
|
+
PreCompact: "pre_compact",
|
|
367
|
+
PostCompact: "post_compact",
|
|
368
|
+
SessionStart: "session_start",
|
|
369
|
+
UserPromptSubmit: "user_prompt_submit",
|
|
370
|
+
SubagentStart: "subagent_start",
|
|
371
|
+
SubagentStop: "subagent_stop",
|
|
372
|
+
Stop: "stop",
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
interface CodexHookTrustEntry {
|
|
376
|
+
key: string;
|
|
377
|
+
trustedHash: string;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export function codexHookTrustEntries(codexHome: string, hooks: ProvisioningHookSet): CodexHookTrustEntry[] {
|
|
381
|
+
const sourcePath = join(codexHome, "hooks.json");
|
|
382
|
+
const entries: CodexHookTrustEntry[] = [];
|
|
383
|
+
for (const [eventName, groups] of Object.entries(hooks)) {
|
|
384
|
+
const eventKey = CODEX_HOOK_EVENT_STATE_KEYS[eventName];
|
|
385
|
+
if (!eventKey) continue;
|
|
386
|
+
groups.forEach((group, groupIndex) => {
|
|
387
|
+
group.hooks.forEach((handler, handlerIndex) => {
|
|
388
|
+
if (handler.type !== "command") return;
|
|
389
|
+
entries.push({
|
|
390
|
+
key: `${sourcePath}:${eventKey}:${groupIndex}:${handlerIndex}`,
|
|
391
|
+
trustedHash: codexCommandHookHash(eventKey, group.matcher, group, handler),
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return entries;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function writeCodexHookTrustState(codexHome: string, hooks: ProvisioningHookSet): void {
|
|
400
|
+
const entries = codexHookTrustEntries(codexHome, hooks);
|
|
401
|
+
if (!entries.length) return;
|
|
402
|
+
const configPath = join(codexHome, "config.toml");
|
|
403
|
+
let config = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
|
|
404
|
+
for (const entry of entries) {
|
|
405
|
+
config = upsertCodexHookTrustEntry(config, entry);
|
|
406
|
+
}
|
|
407
|
+
writeFileSync(configPath, config, { mode: 0o600 });
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function upsertCodexHookTrustEntry(config: string, entry: CodexHookTrustEntry): string {
|
|
411
|
+
const header = `[hooks.state.${tomlQuotedString(entry.key)}]`;
|
|
412
|
+
const lines = config.length ? config.split(/\n/) : [];
|
|
413
|
+
const headerIndex = lines.findIndex((line) => line.trim() === header);
|
|
414
|
+
if (headerIndex < 0) {
|
|
415
|
+
const prefix = config.endsWith("\n") || config.length === 0 ? config : `${config}\n`;
|
|
416
|
+
return `${prefix}\n${header}\ntrusted_hash = ${tomlQuotedString(entry.trustedHash)}\n`;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
let nextHeaderIndex = lines.length;
|
|
420
|
+
for (let i = headerIndex + 1; i < lines.length; i += 1) {
|
|
421
|
+
if (/^\s*\[.*\]\s*$/.test(lines[i] ?? "")) {
|
|
422
|
+
nextHeaderIndex = i;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const trustedHashLine = `trusted_hash = ${tomlQuotedString(entry.trustedHash)}`;
|
|
428
|
+
const existingIndex = lines
|
|
429
|
+
.slice(headerIndex + 1, nextHeaderIndex)
|
|
430
|
+
.findIndex((line) => /^\s*trusted_hash\s*=/.test(line));
|
|
431
|
+
if (existingIndex >= 0) {
|
|
432
|
+
lines[headerIndex + 1 + existingIndex] = trustedHashLine;
|
|
433
|
+
} else {
|
|
434
|
+
lines.splice(nextHeaderIndex, 0, trustedHashLine);
|
|
435
|
+
}
|
|
436
|
+
return lines.join("\n");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function codexCommandHookHash(
|
|
440
|
+
eventKey: string,
|
|
441
|
+
matcher: string | undefined,
|
|
442
|
+
group: ProvisioningHookSet[string][number],
|
|
443
|
+
handler: ProvisioningHookSet[string][number]["hooks"][number],
|
|
444
|
+
): string {
|
|
445
|
+
// Mirrors Codex's command_hook_hash: hash the normalized hook identity, not the source file.
|
|
446
|
+
const normalizedHandler: Record<string, unknown> = {
|
|
447
|
+
type: "command",
|
|
448
|
+
command: handler.command,
|
|
449
|
+
async: false,
|
|
450
|
+
timeout: Math.max(1, handler.timeout ?? 600),
|
|
451
|
+
};
|
|
452
|
+
if (handler.statusMessage !== undefined) normalizedHandler.statusMessage = handler.statusMessage;
|
|
453
|
+
|
|
454
|
+
const identity: Record<string, unknown> = {
|
|
455
|
+
event_name: eventKey,
|
|
456
|
+
hooks: [normalizedHandler],
|
|
457
|
+
};
|
|
458
|
+
if (matcher !== undefined) identity.matcher = matcher;
|
|
459
|
+
|
|
460
|
+
const canonical = canonicalJson(identity);
|
|
461
|
+
const hash = createHash("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
462
|
+
return `sha256:${hash}`;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function canonicalJson(value: unknown): unknown {
|
|
466
|
+
if (Array.isArray(value)) return value.map(canonicalJson);
|
|
467
|
+
if (value && typeof value === "object") {
|
|
468
|
+
return Object.fromEntries(
|
|
469
|
+
Object.entries(value as Record<string, unknown>)
|
|
470
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
471
|
+
.map(([key, val]) => [key, canonicalJson(val)]),
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
return value;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function tomlQuotedString(value: string): string {
|
|
478
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
358
479
|
}
|
|
359
480
|
|
|
360
481
|
// #1096 — write relay-owned settings into an ISOLATED Claude managed home's `settings.json`
|
|
@@ -1598,7 +1598,7 @@ export class AgentRunner {
|
|
|
1598
1598
|
});
|
|
1599
1599
|
this.sessionOutbox.enqueue({
|
|
1600
1600
|
kind: "session-message-batch",
|
|
1601
|
-
idempotencyKey: `session-batch:${this.agentId}:${++this.sessionBatchSeq}:${messages.length}`,
|
|
1601
|
+
idempotencyKey: `session-batch:${this.agentId}:${this.options.instanceId}:${this.options.startedAt}:${++this.sessionBatchSeq}:${messages.length}`,
|
|
1602
1602
|
payload: { messages },
|
|
1603
1603
|
});
|
|
1604
1604
|
}
|
|
@@ -614,7 +614,10 @@ export const postAgentTerminalSession: Handler = async (req, params) => {
|
|
|
614
614
|
resource: { agentId: agent.id, orchestratorId: orchestrator.id, policyName: metaPolicyName, spawnRequestId: metaSpawnRequestId, terminalAttach: true },
|
|
615
615
|
});
|
|
616
616
|
if (denied) return denied;
|
|
617
|
-
|
|
617
|
+
// Provider-owned attach surfaces are more specific than the runner's tmux pane.
|
|
618
|
+
// Codex runs its real interactive TUI as a guest attached to the app-server thread;
|
|
619
|
+
// the runner pane can be a stale launcher frame and is not the right input target.
|
|
620
|
+
if (agent.providerCapabilities?.terminal?.attach?.create !== true && agent.providerCapabilities?.terminal?.live?.read && metaTmuxSession) {
|
|
618
621
|
return json({
|
|
619
622
|
mode: "live",
|
|
620
623
|
orchestratorId: orchestrator.id,
|
package/src/routes/agents.ts
CHANGED
|
@@ -216,6 +216,9 @@ export const postHeartbeat: Handler = async (req, params) => {
|
|
|
216
216
|
if (!session.ok) return error(session.error!, agentSessionStatus(session.error));
|
|
217
217
|
// #416 — capture unavailability before heartbeat to detect the transition.
|
|
218
218
|
const beforeHeartbeat = getAgent(params.id!);
|
|
219
|
+
if (beforeHeartbeat?.kind === "channel" && !beforeHeartbeat.ready) {
|
|
220
|
+
return error("channel agent not ready; re-register required", 409);
|
|
221
|
+
}
|
|
219
222
|
const wasUnavailable = beforeHeartbeat ? isAgentUnavailable(beforeHeartbeat) : false;
|
|
220
223
|
if (!heartbeat(params.id!, guard)) return error("agent not found", 404);
|
|
221
224
|
if (wasUnavailable) {
|
|
@@ -38,7 +38,7 @@ import { errMessage } from "agent-relay-sdk";
|
|
|
38
38
|
import { findSpawnCommandByRequestId } from "../commands-db";
|
|
39
39
|
import { defaultIssueRepo } from "../config";
|
|
40
40
|
import { emitTaskChanged } from "../sse";
|
|
41
|
-
import type { CommandStatus, Task, TaskDetail, TaskEvent, TaskGateState, TaskListItem, TaskStatus, WorkspaceRecord } from "../types";
|
|
41
|
+
import type { CommandStatus, Task, TaskDeliverableEventMetadata, TaskDetail, TaskEvent, TaskGateState, TaskListItem, TaskStatus, WorkspaceRecord } from "../types";
|
|
42
42
|
import { removeSubscriptionsForTask } from "../db/notification-subscriptions";
|
|
43
43
|
import { emitRelayEvent } from "../events";
|
|
44
44
|
import { routeNotification } from "../notification-router";
|
|
@@ -389,6 +389,30 @@ export function reconcileAutoScaffoldedTaskReaps(opts: ReconcileAutoScaffoldedTa
|
|
|
389
389
|
return { dryRun, scanned: completed.length + canceled.length + skipped.length, completed, canceled, skipped };
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
+
function latestDeliverableEvent(taskId: number): TaskEvent | undefined {
|
|
393
|
+
return [...listTaskEvents(taskId)].reverse().find((event) => event.type === "deliverable");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function restoreDeliveredDisposition(task: TaskDetail, event: TaskEvent): void {
|
|
397
|
+
const metadata = event.metadata as unknown as Partial<TaskDeliverableEventMetadata>;
|
|
398
|
+
if (metadata.disposition === "failed" && task.status !== "failed") {
|
|
399
|
+
setTaskEntityStatus(task.id, {
|
|
400
|
+
status: "failed",
|
|
401
|
+
...(typeof metadata.reason === "string" && metadata.reason.trim() ? { note: metadata.reason } : {}),
|
|
402
|
+
actor: "task-lifecycle",
|
|
403
|
+
});
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (metadata.disposition === "blocked" && task.status !== "blocked" && Array.isArray(metadata.blockedBy) && metadata.blockedBy.length > 0) {
|
|
407
|
+
setTaskEntityStatus(task.id, {
|
|
408
|
+
status: "blocked",
|
|
409
|
+
blockedBy: metadata.blockedBy,
|
|
410
|
+
...(typeof metadata.reason === "string" && metadata.reason.trim() ? { note: metadata.reason } : {}),
|
|
411
|
+
actor: "task-lifecycle",
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
392
416
|
// #889 — finalize bound tasks for a reaped agent whose doneWhen is "agent-exit" / "reaped".
|
|
393
417
|
// Called by the transient reaper after requesting shutdown so ephemeral run-and-exit workers
|
|
394
418
|
// don't leave their auto-scaffolded Task stuck in_progress forever.
|
|
@@ -407,6 +431,13 @@ export function finalizeEphemeralTasksOnReap(agentId: string, opts: { spawnReque
|
|
|
407
431
|
if (!isAgentExitDoneWhen(task.doneWhen)) continue;
|
|
408
432
|
if (opts.producedWork === false) {
|
|
409
433
|
try {
|
|
434
|
+
const deliverable = latestDeliverableEvent(taskId);
|
|
435
|
+
if (deliverable) {
|
|
436
|
+
if (!task.reapedAt) markTaskAgentReaped(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
|
|
437
|
+
restoreDeliveredDisposition(task, deliverable);
|
|
438
|
+
finalized.push(taskId);
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
410
441
|
if (!task.reapedAt) markTaskAgentReaped(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
|
|
411
442
|
setTaskEntityStatus(taskId, { status: "canceled", note: "worker reaped without landing or producing work; task canceled", actor: "task-lifecycle" });
|
|
412
443
|
notifyEmptyTransientReap(agentId, task, opts);
|
package/src/workspace-actions.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { LAND_STRATEGIES, DEFAULT_MERGE_STRATEGY } from "./workspace-merge";
|
|
|
28
28
|
import { claimMetadataPatch, workspaceActiveClaim } from "./workspace-claim";
|
|
29
29
|
import { DIRTY_WORKTREE_LAND_SKIP_REASON, READY_TO_LAND_STATUSES, TERMINAL_WORKSPACE_STATUSES, worktreeReapable } from "./workspace-phase";
|
|
30
30
|
import { CLEAR_MERGE_NO_PROGRESS, scheduleRepoMerge } from "./workspace-auto-merge";
|
|
31
|
-
import { fetchHostMergePreview } from "./workspace-probe";
|
|
31
|
+
import { fetchHostMergePreview, refreshWorkspaceGitState } from "./workspace-probe";
|
|
32
32
|
import type { Command, WorkspaceAutoMergePolicy, WorkspaceMergeStrategy, WorkspaceRecord, WorkspaceStatus } from "./types";
|
|
33
33
|
|
|
34
34
|
// Single source of truth for the action verb set. The route's `optionalEnum` and
|
|
@@ -251,7 +251,9 @@ export async function applyWorkspaceAction(workspace: WorkspaceRecord, input: Ap
|
|
|
251
251
|
if (!nextStatus) return { ok: false, httpStatus: 400, error: `unsupported action: ${action}` };
|
|
252
252
|
|
|
253
253
|
if (READY_TO_LAND_STATUSES.has(nextStatus)) {
|
|
254
|
-
|
|
254
|
+
await refreshWorkspaceGitState(workspace);
|
|
255
|
+
const freshWorkspace = getWorkspace(workspace.id) ?? workspace;
|
|
256
|
+
const dirtyCount = metadataNumber(freshWorkspace.metadata, "gitDirtyCount") ?? 0;
|
|
255
257
|
if (dirtyCount > 0) {
|
|
256
258
|
return {
|
|
257
259
|
ok: false,
|