@lensmcp/protocol-types 1.25.1 → 1.25.3
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/lib/bounded-clone.js +1 -1
- package/lib/bounded-map.js +1 -1
- package/lib/bounded-writer.js +1 -1
- package/lib/capture-demand.js +1 -1
- package/lib/dashboard.d.ts +232 -7
- package/lib/dashboard.js +1 -1
- package/lib/error-dismissal.js +1 -1
- package/lib/flood-guard.js +1 -1
- package/lib/log-query.js +1 -1
- package/lib/perf-rules.js +1 -1
- package/lib/pod-memory.js +1 -1
- package/lib/producer-health.js +1 -1
- package/package.json +1 -1
package/lib/bounded-clone.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var T=Object.defineProperty;var
|
|
1
|
+
"use strict";var T=Object.defineProperty;var i=(e,t)=>T(e,"name",{value:t,configurable:!0});var h=Object.defineProperty,l=i((e,t)=>h(e,"name",{value:t,configurable:!0}),"_");export const DEFAULT_RAW_BYTE_LIMIT=32768,DEFAULT_MAX_STRING_BYTES=4096,DEFAULT_MAX_ARRAY_ITEMS=64,DEFAULT_MAX_DEPTH=12,CHEAP_ENTRY_BYTES=512,NOMINAL_DEEP_BYTES=32,DEEP_REPORT_DEPTH=64,SKELETON_STRING_BYTES=256,MAX_RECORDED_PATHS=20,TRUNCATION_MARKER_KEY="__lensmcpTruncation",TRUNCATED_VALUE_KEY="__lensmcpTruncated";export function estimateJsonBytes(e,t=Number.POSITIVE_INFINITY,r=12){return y(e,t,r,32)}i(estimateJsonBytes,"estimateJsonBytes"),l(estimateJsonBytes,"estimateJsonBytes");export function exceedsJsonByteBudget(e,t,r=12){return y(e,t,r,Number.POSITIVE_INFINITY)>t}i(exceedsJsonByteBudget,"exceedsJsonByteBudget"),l(exceedsJsonByteBudget,"exceedsJsonByteBudget");function y(e,t,r,a){switch(typeof e){case"undefined":case"function":case"symbol":return 0;case"boolean":return 5;case"number":return Number.isFinite(e)?8:4;case"bigint":return 20;case"string":return e.length+2;default:break}if(e===null)return 4;if(r<=0)return a;if(e instanceof Date)return 26;if(Array.isArray(e)){let n=2;for(let s=0;s<e.length;s++)if(n+=y(e[s],t-n,r-1,a)+1,n>t)return n;return n}let u=2;const o=e;for(const n in o){if(!Object.prototype.hasOwnProperty.call(o,n))continue;const s=y(o[n],t-u,r-1,a);if(s!==0&&(u+=n.length+4+s,u>t))return u}return u}i(y,"T"),l(y,"walk");function g(e,t){e.truncatedAnything=!0,e.paths.length<20&&e.paths.push(t||"<root>")}i(g,"A"),l(g,"record");function f(e,t,r){return g(e,r),{[TRUNCATED_VALUE_KEY]:!0,originalBytes:estimateJsonBytes(t,Number.POSITIVE_INFINITY,64)}}i(f,"I"),l(f,"stub");function p(e){if(e===null)return!0;const t=typeof e;return t==="number"||t==="boolean"||t==="string"||t==="bigint"}i(p,"y"),l(p,"isScalar");export function clampValue(e,t,r,a){if(typeof e=="string"){const u=t.budget<=0?256:t.maxStringBytes;if(e.length+2<=u)return t.budget-=e.length+2,e;const o=Math.max(0,u-64);return g(t,a),t.budget-=o,`${e.slice(0,o)}\u2026[lensmcp truncated: ${e.length-o} more chars]`}return e===null||typeof e!="object"?(t.budget-=y(e,Number.POSITIVE_INFINITY,1,32),e):r<=0?f(t,e,a):e instanceof Date?(t.budget-=26,e):Array.isArray(e)?m(e,t,r,a):b(e,t,r,a)}i(clampValue,"clampValue"),l(clampValue,"clampValue");function m(e,t,r,a){const u=[],o=Math.min(e.length,t.maxArrayItems);for(let n=0;n<o&&!(t.budget<=0);n++)u.push(clampValue(e[n],t,r-1,`${a}[${n}]`));return u.length<e.length&&g(t,`${a}[] (+${e.length-u.length} items dropped)`),u}i(m,"f"),l(m,"clampArray");function b(e,t,r,a){const u={};let o;const n=t.budget<=0;for(const s in e){if(!Object.prototype.hasOwnProperty.call(e,s))continue;const c=e[s],I=y(c,512,r-1,Number.POSITIVE_INFINITY);if(I<=512&&(!n||p(c))){u[s]=c,t.budget-=s.length+4+I;continue}(o??=[]).push({key:s,bytes:I})}if(!o)return u;o.sort((s,c)=>s.bytes===c.bytes?0:s.bytes<c.bytes?-1:1);for(const{key:s}of o){const c=a?`${a}.${s}`:s;u[s]=clampValue(e[s],t,r-1,c)}return u}i(b,"m"),l(b,"clampObject");export function boundedClone(e,t={}){const r=t.rawByteLimit??32768,a=t.maxDepth??12;if(r<=0)return{value:void 0,truncated:!1,originalBytes:0,keptBytes:0,paths:[]};if(e==null)return{value:e,truncated:!1,originalBytes:0,keptBytes:0,paths:[]};if(!exceedsJsonByteBudget(e,r,a)){const c=estimateJsonBytes(e,r,a),I={budget:r,maxStringBytes:t.maxStringBytes??4096,maxArrayItems:t.maxArrayItems??64,paths:[],truncatedAnything:!1};return{value:clampValue(e,I,a,""),truncated:!1,originalBytes:c,keptBytes:c,paths:[]}}const u=estimateJsonBytes(e,Number.POSITIVE_INFINITY,64),o={budget:r,maxStringBytes:t.maxStringBytes??4096,maxArrayItems:t.maxArrayItems??64,paths:[],truncatedAnything:!1},n=clampValue(e,o,a,""),s=estimateJsonBytes(n,Number.POSITIVE_INFINITY,a);if(o.truncatedAnything&&n!==null&&typeof n=="object"&&!Array.isArray(n)){const c={truncated:!0,originalBytes:u,keptBytes:s,paths:o.paths};n[TRUNCATION_MARKER_KEY]=c}return{value:n,truncated:o.truncatedAnything,originalBytes:u,keptBytes:s,paths:o.paths}}i(boundedClone,"boundedClone"),l(boundedClone,"boundedClone");
|
package/lib/bounded-map.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var t=(e,r)=>c(e,"name",{value:r,configurable:!0});var i=Object.defineProperty,s=t((e,r)=>i(e,"name",{value:r,configurable:!0}),"o");export function capMap(e,r){if(e.size<=r)return 0;let n=0;const o=e.keys();for(;e.size>r;){const a=o.next();if(a.done)break;e.delete(a.value)&&(n+=1)}return n}t(capMap,"capMap"),s(capMap,"capMap");export const MAX_PRODUCER_KEYS=256;
|
package/lib/bounded-writer.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var y=Object.defineProperty;var r=(e,t)=>y(e,"name",{value:t,configurable:!0});var v=Object.defineProperty,o=r((e,t)=>v(e,"name",{value:t,configurable:!0}),"c");import{renameSync as l,statSync as f,unlinkSync as x}from"node:fs";export function eventMaxBytes(e=process.env){const t=Number(e.LENSMCP_EVENT_MAX_BYTES);return Number.isFinite(t)&&t>0?t:50*1024*1024}r(eventMaxBytes,"eventMaxBytes"),o(eventMaxBytes,"eventMaxBytes");export function eventMaxFiles(e=process.env){const t=Number(e.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(t)&&t>=1&&t<=20?Math.floor(t):5}r(eventMaxFiles,"eventMaxFiles"),o(eventMaxFiles,"eventMaxFiles");const E=1024*1024,a=new Map;export function maybeRotateEventFile(e,t,i){const s=(a.get(e)??0)+t,c=i?.maxBytes??eventMaxBytes(),u=i?.maxFiles??eventMaxFiles(),m=Math.min(E,c);if(s<m){a.set(e,s);return}try{const n=f(e).size;if(a.set(e,0),n<=c)return}catch{a.set(e,s);return}try{x(`${e}.${u}`)}catch{}for(let n=u-1;n>=1;n--)try{l(`${e}.${n}`,`${e}.${n+1}`)}catch{}try{l(e,`${e}.1`)}catch{}}r(maybeRotateEventFile,"maybeRotateEventFile"),o(maybeRotateEventFile,"maybeRotateEventFile");export function resetRotationThrottle(e){e===void 0?a.clear():a.delete(e)}r(resetRotationThrottle,"resetRotationThrottle"),o(resetRotationThrottle,"resetRotationThrottle");
|
package/lib/capture-demand.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var o=(t,e)=>c(t,"name",{value:e,configurable:!0});var s=Object.defineProperty,u=o((t,e)=>s(t,"name",{value:e,configurable:!0}),"s");export const CAPTURE_REQUEST_FILENAME="capture-request.json",CAPTURE_PRESENCE_FILENAME="capture-runner.json";export function appMatchesPage(t,e){const r=t.trim().toLowerCase();if(!r)return!1;if(e.project&&e.project.toLowerCase()===r)return!0;const n=e.url.toLowerCase();if(n===r||n.replace(/\/+$/,"")===r.replace(/\/+$/,""))return!0;try{const a=new URL(e.url);return/^\d+$/.test(r)?a.port===r:a.origin.toLowerCase()===r.replace(/\/+$/,"")}catch{return!1}}o(appMatchesPage,"appMatchesPage"),u(appMatchesPage,"appMatchesPage");export const CAPTURE_RULES_FILENAME="capture-rules.json";
|
package/lib/dashboard.d.ts
CHANGED
|
@@ -486,6 +486,17 @@ export interface DashFlowDetail {
|
|
|
486
486
|
segmentStats?: DashSegmentStats;
|
|
487
487
|
/** Present when the read asked for one segment (`?segment=`): `events` then holds only that segment. */
|
|
488
488
|
focus?: DashFlowSegment;
|
|
489
|
+
/**
|
|
490
|
+
* Present when the flow was no longer in the live window and was read back — from the workspace's event history
|
|
491
|
+
* (30 days) or the bus files. `complete: false`: older events of it may be missing.
|
|
492
|
+
*/
|
|
493
|
+
recovered?: {
|
|
494
|
+
from: 'bus' | 'history';
|
|
495
|
+
events: number;
|
|
496
|
+
complete: boolean;
|
|
497
|
+
/** Its list summary (title, route, duration, outcome) — the live flow list does not hold it. */
|
|
498
|
+
summary?: DashFlowSummary;
|
|
499
|
+
};
|
|
489
500
|
}
|
|
490
501
|
export interface DashLogLine {
|
|
491
502
|
seq: number;
|
|
@@ -516,7 +527,9 @@ export interface DashLogsFrame {
|
|
|
516
527
|
export type DashProblemSeverity = 'high' | 'medium' | 'low';
|
|
517
528
|
export type DashProblemKind = 'n-plus-one' | 'db-in-loop' | 'render-storm' | 'slow-path' | 'slow-route' | 'slow-query' | 'missing-index' | 'leak' | 'server-error' | 'browser-error' | 'failed-span' | 'egress-failing' | 'egress-slow' | 'duplicate-requests' | 'build' | 'typecheck' | 'lint' | 'service'
|
|
518
529
|
/** A performance rule's finding (`perf://rules`): build or memory cost, with its fix and how to verify it. */
|
|
519
|
-
| 'perf-rule'
|
|
530
|
+
| 'perf-rule'
|
|
531
|
+
/** A service could not get a database connection, and why (`db://pool`): a hot swap or a blocked loop, a full pool, Postgres full. */
|
|
532
|
+
| 'db-connection' | 'other';
|
|
520
533
|
export interface DashProblem {
|
|
521
534
|
/** Stable across updates — the card's identity for the resolved-lifecycle. */
|
|
522
535
|
id: string;
|
|
@@ -1118,6 +1131,35 @@ export interface DashSqlFinding {
|
|
|
1118
1131
|
tool: string;
|
|
1119
1132
|
at: number;
|
|
1120
1133
|
}
|
|
1134
|
+
/**
|
|
1135
|
+
* A place in the services' own code where something ran — what a coding agent opens. From the stack the tap took at
|
|
1136
|
+
* the call: the service's nearest frame, and the callers above it.
|
|
1137
|
+
*/
|
|
1138
|
+
export interface DashCodeSite {
|
|
1139
|
+
/** `server/apps/engine/src/users/users.service.ts:42 (UsersService.findAll)` — what to open. */
|
|
1140
|
+
at: string;
|
|
1141
|
+
/** Relative to the workspace root when inside it. */
|
|
1142
|
+
file: string;
|
|
1143
|
+
/** The source line: TypeScript's when the lens could map it (`exact`), else the line the stack said. */
|
|
1144
|
+
line: number;
|
|
1145
|
+
column?: number;
|
|
1146
|
+
/** The function the line is in, or — when that one has no name (an arrow) — the nearest named caller. */
|
|
1147
|
+
symbol?: string;
|
|
1148
|
+
/** False: the line is the transpiled module's (close to the source's, not equal) — open `symbol` instead. */
|
|
1149
|
+
exact: boolean;
|
|
1150
|
+
/** The file was edited after this last ran: the line may have moved — find `symbol`. */
|
|
1151
|
+
changed?: boolean;
|
|
1152
|
+
/** The callers above it, nearest first. */
|
|
1153
|
+
via?: Array<{
|
|
1154
|
+
file: string;
|
|
1155
|
+
line: number;
|
|
1156
|
+
symbol?: string;
|
|
1157
|
+
}>;
|
|
1158
|
+
/** Runs that carried this site (the taps sample — a share of all runs), the services, and when it was last seen. */
|
|
1159
|
+
seen: number;
|
|
1160
|
+
services: string[];
|
|
1161
|
+
lastSeenAt: number;
|
|
1162
|
+
}
|
|
1121
1163
|
export interface DashSqlTemplateSummary {
|
|
1122
1164
|
/** 12 hex characters — the statement's shape (`@lensmcp/core/sql-shape`). */
|
|
1123
1165
|
id: string;
|
|
@@ -1129,6 +1171,10 @@ export interface DashSqlTemplateSummary {
|
|
|
1129
1171
|
suggestedName?: string;
|
|
1130
1172
|
/** Its newest finished SQL review, when it has one. */
|
|
1131
1173
|
review?: DashReviewMark;
|
|
1174
|
+
/** Where in the services' code it runs — each code path the taps saw, the busiest first (planning/code-locations). */
|
|
1175
|
+
sites?: DashCodeSite[];
|
|
1176
|
+
/** An unnamed statement its named version replaced (edited as it was named): that statement's id — not one to name. */
|
|
1177
|
+
replacedBy?: string;
|
|
1132
1178
|
/** SELECT · INSERT · UPDATE · DELETE · …; a WITH reads as the statement it leads to. */
|
|
1133
1179
|
verb: string;
|
|
1134
1180
|
tables: string[];
|
|
@@ -1173,6 +1219,8 @@ export interface DashSqlTemplateDetail extends DashSqlTemplateSummary {
|
|
|
1173
1219
|
}
|
|
1174
1220
|
export interface DashSqlTable {
|
|
1175
1221
|
name: string;
|
|
1222
|
+
/** The databases the statements that touch it ran on (the pg tap names each); absent from an older tap. */
|
|
1223
|
+
databases?: string[];
|
|
1176
1224
|
/** Runs of reading statements that touched it, and of writing ones. */
|
|
1177
1225
|
reads: number;
|
|
1178
1226
|
writes: number;
|
|
@@ -1233,6 +1281,62 @@ export interface DashDbStore {
|
|
|
1233
1281
|
/** Connections to the server, all databases. */
|
|
1234
1282
|
connections?: number;
|
|
1235
1283
|
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Data › Databases › Connections: who holds the server's connections, against its limit — read from `pg_stat_activity`
|
|
1286
|
+
* (every database on the server: `max_connections` is the server's). A connection the lens's pg tap opened names its
|
|
1287
|
+
* service and app generation (`foodguard lens:engine:g12`), so a generation a hot swap replaced shows apart.
|
|
1288
|
+
*/
|
|
1289
|
+
export interface DashDbConnections {
|
|
1290
|
+
at: number;
|
|
1291
|
+
store: string;
|
|
1292
|
+
state: 'ok' | 'error';
|
|
1293
|
+
reason?: string;
|
|
1294
|
+
/** `max_connections`, and the slots kept for superusers and `pg_use_reserved_connections` — what the apps cannot use. */
|
|
1295
|
+
max?: number;
|
|
1296
|
+
reserved?: number;
|
|
1297
|
+
/** Client connections now (every database). */
|
|
1298
|
+
used?: number;
|
|
1299
|
+
/** One row per application name (and database), the most connections first. */
|
|
1300
|
+
apps: DashDbConnApp[];
|
|
1301
|
+
/** The sessions worth a look: open in a transaction, waiting on a lock, or running for over a second. */
|
|
1302
|
+
sessions: DashDbConnSession[];
|
|
1303
|
+
}
|
|
1304
|
+
export interface DashDbConnApp {
|
|
1305
|
+
/** As Postgres has it: `foodguard lens:engine:g12`. */
|
|
1306
|
+
app: string;
|
|
1307
|
+
/** From the lens's tag: the service, and the app generation that opened the connections. */
|
|
1308
|
+
service?: string;
|
|
1309
|
+
generation?: number;
|
|
1310
|
+
/** An older generation of a service whose newer one holds connections too — a hot swap that never closed its pool. */
|
|
1311
|
+
leftover?: boolean;
|
|
1312
|
+
database?: string;
|
|
1313
|
+
total: number;
|
|
1314
|
+
active: number;
|
|
1315
|
+
idle: number;
|
|
1316
|
+
idleInTransaction: number;
|
|
1317
|
+
waiting: number;
|
|
1318
|
+
/** The oldest of these connections, ms. */
|
|
1319
|
+
oldestMs?: number;
|
|
1320
|
+
}
|
|
1321
|
+
export interface DashDbConnSession {
|
|
1322
|
+
pid: number;
|
|
1323
|
+
app: string;
|
|
1324
|
+
service?: string;
|
|
1325
|
+
generation?: number;
|
|
1326
|
+
database?: string;
|
|
1327
|
+
state: string;
|
|
1328
|
+
/** `Lock: transactionid` — what it waits on. */
|
|
1329
|
+
waiting?: string;
|
|
1330
|
+
/** How long its transaction has been open, and how long it has been in this state, ms. */
|
|
1331
|
+
xactMs?: number;
|
|
1332
|
+
stateMs?: number;
|
|
1333
|
+
/** Its statement as a shape (no values): the SQL catalog's id, name and template. */
|
|
1334
|
+
statement?: {
|
|
1335
|
+
id: string;
|
|
1336
|
+
name?: string;
|
|
1337
|
+
text: string;
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1236
1340
|
export interface DashDbDatabase {
|
|
1237
1341
|
name: string;
|
|
1238
1342
|
bytes?: number;
|
|
@@ -1394,6 +1498,9 @@ export interface DashDbLintIssue {
|
|
|
1394
1498
|
fix: string;
|
|
1395
1499
|
/** For an unnamed statement: a name in the convention, to start from. */
|
|
1396
1500
|
suggestedName?: string;
|
|
1501
|
+
/** Where in the code it runs — its busiest code path — and the others (planning/code-locations). */
|
|
1502
|
+
where?: string;
|
|
1503
|
+
sites?: DashCodeSite[];
|
|
1397
1504
|
review?: {
|
|
1398
1505
|
runId: string;
|
|
1399
1506
|
at: number;
|
|
@@ -1912,8 +2019,8 @@ export interface DashAiRun {
|
|
|
1912
2019
|
workspace: string;
|
|
1913
2020
|
/** `queued`: waiting for a free slot (`queue` says how many are ahead); one job per target, at most N at once. */
|
|
1914
2021
|
status: 'queued' | 'running' | 'done' | 'failed';
|
|
1915
|
-
/**
|
|
1916
|
-
trigger?:
|
|
2022
|
+
/** Who started it, and so which daily allowance it spends from (`DashAiTrigger`); absent: someone asked, before that was recorded. */
|
|
2023
|
+
trigger?: DashAiTrigger;
|
|
1917
2024
|
queue?: {
|
|
1918
2025
|
ahead: number;
|
|
1919
2026
|
max: number;
|
|
@@ -2062,6 +2169,66 @@ export interface DashReviewMark {
|
|
|
2062
2169
|
overall?: number;
|
|
2063
2170
|
warning?: boolean;
|
|
2064
2171
|
}
|
|
2172
|
+
/**
|
|
2173
|
+
* A target's review as a drawer or a list shows it without opening it — read only, nothing is started
|
|
2174
|
+
* (`/api/ai/review-status`, `/api/ai/review-marks`). `none`: never reviewed; `reviewing`: a run waits or runs now
|
|
2175
|
+
* (`progress`); `reviewed`: its newest review holds, as far as the lens has checked (`checkedAt`); `stale`: it no
|
|
2176
|
+
* longer holds — the thing or the instructions changed since (`why`); `failed`: the newest run failed (`why`). The
|
|
2177
|
+
* newest finished review comes with each state but `none`.
|
|
2178
|
+
*/
|
|
2179
|
+
export interface DashReviewStatus {
|
|
2180
|
+
/** `<kind>:<id>`. */
|
|
2181
|
+
target: string;
|
|
2182
|
+
state: 'none' | 'reviewing' | 'reviewed' | 'stale' | 'failed';
|
|
2183
|
+
/** Why it is out of date, or why its newest run failed. */
|
|
2184
|
+
why?: string;
|
|
2185
|
+
/** When the lens last asked the analyzer whether the review still holds against the thing as it is now; absent: not yet. */
|
|
2186
|
+
checkedAt?: number;
|
|
2187
|
+
review?: DashReviewSummary;
|
|
2188
|
+
/** The run waiting or running now: its step, how many are ahead of it, how far Claude got. */
|
|
2189
|
+
progress?: {
|
|
2190
|
+
runId: string;
|
|
2191
|
+
status: 'queued' | 'running';
|
|
2192
|
+
startedAt: number;
|
|
2193
|
+
step?: string;
|
|
2194
|
+
ahead?: number;
|
|
2195
|
+
turns?: number;
|
|
2196
|
+
tools?: number;
|
|
2197
|
+
};
|
|
2198
|
+
/** The newest run, when it failed: when, and its error. */
|
|
2199
|
+
failed?: {
|
|
2200
|
+
runId: string;
|
|
2201
|
+
at: number;
|
|
2202
|
+
error: string;
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
/** A finished review in a few lines: when, its score, what it is about, the changes it asks for first. */
|
|
2206
|
+
export interface DashReviewSummary {
|
|
2207
|
+
runId: string;
|
|
2208
|
+
at: number;
|
|
2209
|
+
analyzerName: string;
|
|
2210
|
+
overall?: number;
|
|
2211
|
+
/** Under the indicator set's line (70): a warning to coding agents. */
|
|
2212
|
+
warning?: boolean;
|
|
2213
|
+
/** What the reviewed thing is, as the review named it. */
|
|
2214
|
+
title?: string;
|
|
2215
|
+
/** The review's own summary, clipped — in a drawer's status (`review-status`), not in a list's marks. */
|
|
2216
|
+
summary?: string;
|
|
2217
|
+
/** How many changes it asks for, and the first three, most worth doing first. */
|
|
2218
|
+
findings: number;
|
|
2219
|
+
top: Array<{
|
|
2220
|
+
priority: DashAiFinding['priority'];
|
|
2221
|
+
title: string;
|
|
2222
|
+
}>;
|
|
2223
|
+
/** A statement reviewed only in an earlier version under its name: that version's id. */
|
|
2224
|
+
of?: string;
|
|
2225
|
+
}
|
|
2226
|
+
/** `/api/ai/review-marks?kind=`: each target of a kind with a review or a run, by its id — a list's review chip. */
|
|
2227
|
+
export interface DashReviewMarks {
|
|
2228
|
+
at: number;
|
|
2229
|
+
kind: DashAiRun['target']['kind'];
|
|
2230
|
+
marks: Record<string, DashReviewStatus>;
|
|
2231
|
+
}
|
|
2065
2232
|
/** What became of a suggestion: new, accepted (for a coding agent to do), applied, or dismissed. */
|
|
2066
2233
|
export type DashSuggestionState = 'new' | 'accepted' | 'applied' | 'dismissed';
|
|
2067
2234
|
/**
|
|
@@ -2264,12 +2431,24 @@ export interface DashAiTokens {
|
|
|
2264
2431
|
};
|
|
2265
2432
|
providers: DashAiProviderInfo[];
|
|
2266
2433
|
tokens: DashAiToken[];
|
|
2267
|
-
/** What this workspace's model calls cost today (UTC, estimated)
|
|
2434
|
+
/** What this workspace's model calls cost today (UTC, estimated) — and by who asked, against each one's daily allowance. */
|
|
2268
2435
|
today: {
|
|
2269
2436
|
usd: number;
|
|
2270
|
-
|
|
2437
|
+
by?: Record<DashAiTrigger, {
|
|
2438
|
+
usd: number;
|
|
2439
|
+
capUsd?: number;
|
|
2440
|
+
}>;
|
|
2271
2441
|
};
|
|
2272
2442
|
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Who asked for a model call — each has its own daily allowance (Settings › Features), so reviews that start by
|
|
2445
|
+
* themselves can never use up what a person or an agent asks for:
|
|
2446
|
+
* auto started by itself (Settings › Features — a statement once named, a route that changed)
|
|
2447
|
+
* click a person in the dashboard (Review with Claude, Ask AI, a key's test)
|
|
2448
|
+
* agent a coding agent over MCP (`review.* { run: true }`)
|
|
2449
|
+
*/
|
|
2450
|
+
export type DashAiTrigger = 'auto' | 'click' | 'agent';
|
|
2451
|
+
export declare const DASH_AI_TRIGGERS: readonly DashAiTrigger[];
|
|
2273
2452
|
/** One path a service read or wrote, by operation — from the fs tap's per-second aggregates. */
|
|
2274
2453
|
export interface DashFilePath {
|
|
2275
2454
|
/** `<service> <op> <path>`. */
|
|
@@ -2290,6 +2469,45 @@ export interface DashFilePath {
|
|
|
2290
2469
|
flowId?: string;
|
|
2291
2470
|
/** Route catalog ids whose requests touched it, most recent first. */
|
|
2292
2471
|
routes: string[];
|
|
2472
|
+
/** Its latest uses, newest first (at most 20): when, how often in that second, the bytes, and the flow and request. */
|
|
2473
|
+
uses?: DashFileUse[];
|
|
2474
|
+
}
|
|
2475
|
+
/** One use of a path: a second of the fs tap's aggregate, for one flow. */
|
|
2476
|
+
export interface DashFileUse {
|
|
2477
|
+
at: number;
|
|
2478
|
+
n: number;
|
|
2479
|
+
bytes: number;
|
|
2480
|
+
flowId?: string;
|
|
2481
|
+
requestId?: string;
|
|
2482
|
+
}
|
|
2483
|
+
/**
|
|
2484
|
+
* `/api/files/read?path=` — a path the services touched, as it is on disk now (read-only). `content=1` adds its first
|
|
2485
|
+
* 64 KB of text, redacted — never a file named like a secret (`.env`, keys, certificates), never a binary, and only on a
|
|
2486
|
+
* loopback-bound dashboard.
|
|
2487
|
+
*/
|
|
2488
|
+
export interface DashFileRead {
|
|
2489
|
+
path: string;
|
|
2490
|
+
/** Where it was looked for: the workspace root joined with `path`. */
|
|
2491
|
+
resolved: string;
|
|
2492
|
+
exists: boolean;
|
|
2493
|
+
kind?: 'file' | 'directory' | 'other';
|
|
2494
|
+
bytes?: number;
|
|
2495
|
+
modifiedAt?: number;
|
|
2496
|
+
createdAt?: number;
|
|
2497
|
+
/** Why it was not read, when it was not (outside the workspace, a secret's name, binary, not loopback). */
|
|
2498
|
+
refused?: string;
|
|
2499
|
+
/** Present when asked for and readable. */
|
|
2500
|
+
content?: {
|
|
2501
|
+
text: string;
|
|
2502
|
+
truncated: boolean;
|
|
2503
|
+
redacted: boolean;
|
|
2504
|
+
lines: number;
|
|
2505
|
+
};
|
|
2506
|
+
/** A directory's first entries. */
|
|
2507
|
+
entries?: Array<{
|
|
2508
|
+
name: string;
|
|
2509
|
+
kind: 'file' | 'directory' | 'other';
|
|
2510
|
+
}>;
|
|
2293
2511
|
}
|
|
2294
2512
|
/** `/api/catalog/files` — every path the services read or wrote, newest first, kept 30 days. */
|
|
2295
2513
|
export interface DashFiles {
|
|
@@ -2604,8 +2822,9 @@ export interface DashDbPrep {
|
|
|
2604
2822
|
/** One thing an agent did through the lens: a tool call, a resource read, what it said it is doing. */
|
|
2605
2823
|
export interface DashAgentEvent {
|
|
2606
2824
|
at: number;
|
|
2607
|
-
|
|
2608
|
-
|
|
2825
|
+
/** `ask`: a prompt the person gave it (the Claude Code plugin's hook) — `result` holds its first line. */
|
|
2826
|
+
kind: 'tool' | 'read' | 'say' | 'ask';
|
|
2827
|
+
/** The tool or the resource URI; `agent.task` for `say`; `prompt` for `ask`. */
|
|
2609
2828
|
name: string;
|
|
2610
2829
|
/** Its arguments, redacted, as JSON (at most 2 KB). */
|
|
2611
2830
|
args?: string;
|
|
@@ -2635,6 +2854,12 @@ export interface DashAgentSession {
|
|
|
2635
2854
|
task?: string;
|
|
2636
2855
|
step?: string;
|
|
2637
2856
|
saidAt?: number;
|
|
2857
|
+
/**
|
|
2858
|
+
* What the person last asked it — the prompt's first line, recorded by the LensMCP Claude Code plugin's
|
|
2859
|
+
* `UserPromptSubmit` hook, so a session shows its task even when the agent never calls `agent.task`.
|
|
2860
|
+
*/
|
|
2861
|
+
asked?: string;
|
|
2862
|
+
askedAt?: number;
|
|
2638
2863
|
conn: {
|
|
2639
2864
|
transport: string;
|
|
2640
2865
|
/** The lens server's pid, and the shim's (the `lensmcp mcp` process the client started), when it said. */
|
package/lib/dashboard.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export const DASHBOARD_PROTOCOL=1,DASH_PERF_KINDS=["n-plus-one","db-in-loop","render-storm","slow-path","slow-route","slow-query","missing-index","leak","egress-slow","duplicate-requests","perf-rule","other"];
|
|
1
|
+
"use strict";export const DASHBOARD_PROTOCOL=1,DASH_PERF_KINDS=["n-plus-one","db-in-loop","render-storm","slow-path","slow-route","slow-query","missing-index","leak","egress-slow","duplicate-requests","perf-rule","db-connection","other"],DASH_AI_TRIGGERS=["auto","click","agent"];
|
package/lib/error-dismissal.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var s=(t,r)=>f(t,"name",{value:r,configurable:!0});var E=Object.defineProperty,S=s((t,r)=>E(t,"name",{value:r,configurable:!0}),"s");export const ERROR_DISMISSED="error-dismissed",ERROR_RESTORED="error-restored",LENS_EVENT_SOURCE="lens",MAX_DISMISSAL_EVENT_IDS=200;const g=2048;export const MAX_DISMISSAL_REASON_CHARS=500;const m=300,I=new Set(["dashboard","cli","agent"]);export function readErrorDismissal(t){if(t.source!==LENS_EVENT_SOURCE||!t.raw||typeof t.raw!="object")return;const r=t.raw,i=r.groupId;if(typeof i!="string"||i.length===0||i.length>2048)return;if(r.kind===ERROR_RESTORED)return{kind:ERROR_RESTORED,groupId:i};if(r.kind!==ERROR_DISMISSED)return;const n=r.until;if(typeof n!="number"||!Number.isFinite(n))return;const c=Array.isArray(r.eventIds)?r.eventIds.filter(e=>typeof e=="string"&&e.length>0).slice(0,200):[],o=I.has(r.by)?r.by:void 0,a=S((e,l)=>typeof e=="string"&&e.trim()?e.trim().slice(0,l):void 0,"text"),d=a(r.reason,500),u=a(r.title,300);return{kind:ERROR_DISMISSED,groupId:i,until:Math.min(n,t.timestamp),eventIds:c,...o?{by:o}:{},...d?{reason:d}:{},...u?{title:u}:{}}}s(readErrorDismissal,"readErrorDismissal"),S(readErrorDismissal,"readErrorDismissal");
|
package/lib/flood-guard.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var S=Object.defineProperty;var i=(t,
|
|
1
|
+
"use strict";var S=Object.defineProperty;var i=(t,n)=>S(t,"name",{value:n,configurable:!0});var m=Object.defineProperty,u=i((t,n)=>m(t,"name",{value:n,configurable:!0}),"o");function d(){const t=typeof process<"u"?process.env?.LENSMCP_EVENT_MAX_EPS:void 0;if(t===void 0||t==="")return;if(t==="off")return"off";const n=Number(t);if(Number.isFinite(n))return n<=0?"off":n}i(d,"S"),u(d,"envPerSec");export function createEventFloodGuard(t){const n=t?.envOverride===!1?void 0:d();if(n==="off")return{admit:u(()=>({ok:!0,suppressed:0}),"admit")};const l=n??t?.perSec??5,f=Math.max(1,t?.burst??Math.max(30,l*4)),c=t?.maxKeys??2048,r=new Map,p=u(o=>{for(const[s,e]of r)o-e.lastSeenAt>6e4&&r.delete(s);if(r.size>c){const s=[...r.entries()].sort((e,a)=>e[1].lastSeenAt-a[1].lastSeenAt);for(let e=0;e<s.length>>1;e++)r.delete(s[e][0])}},"evictStale");return{admit(o){const s=Date.now();let e=r.get(o);e||(r.size>=c&&p(s),e={tokens:f,lastRefillAt:s,suppressed:0,lastSeenAt:s},r.set(o,e)),e.lastSeenAt=s;const a=s-e.lastRefillAt;if(a>0&&(e.tokens=Math.min(f,e.tokens+a/1e3*l),e.lastRefillAt=s),e.tokens>=1){e.tokens-=1;const v=e.suppressed;return e.suppressed=0,{ok:!0,suppressed:v}}return e.suppressed+=1,{ok:!1,suppressed:0}}}}i(createEventFloodGuard,"createEventFloodGuard"),u(createEventFloodGuard,"createEventFloodGuard");
|
package/lib/log-query.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var m=Object.defineProperty;var a=(e,r)=>m(e,"name",{value:r,configurable:!0});var L=Object.defineProperty,c=a((e,r)=>L(e,"name",{value:r,configurable:!0}),"c");const d={level:"level",severity:"level",service:"service",svc:"service",src:"service",source:"service",flow:"flow",trace:"trace",request:"trace",category:"category",cat:"category",ms:"ms"},h={warn:"warning",err:"error"},p=/(-?)(?:([A-Za-z]+):)?(?:"([^"]*)"|(\S+))/g;export function parseLogQuery(e){const r=[],t=[];for(const s of e.matchAll(p)){const[o,n,f,w,g]=s,u=(w??g??"").trim(),i=f?d[f.toLowerCase()]:void 0;if(i&&u){const y=i==="level"?h[u.toLowerCase()]??u.toLowerCase():u;r.push({key:i,value:y,negate:n==="-"})}else o.trim()&&t.push(o.trim())}return{tokens:r,text:t.join(" ")}}a(parseLogQuery,"parseLogQuery"),c(parseLogQuery,"parseLogQuery");export function formatLogQuery(e){const r=c(t=>/\s/.test(t)?`"${t}"`:t,"quote");return[...e.tokens.map(t=>`${t.negate?"-":""}${t.key}:${r(t.value)}`),e.text].filter(Boolean).join(" ")}a(formatLogQuery,"formatLogQuery"),c(formatLogQuery,"formatLogQuery");function v(e,r){if(e===void 0)return!1;const t=/^(>=|<=|>|<|=)?\s*(\d+(?:\.\d+)?)$/.exec(r);if(!t)return!1;const s=Number(t[2]);switch(t[1]){case">":return e>s;case"<":return e<s;case"<=":return e<=s;case"=":return e===s;default:return e>=s}}a(v,"h"),c(v,"msMatches");function l(e,r){const t=r.value.toLowerCase();switch(r.key){case"level":return e.severity.toLowerCase()===t;case"service":return e.source.toLowerCase()===t;case"flow":return!!e.flowId&&e.flowId.toLowerCase().startsWith(t);case"trace":return!!e.requestId&&e.requestId.toLowerCase().startsWith(t);case"category":return e.category.toLowerCase()===t;case"ms":return v(e.durationMs,r.value)}}a(l,"i"),c(l,"tokenMatches");export function matchesLogQuery(e,r,t){const s=new Map;for(const o of r.tokens){if(o.negate){if(l(e,o))return!1;continue}const n=s.get(o.key);n?n.push(o):s.set(o.key,[o])}for(const o of s.values())if(!o.some(n=>l(e,n)))return!1;if(r.text){const o=`${e.title} ${e.message??""} ${e.source} ${e.flowId??""}`;return t?t(o):o.toLowerCase().includes(r.text.toLowerCase())}return!0}a(matchesLogQuery,"matchesLogQuery"),c(matchesLogQuery,"matchesLogQuery");
|
package/lib/perf-rules.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var o=(r,e)=>u(r,"name",{value:e,configurable:!0});var c=Object.defineProperty,a=o((r,e)=>c(r,"name",{value:e,configurable:!0}),"o");export const PERF_RULE_IDS=["bundle/heavy-barrel-import","pod/heap-budget","pod/retained-generation"],PERF_RULE_EVENT_KINDS=["perf-rule-finding","perf-rule-retracted","perf-rule-scan"],PERF_RULES_DOC="https://github.com/kiwiapps-ltd/lensmcp/blob/main/docs/lensmcp/concepts/memory-and-build-cost.mdx",PERF_RULE_DOCS={"bundle/heavy-barrel-import":`${PERF_RULES_DOC}#bundleheavy-barrel-import`,"pod/heap-budget":`${PERF_RULES_DOC}#podheap-budget`,"pod/retained-generation":`${PERF_RULES_DOC}#podretained-generation`};export function perfRuleFingerprint(r,e,n){return`perf-rule:${r}:${e}:${n}`}o(perfRuleFingerprint,"perfRuleFingerprint"),a(perfRuleFingerprint,"perfRuleFingerprint");export function perfRuleScanFingerprint(r,e){return`perf-rule-scan:${r}:${e}`}o(perfRuleScanFingerprint,"perfRuleScanFingerprint"),a(perfRuleScanFingerprint,"perfRuleScanFingerprint");const s=/^[a-z][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/,l=12,f=4e3,t=a((r,e=f)=>typeof r=="string"&&r.length>0&&r.length<=e,"isText");export function asPerfRuleRaw(r){if(!r||typeof r!="object")return;const e=r;if(!PERF_RULE_EVENT_KINDS.includes(e.kind)||typeof e.rule!="string"||!s.test(e.rule)||!t(e.project,512))return;if(e.kind==="perf-rule-scan"){const i=e.open;return!Array.isArray(i)||i.length>256||!i.every(p=>t(p,512))?void 0:r}if(!t(e.subject,512))return;if(e.kind==="perf-rule-retracted")return r;if(e.severity!=="warning"&&e.severity!=="error"||!t(e.title)||!t(e.summary)||!t(e.verify)||!t(e.docs,1024))return;const n=e.fix;if(!(!Array.isArray(n)||n.length===0||n.length>l||!n.every(i=>t(i)))&&!(!e.evidence||typeof e.evidence!="object"||Array.isArray(e.evidence))&&!(!e.cost||typeof e.cost!="object"||Array.isArray(e.cost)))return r}o(asPerfRuleRaw,"asPerfRuleRaw"),a(asPerfRuleRaw,"asPerfRuleRaw");
|
package/lib/pod-memory.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var t=Object.defineProperty;var r=(o,e)=>t(o,"name",{value:e,configurable:!0});var d=Object.defineProperty,m=r((o,e)=>d(o,"name",{value:e,configurable:!0}),"r");export const POD_MEMORY_KINDS=["pod-memory","pod-memory-retained","pod-memory-released","pod-memory-exited"];export function asPodMemoryRaw(o){if(!o||typeof o!="object")return;const e=o;if(POD_MEMORY_KINDS.includes(e.kind)&&!(typeof e.project!="string"||!e.project)&&!(typeof e.pod!="number"||typeof e.pid!="number")&&!(e.kind==="pod-memory"&&(typeof e.live!="number"||!Number.isFinite(e.live)))&&!((e.kind==="pod-memory-retained"||e.kind==="pod-memory-released")&&typeof e.gen!="number"))return o}r(asPodMemoryRaw,"asPodMemoryRaw"),m(asPodMemoryRaw,"asPodMemoryRaw");
|
package/lib/producer-health.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var m=Object.defineProperty;var i=(t,o)=>m(t,"name",{value:o,configurable:!0});var R=Object.defineProperty,p=i((t,o)=>R(t,"name",{value:o,configurable:!0}),"u");import{z as e}from"zod";export const ProducerStateSchema=e.enum(["none","connected"]),ProducerRunStatusSchema=e.enum(["running","clean","failing","error"]),ProducerReportSchema=e.object({id:e.string(),tool:e.string(),project:e.string().optional(),firstReportedAt:e.number().int().nonnegative(),lastReportedAt:e.number().int().nonnegative(),lastRunStatus:ProducerRunStatusSchema,lastRunDurationMs:e.number().int().nonnegative().optional(),errorCount:e.number().int().nonnegative(),warningCount:e.number().int().nonnegative().optional(),error:e.string().optional()}),ProducerHealthSchema=e.object({producer:ProducerStateSchema,producers:e.array(ProducerReportSchema),lastReportedAt:e.number().int().nonnegative().optional(),ageMs:e.number().int().nonnegative().optional(),stale:e.boolean(),detail:e.string()}),PRODUCER_STALE_AFTER_MS=10*6e4;export function summariseProducers(t){const o=t.now??Date.now(),n=[...t.producers].sort((r,h)=>h.lastReportedAt-r.lastReportedAt);if(n.length===0)return{producer:"none",producers:[],stale:!1,detail:`No ${t.domain} producer has ever reported into this session \u2014 this is NOT a clean result, nothing is watching. ${t.noProducerHint}`};const d=n[0].lastReportedAt,u=Math.max(0,o-d),l=u>PRODUCER_STALE_AFTER_MS,c=n.filter(r=>r.lastRunStatus==="failing"),s=n.filter(r=>r.lastRunStatus==="error"),a=[`${n.length} ${t.domain} producer${n.length===1?"":"s"} reporting (${n.map(r=>r.id).join(", ")}); newest report ${g(u)}.`];return s.length>0&&a.push(`${s.length} produced NO verdict (the tool itself failed): ${s.map(r=>`${r.id} \u2014 ${r.error??"unknown error"}`).join("; ")}.`),c.length>0&&a.push(`${c.length} reporting errors.`),l&&a.push(`Older than ${Math.round(PRODUCER_STALE_AFTER_MS/6e4)}m \u2014 the verdict may predate the current source.`),{producer:"connected",producers:n,lastReportedAt:d,ageMs:u,stale:l,detail:a.join(" ")}}i(summariseProducers,"summariseProducers"),p(summariseProducers,"summariseProducers");function g(t){return t<1e3?"just now":t<6e4?`${Math.round(t/1e3)}s ago`:t<36e5?`${Math.round(t/6e4)}m ago`:`${Math.round(t/36e5)}h ago`}i(g,"g"),p(g,"describeAge");
|