agent-relay-server 0.35.4 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/docs/openapi.json +68 -1
  2. package/package.json +2 -2
  3. package/public/assets/{activity-CPuZGkeP.js → activity-C3mkM6AU.js} +2 -2
  4. package/public/assets/{activity-CPuZGkeP.js.map → activity-C3mkM6AU.js.map} +1 -1
  5. package/public/assets/{agent-profiles-Bs8MAW6j.js → agent-profiles-DS4_jLPT.js} +2 -2
  6. package/public/assets/{agent-profiles-Bs8MAW6j.js.map → agent-profiles-DS4_jLPT.js.map} +1 -1
  7. package/public/assets/agents-CAhQO7JH.js +2 -0
  8. package/public/assets/agents-CAhQO7JH.js.map +1 -0
  9. package/public/assets/{analytics-inmkBD_j.js → analytics-BwihhhNn.js} +3 -3
  10. package/public/assets/{analytics-inmkBD_j.js.map → analytics-BwihhhNn.js.map} +1 -1
  11. package/public/assets/{automation-DRN2lcqQ.js → automation-BLXToUiU.js} +2 -2
  12. package/public/assets/{automation-DRN2lcqQ.js.map → automation-BLXToUiU.js.map} +1 -1
  13. package/public/assets/{badge-t8zAwHW9.js → badge-JVybSpzR.js} +2 -2
  14. package/public/assets/{badge-t8zAwHW9.js.map → badge-JVybSpzR.js.map} +1 -1
  15. package/public/assets/{branch-state-badge-EliCEAQI.js → branch-state-badge-D8-T2c1K.js} +2 -2
  16. package/public/assets/{branch-state-badge-EliCEAQI.js.map → branch-state-badge-D8-T2c1K.js.map} +1 -1
  17. package/public/assets/{button-DDA5P2YQ.js → button-BsMqBNJb.js} +2 -2
  18. package/public/assets/{button-DDA5P2YQ.js.map → button-BsMqBNJb.js.map} +1 -1
  19. package/public/assets/card-I8w4U656.js +2 -0
  20. package/public/assets/{card-CggxP1h9.js.map → card-I8w4U656.js.map} +1 -1
  21. package/public/assets/{channels-BzSpsE5h.js → channels-ppN8k4hu.js} +2 -2
  22. package/public/assets/{channels-BzSpsE5h.js.map → channels-ppN8k4hu.js.map} +1 -1
  23. package/public/assets/chat-8iIPyww9.js +2 -0
  24. package/public/assets/chat-8iIPyww9.js.map +1 -0
  25. package/public/assets/{connectors-DoUgct8f.js → connectors-CL9BALhF.js} +2 -2
  26. package/public/assets/{connectors-DoUgct8f.js.map → connectors-CL9BALhF.js.map} +1 -1
  27. package/public/assets/copy-button-B-XlL8nF.js +2 -0
  28. package/public/assets/{copy-button-CE8e2c-F.js.map → copy-button-B-XlL8nF.js.map} +1 -1
  29. package/public/assets/display-ConJ9cJB.js +3 -0
  30. package/public/assets/{display-Bebqs1qu.js.map → display-ConJ9cJB.js.map} +1 -1
  31. package/public/assets/{dist-CiWi_f7V.js → dist-BQ52MnS1.js} +2 -2
  32. package/public/assets/{dist-CiWi_f7V.js.map → dist-BQ52MnS1.js.map} +1 -1
  33. package/public/assets/{dist-CHi40_tZ.js → dist-BgfF2Rlm.js} +2 -2
  34. package/public/assets/{dist-CHi40_tZ.js.map → dist-BgfF2Rlm.js.map} +1 -1
  35. package/public/assets/dist-CnJzBTp1.js +2 -0
  36. package/public/assets/{dist-DTLaCErY.js.map → dist-CnJzBTp1.js.map} +1 -1
  37. package/public/assets/{dist-xorgjFcF.js → dist-CrBurS6i.js} +2 -2
  38. package/public/assets/{dist-xorgjFcF.js.map → dist-CrBurS6i.js.map} +1 -1
  39. package/public/assets/dist-D6iXJzms.js +2 -0
  40. package/public/assets/{dist-BmYJ5xuf.js.map → dist-D6iXJzms.js.map} +1 -1
  41. package/public/assets/{dist-CkiXMjV0.js → dist-DRlgXPi_.js} +2 -2
  42. package/public/assets/{dist-CkiXMjV0.js.map → dist-DRlgXPi_.js.map} +1 -1
  43. package/public/assets/{dist-B3igiXqp.js → dist-DSNhRDNh.js} +2 -2
  44. package/public/assets/{dist-B3igiXqp.js.map → dist-DSNhRDNh.js.map} +1 -1
  45. package/public/assets/{dist-C3Yx04R4.js → dist-SqFV12iO.js} +2 -2
  46. package/public/assets/{dist-C3Yx04R4.js.map → dist-SqFV12iO.js.map} +1 -1
  47. package/public/assets/{es2015-BDK_SBFZ.js → es2015-iucXYTIE.js} +2 -2
  48. package/public/assets/{es2015-BDK_SBFZ.js.map → es2015-iucXYTIE.js.map} +1 -1
  49. package/public/assets/{formatted-body-impl-DP9iZsd4.js → formatted-body-impl-BHH0wzY7.js} +2 -2
  50. package/public/assets/{formatted-body-impl-DP9iZsd4.js.map → formatted-body-impl-BHH0wzY7.js.map} +1 -1
  51. package/public/assets/index-3pO43nJo.css +2 -0
  52. package/public/assets/index-CaauKXl9.js +21 -0
  53. package/public/assets/index-CaauKXl9.js.map +1 -0
  54. package/public/assets/{input-BW9UD3FM.js → input-dPzf0luy.js} +2 -2
  55. package/public/assets/{input-BW9UD3FM.js.map → input-dPzf0luy.js.map} +1 -1
  56. package/public/assets/{insights-yJFgCa3o.js → insights-5CDeJfoX.js} +2 -2
  57. package/public/assets/{insights-yJFgCa3o.js.map → insights-5CDeJfoX.js.map} +1 -1
  58. package/public/assets/{integrations-CUv4i_4i.js → integrations-DX55ARy0.js} +2 -2
  59. package/public/assets/{integrations-CUv4i_4i.js.map → integrations-DX55ARy0.js.map} +1 -1
  60. package/public/assets/{lib-ZEIADKGq.js → lib-BAE--T4O.js} +3 -3
  61. package/public/assets/{lib-ZEIADKGq.js.map → lib-BAE--T4O.js.map} +1 -1
  62. package/public/assets/lucide-react-DLQFnqNm.js +9 -0
  63. package/public/assets/{lucide-react-CD8Xl2U3.js.map → lucide-react-DLQFnqNm.js.map} +1 -1
  64. package/public/assets/{maintenance-DtfpsMZa.js → maintenance-9n_rJCHT.js} +2 -2
  65. package/public/assets/{maintenance-DtfpsMZa.js.map → maintenance-9n_rJCHT.js.map} +1 -1
  66. package/public/assets/{managed-agents-C5pzetBh.js → managed-agents-Rp2-xpBx.js} +2 -2
  67. package/public/assets/{managed-agents-C5pzetBh.js.map → managed-agents-Rp2-xpBx.js.map} +1 -1
  68. package/public/assets/{markdown-preview-impl-4s9YDGM7.js → markdown-preview-impl-YfJsGh6I.js} +2 -2
  69. package/public/assets/{markdown-preview-impl-4s9YDGM7.js.map → markdown-preview-impl-YfJsGh6I.js.map} +1 -1
  70. package/public/assets/memory-BQONtGQS.js +2 -0
  71. package/public/assets/{memory-BWfDbph3.js.map → memory-BQONtGQS.js.map} +1 -1
  72. package/public/assets/{messages-C8cP25kp.js → messages-DGqpkH72.js} +2 -2
  73. package/public/assets/{messages-C8cP25kp.js.map → messages-DGqpkH72.js.map} +1 -1
  74. package/public/assets/{orchestrators-Clu8MNKo.js → orchestrators-b8k9QoGv.js} +2 -2
  75. package/public/assets/{orchestrators-Clu8MNKo.js.map → orchestrators-b8k9QoGv.js.map} +1 -1
  76. package/public/assets/{overview-CXcGh2D6.js → overview-DSU_CggA.js} +2 -2
  77. package/public/assets/{overview-CXcGh2D6.js.map → overview-DSU_CggA.js.map} +1 -1
  78. package/public/assets/pairs-DGocNC1U.js +2 -0
  79. package/public/assets/{pairs-eOZl_lQn.js.map → pairs-DGocNC1U.js.map} +1 -1
  80. package/public/assets/{react-dom-CX8inunm.js → react-dom-CzfKBOnw.js} +2 -2
  81. package/public/assets/{react-dom-CX8inunm.js.map → react-dom-CzfKBOnw.js.map} +1 -1
  82. package/public/assets/{security-CA03sHyP.js → security-BSh0QxOl.js} +2 -2
  83. package/public/assets/{security-CA03sHyP.js.map → security-BSh0QxOl.js.map} +1 -1
  84. package/public/assets/{settings-KTOwGJiW.js → settings-C03CAJgO.js} +7 -7
  85. package/public/assets/{settings-KTOwGJiW.js.map → settings-C03CAJgO.js.map} +1 -1
  86. package/public/assets/store-DKVWC6Uh.js +9 -0
  87. package/public/assets/store-DKVWC6Uh.js.map +1 -0
  88. package/public/assets/{switch-22dlDUXs.js → switch-W2_mhdrR.js} +2 -2
  89. package/public/assets/{switch-22dlDUXs.js.map → switch-W2_mhdrR.js.map} +1 -1
  90. package/public/assets/tasks-rKbuUPOk.js +2 -0
  91. package/public/assets/{tasks-D6jbr2y6.js.map → tasks-rKbuUPOk.js.map} +1 -1
  92. package/public/assets/{terminal-viewer-impl-DFODXxpG.js → terminal-viewer-impl-CA8u4jh3.js} +3 -3
  93. package/public/assets/{terminal-viewer-impl-DFODXxpG.js.map → terminal-viewer-impl-CA8u4jh3.js.map} +1 -1
  94. package/public/assets/{use-keyboard-viewport-DxY_xJV5.js → use-keyboard-viewport-bZ1J-ZnH.js} +2 -2
  95. package/public/assets/{use-keyboard-viewport-DxY_xJV5.js.map → use-keyboard-viewport-bZ1J-ZnH.js.map} +1 -1
  96. package/public/assets/work-queue-DOsA9s4M.js +2 -0
  97. package/public/assets/{work-queue-BWWckTVy.js.map → work-queue-DOsA9s4M.js.map} +1 -1
  98. package/public/assets/{workspaces-D7lsWShY.js → workspaces-CoC2nflZ.js} +3 -3
  99. package/public/assets/{workspaces-D7lsWShY.js.map → workspaces-CoC2nflZ.js.map} +1 -1
  100. package/public/index.html +20 -20
  101. package/src/db/message-reads.ts +54 -1
  102. package/src/db/migrations.ts +1 -0
  103. package/src/routes/_shared.ts +2 -1
  104. package/src/routes/agents.ts +21 -2
  105. package/src/routes/index.ts +2 -1
  106. package/src/sse.ts +7 -2
  107. package/public/assets/agents-Bz4eJ4zH.js +0 -2
  108. package/public/assets/agents-Bz4eJ4zH.js.map +0 -1
  109. package/public/assets/card-CggxP1h9.js +0 -2
  110. package/public/assets/chat-Dn3TEhl0.js +0 -2
  111. package/public/assets/chat-Dn3TEhl0.js.map +0 -1
  112. package/public/assets/copy-button-CE8e2c-F.js +0 -2
  113. package/public/assets/display-Bebqs1qu.js +0 -3
  114. package/public/assets/dist-BmYJ5xuf.js +0 -2
  115. package/public/assets/dist-DTLaCErY.js +0 -2
  116. package/public/assets/index-BL8r94_U.js +0 -21
  117. package/public/assets/index-BL8r94_U.js.map +0 -1
  118. package/public/assets/index-DeSwlD3c.css +0 -2
  119. package/public/assets/lucide-react-CD8Xl2U3.js +0 -9
  120. package/public/assets/memory-BWfDbph3.js +0 -2
  121. package/public/assets/pairs-eOZl_lQn.js +0 -2
  122. package/public/assets/store-CICRhg1m.js +0 -9
  123. package/public/assets/store-CICRhg1m.js.map +0 -1
  124. package/public/assets/tasks-D6jbr2y6.js +0 -2
  125. package/public/assets/work-queue-BWWckTVy.js +0 -2
