agent-relay-server 0.112.0 → 0.113.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.
Files changed (107) hide show
  1. package/docs/openapi.json +1 -1
  2. package/package.json +3 -3
  3. package/public/assets/{MessageBubble-DtLlfBAK.js → MessageBubble-CFujR6_L.js} +3 -3
  4. package/public/assets/{MessageBubble-DtLlfBAK.js.map → MessageBubble-CFujR6_L.js.map} +1 -1
  5. package/public/assets/{PlanGraphPanel-pcKJ4q_4.js → PlanGraphPanel-BfxvqmNS.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-pcKJ4q_4.js.map → PlanGraphPanel-BfxvqmNS.js.map} +1 -1
  7. package/public/assets/{activity-DRAeL0Jq.js → activity-C7-gIF9O.js} +2 -2
  8. package/public/assets/{activity-DRAeL0Jq.js.map → activity-C7-gIF9O.js.map} +1 -1
  9. package/public/assets/{agent-profiles-cnWPANzx.js → agent-profiles-BGPa2-BZ.js} +2 -2
  10. package/public/assets/{agent-profiles-cnWPANzx.js.map → agent-profiles-BGPa2-BZ.js.map} +1 -1
  11. package/public/assets/{agents-DgUjmk_D.js → agents-CWCbBuq6.js} +2 -2
  12. package/public/assets/{agents-DgUjmk_D.js.map → agents-CWCbBuq6.js.map} +1 -1
  13. package/public/assets/{analytics-Q6Dl_CE9.js → analytics-BhGpT0JR.js} +2 -2
  14. package/public/assets/{analytics-Q6Dl_CE9.js.map → analytics-BhGpT0JR.js.map} +1 -1
  15. package/public/assets/automation-DnpahVqs.js +2 -0
  16. package/public/assets/automation-DnpahVqs.js.map +1 -0
  17. package/public/assets/{branch-state-badge-BRjUWyMT.js → branch-state-badge-CcAq2Igv.js} +2 -2
  18. package/public/assets/{branch-state-badge-BRjUWyMT.js.map → branch-state-badge-CcAq2Igv.js.map} +1 -1
  19. package/public/assets/{channels-DOYB1iiA.js → channels-DBP3-Gg0.js} +2 -2
  20. package/public/assets/{channels-DOYB1iiA.js.map → channels-DBP3-Gg0.js.map} +1 -1
  21. package/public/assets/{chat-C7XCmaZz.js → chat-Bue-qNx_.js} +2 -2
  22. package/public/assets/{chat-C7XCmaZz.js.map → chat-Bue-qNx_.js.map} +1 -1
  23. package/public/assets/{connectors-C5CeK-2M.js → connectors-BJxbuxoU.js} +2 -2
  24. package/public/assets/{connectors-C5CeK-2M.js.map → connectors-BJxbuxoU.js.map} +1 -1
  25. package/public/assets/{formatted-body-impl-rLDPgdmJ.js → formatted-body-impl-CTz6wch8.js} +2 -2
  26. package/public/assets/formatted-body-impl-CTz6wch8.js.map +1 -0
  27. package/public/assets/{index-DGyeTLPg.js → index-BMAblAKQ.js} +7 -7
  28. package/public/assets/{index-DGyeTLPg.js.map → index-BMAblAKQ.js.map} +1 -1
  29. package/public/assets/{insights-C0dDL4El.js → insights-CZ_JrJ8M.js} +2 -2
  30. package/public/assets/{insights-C0dDL4El.js.map → insights-CZ_JrJ8M.js.map} +1 -1
  31. package/public/assets/{integrations-CztQfrI7.js → integrations-L75xhZd5.js} +2 -2
  32. package/public/assets/{integrations-CztQfrI7.js.map → integrations-L75xhZd5.js.map} +1 -1
  33. package/public/assets/{maintenance-DkOkcEkb.js → maintenance-Dpb87NaB.js} +2 -2
  34. package/public/assets/{maintenance-DkOkcEkb.js.map → maintenance-Dpb87NaB.js.map} +1 -1
  35. package/public/assets/{managed-agents-C7Czinaz.js → managed-agents-DyGbrKwJ.js} +2 -2
  36. package/public/assets/{managed-agents-C7Czinaz.js.map → managed-agents-DyGbrKwJ.js.map} +1 -1
  37. package/public/assets/{markdown-preview-impl-BZ7sigEc.js → markdown-preview-impl-Bx4AcI8G.js} +2 -2
  38. package/public/assets/{markdown-preview-impl-BZ7sigEc.js.map → markdown-preview-impl-Bx4AcI8G.js.map} +1 -1
  39. package/public/assets/{memory-Bys-M7GK.js → memory-2l6G_m1p.js} +2 -2
  40. package/public/assets/{memory-Bys-M7GK.js.map → memory-2l6G_m1p.js.map} +1 -1
  41. package/public/assets/{messages-COSJ6trN.js → messages-DC-QXNwz.js} +2 -2
  42. package/public/assets/messages-DC-QXNwz.js.map +1 -0
  43. package/public/assets/{orchestrators-BjLl1Z0L.js → orchestrators-D_X3a0dm.js} +2 -2
  44. package/public/assets/{orchestrators-BjLl1Z0L.js.map → orchestrators-D_X3a0dm.js.map} +1 -1
  45. package/public/assets/{overview-BmU7twic.js → overview-76JPEbGZ.js} +2 -2
  46. package/public/assets/{overview-BmU7twic.js.map → overview-76JPEbGZ.js.map} +1 -1
  47. package/public/assets/{pairs-xclXjw-c.js → pairs-IeLXl-Z8.js} +2 -2
  48. package/public/assets/{pairs-xclXjw-c.js.map → pairs-IeLXl-Z8.js.map} +1 -1
  49. package/public/assets/{projects-cOeuiMjl.js → projects-D8ClXDUg.js} +2 -2
  50. package/public/assets/{projects-cOeuiMjl.js.map → projects-D8ClXDUg.js.map} +1 -1
  51. package/public/assets/{prompt-settings-CtQd0nz0.js → prompt-settings-BRduaHOj.js} +2 -2
  52. package/public/assets/{prompt-settings-CtQd0nz0.js.map → prompt-settings-BRduaHOj.js.map} +1 -1
  53. package/public/assets/{registry-CDe6vjKI.js → registry-CXyaPToV.js} +2 -2
  54. package/public/assets/{registry-CDe6vjKI.js.map → registry-CXyaPToV.js.map} +1 -1
  55. package/public/assets/{security-C9mBNQMZ.js → security-8n8VEsf5.js} +2 -2
  56. package/public/assets/{security-C9mBNQMZ.js.map → security-8n8VEsf5.js.map} +1 -1
  57. package/public/assets/{select-BJDKQk4q.js → select-D-wcg_2U.js} +2 -2
  58. package/public/assets/{select-BJDKQk4q.js.map → select-D-wcg_2U.js.map} +1 -1
  59. package/public/assets/{settings-BmZjWJkI.js → settings-BhnCGXgo.js} +2 -2
  60. package/public/assets/{settings-BmZjWJkI.js.map → settings-BhnCGXgo.js.map} +1 -1
  61. package/public/assets/{store-DDWg67Pg.js → store-Du8k5mLJ.js} +3 -3
  62. package/public/assets/{store-DDWg67Pg.js.map → store-Du8k5mLJ.js.map} +1 -1
  63. package/public/assets/{tasks-DNjZKSM2.js → tasks-DEKQqgPB.js} +2 -2
  64. package/public/assets/{tasks-DNjZKSM2.js.map → tasks-DEKQqgPB.js.map} +1 -1
  65. package/public/assets/{teams-KNzmdolE.js → teams-DoRSWZRQ.js} +2 -2
  66. package/public/assets/{teams-KNzmdolE.js.map → teams-DoRSWZRQ.js.map} +1 -1
  67. package/public/assets/{terminal-viewer-impl-DnFJDl9N.js → terminal-viewer-impl-C_o3BOpu.js} +2 -2
  68. package/public/assets/{terminal-viewer-impl-DnFJDl9N.js.map → terminal-viewer-impl-C_o3BOpu.js.map} +1 -1
  69. package/public/assets/types-DSwhOFcJ.js.map +1 -1
  70. package/public/assets/{user-avatar-C8sbjQke.js → user-avatar-BQoM4jPT.js} +2 -2
  71. package/public/assets/{user-avatar-C8sbjQke.js.map → user-avatar-BQoM4jPT.js.map} +1 -1
  72. package/public/assets/work-queue-CWnf1_iE.js +2 -0
  73. package/public/assets/work-queue-CWnf1_iE.js.map +1 -0
  74. package/public/assets/{workspaces-CSNdUg15.js → workspaces-C_fFCoCu.js} +2 -2
  75. package/public/assets/{workspaces-CSNdUg15.js.map → workspaces-C_fFCoCu.js.map} +1 -1
  76. package/public/index.html +2 -2
  77. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  78. package/runner/plugins/claude/skills/task/SKILL.md +28 -0
  79. package/runner/plugins/codex/skills/task/SKILL.md +28 -0
  80. package/src/agent-lifecycle-events.ts +13 -7
  81. package/src/db/mappers.ts +2 -0
  82. package/src/db/migrations.ts +4 -1
  83. package/src/db/provisioning-registry.ts +148 -2
  84. package/src/db/schema.ts +2 -0
  85. package/src/db/task-entity.ts +37 -12
  86. package/src/db/task-memory.ts +1 -1
  87. package/src/mcp/tools-spawn.ts +3 -0
  88. package/src/mcp-dispatch-tools.ts +2 -2
  89. package/src/mcp-task-tools.ts +9 -3
  90. package/src/prompt-resolver.ts +7 -7
  91. package/src/routes/agents-spawn.ts +8 -1
  92. package/src/routes/tasks.ts +6 -2
  93. package/src/services/plan-graph.ts +1 -1
  94. package/src/services/spawn-agent.ts +82 -35
  95. package/src/services/spawn-registration-watchdog.ts +54 -18
  96. package/src/services/task-context-hydration.ts +1 -1
  97. package/src/services/task-issue-weave.ts +2 -2
  98. package/src/services/task-lifecycle.ts +2 -2
  99. package/src/services/task-semantic-events.ts +4 -4
  100. package/src/token-db.ts +1 -1
  101. package/src/validation.ts +1 -1
  102. package/public/assets/automation-CuTlgY1E.js +0 -2
  103. package/public/assets/automation-CuTlgY1E.js.map +0 -1
  104. package/public/assets/formatted-body-impl-rLDPgdmJ.js.map +0 -1
  105. package/public/assets/messages-COSJ6trN.js.map +0 -1
  106. package/public/assets/work-queue-DINvPVPn.js +0 -2
  107. package/public/assets/work-queue-DINvPVPn.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"formatted-body-impl-rLDPgdmJ.js","names":[],"sources":["../../dashboard/src/components/shared/formatted-body-impl.tsx"],"sourcesContent":["import React, { useMemo } from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize'\nimport remarkGfm from 'remark-gfm'\nimport { CodePreview } from './code-preview'\nimport { cn } from '@/lib/utils'\nimport { parseJsonBody } from '@/lib/display'\nimport { useRelayStore } from '@/store'\n\nexport interface FormattedBodyProps {\n text: string\n rawBody?: string\n className?: string\n onOpenPath?: (path: string, line?: number) => void\n onPreviewPath?: (path: string, line?: number, anchor?: DOMRect) => void\n onPreviewPathEnd?: () => void\n isPathLinkable?: (path: string, line?: number) => boolean\n resolvePathTitle?: (path: string, line?: number) => string | undefined\n /** Per-message tracker repo (`owner/repo`) for bare `#NNN` linkify (#533) — the originating\n * agent's project repo, resolved server-side. Falls back to the server-global default (#511). */\n issueRepo?: string\n /** Rendered inside a primary-background bubble (operator's outbound message). Flips link\n * color to primary-foreground so links stay legible against the accent bg (#612). */\n onPrimary?: boolean\n}\n\n// Order matters: the issue-ref alternative (`#NNN` or `owner/repo#NNN`) is FIRST so the\n// path matcher can't swallow `owner/repo#NNN` as a file path. URLs still win when they\n// start earlier (leftmost-match), so a URL fragment like `…/a#12` is never mis-linkified.\nconst LINK_RE = /((?:[A-Za-z0-9][\\w.-]*\\/[A-Za-z0-9][\\w.-]*)?#\\d+)\\b|(https?:\\/\\/[^\\s`'\")\\]]+)|((?:\\/[\\w.@+-][^\\s`'\")\\]]*|(?:\\.{1,2}\\/|[\\w.@+-]+\\/)[^\\s`'\")\\]]*))/g\nconst TRAILING_PUNCTUATION = /[.,;:!?]+$/\nconst KNOWN_PROJECT_DIRS = new Set(['src', 'app', 'apps', 'lib', 'server', 'client', 'dashboard', 'orchestrator', 'runner', 'sdk', 'codex', 'claude', 'public', 'docs', 'test', 'tests', 'scripts', 'config', 'configs'])\n\nconst markdownSchema = {\n ...defaultSchema,\n attributes: {\n ...defaultSchema.attributes,\n code: [\n ...(defaultSchema.attributes?.code || []),\n ['className', /^language-[\\w-]+$/],\n ],\n },\n}\n\nfunction looksLikeFilePath(path: string): boolean {\n if (path === '/api' || path.startsWith('/api/')) return false\n if (path.startsWith('/')) return true\n if (path.startsWith('./') || path.startsWith('../')) return true\n const segments = path.split('/').filter(Boolean)\n const first = segments[0] ?? ''\n const last = segments[segments.length - 1] ?? ''\n if (first.startsWith('.')) return true\n if (KNOWN_PROJECT_DIRS.has(first)) return true\n return last.includes('.')\n}\n\nexport function linkParts(text: string, issueRepo?: string): Array<{ text: string; path?: string; url?: string; line?: number; issueUrl?: string }> {\n const parts: Array<{ text: string; path?: string; url?: string; line?: number; issueUrl?: string }> = []\n let cursor = 0\n for (const match of text.matchAll(LINK_RE)) {\n const rawIssue = match[1]\n const rawUrl = match[2]\n const rawPath = match[3]\n const raw = rawIssue || rawUrl || rawPath\n const index = match.index ?? 0\n if (!raw || index < cursor) continue\n\n if (rawIssue) {\n // `#NNN` (uses the configured default repo) or `owner/repo#NNN` (explicit repo).\n // With no resolvable repo we leave it as plain text — never emit a broken link.\n const hashIdx = rawIssue.lastIndexOf('#')\n const repo = rawIssue.slice(0, hashIdx) || issueRepo\n const num = rawIssue.slice(hashIdx + 1)\n // Slash-shorthand like `#508/509/513` (#531): the trailing `/509/513` is a run of\n // bare ref numbers, NOT a file path. Consume it as plain text so the path matcher\n // (which would otherwise claim `/509/...` as a phantom path link) can't reach it.\n const trailingRefs = text.slice(index + rawIssue.length).match(/^(?:\\/\\d+)+/)?.[0] ?? ''\n if (repo) {\n if (index > cursor) parts.push({ text: text.slice(cursor, index) })\n parts.push({ text: rawIssue, issueUrl: `https://github.com/${repo}/issues/${num}` })\n if (trailingRefs) parts.push({ text: trailingRefs })\n cursor = index + rawIssue.length + trailingRefs.length\n } else if (trailingRefs) {\n // No repo to link against, but still neutralize the slash run so it stays plain text.\n if (index > cursor) parts.push({ text: text.slice(cursor, index) })\n parts.push({ text: rawIssue + trailingRefs })\n cursor = index + rawIssue.length + trailingRefs.length\n }\n continue\n }\n\n if (rawUrl) {\n const url = rawUrl.replace(TRAILING_PUNCTUATION, '')\n const trimmed = rawUrl.slice(url.length)\n if (index > cursor) parts.push({ text: text.slice(cursor, index) })\n parts.push({ text: url, url })\n if (trimmed) parts.push({ text: trimmed })\n cursor = index + rawUrl.length\n continue\n }\n\n if (!raw.includes('/')) continue\n let path = raw.replace(TRAILING_PUNCTUATION, '')\n const trimmed = raw.slice(path.length)\n const lineMatch = path.match(/^(.*):(\\d+)$/)\n const line = lineMatch ? Number(lineMatch[2]) : undefined\n if (lineMatch) path = lineMatch[1]!\n if (!looksLikeFilePath(path)) continue\n if (index > cursor) parts.push({ text: text.slice(cursor, index) })\n parts.push({ text: path, path, line: Number.isFinite(line) ? line : undefined })\n if (trimmed) parts.push({ text: trimmed })\n cursor = index + raw.length\n }\n if (cursor < text.length) parts.push({ text: text.slice(cursor) })\n return parts\n}\n\nfunction TextWithLinks({\n text,\n onOpenPath,\n onPreviewPath,\n onPreviewPathEnd,\n isPathLinkable,\n resolvePathTitle,\n issueRepo,\n}: {\n text: string\n onOpenPath?: (path: string, line?: number) => void\n onPreviewPath?: (path: string, line?: number, anchor?: DOMRect) => void\n onPreviewPathEnd?: () => void\n isPathLinkable?: (path: string, line?: number) => boolean\n resolvePathTitle?: (path: string, line?: number) => string | undefined\n issueRepo?: string\n}) {\n const parts = linkParts(text, issueRepo)\n if (parts.length === 1 && !parts[0]?.path && !parts[0]?.url && !parts[0]?.issueUrl) return <>{text}</>\n return (\n <>\n {parts.map((part, index) => {\n if (part.issueUrl) {\n return (\n <a\n key={`${part.issueUrl}-${index}`}\n href={part.issueUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium underline decoration-dotted underline-offset-2\"\n onClick={(e) => e.stopPropagation()}\n >\n {part.text}\n </a>\n )\n }\n if (part.url) {\n return (\n <a\n key={`${part.url}-${index}`}\n href={part.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"underline decoration-dotted underline-offset-2\"\n onClick={(e) => e.stopPropagation()}\n >\n {part.text}\n </a>\n )\n }\n if (part.path && onOpenPath) {\n if (isPathLinkable && !isPathLinkable(part.path, part.line)) return <span key={`${part.path}-${index}`}>{part.text}{part.line ? `:${part.line}` : ''}</span>\n const resolvedTitle = resolvePathTitle?.(part.path, part.line)\n return (\n <button\n key={`${part.path}-${index}`}\n type=\"button\"\n className=\"chat-link rounded-sm font-mono underline decoration-dotted underline-offset-2\"\n onClick={(e) => { e.stopPropagation(); onOpenPath(part.path!, part.line) }}\n onMouseEnter={(e) => onPreviewPath?.(part.path!, part.line, e.currentTarget.getBoundingClientRect())}\n onFocus={(e) => onPreviewPath?.(part.path!, part.line, e.currentTarget.getBoundingClientRect())}\n onMouseLeave={() => onPreviewPathEnd?.()}\n onBlur={() => onPreviewPathEnd?.()}\n title={resolvedTitle ? `Open ${resolvedTitle}` : 'Open file'}\n >\n {part.text}{part.line ? `:${part.line}` : ''}\n </button>\n )\n }\n return <span key={index}>{part.text}</span>\n })}\n </>\n )\n}\n\ninterface LinkifyContext {\n onOpenPath?: (path: string, line?: number) => void\n onPreviewPath?: (path: string, line?: number, anchor?: DOMRect) => void\n onPreviewPathEnd?: () => void\n isPathLinkable?: (path: string, line?: number) => boolean\n resolvePathTitle?: (path: string, line?: number) => string | undefined\n issueRepo?: string\n}\n\n// Inline code & fenced blocks (the `code`/`pre` overrides) — descend with `inCode`\n// set so `#NNN` inside backticks renders verbatim instead of linkifying.\nconst CodeComponent = ({ className: codeClass, children }: { className?: string; children?: React.ReactNode }) => {\n const match = /language-([\\w-]+)/.exec(codeClass || '')\n const code = String(children).replace(/\\n$/, '')\n if (match) {\n return <CodePreview content={code} path={`.${match[1]}`} languageHint={match[1]} compact />\n }\n return <code className={codeClass}>{children}</code>\n}\n\n// Markdown links — render the anchor and pass children through untouched. The\n// recursive walk skips this subtree so we never linkify a `#NNN` *inside* link\n// text (which would nest one <a> inside another). Text adjacent to a link still\n// linkifies via the enclosing block's walk.\nconst AnchorComponent = ({ href, children }: { href?: string; children?: React.ReactNode }) => (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" onClick={(e) => e.stopPropagation()}>\n {children}\n </a>\n)\n\n// Recursively linkify every text leaf in a markdown subtree (#550). react-markdown\n// hands each block override its already-rendered React children, so nested inline\n// elements (strong/em/del/headings/table cells/…) arrive as element children with\n// their text strings buried one or more levels deep. We descend through them and\n// apply `linkParts` (via TextWithLinks) at every string leaf, keeping the linkify\n// rule in this ONE place. `inCode` suppresses linkify inside code/pre; anchors are\n// left whole to avoid nested links.\nfunction processTextChildren(children: React.ReactNode, ctx: LinkifyContext, inCode = false): React.ReactNode {\n return React.Children.map(children, (child) => {\n if (typeof child === 'string') {\n if (inCode) return child\n return (\n <TextWithLinks\n text={child}\n onOpenPath={ctx.onOpenPath}\n onPreviewPath={ctx.onPreviewPath}\n onPreviewPathEnd={ctx.onPreviewPathEnd}\n isPathLinkable={ctx.isPathLinkable}\n resolvePathTitle={ctx.resolvePathTitle}\n issueRepo={ctx.issueRepo}\n />\n )\n }\n if (!React.isValidElement(child)) return child\n const type = child.type\n // Already-linkified leaves carry their text in a prop, not children — leave whole.\n if (type === TextWithLinks) return child\n // Never linkify inside a link (no nested <a>); render the anchor subtree verbatim.\n if (type === AnchorComponent || type === 'a') return child\n const props = child.props as { children?: React.ReactNode }\n if (props?.children == null) return child\n const nextInCode = inCode || type === CodeComponent || type === 'code' || type === 'pre'\n return React.cloneElement(child, undefined, processTextChildren(props.children, ctx, nextInCode))\n })\n}\n\nexport function FormattedBody({ text, rawBody, className, onOpenPath, onPreviewPath, onPreviewPathEnd, isPathLinkable, resolvePathTitle, issueRepo: issueRepoProp, onPrimary }: FormattedBodyProps) {\n const parsed = useMemo(() => parseJsonBody(rawBody || ''), [rawBody])\n const content = unescapeNewlines(parsed ? parsed.text : text)\n // Per-message tracker repo for bare #NNN linkify (#533): the originating agent's project\n // repo (`issueRepoProp`) wins; the server-global default (#511) is only a last-resort\n // fallback for messages with no resolvable project. undefined → #NNN stays plain text.\n const globalIssueRepo = useRelayStore((s) => s.stats?.defaultIssueRepo)\n const issueRepo = issueRepoProp ?? globalIssueRepo\n\n const components = useMemo(() => {\n const ctx: LinkifyContext = { onOpenPath, onPreviewPath, onPreviewPathEnd, isPathLinkable, resolvePathTitle, issueRepo }\n // Every text-bearing block routes its children through the recursive walk, which\n // descends into nested inline elements (strong/em/del/code/links) on its own — so\n // these stay one-liners and the linkify rule lives only in processTextChildren.\n const block = (Tag: 'p' | 'li' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'td' | 'th' | 'blockquote') =>\n ({ children }: { children?: React.ReactNode }) => <Tag>{processTextChildren(children, ctx)}</Tag>\n return {\n p: block('p'),\n li: block('li'),\n h1: block('h1'),\n h2: block('h2'),\n h3: block('h3'),\n h4: block('h4'),\n h5: block('h5'),\n h6: block('h6'),\n td: block('td'),\n th: block('th'),\n blockquote: block('blockquote'),\n a: AnchorComponent,\n code: CodeComponent,\n }\n }, [onOpenPath, onPreviewPath, onPreviewPathEnd, isPathLinkable, resolvePathTitle, issueRepo])\n\n return (\n <div className={className}>\n <div className={cn('chat-markdown', onPrimary && 'chat-markdown-on-primary')}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[[rehypeSanitize, markdownSchema]]} components={components}>\n {content}\n </ReactMarkdown>\n </div>\n {parsed && parsed.meta.length > 0 && (\n <div className=\"mt-1.5 flex flex-wrap gap-1\">\n {parsed.meta.map(([k, v]) => (\n <span key={k} className=\"inline-flex text-[10px] leading-tight bg-muted px-1.5 py-0.5 rounded text-muted-foreground font-mono\">\n {k}: {v}\n </span>\n ))}\n </div>\n )}\n </div>\n )\n}\n\nfunction unescapeNewlines(text: string): string {\n if (!text.includes('\\\\n')) return text\n return text.replace(/\\\\n/g, '\\n')\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"messages-COSJ6trN.js","names":[],"sources":["../../dashboard/src/components/views/messages.tsx"],"sourcesContent":["import { useMemo, useState } from 'react'\nimport { useRelayStore, useNow } from '@/store'\nimport { useComposeAgents, useUniqueTags } from '@/hooks/use-selectors'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { FormattedBody } from '@/components/shared/formatted-body'\nimport {\n Mail, Pencil, MessageSquareReply, CheckCircle2, Trash2, X, Hash, AlertTriangle, RotateCcw, Ban,\n} from 'lucide-react'\nimport { displayName, displayTarget, messageBody, timeAgo, fmtTime } from '@/lib/display'\nimport type { Message } from '@/types'\n\nfunction resolveRelativePath(cwd: string, path: string): string {\n if (path.startsWith('/')) return path\n const parts = `${cwd.replace(/\\/+$/, '')}/${path}`.split('/')\n const stack: string[] = []\n for (const part of parts) {\n if (!part || part === '.') continue\n if (part === '..') stack.pop()\n else stack.push(part)\n }\n return '/' + stack.join('/')\n}\n\nfunction parentPath(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const index = trimmed.lastIndexOf('/')\n return index > 0 ? trimmed.slice(0, index) : '/'\n}\n\nexport function MessagesView() {\n const now = useNow()\n const messages = useRelayStore((s) => s.messages)\n const agentsById = useRelayStore((s) => s.agentsById)\n const selectedAgent = useRelayStore((s) => s.selectedAgent)\n const channelFilter = useRelayStore((s) => s.channelFilter)\n const tagFilter = useRelayStore((s) => s.tagFilter)\n const replyTo = useRelayStore((s) => s.replyTo)\n const set = useRelayStore((s) => s.set)\n const openCompose = useRelayStore((s) => s.openCompose)\n const startReply = useRelayStore((s) => s.startReply)\n const doClaim = useRelayStore((s) => s.doClaim)\n const doDeliveryAction = useRelayStore((s) => s.doDeliveryAction)\n const doDeleteMessage = useRelayStore((s) => s.doDeleteMessage)\n const openThread = useRelayStore((s) => s.openThread)\n const cancelReply = useRelayStore((s) => s.cancelReply)\n\n const composeAgents = useComposeAgents()\n const uniqueTags = useUniqueTags()\n\n const filtered = useMemo(() => {\n let list = [...messages].sort((a, b) => b.id - a.id)\n if (selectedAgent) list = list.filter((m) => m.from === selectedAgent || m.to === selectedAgent)\n if (channelFilter) list = list.filter((m) => m.channel === channelFilter)\n if (tagFilter) list = list.filter((m) => {\n const agent = agentsById[m.from] || agentsById[m.to]\n return (agent?.tags || []).includes(tagFilter)\n })\n return list\n }, [messages, selectedAgent, channelFilter, tagFilter, agentsById])\n\n // Group by threadId — show root messages, collapse replies\n const grouped = useMemo(() => {\n const roots: Message[] = []\n const threads = new Map<number, Message[]>()\n for (const msg of filtered) {\n const tid = msg.threadId ?? msg.id\n if (!threads.has(tid)) threads.set(tid, [])\n threads.get(tid)!.push(msg)\n if (msg.id === tid) roots.push(msg)\n }\n // messages without a known root\n const seenRoots = new Set(roots.map((r) => r.id))\n for (const msg of filtered) {\n if (!seenRoots.has(msg.threadId ?? msg.id) && !roots.find((r) => r.id === msg.id)) {\n roots.push(msg)\n }\n }\n roots.sort((a, b) => b.id - a.id)\n return roots.map((r) => ({ root: r, replies: (threads.get(r.id) || []).filter((m) => m.id !== r.id).sort((a, b) => a.id - b.id) }))\n }, [filtered])\n\n function agentLabel(id: string) {\n return agentsById[id] ? displayName(agentsById[id]) : id.slice(-10)\n }\n\n const uniqueChannels = useMemo(() => {\n return [...new Set(messages.map((m) => m.channel).filter(Boolean) as string[])]\n }, [messages])\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 <Mail className=\"w-5 h-5 text-muted-foreground\" />\n <h2 className=\"text-lg font-semibold\">Messages</h2>\n <Badge variant=\"secondary\">{filtered.length}</Badge>\n </div>\n <Button size=\"sm\" onClick={openCompose}>\n <Pencil className=\"w-4 h-4 mr-1\" /> Compose\n </Button>\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={selectedAgent}\n onChange={(e) => set({ selectedAgent: e.target.value })}\n >\n <option value=\"\">All agents</option>\n {composeAgents.map((a) => <option key={a.id} value={a.id}>{displayName(a)}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={tagFilter}\n onChange={(e) => set({ tagFilter: e.target.value })}\n >\n <option value=\"\">All tags</option>\n {uniqueTags.map((t) => <option key={t} value={t}>#{t}</option>)}\n </select>\n <select\n className=\"rounded-md border border-input bg-background px-3 py-1.5 text-sm\"\n value={channelFilter}\n onChange={(e) => set({ channelFilter: e.target.value })}\n >\n <option value=\"\">All channels</option>\n {uniqueChannels.map((c) => <option key={c} value={c}>{c}</option>)}\n </select>\n </div>\n\n {replyTo && (\n <div className=\"flex items-center gap-2 rounded-md bg-blue-500/10 border border-blue-500/20 px-3 py-2 text-sm text-blue-300\">\n <MessageSquareReply className=\"w-4 h-4 shrink-0\" />\n <span>Replying to message #{replyTo.id} from <strong>{agentLabel(replyTo.from)}</strong></span>\n <Button variant=\"ghost\" size=\"sm\" className=\"ml-auto h-6 px-1.5\" onClick={cancelReply}>\n <X className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n )}\n\n <div className=\"h-[calc(100dvh-15rem)] overflow-y-auto\">\n <div className=\"space-y-2 pr-2\">\n {grouped.length === 0 && (\n <div className=\"text-center text-muted-foreground py-16 text-sm\">No messages</div>\n )}\n {grouped.map(({ root, replies }) => (\n <div key={root.id} className=\"space-y-1\">\n <MessageRow\n msg={root}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(root)}\n onClaim={() => doClaim(root.id)}\n onRetry={() => doDeliveryAction(root.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(root.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(root.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(root.id)}\n onThread={root.threadId ? () => openThread(root.threadId!) : undefined}\n replyCount={replies.length}\n />\n {replies.map((r) => (\n <div key={r.id} className=\"ml-6\">\n <MessageRow\n msg={r}\n now={now}\n agentLabel={agentLabel}\n agentsById={agentsById}\n onReply={() => startReply(r)}\n onClaim={() => doClaim(r.id)}\n onRetry={() => doDeliveryAction(r.id, 'retry-now')}\n onMarkDead={() => doDeliveryAction(r.id, 'mark-dead', 'Marked dead from dashboard')}\n onClear={() => doDeliveryAction(r.id, 'clear', 'Cleared after manual handling')}\n onDelete={() => doDeleteMessage(r.id)}\n />\n </div>\n ))}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nfunction MessageRow({\n msg, now, agentLabel, agentsById, onReply, onClaim, onRetry, onMarkDead, onClear, onDelete, onThread, replyCount,\n}: {\n msg: Message\n now: number\n agentLabel: (id: string) => string\n agentsById: Record<string, import('@/types').Agent>\n onReply: () => void\n onClaim: () => void\n onRetry: () => void\n onMarkDead: () => void\n onClear: () => void\n onDelete: () => void\n onThread?: () => void\n replyCount?: number\n}) {\n const [expanded, setExpanded] = useState(false)\n const body = messageBody(msg)\n const openFilesAt = useRelayStore((s) => s.openFilesAt)\n const deliveryProblem = msg.deliveryStatus === 'queued' || msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead' || Boolean(msg.deliveryLastError || msg.deliveryPoisonReason)\n const peer = msg.from === 'user' ? msg.to : msg.from\n const peerAgent = agentsById[peer]\n\n function resolvedReferencedPath(path: string): string {\n const cwd = typeof peerAgent?.meta?.cwd === 'string' ? peerAgent.meta.cwd : ''\n return resolveRelativePath(cwd || '/', path)\n }\n\n function openReferencedPath(path: string, line?: number) {\n const absolute = resolvedReferencedPath(path)\n void openFilesAt({ path: parentPath(absolute), selectedPath: absolute, line, overlay: true })\n }\n\n return (\n <Card className=\"group relative\">\n <CardContent className=\"p-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap text-xs text-muted-foreground mb-1\">\n <span className=\"font-medium text-foreground\">{agentLabel(msg.from)}</span>\n <span>→</span>\n <span>{displayTarget(msg.to, agentsById)}</span>\n {msg.channel && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 gap-0.5\">\n <Hash className=\"w-2.5 h-2.5\" />{msg.channel}\n </Badge>\n )}\n {msg.claimedBy && (\n <Badge variant=\"outline\" className=\"text-xs px-1.5 py-0 text-emerald-400 border-emerald-500/30\">\n <CheckCircle2 className=\"w-2.5 h-2.5 mr-0.5\" />claimed\n </Badge>\n )}\n {deliveryProblem && <DeliveryBadge msg={msg} now={now} />}\n {msg.subject && <span className=\"font-medium text-foreground\">{msg.subject}</span>}\n <span className=\"ml-auto shrink-0\" title={fmtTime(msg.createdAt)}><span className=\"opacity-40 mr-1\">#{msg.id}</span>{timeAgo(now, msg.createdAt)}</span>\n </div>\n {body && (\n <div className=\"cursor-pointer\" onClick={() => setExpanded((v) => !v)}>\n <FormattedBody text={body} rawBody={msg.body} issueRepo={peerAgent?.issueRepo} className={`text-sm text-muted-foreground ${expanded ? '' : 'max-h-[3.75rem] overflow-hidden'}`} onOpenPath={openReferencedPath} resolvePathTitle={(path, line) => `${resolvedReferencedPath(path)}${line ? `:${line}` : ''}`} />\n </div>\n )}\n </div>\n <div className=\"absolute top-2 right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity bg-card rounded-md shadow-sm border border-border px-1 py-0.5\">\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onReply} title=\"Reply\">\n <MessageSquareReply className=\"w-3.5 h-3.5\" />\n </Button>\n {msg.claimable && !msg.claimedBy && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-orange-400 hover:text-orange-300\" onClick={onClaim} title=\"Claim\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-blue-400 hover:text-blue-300\" onClick={onRetry} title=\"Retry delivery now\">\n <RotateCcw className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {msg.deliveryStatus !== 'dead' && deliveryProblem && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onMarkDead} title=\"Mark dead\">\n <Ban className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {(msg.deliveryStatus === 'failed' || msg.deliveryStatus === 'dead') && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-emerald-400 hover:text-emerald-300\" onClick={onClear} title=\"Clear after manual handling\">\n <CheckCircle2 className=\"w-3.5 h-3.5\" />\n </Button>\n )}\n {onThread && (replyCount ?? 0) > 0 && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs\" onClick={onThread} title=\"Thread\">\n +{replyCount}\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 text-xs text-red-400 hover:text-red-300\" onClick={onDelete} title=\"Delete\">\n <Trash2 className=\"w-3.5 h-3.5\" />\n </Button>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nfunction DeliveryBadge({ msg, now }: { msg: Message; now: number }) {\n const status = msg.deliveryStatus || 'pending'\n const detail = msg.deliveryPoisonReason || msg.deliveryLastError || (msg.deliveryNextRetryAt ? `retry ${timeAgo(now, msg.deliveryNextRetryAt)}` : undefined)\n const className = status === 'dead'\n ? 'text-red-300 border-red-500/30 bg-red-500/10'\n : status === 'failed'\n ? 'text-amber-300 border-amber-500/30 bg-amber-500/10'\n : 'text-blue-300 border-blue-500/30 bg-blue-500/10'\n return (\n <Badge variant=\"outline\" className={`text-xs px-1.5 py-0 ${className}`} title={detail || status}>\n <AlertTriangle className=\"w-2.5 h-2.5 mr-0.5\" />\n {status}{msg.deliveryAttempts ? ` ${msg.deliveryAttempts}x` : ''}\n </Badge>\n )\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{$n as e,_n as t,a as n,kn as r,mt as i}from"./lucide-react-DmbfpRvJ.js";import{f as a,t as o}from"./store-DDWg67Pg.js";import{K as s,ct as c,d as l}from"./display-_5kFrHJh.js";import{t as u}from"./badge-kdQDWO6e.js";import{t as d}from"./button-BKFvNXa3.js";import{K as f,Q as p,u as m}from"./index-DGyeTLPg.js";import{r as h,t as g}from"./card-B0y1i_2D.js";var _=e(),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(),t=o(e=>e.agentsById),n=o(e=>e.compose),r=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=f(),S=p(),C=S.filter(e=>e.claimable).length;function w(e){if(!n.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`?`Task #${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)(i,{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:n.from,onChange:e=>r({compose:{...n,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)(m,{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(n=>(0,_.jsx)(b,{item:n,now:e,agentName:e=>t[e]?l(t[e]):e.slice(-10),onClaim:()=>w(n),onCancel:()=>T(n),onEvents:n.task?()=>E(n):void 0},n.id))]})})]})}function b({item:e,now:i,agentName:a,onClaim:o,onCancel:l,onEvents:f}){let p=c[e.severity]||c.info,m=v[e.status]||`bg-zinc-500/10 text-zinc-400 border-zinc-500/20`;return(0,_.jsx)(g,{className:e.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:e.title}),(0,_.jsx)(u,{variant:`outline`,className:`text-xs px-1.5 py-0 border ${p}`,children:e.severity}),(0,_.jsx)(u,{variant:`outline`,className:`text-xs px-1.5 py-0 border ${m}`,children:e.status}),e.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`})]}),e.body&&(0,_.jsx)(`p`,{className:`text-xs text-muted-foreground line-clamp-2 mb-2`,children:e.body}),(0,_.jsxs)(`div`,{className:`flex items-center gap-3 text-xs text-muted-foreground flex-wrap`,children:[e.owner&&(0,_.jsxs)(`span`,{title:`Owner`,children:[(0,_.jsx)(t,{className:`w-3 h-3 inline mr-1`}),a(e.owner)]}),e.source&&(0,_.jsx)(`span`,{className:`font-mono`,children:e.source}),(0,_.jsxs)(`span`,{title:String(e.updatedAt),children:[(0,_.jsx)(r,{className:`w-3 h-3 inline mr-1`}),s(i,e.updatedAt)]})]})]}),(0,_.jsxs)(`div`,{className:`flex flex-col gap-1 shrink-0`,children:[e.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)(t,{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)(n,{className:`w-3.5 h-3.5 mr-1`}),` Cancel`]})]})]})})})}export{y as WorkQueueView};
2
- //# sourceMappingURL=work-queue-DINvPVPn.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"work-queue-DINvPVPn.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' ? `Task #${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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"}