agent-lookout 0.2.3 → 0.2.5

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 (38) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/PRIVACY.md +139 -19
  3. package/README.md +18 -8
  4. package/SECURITY.md +36 -8
  5. package/dist/THIRD-PARTY-LICENSES.md +195 -0
  6. package/dist/assets/HistoryPanel-TXa0oPH4.js +1 -0
  7. package/dist/assets/SessionPanel-BStoG7uq.js +1 -0
  8. package/dist/assets/index-BsTJp5-3.css +1 -0
  9. package/dist/assets/index-a7ubgAmE.js +3 -0
  10. package/dist/assets/radix-BH0JH8UU.js +41 -0
  11. package/dist/cli/agent-lookout.js +4 -4
  12. package/dist/cli/{chunk-4C34YX6S.js → chunk-NWVEVCRT.js} +14 -3
  13. package/dist/cli/{chunk-GOX5UB5L.js → chunk-OT3EGOTY.js} +120 -7
  14. package/dist/cli/{chunk-54ODUY75.js → chunk-Q73JDXXW.js} +1 -1
  15. package/dist/cli/mcpServer-IFB2FEOZ.js +23667 -0
  16. package/dist/cli/{startCommand-H6O35VYR.js → startCommand-J3QS26SZ.js} +4887 -1216
  17. package/dist/index.html +3 -3
  18. package/docs/API.md +266 -55
  19. package/docs/GUIDE.md +396 -61
  20. package/package.json +5 -5
  21. package/dist/assets/HistoryPanel-DMnhIoFB.js +0 -1
  22. package/dist/assets/SessionPanel-BNm9wCzf.js +0 -1
  23. package/dist/assets/atkinson-hyperlegible-mono-latin-400-normal-Cmjm2dBj.woff +0 -0
  24. package/dist/assets/atkinson-hyperlegible-mono-latin-500-normal-BV5ipwqM.woff +0 -0
  25. package/dist/assets/atkinson-hyperlegible-mono-latin-600-normal-CuPF9o0F.woff +0 -0
  26. package/dist/assets/atkinson-hyperlegible-mono-latin-ext-400-normal-ITMuFrSK.woff +0 -0
  27. package/dist/assets/atkinson-hyperlegible-mono-latin-ext-500-normal-BiHEOgiK.woff +0 -0
  28. package/dist/assets/atkinson-hyperlegible-mono-latin-ext-600-normal-ZiH-ObRk.woff +0 -0
  29. package/dist/assets/atkinson-hyperlegible-next-latin-400-normal-DPp7N0cD.woff +0 -0
  30. package/dist/assets/atkinson-hyperlegible-next-latin-500-normal-B0CYqHl3.woff +0 -0
  31. package/dist/assets/atkinson-hyperlegible-next-latin-600-normal-BhgCag5w.woff +0 -0
  32. package/dist/assets/atkinson-hyperlegible-next-latin-ext-400-normal-qxMiU51n.woff +0 -0
  33. package/dist/assets/atkinson-hyperlegible-next-latin-ext-500-normal-oZS3KxrF.woff +0 -0
  34. package/dist/assets/atkinson-hyperlegible-next-latin-ext-600-normal-BBAQIogt.woff +0 -0
  35. package/dist/assets/index-Ckda8OV4.js +0 -2
  36. package/dist/assets/index-DFR77qn5.css +0 -1
  37. package/dist/assets/radix-27o0jeIu.js +0 -41
  38. package/dist/cli/mcpServer-QQFQR6DC.js +0 -246
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-lookout",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Shows the AI agent sessions on your computer in one browser page, and which need you.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -71,14 +71,13 @@
71
71
  "check": "npm run check:layout && npm run typecheck && npm run lint && npm run format:check && npm run test"
72
72
  },
73
73
  "dependencies": {
74
- "@modelcontextprotocol/sdk": "^1.32.1",
75
- "nodemailer": "^10.0.15",
76
- "zod": "^4.6.5"
74
+ "nodemailer": "^10.0.15"
77
75
  },
