@lensmcp/core 1.22.3 → 1.22.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.
package/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from './lib/graph-store.js';
7
7
  export * from './lib/fingerprint.js';
8
8
  export * from './lib/reducer-registry.js';
9
9
  export * from './lib/story.js';
10
+ export * from './lib/flow-shape.js';
10
11
  export * from './lib/patterns.js';
11
12
  export * from './lib/thresholds.js';
12
13
  export * from './lib/graph-from-events.js';
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";export*from"./lib/common.js";export*from"./lib/ulid.js";export*from"./lib/event-bus.js";export*from"./lib/event-redactor.js";export*from"./lib/resource-store.js";export*from"./lib/graph-store.js";export*from"./lib/fingerprint.js";export*from"./lib/reducer-registry.js";export*from"./lib/story.js";export*from"./lib/patterns.js";export*from"./lib/thresholds.js";export*from"./lib/graph-from-events.js";
1
+ "use strict";export*from"./lib/common.js";export*from"./lib/ulid.js";export*from"./lib/event-bus.js";export*from"./lib/event-redactor.js";export*from"./lib/resource-store.js";export*from"./lib/graph-store.js";export*from"./lib/fingerprint.js";export*from"./lib/reducer-registry.js";export*from"./lib/story.js";export*from"./lib/flow-shape.js";export*from"./lib/patterns.js";export*from"./lib/thresholds.js";export*from"./lib/graph-from-events.js";
@@ -0,0 +1,100 @@
1
+ import { type BaseEvent } from '@lensmcp/protocol-types';
2
+ /**
3
+ * Architectural area of one flow event — the swimlane it renders in, and a
4
+ * classification agents can reuse. Order mirrors the request's journey:
5
+ * browser → state → network → gateway → services → data.
6
+ */
7
+ export type FlowArea = 'browser' | 'state' | 'network' | 'gateway' | 'services' | 'data' | 'ai';
8
+ export declare function areaOf(event: {
9
+ source: string;
10
+ category: string;
11
+ title: string;
12
+ kind?: string | undefined;
13
+ }): FlowArea;
14
+ /** One chart-ready node per flow event: area-typed, titled, with start/duration/payload. */
15
+ export interface FlowShapeOptions {
16
+ /**
17
+ * Inline an AI turn's full `raw` payload — prompt messages, completion text, tool-call inputs and
18
+ * outputs. Off by default; `/api/flow` requires `?raw=1` AND a loopback-bound dashboard.
19
+ */
20
+ includeRaw?: boolean;
21
+ }
22
+ export declare function trimFlowEvent(event: BaseEvent, opts?: FlowShapeOptions): {
23
+ steps?: string[] | undefined;
24
+ detail?: string | undefined;
25
+ ai?: Record<string, unknown> | undefined;
26
+ fetchStartedAt?: number | undefined;
27
+ durationMs?: number | undefined;
28
+ project?: string | undefined;
29
+ why?: string[] | undefined;
30
+ phase?: string | undefined;
31
+ component?: string | undefined;
32
+ commitId?: string | undefined;
33
+ parentRequestId?: string | undefined;
34
+ requestId?: string | undefined;
35
+ role?: string | undefined;
36
+ source: "nx" | "vite" | "typescript" | "eslint" | "rollup" | "client-runtime" | "chrome" | "react" | "valtio" | "nestjs" | "nextjs" | "db" | "redis" | "queue" | "memory" | "visual" | "perf" | "security" | "gateway" | "external" | "ai";
37
+ category: "db" | "memory" | "visual" | "security" | "ai" | "build" | "lint" | "typecheck" | "test" | "runtime" | "render" | "trace" | "state" | "network" | "backend" | "performance" | "deps" | "cluster";
38
+ severity: "error" | "debug" | "info" | "warning" | "fatal";
39
+ title: string;
40
+ kind: string | undefined;
41
+ area: FlowArea;
42
+ jobId?: string | undefined;
43
+ queue?: string | undefined;
44
+ urlKey?: string | undefined;
45
+ sig?: string | undefined;
46
+ id: string;
47
+ t: number;
48
+ start: number;
49
+ };
50
+ /**
51
+ * The pure flow transform: raw correlated events → ordered, parented,
52
+ * aggregated display nodes. No I/O, no server — see module header.
53
+ */
54
+ export declare function buildFlowDetail(rawEvents: BaseEvent[], opts?: FlowShapeOptions): {
55
+ events: ({
56
+ steps?: string[] | undefined;
57
+ detail?: string | undefined;
58
+ ai?: Record<string, unknown> | undefined;
59
+ fetchStartedAt?: number | undefined;
60
+ durationMs?: number | undefined;
61
+ project?: string | undefined;
62
+ why?: string[] | undefined;
63
+ phase?: string | undefined;
64
+ component?: string | undefined;
65
+ commitId?: string | undefined;
66
+ parentRequestId?: string | undefined;
67
+ requestId?: string | undefined;
68
+ role?: string | undefined;
69
+ source: "nx" | "vite" | "typescript" | "eslint" | "rollup" | "client-runtime" | "chrome" | "react" | "valtio" | "nestjs" | "nextjs" | "db" | "redis" | "queue" | "memory" | "visual" | "perf" | "security" | "gateway" | "external" | "ai";
70
+ category: "db" | "memory" | "visual" | "security" | "ai" | "build" | "lint" | "typecheck" | "test" | "runtime" | "render" | "trace" | "state" | "network" | "backend" | "performance" | "deps" | "cluster";
71
+ severity: "error" | "debug" | "info" | "warning" | "fatal";
72
+ title: string;
73
+ kind: string | undefined;
74
+ area: FlowArea;
75
+ jobId?: string | undefined;
76
+ queue?: string | undefined;
77
+ urlKey?: string | undefined;
78
+ sig?: string | undefined;
79
+ id: string;
80
+ t: number;
81
+ start: number;
82
+ } & {
83
+ parent?: string;
84
+ group?: string;
85
+ } & {
86
+ sig?: string;
87
+ count?: number;
88
+ parallel?: boolean;
89
+ avgMs?: number;
90
+ wallMs?: number;
91
+ items?: Array<{
92
+ start: number;
93
+ durationMs?: number;
94
+ }>;
95
+ selfMs?: number;
96
+ detail?: string;
97
+ /** Every event id this node stands for, so a collapsed node can be opened again. */
98
+ memberIds?: string[];
99
+ })[];
100
+ };
@@ -0,0 +1 @@
1
+ "use strict";var V=Object.defineProperty;var S=(i,y)=>V(i,"name",{value:y,configurable:!0});var X=Object.defineProperty,M=S((i,y)=>X(i,"name",{value:y,configurable:!0}),"I");import{redactDeep as Y,redactText as G}from"./redact.js";import{boundedClone as Z}from"@lensmcp/protocol-types";export function areaOf(i){const{source:y,category:e,title:$,kind:c}=i;return y==="ai"?"ai":c?.startsWith("memory")||c==="db-query"?"data":y==="gateway"||c==="gateway-request"?"gateway":c==="queue-process"||c==="queue-active"||c==="queue-completed"||c==="queue-failed"?"services":y==="db"||y==="redis"||y==="queue"||c==="redis-op"||c?.startsWith("queue-")?"data":y==="external"||c==="egress"?"network":y==="nestjs"||y==="nest"?/(?:Repository|Repo|Dao|Store)\./.test($)?"data":"services":y==="valtio"?"state":e==="network"?"network":"browser"}S(areaOf,"areaOf"),M(areaOf,"areaOf");const J=240,tt=new Set(["systemPrompt","prompt","prompts","messages","completion","completions","input","output","draft","text","content","result","arguments","params"]),et=new Set(["tenantId","caller","userId","accountId","email","subject"]),rt=8;function U(i){const y=W(i,0);return Z(Y({redacted:!0,...y}),{rawByteLimit:16*1024}).value}S(U,"X"),M(U,"aiProjection");function W(i,y){if(typeof i=="string")return _(i);if(i===null||typeof i!="object")return i;if(y>=rt)return;if(Array.isArray(i))return i.slice(0,32).map($=>W($,y+1));const e={};for(const[$,c]of Object.entries(i))if(!et.has($)){if(tt.has($)){typeof c=="string"?e[`${$}Chars`]=c.length:Array.isArray(c)?e[`${$}Count`]=c.length:c!=null&&(e[`${$}Present`]=!0);continue}e[$]=W(c,y+1)}return e}S(W,"G"),M(W,"projectAi");function _(i){return i.length<=J?G(i):`${G(i.slice(0,J))}\u2026`}S(_,"Z"),M(_,"clipText");export function trimFlowEvent(i,y={}){const e=i.raw??{},$=e.render??{},c=e.span??{},N=e.request??{},l=M(a=>typeof a=="number"?a:void 0,"num"),I=e.loop??{},B=l(e.durationMs)??l(c.durationMs)??l(N.durationMs)??l(I.durationMs)??l($.actualDurationMs),p=typeof e.kind=="string"?e.kind:void 0,E=p==="fetch-done"||p==="fetch-error",A=E?i.timestamp:l(e.startedAt)??l(c.startTime)??l(N.startedAt)??l(I.startedAt)??(B!==void 0?i.timestamp-B:i.timestamp);let k;if(typeof e.query=="string"){const a=Array.isArray(e.params)?` [${e.params.join(", ")}]`:"",g=typeof e.result=="string"?` \u2192 ${e.result}`:"";k=e.query+a+g}else if(typeof e.command=="string"){const a=typeof e.value=="string"?` \u2192 ${e.value}`:e.hit===!1?" \u2192 (miss)":"";k=e.command+a}else if(p==="state-update"){const a=e.update??{};let g="";try{g=JSON.stringify(a.preview)}catch{}k=`${a.storeId??""}.${a.path??""} = ${g}`}else p==="queue-completed"&&typeof e.returned=="string"?k=`returned ${e.returned}`:p==="queue-enqueued"&&(k=`${e.job??"job"}#${e.jobId??"?"} \u2192 ${e.queue??""}${typeof e.data=="string"?" "+e.data:""}`);let D;if(p==="gateway-request")D=`${e.host??""}${String(e.url??"").split("?")[0]}`;else if(p==="fetch-start"||p==="fetch-done"||p==="fetch-error")try{const a=new URL(String(e.href??e.url??""));D=`${a.hostname}${a.pathname}`}catch{}let R;if(p==="gateway-request"&&Array.isArray(e.steps))R=e.steps.map(a=>{const g=[String(a.step)];return a.project&&g.push(String(a.project)),a.prefix&&g.push(String(a.prefix)),a.mode&&g.push(String(a.mode)+(a.ok===!1?" \u2717":a.ok===!0?" \u2713":"")),a.caller&&g.push("by "+String(a.caller)),a.pod&&g.push(String(a.pod)),typeof a.atMs=="number"&&g.push(`@${a.atMs}ms`),g.join(" ")}),k=R.map(a=>a.replace(/ @\d+ms$/,"")).join(" \u2192 ");else if(p==="egress")k=`${e.method??"GET"} ${e.host??""} \u2192 ${e.status??"?"}`;else if(i.source==="ai"){if(p==="ai-round"){const a=e.model??{},g=e.usage??{},v=Array.isArray(e.toolCalls)?e.toolCalls:[],P=`${l(g.promptTokens)??"?"}\u2192${l(g.completionTokens)??"?"} tok`,t=v.length?` \xB7 ${v.length} tool call${v.length===1?"":"s"}`:"",s=l(e.durationMs)!==void 0?` \xB7 ${(l(e.durationMs)/1e3).toFixed(1)}s`:"";k=`${a.provider??""}/${a.model??""} \xB7 ${P}${t}${s}`}else if(p==="ai-turn-start"){const a=Array.isArray(e.tools)?e.tools:[];k=`skill ${e.skill??""} \xB7 ${e.output??""}${a.length?" \xB7 tools: "+a.join(", "):""}`}else if(p==="ai-tool-call"){const a=e.call??{},g=e.result??{},v=l(e.durationMs)!==void 0?` \xB7 ${(l(e.durationMs)/1e3).toFixed(1)}s`:"";k=`${a.name??"tool"} ${g.error!=null?"\u2717 "+String(g.error):"\u2713"}${v}`}else if(p==="ai-turn-end"){const a=e.usage??{},g=l(e.rounds)!==void 0?` \xB7 ${l(e.rounds)} round${l(e.rounds)===1?"":"s"}`:"",v=l(e.durationMs)!==void 0?` \xB7 ${(l(e.durationMs)/1e3).toFixed(1)}s`:"";k=`${e.ok===!1?"FAILED":"ok"} \xB7 ${l(a.promptTokens)??"?"}+${l(a.completionTokens)??"?"} tok${g}${v}`}}let b;p==="db-query"&&typeof e.query=="string"?b=e.query:p==="redis-op"?b=`${e.op??""} ${String(e.key??"").replace(/\d+/g,"#")}`:p==="egress"?b=`${e.method??"GET"} ${e.host??""}`:p==="queue-enqueued"?b=`enqueue ${e.queue??""}`:p==="span"&&typeof c.name=="string"&&(b=c.name);const x=i.context??{},O=e.effect??{},C=$.commitId??O.commitId??e.commitId,m=Array.isArray($.why)?$.why.map(a=>typeof a?.type=="string"?a.type:void 0).filter(a=>!!a):[];return{id:i.id,t:i.timestamp,start:A,...b?{sig:b}:{},...D?{urlKey:D}:{},...typeof e.queue=="string"?{queue:e.queue}:{},...e.jobId!=null?{jobId:String(e.jobId)}:{},source:i.source,category:i.category,severity:i.severity,title:i.title,kind:p,area:areaOf({source:i.source,category:i.category,title:i.title,kind:p}),...typeof c.role=="string"?{role:c.role}:{},...typeof x.requestId=="string"?{requestId:x.requestId}:{},...typeof x.parentRequestId=="string"?{parentRequestId:x.parentRequestId}:{},...typeof C=="string"?{commitId:C}:{},...typeof $.componentName=="string"?{component:$.componentName}:{},...typeof $.phase=="string"?{phase:$.phase}:{},...m.length?{why:m}:{},...typeof x.projectName=="string"?{project:x.projectName}:typeof e.project=="string"?{project:e.project}:{},...B!==void 0?{durationMs:B}:{},...E&&l(e.startedAt)!==void 0?{fetchStartedAt:l(e.startedAt)}:{},...i.source==="ai"?{ai:y.includeRaw?e:U(e)}:{},...k?{detail:k}:{},...R?{steps:R}:{}}}S(trimFlowEvent,"trimFlowEvent"),M(trimFlowEvent,"trimFlowEvent");function H(i){return i==="flow-origin"?0:i?.endsWith("-start")?1:i==="gateway-request"?2:i==="server-request"?3:i==="span"?4:5}S(H,"tt"),M(H,"kindRank");function F(i){return i.kind==="span"&&i.role==="controller"?3.5:i.kind==="queue-process"?3:H(i.kind)}S(F,"T"),M(F,"causalRank");export function buildFlowDetail(i,y={}){const e=i.slice().filter(t=>{const s=t.raw??{},n=typeof s.kind=="string"?s.kind:"";if(n==="subscription-added"||n==="subscription-removed"||n==="hook-run"||n==="store-created"||n==="singleton-instance")return!1;const r=s.span;return!(typeof r?.name=="string"&&r.name.startsWith("nest.request "))}).map(t=>trimFlowEvent(t,y)),$=new Set;for(let t=e.length-1;t>=0;t--)$.has(e[t].id)?e.splice(t,1):$.add(e[t].id);const c=new Map;for(const t of e)(t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&!c.has(t.requestId)&&c.set(t.requestId,t.start);const N=M(t=>t.source!=="react"&&t.source!=="valtio"&&t.requestId&&c.has(t.requestId)?c.get(t.requestId):t.start,"anchorOf");e.sort((t,s)=>N(t)-N(s)||t.start-s.start||F(t)-F(s)||(s.durationMs??0)-(t.durationMs??0)||t.t-s.t);const l=M(t=>(t.kind==="span"||t.kind==="server-request"||t.kind==="gateway-request"||t.kind==="queue-process")&&(t.durationMs??0)>0,"spanLike"),I=e;for(const t of I)t.group=t.source==="react"||t.source==="valtio"||t.source==="client-runtime"||t.source==="visual"?"browser":"server";const B=new Map;for(const t of I)(t.kind==="gateway-request"||t.kind==="queue-process")&&t.requestId&&t.project&&B.set(t.requestId,t.project);for(const t of I)if(!t.project&&t.source==="nestjs"&&t.requestId){const s=B.get(t.requestId);s&&(t.project=s)}for(const t of I){let s;const n=t.requestId;for(const r of I){if(r===t||!l(r)||r.group!==t.group||r.requestId!==n)continue;const o=r.project,d=t.project;if(r.kind!=="gateway-request"&&t.kind!=="gateway-request"&&o!==void 0&&d!==void 0&&o!==d)continue;const q=r.durationMs??0,h=t.durationMs??0;r.start<=t.start&&r.start+q>t.start&&(r.start<t.start||q>h||q===h&&F(r)<F(t))&&(!s||r.start>s.start||r.start===s.start&&(r.durationMs??0)<(s.durationMs??0)||r.start===s.start&&(r.durationMs??0)===(s.durationMs??0)&&F(r)>F(s))&&(s=r)}s&&(t.parent=s.id)}const p=new Map;for(const t of I){if(!t.requestId)continue;const s=p.get(t.requestId);s?s.push(t):p.set(t.requestId,[t])}const E=M((t,s)=>{const n=(p.get(t)??[]).filter(r=>l(r)&&r.start<=s&&r.start+(r.durationMs??0)>=s);if(n.length!==0)return n.sort((r,o)=>o.start-r.start||(r.durationMs??0)-(o.durationMs??0)),n[0]},"callerNodeFor");for(const t of I){if(!t.parentRequestId||t.kind!=="server-request")continue;const s=E(t.parentRequestId,t.start);s&&s!==t&&s.start<=t.start&&(t.parent=s.id)}const A=I,k=new Map;for(const t of A)t.kind==="gateway-request"&&t.requestId&&!k.has(t.requestId)&&k.set(t.requestId,t);for(const t of A)if(t.group==="server"&&!t.parent&&t.requestId&&t.kind!=="gateway-request"){const s=k.get(t.requestId);s&&s!==t&&s.start<=t.start&&(t.parent=s.id)}const D=new Set,R=new Set,b=[];for(const t of A){if(t.kind!=="gateway-request")continue;if(!t.requestId){b.push(t);continue}const s=p.get(t.requestId)??[];if(s.filter(o=>o.kind==="gateway-request").sort((o,d)=>o.start-d.start)[0]!==t)continue;const n=s.find(o=>o.kind==="fetch-start"),r=s.find(o=>o.kind==="fetch-done"||o.kind==="fetch-error");if(!n&&!r){b.push(t);continue}n&&(t.fetchStartId=n.id,D.add(n.id)),r&&(t.fetchDoneId=r.id,R.add(r.id))}const x=new Map;for(const t of A){if(!t.urlKey)continue;const s=x.get(t.urlKey)??{gws:[],starts:[],dones:[]};t.kind==="gateway-request"?b.includes(t)&&s.gws.push(t):t.kind==="fetch-start"?D.has(t.id)||s.starts.push(t):(t.kind==="fetch-done"||t.kind==="fetch-error")&&(R.has(t.id)||s.dones.push(t)),x.set(t.urlKey,s)}for(const{gws:t,starts:s,dones:n}of x.values()){t.sort((o,d)=>o.start-d.start),s.sort((o,d)=>o.start-d.start);const r=new Set;t.forEach((o,d)=>{const q=s[d];q&&(o.fetchStartId=q.id);const h=q?q.t:o.start;let w,u=1/0;for(const j of n){if(r.has(j.id))continue;const z=j.fetchStartedAt??j.start-(j.durationMs??0),K=Math.abs(z-h);K<u&&(u=K,w=j)}w&&(o.fetchDoneId=w.id,r.add(w.id))})}const O=new Map,C=new Map;for(const t of A)!t.queue||!t.jobId||(t.kind==="queue-enqueued"&&O.set(`${t.queue}#${t.jobId}`,t),t.kind==="queue-process"&&C.set(`${t.queue}#${t.jobId}`,t));for(const t of A){if(!t.queue||!t.jobId)continue;const s=`${t.queue}#${t.jobId}`;if(t.kind==="queue-process"&&!t.parent){const n=O.get(s);n&&n!==t&&n.start<=t.start&&(t.parent=n.id)}else if(t.kind==="queue-active"||t.kind==="queue-completed"||t.kind==="queue-failed"){const n=C.get(s);n&&n!==t&&(t.parent=n.id)}}let m=I;{const t=new Map;for(const n of m)n.kind==="fetch-start"&&t.set(n.id,n);const s=new Map;for(const n of m){if(n.kind!=="fetch-done"&&n.kind!=="fetch-error")continue;const r=[...t.values()].find(q=>q.requestId&&q.requestId===n.requestId)?.id,o=r?t.get(r):void 0;if(!o)continue;const d=n.fetchStartedAt??o.start;o.title=n.title,o.severity=n.severity,o.durationMs=n.durationMs??Math.max(0,n.t-d),o.kind="fetch",n.detail&&!o.detail&&(o.detail=n.detail),s.set(n.id,o.id)}if(s.size>0){m=m.filter(n=>!s.has(n.id));for(const n of m)for(n.fetchDoneId&&s.has(n.fetchDoneId)&&(n.fetchDoneId=s.get(n.fetchDoneId));n.parent&&s.has(n.parent);)n.parent=s.get(n.parent)}}const a=M(t=>!!t.commitId&&(t.kind==="render"||t.kind==="effect-run"),"commitMember"),g=[],v=new Map;for(let t=0;t<m.length;){const s=m[t];if(!a(s)){g.push(s),t+=1;continue}let n=t+1;for(;n<m.length;){const f=m[n];if(!a(f)||f.commitId!==s.commitId)break;n+=1}const r=m.slice(t,n);if(t=n,r.length<2){g.push(...r);continue}const o=r.filter(f=>f.kind==="render"),d=r.filter(f=>f.kind==="effect-run"),q=o.filter(f=>!(f.why??[]).includes("parent-render")),h=[...new Set(q.flatMap(f=>f.why??[]))],w=[...new Set(q.map(f=>f.component).filter(Boolean))],u=[...new Set(o.map(f=>f.component).filter(Boolean))],j=Math.min(...r.map(f=>f.start)),z=Math.max(...r.map(f=>f.start+(f.durationMs??0))),K=w.length===1?w[0]:w.length>1?`${w.length} roots`:u[0]??"view",L=h.length===1?h[0]:h.length>1?h.join(" + "):void 0,Q=o.some(f=>f.phase==="mount"),T={...s,kind:"view-update",title:`view update \xB7 ${K}${L?` \u2190 ${L}`:""}`,start:j,durationMs:z-j,commitId:s.commitId,cause:L,components:u,effects:d.length,memberIds:r.map(f=>f.id),sig:`commit:${L??"-"}:${w.join(",")}:${u.slice().sort().join(",")}`,detail:[`${u.length} component${u.length===1?"":"s"}${Q?" (mount)":""}`,d.length?`${d.length} effect${d.length===1?"":"s"}`:"",u.join(", ")].filter(Boolean).join(" \xB7 "),severity:r.some(f=>f.severity==="error")?"error":s.severity};delete T.component,delete T.why,delete T.phase;for(const f of r)f.id!==T.id&&v.set(f.id,T.id);g.push(T)}if(v.size>0){m=g;for(const t of m)for(;t.parent&&v.has(t.parent);)t.parent=v.get(t.parent)}for(let t=1;t<m.length;t++){const s=m[t-1],n=m[t];n.kind!=="view-update"||s.kind!=="view-update"||n.sig&&n.sig===s.sig&&(s.redundant=!0,n.redundant=!0)}const P=M(t=>{const s=new Map;for(const r of m){if(!r.sig||l(r)!==t||r.kind==="server-request"||r.kind==="gateway-request")continue;const o=`${r.parent??"root"}|${r.kind}|${r.sig}`,d=s.get(o);d?d.push(r):s.set(o,[r])}const n=new Map;for(const r of s.values()){if(r.length<3)continue;r.sort((u,j)=>u.start-j.start);const o=r[0];let d=!1;for(let u=0;u+1<r.length;u++)if(r[u+1].start<r[u].start+(r[u].durationMs??0)){d=!0;break}const q=o.start,h=Math.max(...r.map(u=>u.start+(u.durationMs??0))),w=r.reduce((u,j)=>u+(j.durationMs??0),0);if(o.count=r.length,o.parallel=d,o.avgMs=Math.round(w/r.length*10)/10,o.wallMs=h-q,o.durationMs=h-q,o.title=`\xD7${r.length} ${o.title.replace(/\s*\((?:\d+ rows?, )?\d+ms\)$/,"")}`,o.kind==="view-update"){const u=o.redundant===!0;o.detail=[`${r.length} commits \xB7 avg ${o.avgMs}ms \xB7 wall ${o.wallMs}ms`,u?`no state change between them \u2014 ${r.length-1} of these had nothing new to render`:"one per update \u2014 expected for this many changes",o.components?.join(", ")??""].filter(Boolean).join(" \xB7 ")}else o.detail=`${o.sig} \xD7${r.length} ${d?"\u2016 parallel":"\u21BB sequential loop"} \xB7 avg ${o.avgMs}ms \xB7 wall ${o.wallMs}ms`;o.items=r.slice(0,12).map(u=>({start:u.start-q,...u.durationMs!=null?{durationMs:u.durationMs}:{}})),o.memberIds=r.flatMap(u=>u.memberIds??[u.id]),r.some(u=>u.severity==="error")&&(o.severity="error");for(const u of r.slice(1))n.set(u.id,o.id)}if(n.size!==0){m=m.filter(r=>!n.has(r.id));for(const r of m)for(;r.parent&&n.has(r.parent);)r.parent=n.get(r.parent)}},"aggregatePass");P(!0),P(!1);for(const t of m){if(!l(t))continue;const s=t.durationMs??0;if(s<40)continue;const n=m.filter(h=>h.parent===t.id&&(h.durationMs??0)>0).map(h=>[h.start,h.start+(h.durationMs??0)]).sort((h,w)=>h[0]-w[0]);let r=0,o=-1,d=-1;for(const[h,w]of n)h>d?(d>o&&(r+=d-o),o=h,d=w):w>d&&(d=w);d>o&&(r+=d-o);const q=Math.max(0,s-r);(q>=50||q/s>=.7&&s>=40)&&(t.selfMs=q,t.detail=`\u26A0 cpu-heavy: ${q}ms self-time of ${s}ms${t.detail?" \xB7 "+t.detail:""}`)}return{events:m}}S(buildFlowDetail,"buildFlowDetail"),M(buildFlowDetail,"buildFlowDetail");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/core",
3
- "version": "1.22.3",
3
+ "version": "1.22.5",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -19,7 +19,7 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@lensmcp/protocol-types": "1.22.3",
22
+ "@lensmcp/protocol-types": "1.22.5",
23
23
  "tslib": "^2.3.0"
24
24
  },
25
25
  "license": "Apache-2.0",