@@ -1,2 +1,2 @@
1
- import"./chunk-CilyBKbf.js";import{Dn as e,Vn as t,kn as n}from"./lucide-react-CD8Xl2U3.js";t();var r=n();function i({className:t,type:n,...i}){return(0,r.jsx)(`input`,{type:n,"data-slot":`input`,className:e(`h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,t),...i})}export{i as t};
2
- //# sourceMappingURL=input-BW9UD3FM.js.map
1
+ import"./chunk-CilyBKbf.js";import{An as e,Hn as t,On as n}from"./lucide-react-DLQFnqNm.js";t();var r=e();function i({className:e,type:t,...i}){return(0,r.jsx)(`input`,{type:t,"data-slot":`input`,className:n(`h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,e),...i})}export{i as t};
2
+ //# sourceMappingURL=input-dPzf0luy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input-BW9UD3FM.js","names":[],"sources":["../../dashboard/src/components/ui/input.tsx"],"sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(\n \"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Input }\n"],"mappings":"0GAIA,SAAS,EAAM,CAAE,YAAW,OAAM,GAAG,GAAwC,CAC3E,OACE,EAAA,EAAA,KAAC,QAAD,CACQ,OACN,YAAU,QACV,UAAW,EACT,8oBACA,EACD,CACD,GAAI,EACJ,CAAA"}
1
+ {"version":3,"file":"input-dPzf0luy.js","names":[],"sources":["../../dashboard/src/components/ui/input.tsx"],"sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(\n \"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Input }\n"],"mappings":"0GAIA,SAAS,EAAM,CAAE,YAAW,OAAM,GAAG,GAAwC,CAC3E,OACE,EAAA,EAAA,KAAC,QAAD,CACQ,OACN,YAAU,QACV,UAAW,EACT,8oBACA,EACD,CACD,GAAI,EACJ,CAAA"}
@@ -1,2 +1,2 @@
1
- import{r as e}from"./chunk-CilyBKbf.js";import{An as t,M as n,Vn as r,kn as i,lt as a}from"./lucide-react-CD8Xl2U3.js";import{G as o,z as s}from"./display-Bebqs1qu.js";import{t as c}from"./switch-22dlDUXs.js";import{t as l}from"./badge-t8zAwHW9.js";import{t as u}from"./button-DDA5P2YQ.js";import{t as d}from"./input-BW9UD3FM.js";import{i as f,n as p,r as m,t as h}from"./card-CggxP1h9.js";var g=e(r(),1),_=i(),v={enabled:!0,contextRatio:{enabled:!0},introspection:{enabled:!0,minTurns:4,minContextRemaining:.15}};function y(e){return!e||Object.keys(e).length===0?`—`:Object.entries(e).map(([e,t])=>`${e}: ${typeof t==`number`?Math.round(t*1e3)/1e3:String(t)}`).join(` `)}function b(){let[e,r]=(0,g.useState)(v),[i,b]=(0,g.useState)(0),[x,S]=(0,g.useState)([]),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)([]),[D,O]=(0,g.useState)(``),[k,A]=(0,g.useState)(``),[j,M]=(0,g.useState)(!1),[N,P]=(0,g.useState)(null),[F,I]=(0,g.useState)(()=>Date.now());async function L(){P(null);try{let e=new URLSearchParams;D&&e.set(`project`,D),k&&e.set(`signal`,k);let n=e.toString(),[i,a]=await Promise.all([t(`GET`,`/insights/config`),t(`GET`,`/insights/observations${n?`?${n}`:``}`)]);r(i.value),b(i.version),S(a.observations),w(a.stats),E(a.projects),I(Date.now())}catch(e){P(o(e))}}(0,g.useEffect)(()=>{L()},[D,k]);async function R(n){M(!0),P(null);let i=e;r(n);try{let e=await t(`PUT`,`/insights/config`,{value:n,updatedBy:`dashboard`});r(e.value),b(e.version)}catch(e){r(i),P(o(e))}finally{M(!1)}}let z=(0,g.useMemo)(()=>[...new Set(C.map(e=>e.signal))].sort(),[C]),B=(0,g.useMemo)(()=>C.filter(e=>e.project===null),[C]),V=(0,g.useMemo)(()=>C.filter(e=>e.project!==null),[C]);return(0,_.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(a,{className:`size-5 text-primary`}),(0,_.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Insights`}),(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`continuous self-improvement · epic #183`})]}),(0,_.jsxs)(u,{variant:`outline`,size:`sm`,onClick:()=>void L(),children:[(0,_.jsx)(n,{className:`size-4`}),` Refresh`]})]}),N&&(0,_.jsx)(`div`,{className:`rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:N}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsxs)(f,{className:`flex items-center justify-between`,children:[(0,_.jsx)(`span`,{children:`Features`}),(0,_.jsxs)(`span`,{className:`text-xs font-normal text-muted-foreground`,children:[`config v`,i,` · saved by `,e&&`dashboard`]})]})}),(0,_.jsxs)(p,{className:`space-y-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`div`,{className:`text-sm font-medium`,children:`Insights enabled`}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Master switch. When off, no signals are recorded regardless of the toggles below.`})]}),(0,_.jsx)(c,{checked:e.enabled,disabled:j,onCheckedChange:t=>void R({...e,enabled:t})})]}),(0,_.jsxs)(`div`,{className:`flex items-center justify-between border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`Context-gathering ratio `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#184)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Server-side: read/search vs. action before first substantive move, per session.`})]}),(0,_.jsx)(c,{checked:e.contextRatio.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,contextRatio:{enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`End-of-session introspection `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#185)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Agent-authored 3-field artifact at session end. Gated below.`})]}),(0,_.jsx)(c,{checked:e.introspection.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,introspection:{...e.introspection,enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-4`,children:[(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min turns`,(0,_.jsx)(d,{type:`number`,className:`h-7 w-20`,value:e.introspection.minTurns,disabled:j||!e.enabled||!e.introspection.enabled,onChange:t=>r({...e,introspection:{...e.introspection,minTurns:Number(t.target.value)}}),onBlur:()=>void R(e)})]}),(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min context remaining (0–1)`,(0,_.jsx)(d,{type:`number`,step:`0.05`,min:`0`,max:`1`,className:`h-7 w-24`,value:e.introspection.minContextRemaining,disabled:j||!e.enabled||!e.introspection.enabled,onChange:t=>r({...e,introspection:{...e.introspection,minContextRemaining:Number(t.target.value)}}),onBlur:()=>void R(e)})]})]})]})]})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsx)(f,{children:`Signals`})}),(0,_.jsx)(p,{children:B.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations yet — they appear after sessions end with Insights enabled.`}):(0,_.jsx)(`div`,{className:`space-y-4`,children:B.map(e=>(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`mb-1 flex items-center gap-2`,children:[(0,_.jsx)(l,{variant:`secondary`,children:e.signal}),(0,_.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[e.count,` obs · `,e.avgRatio===null?`no ratio`:`avg ratio ${e.avgRatio.toFixed(2)}`,` · `,s(F,e.lastAt)]})]}),(0,_.jsx)(`div`,{className:`flex flex-wrap gap-2 pl-2`,children:V.filter(t=>t.signal===e.signal).map(t=>(0,_.jsxs)(`span`,{className:`rounded border border-border px-2 py-0.5 text-xs text-muted-foreground`,children:[t.project,`: `,t.count,t.avgRatio===null?``:` · ${t.avgRatio.toFixed(2)}`]},`${e.signal}-${t.project}`))})]},e.signal))})})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsxs)(f,{className:`flex flex-wrap items-center gap-3`,children:[(0,_.jsx)(`span`,{children:`Observations`}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:D,onChange:e=>O(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all projects`}),T.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:k,onChange:e=>A(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all signals`}),z.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]})]})}),(0,_.jsx)(p,{children:x.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations match.`}):(0,_.jsx)(`div`,{className:`overflow-x-auto`,children:(0,_.jsxs)(`table`,{className:`w-full min-w-[680px] text-left text-xs`,children:[(0,_.jsx)(`thead`,{className:`text-muted-foreground`,children:(0,_.jsxs)(`tr`,{className:`border-b border-border`,children:[(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`when`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`project`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`signal`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`src`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`value`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`outcome`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`session`})]})}),(0,_.jsx)(`tbody`,{children:x.map(e=>(0,_.jsxs)(`tr`,{className:`border-b border-border/50`,children:[(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:s(F,e.createdAt)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:e.project}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:(0,_.jsx)(l,{variant:`outline`,children:e.signal})}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.source}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono`,children:y(e.value)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono text-muted-foreground`,children:y(e.outcome)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.agentId??e.sessionId.slice(0,12)})]},e.id))})]})})})]})]})}export{b as InsightsView};
2
- //# sourceMappingURL=insights-yJFgCa3o.js.map
1
+ import{r as e}from"./chunk-CilyBKbf.js";import{An as t,Hn as n,M as r,jn as i,lt as a}from"./lucide-react-DLQFnqNm.js";import{H as o,J as s}from"./display-ConJ9cJB.js";import{t as c}from"./switch-W2_mhdrR.js";import{t as l}from"./badge-JVybSpzR.js";import{t as u}from"./button-BsMqBNJb.js";import{t as d}from"./input-dPzf0luy.js";import{i as f,n as p,r as m,t as h}from"./card-I8w4U656.js";var g=e(n(),1),_=t(),v={enabled:!0,contextRatio:{enabled:!0},introspection:{enabled:!0,minTurns:4,minContextRemaining:.15}};function y(e){return!e||Object.keys(e).length===0?`—`:Object.entries(e).map(([e,t])=>`${e}: ${typeof t==`number`?Math.round(t*1e3)/1e3:String(t)}`).join(` `)}function b(){let[e,t]=(0,g.useState)(v),[n,b]=(0,g.useState)(0),[x,S]=(0,g.useState)([]),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)([]),[D,O]=(0,g.useState)(``),[k,A]=(0,g.useState)(``),[j,M]=(0,g.useState)(!1),[N,P]=(0,g.useState)(null),[F,I]=(0,g.useState)(()=>Date.now());async function L(){P(null);try{let e=new URLSearchParams;D&&e.set(`project`,D),k&&e.set(`signal`,k);let n=e.toString(),[r,a]=await Promise.all([i(`GET`,`/insights/config`),i(`GET`,`/insights/observations${n?`?${n}`:``}`)]);t(r.value),b(r.version),S(a.observations),w(a.stats),E(a.projects),I(Date.now())}catch(e){P(s(e))}}(0,g.useEffect)(()=>{L()},[D,k]);async function R(n){M(!0),P(null);let r=e;t(n);try{let e=await i(`PUT`,`/insights/config`,{value:n,updatedBy:`dashboard`});t(e.value),b(e.version)}catch(e){t(r),P(s(e))}finally{M(!1)}}let z=(0,g.useMemo)(()=>[...new Set(C.map(e=>e.signal))].sort(),[C]),B=(0,g.useMemo)(()=>C.filter(e=>e.project===null),[C]),V=(0,g.useMemo)(()=>C.filter(e=>e.project!==null),[C]);return(0,_.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(a,{className:`size-5 text-primary`}),(0,_.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Insights`}),(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`continuous self-improvement · epic #183`})]}),(0,_.jsxs)(u,{variant:`outline`,size:`sm`,onClick:()=>void L(),children:[(0,_.jsx)(r,{className:`size-4`}),` Refresh`]})]}),N&&(0,_.jsx)(`div`,{className:`rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:N}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsxs)(f,{className:`flex items-center justify-between`,children:[(0,_.jsx)(`span`,{children:`Features`}),(0,_.jsxs)(`span`,{className:`text-xs font-normal text-muted-foreground`,children:[`config v`,n,` · saved by `,e&&`dashboard`]})]})}),(0,_.jsxs)(p,{className:`space-y-4`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`div`,{className:`text-sm font-medium`,children:`Insights enabled`}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Master switch. When off, no signals are recorded regardless of the toggles below.`})]}),(0,_.jsx)(c,{checked:e.enabled,disabled:j,onCheckedChange:t=>void R({...e,enabled:t})})]}),(0,_.jsxs)(`div`,{className:`flex items-center justify-between border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`Context-gathering ratio `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#184)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Server-side: read/search vs. action before first substantive move, per session.`})]}),(0,_.jsx)(c,{checked:e.contextRatio.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,contextRatio:{enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`border-t border-border pt-3`,children:[(0,_.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`text-sm font-medium`,children:[`End-of-session introspection `,(0,_.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(#185)`})]}),(0,_.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`Agent-authored 3-field artifact at session end. Gated below.`})]}),(0,_.jsx)(c,{checked:e.introspection.enabled,disabled:j||!e.enabled,onCheckedChange:t=>void R({...e,introspection:{...e.introspection,enabled:t}})})]}),(0,_.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-4`,children:[(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min turns`,(0,_.jsx)(d,{type:`number`,className:`h-7 w-20`,value:e.introspection.minTurns,disabled:j||!e.enabled||!e.introspection.enabled,onChange:n=>t({...e,introspection:{...e.introspection,minTurns:Number(n.target.value)}}),onBlur:()=>void R(e)})]}),(0,_.jsxs)(`label`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[`min context remaining (0–1)`,(0,_.jsx)(d,{type:`number`,step:`0.05`,min:`0`,max:`1`,className:`h-7 w-24`,value:e.introspection.minContextRemaining,disabled:j||!e.enabled||!e.introspection.enabled,onChange:n=>t({...e,introspection:{...e.introspection,minContextRemaining:Number(n.target.value)}}),onBlur:()=>void R(e)})]})]})]})]})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsx)(f,{children:`Signals`})}),(0,_.jsx)(p,{children:B.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations yet — they appear after sessions end with Insights enabled.`}):(0,_.jsx)(`div`,{className:`space-y-4`,children:B.map(e=>(0,_.jsxs)(`div`,{children:[(0,_.jsxs)(`div`,{className:`mb-1 flex items-center gap-2`,children:[(0,_.jsx)(l,{variant:`secondary`,children:e.signal}),(0,_.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[e.count,` obs · `,e.avgRatio===null?`no ratio`:`avg ratio ${e.avgRatio.toFixed(2)}`,` · `,o(F,e.lastAt)]})]}),(0,_.jsx)(`div`,{className:`flex flex-wrap gap-2 pl-2`,children:V.filter(t=>t.signal===e.signal).map(t=>(0,_.jsxs)(`span`,{className:`rounded border border-border px-2 py-0.5 text-xs text-muted-foreground`,children:[t.project,`: `,t.count,t.avgRatio===null?``:` · ${t.avgRatio.toFixed(2)}`]},`${e.signal}-${t.project}`))})]},e.signal))})})]}),(0,_.jsxs)(h,{children:[(0,_.jsx)(m,{children:(0,_.jsxs)(f,{className:`flex flex-wrap items-center gap-3`,children:[(0,_.jsx)(`span`,{children:`Observations`}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:D,onChange:e=>O(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all projects`}),T.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]}),(0,_.jsxs)(`select`,{className:`h-7 rounded border border-border bg-background px-2 text-xs`,value:k,onChange:e=>A(e.target.value),children:[(0,_.jsx)(`option`,{value:``,children:`all signals`}),z.map(e=>(0,_.jsx)(`option`,{value:e,children:e},e))]})]})}),(0,_.jsx)(p,{children:x.length===0?(0,_.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:`No observations match.`}):(0,_.jsx)(`div`,{className:`overflow-x-auto`,children:(0,_.jsxs)(`table`,{className:`w-full min-w-[680px] text-left text-xs`,children:[(0,_.jsx)(`thead`,{className:`text-muted-foreground`,children:(0,_.jsxs)(`tr`,{className:`border-b border-border`,children:[(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`when`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`project`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`signal`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`src`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`value`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`outcome`}),(0,_.jsx)(`th`,{className:`py-1 pr-3 font-medium`,children:`session`})]})}),(0,_.jsx)(`tbody`,{children:x.map(e=>(0,_.jsxs)(`tr`,{className:`border-b border-border/50`,children:[(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:o(F,e.createdAt)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:e.project}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap`,children:(0,_.jsx)(l,{variant:`outline`,children:e.signal})}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.source}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono`,children:y(e.value)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 font-mono text-muted-foreground`,children:y(e.outcome)}),(0,_.jsx)(`td`,{className:`py-1 pr-3 whitespace-nowrap text-muted-foreground`,children:e.agentId??e.sessionId.slice(0,12)})]},e.id))})]})})})]})]})}export{b as InsightsView};
2
+ //# sourceMappingURL=insights-5CDeJfoX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"insights-yJFgCa3o.js","names":[],"sources":["../../dashboard/src/components/views/insights.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { errMessage } from 'agent-relay-sdk/types'\nimport { api } from '@/lib/api'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { timeAgo } from '@/lib/display'\nimport { Lightbulb, RefreshCw } from 'lucide-react'\n\n// Insights — continuous self-improvement module (epic #183, docs/self-improvement.md).\n// v0: feature toggles + a raw per-project/global view of the observations the relay\n// collects. No charts, no alerting — the data earns those once a week proves it's real.\n\ninterface InsightsConfig {\n enabled: boolean\n contextRatio: { enabled: boolean }\n introspection: { enabled: boolean; minTurns: number; minContextRemaining: number }\n}\n\ninterface ConfigEntry {\n value: InsightsConfig\n version: number\n updatedAt: string\n updatedBy?: string\n}\n\ninterface Observation {\n id: number\n sessionId: string\n agentId?: string\n project: string\n signal: string\n value: Record<string, unknown>\n outcome?: Record<string, unknown>\n source: 'server' | 'agent'\n createdAt: number\n}\n\ninterface Stat {\n signal: string\n project: string | null\n count: number\n avgRatio: number | null\n lastAt: number | null\n}\n\ninterface ObservationsResponse {\n observations: Observation[]\n stats: Stat[]\n projects: string[]\n}\n\nconst DEFAULT_CONFIG: InsightsConfig = {\n enabled: true,\n contextRatio: { enabled: true },\n introspection: { enabled: true, minTurns: 4, minContextRemaining: 0.15 },\n}\n\nfunction compactJson(value: Record<string, unknown> | undefined): string {\n if (!value || Object.keys(value).length === 0) return '—'\n return Object.entries(value)\n .map(([k, v]) => `${k}: ${typeof v === 'number' ? Math.round(v * 1000) / 1000 : String(v)}`)\n .join(' ')\n}\n\nexport function InsightsView() {\n const [config, setConfig] = useState<InsightsConfig>(DEFAULT_CONFIG)\n const [version, setVersion] = useState(0)\n const [observations, setObservations] = useState<Observation[]>([])\n const [stats, setStats] = useState<Stat[]>([])\n const [projects, setProjects] = useState<string[]>([])\n const [projectFilter, setProjectFilter] = useState<string>('')\n const [signalFilter, setSignalFilter] = useState<string>('')\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [now, setNow] = useState(() => Date.now())\n\n async function refresh() {\n setError(null)\n try {\n const params = new URLSearchParams()\n if (projectFilter) params.set('project', projectFilter)\n if (signalFilter) params.set('signal', signalFilter)\n const query = params.toString()\n const [cfg, obs] = await Promise.all([\n api<ConfigEntry>('GET', '/insights/config'),\n api<ObservationsResponse>('GET', `/insights/observations${query ? `?${query}` : ''}`),\n ])\n setConfig(cfg.value)\n setVersion(cfg.version)\n setObservations(obs.observations)\n setStats(obs.stats)\n setProjects(obs.projects)\n setNow(Date.now())\n } catch (e) {\n setError(errMessage(e))\n }\n }\n\n // Mount + filter-change: synchronize the view with the relay's stored data.\n useEffect(() => {\n void refresh()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [projectFilter, signalFilter])\n\n async function saveConfig(next: InsightsConfig) {\n setSaving(true)\n setError(null)\n const previous = config\n setConfig(next) // optimistic\n try {\n const entry = await api<ConfigEntry>('PUT', '/insights/config', { value: next, updatedBy: 'dashboard' })\n setConfig(entry.value)\n setVersion(entry.version)\n } catch (e) {\n setConfig(previous) // revert on failure\n setError(errMessage(e))\n } finally {\n setSaving(false)\n }\n }\n\n const signals = useMemo(() => {\n const set = new Set<string>(stats.map((s) => s.signal))\n return [...set].sort()\n }, [stats])\n\n const globalStats = useMemo(() => stats.filter((s) => s.project === null), [stats])\n const projectStats = useMemo(() => stats.filter((s) => s.project !== null), [stats])\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Lightbulb className=\"size-5 text-primary\" />\n <h1 className=\"text-lg font-semibold\">Insights</h1>\n <span className=\"text-xs text-muted-foreground\">continuous self-improvement · epic #183</span>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void refresh()}>\n <RefreshCw className=\"size-4\" /> Refresh\n </Button>\n </div>\n\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">{error}</div>\n )}\n\n {/* Feature toggles */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Features</span>\n <span className=\"text-xs font-normal text-muted-foreground\">config v{version} · saved by {config && 'dashboard'}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">Insights enabled</div>\n <div className=\"text-xs text-muted-foreground\">Master switch. When off, no signals are recorded regardless of the toggles below.</div>\n </div>\n <Switch checked={config.enabled} disabled={saving} onCheckedChange={(v) => void saveConfig({ ...config, enabled: v })} />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border pt-3\">\n <div>\n <div className=\"text-sm font-medium\">Context-gathering ratio <span className=\"text-xs text-muted-foreground\">(#184)</span></div>\n <div className=\"text-xs text-muted-foreground\">Server-side: read/search vs. action before first substantive move, per session.</div>\n </div>\n <Switch checked={config.contextRatio.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, contextRatio: { enabled: v } })} />\n </div>\n\n <div className=\"border-t border-border pt-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">End-of-session introspection <span className=\"text-xs text-muted-foreground\">(#185)</span></div>\n <div className=\"text-xs text-muted-foreground\">Agent-authored 3-field artifact at session end. Gated below.</div>\n </div>\n <Switch checked={config.introspection.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, introspection: { ...config.introspection, enabled: v } })} />\n </div>\n <div className=\"mt-3 flex flex-wrap gap-4\">\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min turns\n <Input type=\"number\" className=\"h-7 w-20\" value={config.introspection.minTurns}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minTurns: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min context remaining (0–1)\n <Input type=\"number\" step=\"0.05\" min=\"0\" max=\"1\" className=\"h-7 w-24\" value={config.introspection.minContextRemaining}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minContextRemaining: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Stats rollup */}\n <Card>\n <CardHeader>\n <CardTitle>Signals</CardTitle>\n </CardHeader>\n <CardContent>\n {globalStats.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations yet — they appear after sessions end with Insights enabled.</div>\n ) : (\n <div className=\"space-y-4\">\n {globalStats.map((g) => (\n <div key={g.signal}>\n <div className=\"mb-1 flex items-center gap-2\">\n <Badge variant=\"secondary\">{g.signal}</Badge>\n <span className=\"text-xs text-muted-foreground\">\n {g.count} obs · {g.avgRatio !== null ? `avg ratio ${g.avgRatio.toFixed(2)}` : 'no ratio'} · {timeAgo(now, g.lastAt)}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2 pl-2\">\n {projectStats.filter((p) => p.signal === g.signal).map((p) => (\n <span key={`${g.signal}-${p.project}`} className=\"rounded border border-border px-2 py-0.5 text-xs text-muted-foreground\">\n {p.project}: {p.count}{p.avgRatio !== null ? ` · ${p.avgRatio.toFixed(2)}` : ''}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Raw observations */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-3\">\n <span>Observations</span>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={projectFilter} onChange={(e) => setProjectFilter(e.target.value)}>\n <option value=\"\">all projects</option>\n {projects.map((p) => <option key={p} value={p}>{p}</option>)}\n </select>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={signalFilter} onChange={(e) => setSignalFilter(e.target.value)}>\n <option value=\"\">all signals</option>\n {signals.map((s) => <option key={s} value={s}>{s}</option>)}\n </select>\n </CardTitle>\n </CardHeader>\n <CardContent>\n {observations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations match.</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[680px] text-left text-xs\">\n <thead className=\"text-muted-foreground\">\n <tr className=\"border-b border-border\">\n <th className=\"py-1 pr-3 font-medium\">when</th>\n <th className=\"py-1 pr-3 font-medium\">project</th>\n <th className=\"py-1 pr-3 font-medium\">signal</th>\n <th className=\"py-1 pr-3 font-medium\">src</th>\n <th className=\"py-1 pr-3 font-medium\">value</th>\n <th className=\"py-1 pr-3 font-medium\">outcome</th>\n <th className=\"py-1 pr-3 font-medium\">session</th>\n </tr>\n </thead>\n <tbody>\n {observations.map((o) => (\n <tr key={o.id} className=\"border-b border-border/50\">\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{timeAgo(now, o.createdAt)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\">{o.project}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\"><Badge variant=\"outline\">{o.signal}</Badge></td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.source}</td>\n <td className=\"py-1 pr-3 font-mono\">{compactJson(o.value)}</td>\n <td className=\"py-1 pr-3 font-mono text-muted-foreground\">{compactJson(o.outcome)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.agentId ?? o.sessionId.slice(0, 12)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"insights-5CDeJfoX.js","names":[],"sources":["../../dashboard/src/components/views/insights.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react'\nimport { errMessage } from 'agent-relay-sdk/types'\nimport { api } from '@/lib/api'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { timeAgo } from '@/lib/display'\nimport { Lightbulb, RefreshCw } from 'lucide-react'\n\n// Insights — continuous self-improvement module (epic #183, docs/self-improvement.md).\n// v0: feature toggles + a raw per-project/global view of the observations the relay\n// collects. No charts, no alerting — the data earns those once a week proves it's real.\n\ninterface InsightsConfig {\n enabled: boolean\n contextRatio: { enabled: boolean }\n introspection: { enabled: boolean; minTurns: number; minContextRemaining: number }\n}\n\ninterface ConfigEntry {\n value: InsightsConfig\n version: number\n updatedAt: string\n updatedBy?: string\n}\n\ninterface Observation {\n id: number\n sessionId: string\n agentId?: string\n project: string\n signal: string\n value: Record<string, unknown>\n outcome?: Record<string, unknown>\n source: 'server' | 'agent'\n createdAt: number\n}\n\ninterface Stat {\n signal: string\n project: string | null\n count: number\n avgRatio: number | null\n lastAt: number | null\n}\n\ninterface ObservationsResponse {\n observations: Observation[]\n stats: Stat[]\n projects: string[]\n}\n\nconst DEFAULT_CONFIG: InsightsConfig = {\n enabled: true,\n contextRatio: { enabled: true },\n introspection: { enabled: true, minTurns: 4, minContextRemaining: 0.15 },\n}\n\nfunction compactJson(value: Record<string, unknown> | undefined): string {\n if (!value || Object.keys(value).length === 0) return '—'\n return Object.entries(value)\n .map(([k, v]) => `${k}: ${typeof v === 'number' ? Math.round(v * 1000) / 1000 : String(v)}`)\n .join(' ')\n}\n\nexport function InsightsView() {\n const [config, setConfig] = useState<InsightsConfig>(DEFAULT_CONFIG)\n const [version, setVersion] = useState(0)\n const [observations, setObservations] = useState<Observation[]>([])\n const [stats, setStats] = useState<Stat[]>([])\n const [projects, setProjects] = useState<string[]>([])\n const [projectFilter, setProjectFilter] = useState<string>('')\n const [signalFilter, setSignalFilter] = useState<string>('')\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [now, setNow] = useState(() => Date.now())\n\n async function refresh() {\n setError(null)\n try {\n const params = new URLSearchParams()\n if (projectFilter) params.set('project', projectFilter)\n if (signalFilter) params.set('signal', signalFilter)\n const query = params.toString()\n const [cfg, obs] = await Promise.all([\n api<ConfigEntry>('GET', '/insights/config'),\n api<ObservationsResponse>('GET', `/insights/observations${query ? `?${query}` : ''}`),\n ])\n setConfig(cfg.value)\n setVersion(cfg.version)\n setObservations(obs.observations)\n setStats(obs.stats)\n setProjects(obs.projects)\n setNow(Date.now())\n } catch (e) {\n setError(errMessage(e))\n }\n }\n\n // Mount + filter-change: synchronize the view with the relay's stored data.\n useEffect(() => {\n void refresh()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [projectFilter, signalFilter])\n\n async function saveConfig(next: InsightsConfig) {\n setSaving(true)\n setError(null)\n const previous = config\n setConfig(next) // optimistic\n try {\n const entry = await api<ConfigEntry>('PUT', '/insights/config', { value: next, updatedBy: 'dashboard' })\n setConfig(entry.value)\n setVersion(entry.version)\n } catch (e) {\n setConfig(previous) // revert on failure\n setError(errMessage(e))\n } finally {\n setSaving(false)\n }\n }\n\n const signals = useMemo(() => {\n const set = new Set<string>(stats.map((s) => s.signal))\n return [...set].sort()\n }, [stats])\n\n const globalStats = useMemo(() => stats.filter((s) => s.project === null), [stats])\n const projectStats = useMemo(() => stats.filter((s) => s.project !== null), [stats])\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Lightbulb className=\"size-5 text-primary\" />\n <h1 className=\"text-lg font-semibold\">Insights</h1>\n <span className=\"text-xs text-muted-foreground\">continuous self-improvement · epic #183</span>\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => void refresh()}>\n <RefreshCw className=\"size-4\" /> Refresh\n </Button>\n </div>\n\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive\">{error}</div>\n )}\n\n {/* Feature toggles */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Features</span>\n <span className=\"text-xs font-normal text-muted-foreground\">config v{version} · saved by {config && 'dashboard'}</span>\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">Insights enabled</div>\n <div className=\"text-xs text-muted-foreground\">Master switch. When off, no signals are recorded regardless of the toggles below.</div>\n </div>\n <Switch checked={config.enabled} disabled={saving} onCheckedChange={(v) => void saveConfig({ ...config, enabled: v })} />\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border pt-3\">\n <div>\n <div className=\"text-sm font-medium\">Context-gathering ratio <span className=\"text-xs text-muted-foreground\">(#184)</span></div>\n <div className=\"text-xs text-muted-foreground\">Server-side: read/search vs. action before first substantive move, per session.</div>\n </div>\n <Switch checked={config.contextRatio.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, contextRatio: { enabled: v } })} />\n </div>\n\n <div className=\"border-t border-border pt-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"text-sm font-medium\">End-of-session introspection <span className=\"text-xs text-muted-foreground\">(#185)</span></div>\n <div className=\"text-xs text-muted-foreground\">Agent-authored 3-field artifact at session end. Gated below.</div>\n </div>\n <Switch checked={config.introspection.enabled} disabled={saving || !config.enabled}\n onCheckedChange={(v) => void saveConfig({ ...config, introspection: { ...config.introspection, enabled: v } })} />\n </div>\n <div className=\"mt-3 flex flex-wrap gap-4\">\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min turns\n <Input type=\"number\" className=\"h-7 w-20\" value={config.introspection.minTurns}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minTurns: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n min context remaining (0–1)\n <Input type=\"number\" step=\"0.05\" min=\"0\" max=\"1\" className=\"h-7 w-24\" value={config.introspection.minContextRemaining}\n disabled={saving || !config.enabled || !config.introspection.enabled}\n onChange={(e) => setConfig({ ...config, introspection: { ...config.introspection, minContextRemaining: Number(e.target.value) } })}\n onBlur={() => void saveConfig(config)} />\n </label>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Stats rollup */}\n <Card>\n <CardHeader>\n <CardTitle>Signals</CardTitle>\n </CardHeader>\n <CardContent>\n {globalStats.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations yet — they appear after sessions end with Insights enabled.</div>\n ) : (\n <div className=\"space-y-4\">\n {globalStats.map((g) => (\n <div key={g.signal}>\n <div className=\"mb-1 flex items-center gap-2\">\n <Badge variant=\"secondary\">{g.signal}</Badge>\n <span className=\"text-xs text-muted-foreground\">\n {g.count} obs · {g.avgRatio !== null ? `avg ratio ${g.avgRatio.toFixed(2)}` : 'no ratio'} · {timeAgo(now, g.lastAt)}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2 pl-2\">\n {projectStats.filter((p) => p.signal === g.signal).map((p) => (\n <span key={`${g.signal}-${p.project}`} className=\"rounded border border-border px-2 py-0.5 text-xs text-muted-foreground\">\n {p.project}: {p.count}{p.avgRatio !== null ? ` · ${p.avgRatio.toFixed(2)}` : ''}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Raw observations */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-3\">\n <span>Observations</span>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={projectFilter} onChange={(e) => setProjectFilter(e.target.value)}>\n <option value=\"\">all projects</option>\n {projects.map((p) => <option key={p} value={p}>{p}</option>)}\n </select>\n <select className=\"h-7 rounded border border-border bg-background px-2 text-xs\"\n value={signalFilter} onChange={(e) => setSignalFilter(e.target.value)}>\n <option value=\"\">all signals</option>\n {signals.map((s) => <option key={s} value={s}>{s}</option>)}\n </select>\n </CardTitle>\n </CardHeader>\n <CardContent>\n {observations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No observations match.</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[680px] text-left text-xs\">\n <thead className=\"text-muted-foreground\">\n <tr className=\"border-b border-border\">\n <th className=\"py-1 pr-3 font-medium\">when</th>\n <th className=\"py-1 pr-3 font-medium\">project</th>\n <th className=\"py-1 pr-3 font-medium\">signal</th>\n <th className=\"py-1 pr-3 font-medium\">src</th>\n <th className=\"py-1 pr-3 font-medium\">value</th>\n <th className=\"py-1 pr-3 font-medium\">outcome</th>\n <th className=\"py-1 pr-3 font-medium\">session</th>\n </tr>\n </thead>\n <tbody>\n {observations.map((o) => (\n <tr key={o.id} className=\"border-b border-border/50\">\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{timeAgo(now, o.createdAt)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\">{o.project}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap\"><Badge variant=\"outline\">{o.signal}</Badge></td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.source}</td>\n <td className=\"py-1 pr-3 font-mono\">{compactJson(o.value)}</td>\n <td className=\"py-1 pr-3 font-mono text-muted-foreground\">{compactJson(o.outcome)}</td>\n <td className=\"py-1 pr-3 whitespace-nowrap text-muted-foreground\">{o.agentId ?? o.sessionId.slice(0, 12)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{$t as e,En as t,L as n,Nt as r,Zt as i,at as a,kn as o}from"./lucide-react-CD8Xl2U3.js";import{t as s}from"./store-CICRhg1m.js";import{V as c,_ as l}from"./display-Bebqs1qu.js";import{t as u}from"./badge-t8zAwHW9.js";import{t as d}from"./button-DDA5P2YQ.js";import{i as f,n as p,r as m,t as h}from"./card-CggxP1h9.js";var g=o(),_={PlugZap:n,AlertCircle:e,Activity:t,Eye:r,CircleCheck:i};function v(){let e=s(e=>e.integrations),t=s(e=>e.set),r=s(e=>e.switchView),i=e.reduce((e,t)=>e+(t.taskStats?.waitingTasks||0),0);function o(e){t({taskSourceFilter:e}),r(`tasks`)}return(0,g.jsxs)(`div`,{className:`space-y-6`,children:[(0,g.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,g.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,g.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Integrations`}),(0,g.jsxs)(u,{variant:`outline`,className:`text-xs`,children:[e.length,` total`]}),i>0&&(0,g.jsxs)(u,{className:`bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs`,children:[i,` waiting`]})]})}),e.length===0?(0,g.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-16 text-center`,children:[(0,g.jsx)(n,{className:`w-10 h-10 text-zinc-600 mb-3`}),(0,g.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No integrations configured`})]}):(0,g.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:e.map(e=>{let t=l(e),r=_[e.icon||t.icon]||_[t.icon]||n,i=e.taskStats||{};return(0,g.jsxs)(h,{className:`flex flex-col border-l-2`,style:{borderLeftColor:e.accentColor||void 0},children:[(0,g.jsxs)(m,{children:[(0,g.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,g.jsxs)(`div`,{className:`min-w-0`,children:[(0,g.jsx)(f,{className:`text-sm font-medium truncate`,children:e.displayName||e.name}),e.description&&(0,g.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-2`,children:e.description})]}),(0,g.jsxs)(`div`,{className:`flex items-center gap-1.5 shrink-0`,children:[(0,g.jsx)(r,{className:`w-3.5 h-3.5 ${c(t.tone)}`}),(0,g.jsx)(`span`,{className:`text-xs ${c(t.tone)}`,children:t.label})]})]}),(0,g.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-1`,children:[e.configured&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-emerald-400 border-emerald-500/30`,children:`configured`}),e.observed&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-blue-400 border-blue-500/30`,children:`observed`}),!e.enabled&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-red-400 border-red-500/30`,children:`disabled`}),e.type&&(0,g.jsx)(u,{variant:`secondary`,className:`text-xs`,children:e.type}),e.tags?.map(e=>(0,g.jsxs)(u,{variant:`outline`,className:`text-xs text-zinc-400`,children:[`#`,e]},e))]})]}),(0,g.jsxs)(p,{className:`flex-1 space-y-3`,children:[(0,g.jsxs)(`div`,{className:`grid grid-cols-4 gap-2 text-center`,children:[(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums`,children:i.tasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`tasks`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums text-blue-400`,children:i.openTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`open`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.waitingTasks??0)>0?`text-yellow-400`:``}`,children:i.waitingTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`waiting`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.failedTasks??0)>0?`text-red-400`:``}`,children:i.failedTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`failed`})]})]}),(e.scopes?.length>0||e.targets?.length>0||e.channels?.length>0)&&(0,g.jsxs)(`div`,{className:`space-y-1.5`,children:[e.scopes?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.scopes.map(e=>(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-zinc-400`,children:e},e))}),e.targets?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.targets.map(e=>(0,g.jsx)(u,{variant:`secondary`,className:`text-xs`,children:e},e))}),e.channels?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.channels.map(e=>(0,g.jsxs)(u,{className:`text-xs bg-blue-500/10 text-blue-400 border-blue-500/20`,children:[`#`,e]},e))})]})]}),(i.tasks??0)>0&&(0,g.jsx)(`div`,{className:`px-4 pb-4`,children:(0,g.jsxs)(d,{variant:`outline`,size:`sm`,className:`w-full gap-1.5`,onClick:()=>o(i.source||e.name),children:[(0,g.jsx)(a,{className:`w-3.5 h-3.5`}),`Show tasks`]})})]},e.name)})})]})}export{v as IntegrationsView};
2
- //# sourceMappingURL=integrations-CUv4i_4i.js.map
1
+ import{$t as e,An as t,Dn as n,L as r,Nt as i,Zt as a,at as o}from"./lucide-react-DLQFnqNm.js";import{t as s}from"./store-DKVWC6Uh.js";import{W as c,v as l}from"./display-ConJ9cJB.js";import{t as u}from"./badge-JVybSpzR.js";import{t as d}from"./button-BsMqBNJb.js";import{i as f,n as p,r as m,t as h}from"./card-I8w4U656.js";var g=t(),_={PlugZap:r,AlertCircle:e,Activity:n,Eye:i,CircleCheck:a};function v(){let e=s(e=>e.integrations),t=s(e=>e.set),n=s(e=>e.switchView),i=e.reduce((e,t)=>e+(t.taskStats?.waitingTasks||0),0);function a(e){t({taskSourceFilter:e}),n(`tasks`)}return(0,g.jsxs)(`div`,{className:`space-y-6`,children:[(0,g.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,g.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,g.jsx)(`h1`,{className:`text-lg font-semibold`,children:`Integrations`}),(0,g.jsxs)(u,{variant:`outline`,className:`text-xs`,children:[e.length,` total`]}),i>0&&(0,g.jsxs)(u,{className:`bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs`,children:[i,` waiting`]})]})}),e.length===0?(0,g.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-16 text-center`,children:[(0,g.jsx)(r,{className:`w-10 h-10 text-zinc-600 mb-3`}),(0,g.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No integrations configured`})]}):(0,g.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4`,children:e.map(e=>{let t=l(e),n=_[e.icon||t.icon]||_[t.icon]||r,i=e.taskStats||{};return(0,g.jsxs)(h,{className:`flex flex-col border-l-2`,style:{borderLeftColor:e.accentColor||void 0},children:[(0,g.jsxs)(m,{children:[(0,g.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,g.jsxs)(`div`,{className:`min-w-0`,children:[(0,g.jsx)(f,{className:`text-sm font-medium truncate`,children:e.displayName||e.name}),e.description&&(0,g.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-2`,children:e.description})]}),(0,g.jsxs)(`div`,{className:`flex items-center gap-1.5 shrink-0`,children:[(0,g.jsx)(n,{className:`w-3.5 h-3.5 ${c(t.tone)}`}),(0,g.jsx)(`span`,{className:`text-xs ${c(t.tone)}`,children:t.label})]})]}),(0,g.jsxs)(`div`,{className:`flex flex-wrap gap-1 mt-1`,children:[e.configured&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-emerald-400 border-emerald-500/30`,children:`configured`}),e.observed&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-blue-400 border-blue-500/30`,children:`observed`}),!e.enabled&&(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-red-400 border-red-500/30`,children:`disabled`}),e.type&&(0,g.jsx)(u,{variant:`secondary`,className:`text-xs`,children:e.type}),e.tags?.map(e=>(0,g.jsxs)(u,{variant:`outline`,className:`text-xs text-zinc-400`,children:[`#`,e]},e))]})]}),(0,g.jsxs)(p,{className:`flex-1 space-y-3`,children:[(0,g.jsxs)(`div`,{className:`grid grid-cols-4 gap-2 text-center`,children:[(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums`,children:i.tasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`tasks`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums text-blue-400`,children:i.openTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`open`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.waitingTasks??0)>0?`text-yellow-400`:``}`,children:i.waitingTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`waiting`})]}),(0,g.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,g.jsx)(`p`,{className:`text-base font-semibold tabular-nums ${(i.failedTasks??0)>0?`text-red-400`:``}`,children:i.failedTasks??0}),(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`failed`})]})]}),(e.scopes?.length>0||e.targets?.length>0||e.channels?.length>0)&&(0,g.jsxs)(`div`,{className:`space-y-1.5`,children:[e.scopes?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.scopes.map(e=>(0,g.jsx)(u,{variant:`outline`,className:`text-xs text-zinc-400`,children:e},e))}),e.targets?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.targets.map(e=>(0,g.jsx)(u,{variant:`secondary`,className:`text-xs`,children:e},e))}),e.channels?.length>0&&(0,g.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:e.channels.map(e=>(0,g.jsxs)(u,{className:`text-xs bg-blue-500/10 text-blue-400 border-blue-500/20`,children:[`#`,e]},e))})]})]}),(i.tasks??0)>0&&(0,g.jsx)(`div`,{className:`px-4 pb-4`,children:(0,g.jsxs)(d,{variant:`outline`,size:`sm`,className:`w-full gap-1.5`,onClick:()=>a(i.source||e.name),children:[(0,g.jsx)(o,{className:`w-3.5 h-3.5`}),`Show tasks`]})})]},e.name)})})]})}export{v as IntegrationsView};
2
+ //# sourceMappingURL=integrations-DX55ARy0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"integrations-CUv4i_4i.js","names":[],"sources":["../../dashboard/src/components/views/integrations.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { integrationPresence, toneToColor } from '@/lib/display'\nimport { PlugZap, AlertCircle, Activity, Eye, CircleCheck, ListChecks } from 'lucide-react'\n\nconst PRESENCE_ICONS: Record<string, typeof PlugZap> = {\n PlugZap, AlertCircle, Activity, Eye, CircleCheck,\n}\n\nexport function IntegrationsView() {\n const integrations = useRelayStore((s) => s.integrations)\n const set = useRelayStore((s) => s.set)\n const switchView = useRelayStore((s) => s.switchView)\n\n const waitingCount = integrations.reduce((sum, i) => sum + (i.taskStats?.waitingTasks || 0), 0)\n\n function showTasks(source: string) {\n set({ taskSourceFilter: source })\n switchView('tasks')\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-lg font-semibold\">Integrations</h1>\n <Badge variant=\"outline\" className=\"text-xs\">\n {integrations.length} total\n </Badge>\n {waitingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs\">\n {waitingCount} waiting\n </Badge>\n )}\n </div>\n </div>\n\n {integrations.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <PlugZap className=\"w-10 h-10 text-zinc-600 mb-3\" />\n <p className=\"text-muted-foreground text-sm\">No integrations configured</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {integrations.map((integration) => {\n const presence = integrationPresence(integration)\n const PresenceIcon = PRESENCE_ICONS[integration.icon || presence.icon] || PRESENCE_ICONS[presence.icon] || PlugZap\n const stats = integration.taskStats || {}\n\n return (\n <Card key={integration.name} className=\"flex flex-col border-l-2\" style={{ borderLeftColor: integration.accentColor || undefined }}>\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{integration.displayName || integration.name}</CardTitle>\n {integration.description && <p className=\"mt-1 text-xs text-muted-foreground line-clamp-2\">{integration.description}</p>}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <PresenceIcon className={`w-3.5 h-3.5 ${toneToColor(presence.tone)}`} />\n <span className={`text-xs ${toneToColor(presence.tone)}`}>{presence.label}</span>\n </div>\n </div>\n\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {integration.configured && (\n <Badge variant=\"outline\" className=\"text-xs text-emerald-400 border-emerald-500/30\">\n configured\n </Badge>\n )}\n {integration.observed && (\n <Badge variant=\"outline\" className=\"text-xs text-blue-400 border-blue-500/30\">\n observed\n </Badge>\n )}\n {!integration.enabled && (\n <Badge variant=\"outline\" className=\"text-xs text-red-400 border-red-500/30\">\n disabled\n </Badge>\n )}\n {integration.type && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {integration.type}\n </Badge>\n )}\n {integration.tags?.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs text-zinc-400\">\n #{tag}\n </Badge>\n ))}\n </div>\n </CardHeader>\n\n <CardContent className=\"flex-1 space-y-3\">\n {/* Mini stats */}\n <div className=\"grid grid-cols-4 gap-2 text-center\">\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums\">{stats.tasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">tasks</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums text-blue-400\">{stats.openTasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">open</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.waitingTasks ?? 0) > 0 ? 'text-yellow-400' : ''}`}>\n {stats.waitingTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">waiting</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.failedTasks ?? 0) > 0 ? 'text-red-400' : ''}`}>\n {stats.failedTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">failed</p>\n </div>\n </div>\n\n {/* Scopes / Targets / Channels */}\n {(integration.scopes?.length > 0 || integration.targets?.length > 0 || integration.channels?.length > 0) && (\n <div className=\"space-y-1.5\">\n {integration.scopes?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.scopes.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-xs text-zinc-400\">\n {s}\n </Badge>\n ))}\n </div>\n )}\n {integration.targets?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.targets.map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-xs\">\n {t}\n </Badge>\n ))}\n </div>\n )}\n {integration.channels?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.channels.map((c) => (\n <Badge key={c} className=\"text-xs bg-blue-500/10 text-blue-400 border-blue-500/20\">\n #{c}\n </Badge>\n ))}\n </div>\n )}\n </div>\n )}\n </CardContent>\n\n {(stats.tasks ?? 0) > 0 && (\n <div className=\"px-4 pb-4\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full gap-1.5\"\n onClick={() => showTasks(stats.source || integration.name)}\n >\n <ListChecks className=\"w-3.5 h-3.5\" />\n Show tasks\n </Button>\n </div>\n )}\n </Card>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"integrations-DX55ARy0.js","names":[],"sources":["../../dashboard/src/components/views/integrations.tsx"],"sourcesContent":["import { useRelayStore } from '@/store'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { integrationPresence, toneToColor } from '@/lib/display'\nimport { PlugZap, AlertCircle, Activity, Eye, CircleCheck, ListChecks } from 'lucide-react'\n\nconst PRESENCE_ICONS: Record<string, typeof PlugZap> = {\n PlugZap, AlertCircle, Activity, Eye, CircleCheck,\n}\n\nexport function IntegrationsView() {\n const integrations = useRelayStore((s) => s.integrations)\n const set = useRelayStore((s) => s.set)\n const switchView = useRelayStore((s) => s.switchView)\n\n const waitingCount = integrations.reduce((sum, i) => sum + (i.taskStats?.waitingTasks || 0), 0)\n\n function showTasks(source: string) {\n set({ taskSourceFilter: source })\n switchView('tasks')\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-lg font-semibold\">Integrations</h1>\n <Badge variant=\"outline\" className=\"text-xs\">\n {integrations.length} total\n </Badge>\n {waitingCount > 0 && (\n <Badge className=\"bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs\">\n {waitingCount} waiting\n </Badge>\n )}\n </div>\n </div>\n\n {integrations.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <PlugZap className=\"w-10 h-10 text-zinc-600 mb-3\" />\n <p className=\"text-muted-foreground text-sm\">No integrations configured</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {integrations.map((integration) => {\n const presence = integrationPresence(integration)\n const PresenceIcon = PRESENCE_ICONS[integration.icon || presence.icon] || PRESENCE_ICONS[presence.icon] || PlugZap\n const stats = integration.taskStats || {}\n\n return (\n <Card key={integration.name} className=\"flex flex-col border-l-2\" style={{ borderLeftColor: integration.accentColor || undefined }}>\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"text-sm font-medium truncate\">{integration.displayName || integration.name}</CardTitle>\n {integration.description && <p className=\"mt-1 text-xs text-muted-foreground line-clamp-2\">{integration.description}</p>}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <PresenceIcon className={`w-3.5 h-3.5 ${toneToColor(presence.tone)}`} />\n <span className={`text-xs ${toneToColor(presence.tone)}`}>{presence.label}</span>\n </div>\n </div>\n\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {integration.configured && (\n <Badge variant=\"outline\" className=\"text-xs text-emerald-400 border-emerald-500/30\">\n configured\n </Badge>\n )}\n {integration.observed && (\n <Badge variant=\"outline\" className=\"text-xs text-blue-400 border-blue-500/30\">\n observed\n </Badge>\n )}\n {!integration.enabled && (\n <Badge variant=\"outline\" className=\"text-xs text-red-400 border-red-500/30\">\n disabled\n </Badge>\n )}\n {integration.type && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {integration.type}\n </Badge>\n )}\n {integration.tags?.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs text-zinc-400\">\n #{tag}\n </Badge>\n ))}\n </div>\n </CardHeader>\n\n <CardContent className=\"flex-1 space-y-3\">\n {/* Mini stats */}\n <div className=\"grid grid-cols-4 gap-2 text-center\">\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums\">{stats.tasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">tasks</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className=\"text-base font-semibold tabular-nums text-blue-400\">{stats.openTasks ?? 0}</p>\n <p className=\"text-xs text-muted-foreground\">open</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.waitingTasks ?? 0) > 0 ? 'text-yellow-400' : ''}`}>\n {stats.waitingTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">waiting</p>\n </div>\n <div className=\"space-y-0.5\">\n <p className={`text-base font-semibold tabular-nums ${(stats.failedTasks ?? 0) > 0 ? 'text-red-400' : ''}`}>\n {stats.failedTasks ?? 0}\n </p>\n <p className=\"text-xs text-muted-foreground\">failed</p>\n </div>\n </div>\n\n {/* Scopes / Targets / Channels */}\n {(integration.scopes?.length > 0 || integration.targets?.length > 0 || integration.channels?.length > 0) && (\n <div className=\"space-y-1.5\">\n {integration.scopes?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.scopes.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-xs text-zinc-400\">\n {s}\n </Badge>\n ))}\n </div>\n )}\n {integration.targets?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.targets.map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-xs\">\n {t}\n </Badge>\n ))}\n </div>\n )}\n {integration.channels?.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {integration.channels.map((c) => (\n <Badge key={c} className=\"text-xs bg-blue-500/10 text-blue-400 border-blue-500/20\">\n #{c}\n </Badge>\n ))}\n </div>\n )}\n </div>\n )}\n </CardContent>\n\n {(stats.tasks ?? 0) > 0 && (\n <div className=\"px-4 pb-4\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"w-full gap-1.5\"\n onClick={() => showTasks(stats.source || integration.name)}\n >\n <ListChecks className=\"w-3.5 h-3.5\" />\n Show tasks\n </Button>\n </div>\n )}\n </Card>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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"}