78
76
  "devDependencies": {
79
77
  "@eslint/js": "^10.0.1",
80
78
  "@fontsource/atkinson-hyperlegible-mono": "^5.3.0",
81
79
  "@fontsource/atkinson-hyperlegible-next": "^5.3.0",
80
+ "@modelcontextprotocol/sdk": "^1.32.1",
82
81
  "@tailwindcss/vite": "^4.3.3",
83
82
  "@types/node": "^20.19.43",
84
83
  "@types/react": "^19.3.0",
@@ -110,6 +109,7 @@
110
109
  "typescript-eslint": "^8.71.0",
111
110
  "vite": "^7.3.6",
112
111
  "vitest": "^4.1.11",
113
- "vitest-browser-react": "^2.3.0"
112
+ "vitest-browser-react": "^2.3.0",
113
+ "zod": "^4.6.5"
114
114
  }
115
115
  }
@@ -1 +0,0 @@
1
- import{r as y,j as t}from"./react-C2DiJaR6.js";import{b as G,t as K,r as q,f as U,a as _,c as X,d as V,h as $,m as J,H as Q,e as Z,D as ee,g as M,s as te,i as se,j as ne,S as oe,L as ae,C as re,k as ie}from"./index-Ckda8OV4.js";import"./motion-BAhdRuCw.js";import"./radix-27o0jeIu.js";const le={"needs-you":"text-status-needs-you-edge",working:"text-status-working",idle:"text-status-idle"},L={top:12,right:12,bottom:24,left:30},T=220,de=76,ce=104,I=1/60;function ue({samples:s,start:n,end:a,tone:g,label:w,describe:l,className:m}){const p=y.useRef(null),[c,k]=y.useState(0),[u,i]=y.useState(null);y.useEffect(()=>{const e=p.current;if(!e)return;const o=new ResizeObserver(([j])=>{j&&k(Math.floor(j.contentRect.width))});return o.observe(e),()=>o.disconnect()},[]);const r=L.left,h=Math.max(r+1,c-L.right),x=L.top,d=T-L.bottom,N=a-n;let O=0;for(const e of s)e.at>=n&&e.at<=a&&e.value>O&&(O=e.value);const A=V(O),b=G(s,{start:n,end:a},{left:r,right:h,top:x,bottom:d,ceiling:A.ceiling}),W=e=>r+(e-n)/N*(h-r),S=e=>d-e/A.ceiling*(d-x),B=K(n,a,Math.max(1,Math.floor((h-r)/de))),R=u??1,H=n+R*N,E=q(b.runs,H),C=E?l(E.value):"Not measured",v=W(H),z=(e,o)=>{const j=o.left+r,f=h-r;i(Math.min(1,Math.max(0,(e-j)/f)))},Y=e=>{const j={ArrowLeft:f=>f-I,ArrowRight:f=>f+I,PageDown:f=>f-I*10,PageUp:f=>f+I*10,Home:()=>0,End:()=>1}[e.key];j&&(e.preventDefault(),i(Math.min(1,Math.max(0,j(u??1)))))};return t.jsxs("div",{ref:p,"data-slot":"history-chart",role:"slider",tabIndex:0,"aria-label":`${w}. Arrow keys read the count at each moment.`,"aria-orientation":"horizontal","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":Math.round(R*100),"aria-valuetext":`${_(H)}: ${C}`,onPointerMove:e=>z(e.clientX,e.currentTarget.getBoundingClientRect()),onPointerLeave:()=>i(null),onFocus:e=>{e.currentTarget.matches(":focus-visible")&&i(o=>o??1)},onBlur:()=>i(null),onKeyDown:Y,className:X("relative w-full cursor-crosshair rounded-row",le[g],m),style:{height:T},children:[c>0&&b.unmeasured.map((e,o)=>t.jsx("div",{"aria-hidden":!0,"data-part":"unmeasured",className:"unmeasured-hatch absolute",style:{left:e.x,top:x,width:e.width,height:d-x}},o)),c>0&&t.jsxs("svg",{"aria-hidden":!0,width:c,height:T,className:"relative block",children:[A.ticks.map(e=>t.jsxs("g",{children:[t.jsx("line",{"data-part":"grid",x1:r,x2:h,y1:S(e),y2:S(e),stroke:e===0?"var(--rule-strong)":"var(--hairline)",strokeWidth:1,shapeRendering:"crispEdges"}),t.jsx("text",{x:r-8,y:S(e),dy:"0.32em",textAnchor:"end",className:"fill-ink-muted font-mono text-micro",children:e})]},e)),b.unmeasured.map((e,o)=>e.width>=ce&&t.jsx("text",{"data-part":"unmeasured-label",x:e.x+8,y:x+14,className:"fill-ink-muted font-mono text-micro",stroke:"var(--glass-float)",strokeWidth:4,strokeLinejoin:"round",paintOrder:"stroke",children:"Not measured"},o)),b.areas.map((e,o)=>t.jsx("path",{d:e,fill:"currentColor",stroke:"none",opacity:.1},o)),b.lines.map((e,o)=>t.jsx("path",{"data-part":"line",d:e,fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"},o)),B.map(e=>{const o=W(e);return o<r+16||o>h-16?null:t.jsx("text",{"data-part":"time-tick",x:o,y:T-6,textAnchor:"middle",className:"fill-ink-muted font-mono text-micro",children:U(e)},e)}),u!==null&&t.jsxs("g",{"data-part":"crosshair",children:[t.jsx("line",{x1:v,x2:v,y1:x,y2:d,stroke:"var(--ink-muted)",strokeWidth:1,shapeRendering:"crispEdges"}),E&&t.jsx("circle",{cx:v,cy:S(Math.min(E.value,A.ceiling)),r:4.5,fill:"currentColor",stroke:"var(--glass-float)",strokeWidth:2})]})]}),u!==null&&c>0&&t.jsxs("div",{"aria-hidden":!0,"data-part":"reading",className:"pointer-events-none absolute z-10 rounded-row bg-glass-float px-2.5 py-1.5 font-mono text-fact whitespace-nowrap inset-ring inset-ring-rule",style:R>.62?{top:x,right:c-v+10}:{top:x,left:v+10},children:[t.jsx("span",{className:"block text-ink-muted",children:_(H)}),t.jsx("span",{className:"block text-ink",children:C})]})]})}const he=6e4;function me(s,n){const[a,g]=y.useState(null),[w,l]=y.useState(null),m=s>Q,p=n?.startedAt??null,c=n?$(n).at:null;if(y.useEffect(()=>{if(!m)return;let u=!0;const i=()=>{Z(s).then(h=>{u&&(g({windowMs:s,history:h}),l(null))},()=>{u&&l(s)})};i();const r=setInterval(i,he);return()=>{u=!1,clearInterval(r)}},[m,s,p,c]),!m)return{history:n,status:n?"ready":"loading"};const k=a?.windowMs===s&&(p===null||a.history.startedAt===p)&&(c===null||$(a.history).at===c)?a.history:null;return k?{history:J(k,n),status:"ready"}:{history:null,status:w===s?"failed":"loading"}}const P={needsYou:{title:"Needs you",about:"How many sessions were waiting on you, over time.",tone:"needs-you",chart:"Sessions that need you",describe:s=>`${s} ${s===1?"needs":"need"} you`,explainer:"A session needs you when it has stopped and cannot go on without an answer: a permission to grant, a question, or a plan to approve. The line is how many were waiting at each moment."},working:{title:"Working",about:"How many sessions were in the middle of a task, over time.",tone:"working",chart:"Sessions working",describe:s=>`${s} working`,explainer:"A session is working while it is in the middle of a task. The line is how many were busy at each moment."},idle:{title:"Idle",about:"How many sessions were ready for a new prompt, over time.",tone:"idle",chart:"Idle sessions",describe:s=>`${s} idle`,explainer:"A session is idle when it has finished what it was asked and is ready for a new prompt. One left idle a day or more is stale, and is counted under Stale instead. The line is how many were idle at each moment."}},D="–";function F({label:s,value:n,caption:a}){return t.jsxs("div",{"data-slot":"figure",className:"min-w-0",children:[t.jsx("p",{className:"text-body font-medium text-ink-secondary",children:s}),t.jsx("p",{className:"mt-2 text-stat font-medium tabular-nums",children:n}),t.jsx("p",{className:"mt-2 text-caption text-ink-muted",children:a})]})}function xe({metric:s,state:n,now:a}){const[g,w]=y.useState("15m"),l=M.find(d=>d.id===g)??M[0],m=P[s],{history:p,status:c}=me(l.ms,n.history),k=a-l.ms,u=p?te(p.points,s):[];let i=null;for(const d of u)d.at<k||d.at>a||(i===null||d.value>i)&&(i=d.value);const r=u[u.length-1],h=r&&a-r.at<=se?r.value:null,x=m.tone==="needs-you"&&ne(n.snapshot?.sessions)===0?"idle":m.tone;return t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"mt-5 flex flex-wrap items-end justify-between gap-x-6 gap-y-4",children:[t.jsxs("div",{className:"flex gap-6",children:[t.jsx(F,{label:"Now",value:h===null?D:String(h),caption:h===null?"Not being measured":"At the last check"}),t.jsx("div",{className:"border-l border-rule pl-6",children:t.jsx(F,{label:"Highest",value:i===null?D:String(i),caption:i===null?"Nothing measured":`In ${l.words}`})})]}),t.jsx(oe,{label:"Time window",value:g,onValueChange:w,options:M.map(({id:d,label:N})=>({value:d,label:N}))})]}),t.jsx("div",{className:"mt-5 h-55",children:c==="ready"?t.jsx(ue,{samples:u,start:k,end:a,tone:x,label:`${m.chart} over ${l.words}`,describe:m.describe}):c==="loading"?t.jsx(ae,{label:`Reading ${l.words}`,className:"h-full"}):t.jsx(re,{tone:"error",title:`${ie(l.words)} could not be read`,children:t.jsx("p",{children:"Agent Lookout did not answer when asked for it. The page asks again every minute. The 15 minute window is still there."})})}),t.jsxs("div",{"data-slot":"explainer",className:"mt-5 rounded-inner bg-fill-quiet px-4 py-3 inset-ring inset-ring-hairline",children:[t.jsx("p",{className:"text-row font-semibold text-ink",children:"What this counts"}),t.jsx("p",{className:"mt-0.5 text-body text-ink-secondary",children:m.explainer}),t.jsxs("p",{className:"mt-1.5 text-body text-ink-secondary",children:["Hatched time was not measured: Agent Lookout was not running, or could not read its source, or the history was cleared then. It is never drawn as zero."," ",n.history?.kept?.where==="memory"?"History covers the last six hours and starts again when Agent Lookout restarts.":"History covers the last six hours, and is kept when Agent Lookout restarts."]})]})]})}function we({metric:s,open:n,onOpenChange:a,state:g,now:w}){const l=P[s];return t.jsx(ee,{open:n,onOpenChange:a,title:l.title,description:l.about,size:"wide",children:t.jsx(xe,{metric:s,state:g,now:w})})}export{we as HistoryPanel};
@@ -1 +0,0 @@
1
- import{r as y,j as e}from"./react-C2DiJaR6.js";import{w as F,u as A,J as $,c as E,D as L,l as M,n as O,M as v,o as q,p as D,q as C,F as I,v as h,x as P,y as k,O as R,f as g,T as W,z as B,A as J,B as K,E as _,G as z,I as G,K as U,N as w,P as S,Q as H,R as Q,L as V,U as X}from"./index-Ckda8OV4.js";import"./motion-BAhdRuCw.js";import"./radix-27o0jeIu.js";const T=[];function Y(s,n){const t=CSS.escape(s),a=[...document.querySelectorAll(`:is([data-slot="session-row"], [data-slot="board-card"], [data-slot="hero-session"])[data-session="${t}"] a[data-part="name"]`)];return n!==null&&a.includes(n)?n:a.find(l=>!l.closest('[data-slot="hero-session"]'))??a[0]??null}function Z({session:s,gone:n,asOf:t,now:a}){const l=s.status==="finished"||s.status==="failed",r=B(s),o=r?"stale":n&&s.status==="needs-you"?"answered":s.status,c=s.statusSince,i=c!==null?Math.max(0,t-c):null,m=J(s,t),d=s.status==="needs-you",p=d?K(s):null,j=d&&!n&&s.waitingText?.trim()||null,u=c!==null?`${l?"at":r?"idle since":"since"} ${k(c,a)}`:"time not reported",x=[d?_(s):null,u,m&&z(m)].filter(f=>typeof f=="string");return e.jsxs(h,{label:"Status",note:j?e.jsxs(e.Fragment,{children:[e.jsx(H,{"data-part":"asking",lines:2,className:"wrap-anywhere",children:j}),p&&e.jsx("span",{className:"block",children:p})]}):p??void 0,children:[e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx(G,{kind:o}),e.jsx("span",{"data-part":"status",children:r?"Stale":U[s.status]}),i!==null&&e.jsxs("span",{"data-part":"duration",className:"tabular-nums",children:[e.jsx("span",{className:"sr-only",children:l?` ${w(i)} ago`:` for ${w(i)}`}),e.jsxs("span",{"aria-hidden":!0,children:[S(i),l&&" ago"]})]})]}),e.jsx("span",{"data-part":"since",className:"block text-caption font-normal text-ink-secondary tabular-nums",children:x.join(", ")})]})}function ee({session:s,state:n,now:t,asOf:a}){const l=y.useMemo(()=>Q({sessions:n.snapshot?.sessions??T,events:n.events,history:n.history,now:t,asOf:a,eventsFull:n.events.length>=v}),[n.snapshot,n.events,n.history,t,a]);if(!l)return e.jsxs(h,{label:"Waits",children:["Not known",e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:"The history could not be read"})]});const r=l.sessions.find(i=>i.id===s.id),o=l.period.today?"today":`since ${g(l.period.from)}`;let c="None";if(r){const i=`${r.startKnown?"":"at least "}${S(r.ms)}`;c=r.times===1?`Once, ${i}`:`${r.times} times, ${i} in all`}return e.jsxs(h,{label:"Waits",children:[e.jsx("span",{"data-part":"waits",className:"tabular-nums",children:c}),e.jsx("span",{className:"block text-caption font-normal text-ink-secondary",children:o})]})}function N({title:s,aside:n,children:t,...a}){return e.jsxs("section",{...a,"aria-label":s,className:"mt-6",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-4 border-b border-hairline pb-2",children:[e.jsx("h3",{className:"text-body font-semibold text-ink",children:s}),n&&e.jsx("p",{className:"text-caption text-ink-muted",children:n})]}),t]})}function se({session:s,gone:n,state:t,now:a,asOf:l}){const r=t.snapshot?.sources??[],o=t.snapshot?.sessions??T,c=O(s.surface),i=t.events.length>=v,m=y.useMemo(()=>q(t.events.filter(u=>u.sessionId===s.id),o),[t.events,o,s.id]),d=D(t.events,t.history,i),p=y.useMemo(()=>t.history?C({sessions:o,events:t.events,history:t.history,now:a,asOf:l,eventsFull:i}):null,[o,t.events,t.history,a,l,i]),j=p?.rows.find(u=>u.id===s.id);return e.jsxs(e.Fragment,{children:[n&&e.jsx("p",{"data-part":"gone",className:"mt-4 text-body text-ink-secondary",children:"This session has left the list. Here is what was last known of it."}),e.jsxs(I,{className:"mt-3",children:[e.jsx(Z,{session:s,gone:n,asOf:l,now:a}),e.jsx(h,{label:"Agent",children:P(s,r)}),c!==null&&e.jsx(h,{label:"App",children:c}),e.jsx(h,{label:"Folder",mono:s.cwd!==null,children:s.cwd!==null?e.jsx("span",{"data-part":"folder",className:"wrap-anywhere select-text",children:s.cwd.split("/").map((u,x,f)=>e.jsxs(y.Fragment,{children:[u,x<f.length-1&&e.jsxs(e.Fragment,{children:["/",e.jsx("wbr",{})]})]},x))}):"Not known"}),s.git?.repository!==void 0&&e.jsx(h,{label:"Repository",children:e.jsx("span",{"data-part":"repository",className:"wrap-anywhere",children:s.git.repository.name})}),s.git?.branch!==void 0?e.jsx(h,{label:"Branch",children:e.jsx("span",{"data-part":"branch",className:"wrap-anywhere",children:s.git.branch})}):s.git?.commit!==void 0&&e.jsx(h,{label:"Commit",mono:!0,children:s.git.commit}),e.jsx(h,{label:"Started",children:e.jsx("span",{className:"tabular-nums",children:s.startedAt!==null?k(s.startedAt,a):"Not reported"})}),s.pid!==void 0&&e.jsx(h,{label:"Process",mono:!0,note:s.alive===!1?"The process has ended.":void 0,children:s.pid}),e.jsx(ee,{session:s,state:t,now:a,asOf:l})]}),e.jsx(N,{"data-part":"events",title:"Events",aside:d?`since ${g(d.at)}`:void 0,children:m.length>0?e.jsx(R,{entries:m,now:a,className:"pt-0.5"}):e.jsxs("p",{className:"py-2.5 text-body text-ink-secondary",children:["Nothing has happened to this session"," ",d?`since ${g(d.at)}`:"yet","."]})}),e.jsx(N,{"data-part":"timeline",title:"Timeline",aside:"last hour",children:p&&j?e.jsx(W,{timeline:p,rows:[j],named:!1,label:"Its last hour",className:"pt-3"}):e.jsx("p",{className:"py-2.5 text-body text-ink-secondary",children:p?"It did not run in the last hour.":"The last hour could not be read. The page asks again every two seconds."})})]})}function te({sessionId:s,open:n,onClose:t,state:a,now:l}){const r=a.snapshot?.sessions.find(b=>b.id===s)??null,[o,c]=y.useState(null);r!==null&&r!==o?.session?c({session:r,at:a.lastOkAt??l}):r===null&&o?.session.waitingText!==void 0&&c({...o,session:F(o.session)});const i=r??o?.session??null,m=r===null&&o!==null,d=A(i??{id:s,source:"status-files",surface:"unknown",links:{}}),p=m&&o?o.at:a.phase==="stalled"&&a.lastOkAt!==null?a.lastOkAt:l,j=d.outcome!==null||d.asking!==null;let u,x,f="wide";return i?(u=i.name,x=e.jsxs(e.Fragment,{children:[!m&&e.jsx("div",{className:E("flex flex-wrap items-center gap-x-2 gap-y-1",j&&"mt-3"),children:e.jsx($,{session:i,jump:d})}),e.jsx(se,{session:i,gone:m,state:a,now:l,asOf:p})]})):a.snapshot===null?(u="Session",x=e.jsx(V,{label:"Reading sessions",className:"justify-start px-0 pt-5 pb-1"})):(u="No such session",f="sm",x=e.jsxs("div",{"data-part":"missing",children:[e.jsx("p",{className:"mt-2 text-body text-ink-secondary",children:"Agent Lookout is not watching a session at this address. It may have ended before this page was opened."}),e.jsx(X,{className:"mt-4",onClick:t,children:"Go to the Overview"})]})),e.jsx(L,{open:n,onOpenChange:b=>{b||t()},title:u,size:f,focusTitle:!0,returnFocus:b=>Y(s,b)??document.querySelector("main"),actions:i&&!m&&e.jsx(M,{session:i,jump:d,variant:i.status==="needs-you"?"needs-you":"quiet"}),children:x})}function re({sessionId:s,onClose:n,state:t,now:a}){const[l,r]=y.useState(s);return s!==null&&s!==l&&r(s),l===null?null:e.jsx(te,{sessionId:l,open:s!==null,onClose:n,state:t,now:a},l)}export{re as SessionPanel};