context-lens 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +120 -25
  2. package/dist/cli-utils.d.ts +2 -1
  3. package/dist/cli-utils.d.ts.map +1 -1
  4. package/dist/cli-utils.js +40 -13
  5. package/dist/cli-utils.js.map +1 -1
  6. package/dist/cli.js +184 -68
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/conversation.d.ts +63 -0
  9. package/dist/core/conversation.d.ts.map +1 -0
  10. package/dist/core/conversation.js +305 -0
  11. package/dist/core/conversation.js.map +1 -0
  12. package/dist/core/health.d.ts +7 -0
  13. package/dist/core/health.d.ts.map +1 -0
  14. package/dist/core/health.js +311 -0
  15. package/dist/core/health.js.map +1 -0
  16. package/dist/core/models.d.ts +36 -0
  17. package/dist/core/models.d.ts.map +1 -0
  18. package/dist/core/models.js +111 -0
  19. package/dist/core/models.js.map +1 -0
  20. package/dist/core/parse.d.ts +17 -0
  21. package/dist/core/parse.d.ts.map +1 -0
  22. package/dist/core/parse.js +349 -0
  23. package/dist/core/parse.js.map +1 -0
  24. package/dist/core/routing.d.ts +47 -0
  25. package/dist/core/routing.d.ts.map +1 -0
  26. package/dist/core/routing.js +132 -0
  27. package/dist/core/routing.js.map +1 -0
  28. package/dist/core/security.d.ts +8 -0
  29. package/dist/core/security.d.ts.map +1 -0
  30. package/dist/core/security.js +222 -0
  31. package/dist/core/security.js.map +1 -0
  32. package/dist/core/source.d.ts +22 -0
  33. package/dist/core/source.d.ts.map +1 -0
  34. package/dist/core/source.js +56 -0
  35. package/dist/core/source.js.map +1 -0
  36. package/dist/core/tokens.d.ts +29 -0
  37. package/dist/core/tokens.d.ts.map +1 -0
  38. package/dist/core/tokens.js +163 -0
  39. package/dist/core/tokens.js.map +1 -0
  40. package/dist/core.d.ts +14 -22
  41. package/dist/core.d.ts.map +1 -1
  42. package/dist/core.js +14 -471
  43. package/dist/core.js.map +1 -1
  44. package/dist/http/headers.d.ts +25 -0
  45. package/dist/http/headers.d.ts.map +1 -0
  46. package/dist/http/headers.js +54 -0
  47. package/dist/http/headers.js.map +1 -0
  48. package/dist/lhar/composition.d.ts +12 -0
  49. package/dist/lhar/composition.d.ts.map +1 -0
  50. package/dist/lhar/composition.js +258 -0
  51. package/dist/lhar/composition.js.map +1 -0
  52. package/dist/lhar/export.d.ts +5 -0
  53. package/dist/lhar/export.d.ts.map +1 -0
  54. package/dist/lhar/export.js +59 -0
  55. package/dist/lhar/export.js.map +1 -0
  56. package/dist/lhar/record.d.ts +6 -0
  57. package/dist/lhar/record.d.ts.map +1 -0
  58. package/dist/lhar/record.js +216 -0
  59. package/dist/lhar/record.js.map +1 -0
  60. package/dist/lhar/response.d.ts +11 -0
  61. package/dist/lhar/response.d.ts.map +1 -0
  62. package/dist/lhar/response.js +132 -0
  63. package/dist/lhar/response.js.map +1 -0
  64. package/dist/lhar-types.generated.d.ts +24 -3
  65. package/dist/lhar-types.generated.d.ts.map +1 -1
  66. package/dist/lhar.d.ts +12 -19
  67. package/dist/lhar.d.ts.map +1 -1
  68. package/dist/lhar.js +16 -473
  69. package/dist/lhar.js.map +1 -1
  70. package/dist/server/api.d.ts +8 -0
  71. package/dist/server/api.d.ts.map +1 -0
  72. package/dist/server/api.js +292 -0
  73. package/dist/server/api.js.map +1 -0
  74. package/dist/server/config.d.ts +13 -0
  75. package/dist/server/config.d.ts.map +1 -0
  76. package/dist/server/config.js +36 -0
  77. package/dist/server/config.js.map +1 -0
  78. package/dist/server/projection.d.ts +9 -0
  79. package/dist/server/projection.d.ts.map +1 -0
  80. package/dist/server/projection.js +47 -0
  81. package/dist/server/projection.js.map +1 -0
  82. package/dist/server/proxy.d.ts +13 -0
  83. package/dist/server/proxy.d.ts.map +1 -0
  84. package/dist/server/proxy.js +218 -0
  85. package/dist/server/proxy.js.map +1 -0
  86. package/dist/server/static.d.ts +9 -0
  87. package/dist/server/static.d.ts.map +1 -0
  88. package/dist/server/static.js +78 -0
  89. package/dist/server/static.js.map +1 -0
  90. package/dist/server/store.d.ts +81 -0
  91. package/dist/server/store.d.ts.map +1 -0
  92. package/dist/server/store.js +632 -0
  93. package/dist/server/store.js.map +1 -0
  94. package/dist/server/webui.d.ts +5 -0
  95. package/dist/server/webui.d.ts.map +1 -0
  96. package/dist/server/webui.js +42 -0
  97. package/dist/server/webui.js.map +1 -0
  98. package/dist/server-utils.d.ts +2 -2
  99. package/dist/server-utils.d.ts.map +1 -1
  100. package/dist/server-utils.js +12 -21
  101. package/dist/server-utils.js.map +1 -1
  102. package/dist/server.js +31 -697
  103. package/dist/server.js.map +1 -1
  104. package/dist/types.d.ts +94 -10
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/version.generated.d.ts +2 -0
  107. package/dist/version.generated.d.ts.map +1 -0
  108. package/dist/version.generated.js +2 -0
  109. package/dist/version.generated.js.map +1 -0
  110. package/findings-screenshot.png +0 -0
  111. package/messages-screenshot.png +0 -0
  112. package/package.json +23 -10
  113. package/schema/lhar.schema.json +58 -4
  114. package/screenshot-overview.png +0 -0
  115. package/sessions-screenshot.png +0 -0
  116. package/timeline-screenshot.png +0 -0
  117. package/diff.png +0 -0
  118. package/overview-sidebar.png +0 -0
  119. package/public/index.html +0 -2804
@@ -0,0 +1,305 @@
1
+ import { createHash } from "node:crypto";
2
+ /**
3
+ * Extract readable text from message content.
4
+ *
5
+ * This is used for labels/fingerprints where we want the "real" prompt text, not wrappers.
6
+ * It understands a few common JSON wrappers used by tool APIs.
7
+ *
8
+ * @param content - Raw message content (string, often JSON-encoded).
9
+ * @returns A trimmed text string or `null` if no readable text exists.
10
+ */
11
+ export function extractReadableText(content) {
12
+ if (!content)
13
+ return null;
14
+ let text = content;
15
+ try {
16
+ const parsed = JSON.parse(text);
17
+ if (Array.isArray(parsed)) {
18
+ const textBlock = parsed.find((b) => (b.type === "text" &&
19
+ b.text &&
20
+ !b.text.startsWith("<system-reminder>")) ||
21
+ (b.type === "input_text" &&
22
+ b.text &&
23
+ !b.text.startsWith("#") &&
24
+ !b.text.startsWith("<environment")));
25
+ if (textBlock)
26
+ text = textBlock.text;
27
+ }
28
+ }
29
+ catch {
30
+ // Expected: input may not be valid JSON; fall through to raw text
31
+ }
32
+ text = text.replace(/\s+/g, " ").trim();
33
+ return text || null;
34
+ }
35
+ /**
36
+ * Extract the working directory from captured content when a tool embeds it.
37
+ *
38
+ * Supports:
39
+ * - Claude Code: "Primary working directory: `/path`"
40
+ * - Codex: "<cwd>/path</cwd>"
41
+ * - Generic: "working directory is /path" or "cwd: /path"
42
+ */
43
+ export function extractWorkingDirectory(contextInfo, rawBody) {
44
+ const allText = [
45
+ ...(contextInfo.systemPrompts || []).map((sp) => sp.content),
46
+ ...(contextInfo.messages || [])
47
+ .filter((m) => m.role === "user")
48
+ .map((m) => m.content),
49
+ ].join("\n");
50
+ let match = allText.match(/[Pp]rimary working directory[:\s]+[`]?([/~][^\s`\n]+)/);
51
+ if (match)
52
+ return match[1];
53
+ match = allText.match(/<cwd>([^<]+)<\/cwd>/);
54
+ if (match)
55
+ return match[1];
56
+ // Generic: "working directory is /path" or "working directory = /path"
57
+ match = allText.match(/working directory (?:is |= ?)[`"]?([/~][^\s`"'\n]+)/i);
58
+ if (match)
59
+ return match[1];
60
+ // Generic: "working directory: /path" or "working directory /path"
61
+ match = allText.match(/working directory[:\s]+[`"]?([/~][^\s`"'\n]+)/i);
62
+ if (match)
63
+ return match[1];
64
+ match = allText.match(/\bcwd[:\s]+[`"]?([/~][^\s`"'\n]+)/);
65
+ if (match)
66
+ return match[1];
67
+ // Structured payload fallback (Gemini Code Assist and similar tools may
68
+ // carry cwd in JSON fields instead of prompt text).
69
+ const fromBody = findWorkingDirectoryInObject(rawBody ?? null);
70
+ if (fromBody)
71
+ return fromBody;
72
+ return null;
73
+ }
74
+ /**
75
+ * Normalize and validate string values that might represent filesystem paths.
76
+ */
77
+ function toPathCandidate(value) {
78
+ if (typeof value !== "string")
79
+ return null;
80
+ const trimmed = value.trim().replace(/^['"`]|['"`]$/g, "");
81
+ if (!trimmed)
82
+ return null;
83
+ // Accept POSIX, home-relative, or Windows absolute paths.
84
+ if (/^(\/|~\/|[A-Za-z]:[\\/])/.test(trimmed))
85
+ return trimmed;
86
+ return null;
87
+ }
88
+ /**
89
+ * Recursive search for cwd-like fields in structured request payloads.
90
+ *
91
+ * Traversal is depth-limited and prioritizes common wrapper keys first to
92
+ * find useful candidates quickly before falling back to a full walk.
93
+ */
94
+ function findWorkingDirectoryInObject(node, depth = 0) {
95
+ if (!node || depth > 8)
96
+ return null;
97
+ if (Array.isArray(node)) {
98
+ for (const item of node) {
99
+ const found = findWorkingDirectoryInObject(item, depth + 1);
100
+ if (found)
101
+ return found;
102
+ }
103
+ return null;
104
+ }
105
+ if (typeof node !== "object")
106
+ return null;
107
+ const obj = node;
108
+ const preferredKeys = [
109
+ "workingDirectory",
110
+ "currentWorkingDirectory",
111
+ "working_directory",
112
+ "current_working_directory",
113
+ "cwd",
114
+ "workdir",
115
+ "workspaceRoot",
116
+ "workspace_root",
117
+ "projectRoot",
118
+ "project_root",
119
+ "rootDir",
120
+ "root_dir",
121
+ "sandboxCwd",
122
+ "sandbox_cwd",
123
+ ];
124
+ for (const key of preferredKeys) {
125
+ const candidate = toPathCandidate(obj[key]);
126
+ if (candidate)
127
+ return candidate;
128
+ }
129
+ // Check common wrapper objects first.
130
+ const wrappers = [
131
+ "request",
132
+ "context",
133
+ "environment",
134
+ "session",
135
+ "workspace",
136
+ "project",
137
+ "config",
138
+ "client",
139
+ "agent",
140
+ "metadata",
141
+ ];
142
+ for (const key of wrappers) {
143
+ if (key in obj) {
144
+ const found = findWorkingDirectoryInObject(obj[key], depth + 1);
145
+ if (found)
146
+ return found;
147
+ }
148
+ }
149
+ // Generic fallback: key names that strongly imply cwd.
150
+ for (const [key, value] of Object.entries(obj)) {
151
+ if (/(^|_)(cwd|workdir|working_?directory|workspace_?root|project_?root|root_dir|sandbox_?cwd)$/i.test(key)) {
152
+ const candidate = toPathCandidate(value);
153
+ if (candidate)
154
+ return candidate;
155
+ }
156
+ }
157
+ // Last resort recursive walk over remaining fields.
158
+ for (const value of Object.values(obj)) {
159
+ const found = findWorkingDirectoryInObject(value, depth + 1);
160
+ if (found)
161
+ return found;
162
+ }
163
+ return null;
164
+ }
165
+ /**
166
+ * For OpenAI Responses-style input arrays, extract the first "real" user prompt.
167
+ *
168
+ * Skips boilerplate blocks (AGENTS.md / environment wrappers).
169
+ */
170
+ export function extractUserPrompt(messages) {
171
+ for (const m of messages) {
172
+ if (m.role !== "user" || !m.content)
173
+ continue;
174
+ try {
175
+ const parsed = JSON.parse(m.content);
176
+ if (Array.isArray(parsed) &&
177
+ parsed[0] &&
178
+ parsed[0].type === "input_text") {
179
+ const text = parsed[0].text || "";
180
+ if (text.startsWith("#") || text.startsWith("<environment"))
181
+ continue;
182
+ return m.content;
183
+ }
184
+ }
185
+ catch {
186
+ // Expected: content may not be valid JSON; skip this message
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+ /**
192
+ * Extract a stable session identifier when the upstream/tool provides one.
193
+ *
194
+ * Supported:
195
+ * - Anthropic: `metadata.user_id` contains `session_<uuid>`
196
+ * - Gemini Code Assist: `request.session_id` (uuid)
197
+ */
198
+ export function extractSessionId(rawBody) {
199
+ const userId = rawBody?.metadata?.user_id;
200
+ if (userId) {
201
+ const match = userId.match(/session_([a-f0-9-]+)/);
202
+ if (match)
203
+ return match[0];
204
+ }
205
+ const geminiSessionId = rawBody?.request?.session_id;
206
+ if (geminiSessionId && typeof geminiSessionId === "string")
207
+ return `gemini_${geminiSessionId}`;
208
+ return null;
209
+ }
210
+ /**
211
+ * Compute a sub-key to distinguish agents within a session (main vs subagents).
212
+ *
213
+ * Currently derived from the first readable user message.
214
+ */
215
+ export function computeAgentKey(contextInfo) {
216
+ const userMsgs = (contextInfo.messages || []).filter((m) => m.role === "user");
217
+ let realText = "";
218
+ for (const msg of userMsgs) {
219
+ const t = extractReadableText(msg.content);
220
+ if (t) {
221
+ realText = t;
222
+ break;
223
+ }
224
+ }
225
+ if (!realText)
226
+ return null;
227
+ return createHash("sha256").update(realText).digest("hex").slice(0, 12);
228
+ }
229
+ /**
230
+ * Compute a conversation fingerprint for grouping.
231
+ *
232
+ * Priority:
233
+ * 1. explicit session IDs (most stable)
234
+ * 2. Responses API chaining (`previous_response_id`)
235
+ * 3. content hash of system + first prompt
236
+ */
237
+ export function computeFingerprint(contextInfo, rawBody, responseIdToConvo) {
238
+ const sessionId = extractSessionId(rawBody);
239
+ if (sessionId) {
240
+ return createHash("sha256").update(sessionId).digest("hex").slice(0, 16);
241
+ }
242
+ if (rawBody?.previous_response_id && responseIdToConvo) {
243
+ const existing = responseIdToConvo.get(rawBody.previous_response_id);
244
+ if (existing)
245
+ return existing;
246
+ }
247
+ const userMsgs = (contextInfo.messages || []).filter((m) => m.role === "user");
248
+ let promptText;
249
+ if (contextInfo.apiFormat === "responses" && userMsgs.length > 1) {
250
+ promptText = extractUserPrompt(userMsgs) || "";
251
+ }
252
+ else {
253
+ const firstUser = userMsgs[0];
254
+ promptText = firstUser ? firstUser.content : "";
255
+ }
256
+ const systemText = (contextInfo.systemPrompts || [])
257
+ .map((sp) => sp.content)
258
+ .join("\n");
259
+ if (!systemText && !promptText)
260
+ return null;
261
+ return createHash("sha256")
262
+ .update(`${systemText}\0${promptText}`)
263
+ .digest("hex")
264
+ .slice(0, 16);
265
+ }
266
+ /**
267
+ * Extract a readable label for a conversation, primarily for UI display.
268
+ */
269
+ export function extractConversationLabel(contextInfo) {
270
+ const userMsgs = (contextInfo.messages || []).filter((m) => m.role === "user");
271
+ if (contextInfo.apiFormat === "responses" && userMsgs.length > 1) {
272
+ const prompt = extractUserPrompt(userMsgs);
273
+ const text = extractReadableText(prompt);
274
+ if (text)
275
+ return text.length > 80 ? `${text.slice(0, 77)}...` : text;
276
+ }
277
+ for (let i = userMsgs.length - 1; i >= 0; i--) {
278
+ const text = extractReadableText(userMsgs[i].content);
279
+ if (text)
280
+ return text.length > 80 ? `${text.slice(0, 77)}...` : text;
281
+ }
282
+ return "Unnamed conversation";
283
+ }
284
+ /**
285
+ * Extract all tool names used in a conversation's messages.
286
+ *
287
+ * Scans content blocks for tool_use blocks and collects their names.
288
+ *
289
+ * @param messages - Array of messages from one or more entries.
290
+ * @returns Set of tool names that were used.
291
+ */
292
+ export function extractToolsUsed(messages) {
293
+ const toolsUsed = new Set();
294
+ for (const msg of messages) {
295
+ if (msg.contentBlocks) {
296
+ for (const block of msg.contentBlocks) {
297
+ if (block.type === "tool_use" && "name" in block && block.name) {
298
+ toolsUsed.add(block.name);
299
+ }
300
+ }
301
+ }
302
+ }
303
+ return toolsUsed;
304
+ }
305
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/core/conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { CompositionEntry, ContextInfo, HealthScore } from "../types.js";
2
+ export declare function computeHealthScore(entry: {
3
+ contextInfo: ContextInfo;
4
+ contextLimit: number;
5
+ composition: CompositionEntry[];
6
+ }, previousEntryTokens: number | null, sessionToolsUsed: Set<string>, turnCount: number): HealthScore;
7
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EAEX,WAAW,EAGZ,MAAM,aAAa,CAAC;AA+UrB,wBAAgB,kBAAkB,CAChC,KAAK,EAAE;IACL,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC,EACD,mBAAmB,EAAE,MAAM,GAAG,IAAI,EAClC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC7B,SAAS,EAAE,MAAM,GAChB,WAAW,CA0Eb"}
@@ -0,0 +1,311 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Linear interpolation helper
3
+ // ---------------------------------------------------------------------------
4
+ /**
5
+ * Given a sorted array of [threshold, score] breakpoints, linearly interpolate
6
+ * a score for the given value. Values below the first breakpoint get its score;
7
+ * values above the last get the last score.
8
+ */
9
+ function lerp(value, breakpoints) {
10
+ if (breakpoints.length === 0)
11
+ return 100;
12
+ if (value <= breakpoints[0][0])
13
+ return breakpoints[0][1];
14
+ if (value >= breakpoints[breakpoints.length - 1][0])
15
+ return breakpoints[breakpoints.length - 1][1];
16
+ for (let i = 0; i < breakpoints.length - 1; i++) {
17
+ const [x0, y0] = breakpoints[i];
18
+ const [x1, y1] = breakpoints[i + 1];
19
+ if (value >= x0 && value <= x1) {
20
+ const t = (value - x0) / (x1 - x0);
21
+ return Math.round(y0 + t * (y1 - y0));
22
+ }
23
+ }
24
+ return breakpoints[breakpoints.length - 1][1];
25
+ }
26
+ function totalCompositionTokens(composition) {
27
+ return composition.reduce((s, c) => s + c.tokens, 0);
28
+ }
29
+ function compositionCategoryTokens(composition, category) {
30
+ return composition.find((c) => c.category === category)?.tokens ?? 0;
31
+ }
32
+ function compositionCategoryPct(composition, category) {
33
+ return Math.round(composition.find((c) => c.category === category)?.pct ?? 0);
34
+ }
35
+ function largestToolResultTokens(messages) {
36
+ let largest = 0;
37
+ for (const m of messages) {
38
+ if (!m.contentBlocks)
39
+ continue;
40
+ for (const b of m.contentBlocks) {
41
+ if (b.type === "tool_result" && m.tokens > largest) {
42
+ largest = m.tokens;
43
+ }
44
+ }
45
+ }
46
+ return largest;
47
+ }
48
+ function definedToolNames(tools) {
49
+ const names = new Set();
50
+ for (const t of tools) {
51
+ const name = "name" in t
52
+ ? t.name
53
+ : "function" in t
54
+ ? t.function.name
55
+ : null;
56
+ if (name)
57
+ names.add(name);
58
+ }
59
+ return names;
60
+ }
61
+ function countUsedDefinedTools(sessionToolsUsed, definedNames) {
62
+ let usedCount = 0;
63
+ for (const name of sessionToolsUsed) {
64
+ if (definedNames.has(name))
65
+ usedCount++;
66
+ }
67
+ return usedCount;
68
+ }
69
+ // ---------------------------------------------------------------------------
70
+ // Audit 1: Context Utilization (weight 30)
71
+ // ---------------------------------------------------------------------------
72
+ function scoreUtilization(totalTokens, contextLimit) {
73
+ if (contextLimit <= 0)
74
+ return 100;
75
+ const pct = (totalTokens / contextLimit) * 100;
76
+ return lerp(pct, [
77
+ [50, 100],
78
+ [65, 90],
79
+ [75, 70],
80
+ [85, 45],
81
+ [95, 20],
82
+ [100, 5],
83
+ ]);
84
+ }
85
+ function describeUtilization(totalTokens, contextLimit) {
86
+ if (contextLimit <= 0)
87
+ return "No context limit known.";
88
+ const pct = Math.round((totalTokens / contextLimit) * 100);
89
+ if (pct <= 50)
90
+ return `Context ${pct}% full — plenty of room.`;
91
+ if (pct <= 75)
92
+ return `Context ${pct}% full — moderate usage.`;
93
+ if (pct <= 85)
94
+ return `Context ${pct}% full — approaching limit, compaction risk.`;
95
+ return `Context ${pct}% full — near overflow, compaction imminent.`;
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Audit 2: Tool Results Proportion (weight 25)
99
+ // ---------------------------------------------------------------------------
100
+ function scoreToolResults(composition, messages, utilizationPct) {
101
+ const totalTok = totalCompositionTokens(composition);
102
+ if (totalTok === 0)
103
+ return 100;
104
+ const toolResultTokens = compositionCategoryTokens(composition, "tool_results");
105
+ const aggPct = (toolResultTokens / totalTok) * 100;
106
+ const aggregateScore = lerp(aggPct, [
107
+ [30, 100],
108
+ [50, 80],
109
+ [65, 60],
110
+ [75, 35],
111
+ [76, 15],
112
+ ]);
113
+ // Find largest single tool result message
114
+ const largestResult = largestToolResultTokens(messages);
115
+ const largestScore = lerp(largestResult, [
116
+ [2000, 100],
117
+ [5000, 80],
118
+ [10000, 50],
119
+ [10001, 20],
120
+ ]);
121
+ const rawScore = Math.min(aggregateScore, largestScore);
122
+ // Context-dependent: tool results only matter when the window is filling up.
123
+ // Scale the penalty by how full the context is.
124
+ // At 0% util → full score (100), at 75%+ util → raw score, smooth blend between.
125
+ const utilizationFactor = Math.min(Math.max(utilizationPct / 75, 0), 1);
126
+ return Math.round(rawScore + (100 - rawScore) * (1 - utilizationFactor));
127
+ }
128
+ function describeToolResults(composition, messages, utilizationPct) {
129
+ const totalTok = totalCompositionTokens(composition);
130
+ if (totalTok === 0)
131
+ return "No context data.";
132
+ const pct = compositionCategoryPct(composition, "tool_results");
133
+ const largestResult = largestToolResultTokens(messages);
134
+ const largestK = largestResult > 1000
135
+ ? `${Math.round(largestResult / 1000)}K`
136
+ : `${largestResult}`;
137
+ const suffix = utilizationPct < 40
138
+ ? " Plenty of room."
139
+ : utilizationPct < 65
140
+ ? " Monitor as context grows."
141
+ : " Context is filling up.";
142
+ if (pct <= 30 && largestResult <= 2000)
143
+ return "Tool results are a small part of context.";
144
+ if (pct > 60)
145
+ return `Tool results are ${pct}% of context, largest ${largestK} tokens.${suffix}`;
146
+ if (largestResult > 5000)
147
+ return `Tool results are ${pct}% of context, largest ${largestK} tokens.${suffix}`;
148
+ return `Tool results are ${pct}% of context.${suffix}`;
149
+ }
150
+ // ---------------------------------------------------------------------------
151
+ // Audit 3: Tool Definition Efficiency (weight 20)
152
+ // ---------------------------------------------------------------------------
153
+ function scoreToolEfficiency(composition, tools, sessionToolsUsed, turnCount) {
154
+ const totalTok = totalCompositionTokens(composition);
155
+ if (totalTok === 0 || tools.length === 0)
156
+ return 100;
157
+ const toolDefTokens = compositionCategoryTokens(composition, "tool_definitions");
158
+ const overheadPct = (toolDefTokens / totalTok) * 100;
159
+ const overheadScore = lerp(overheadPct, [
160
+ [15, 100],
161
+ [25, 80],
162
+ [40, 50],
163
+ [41, 20],
164
+ ]);
165
+ // Compute usage ratio
166
+ const definedNames = definedToolNames(tools);
167
+ const totalDefined = definedNames.size || 1;
168
+ const usedCount = countUsedDefinedTools(sessionToolsUsed, definedNames);
169
+ const usageRatio = (usedCount / totalDefined) * 100;
170
+ let usageScore = lerp(usageRatio, [
171
+ [0, 30],
172
+ [10, 50],
173
+ [30, 80],
174
+ [50, 100],
175
+ ]);
176
+ // Early-turn floor: if turnCount ≤ 2, usage score ≥ 60
177
+ if (turnCount <= 2 && usageScore < 60) {
178
+ usageScore = 60;
179
+ }
180
+ return Math.round(0.6 * overheadScore + 0.4 * usageScore);
181
+ }
182
+ function describeToolEfficiency(composition, tools, sessionToolsUsed) {
183
+ const totalTok = totalCompositionTokens(composition);
184
+ if (totalTok === 0 || tools.length === 0)
185
+ return "No tool definitions.";
186
+ const pct = compositionCategoryPct(composition, "tool_definitions");
187
+ const definedNames = definedToolNames(tools);
188
+ const usedCount = countUsedDefinedTools(sessionToolsUsed, definedNames);
189
+ return `Tool definitions are ${pct}% of context. ${usedCount}/${definedNames.size} tools used in session.`;
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // Audit 4: Context Growth Rate (weight 15)
193
+ // ---------------------------------------------------------------------------
194
+ function scoreGrowthRate(currentTokens, previousTokens, contextLimit) {
195
+ if (previousTokens === null)
196
+ return 100; // first turn
197
+ // Compaction detected
198
+ if (currentTokens < previousTokens * 0.7)
199
+ return 40;
200
+ if (contextLimit <= 0)
201
+ return 100;
202
+ const growthPct = ((currentTokens - previousTokens) / contextLimit) * 100;
203
+ return lerp(growthPct, [
204
+ [5, 100],
205
+ [10, 85],
206
+ [20, 65],
207
+ [30, 40],
208
+ [31, 20],
209
+ ]);
210
+ }
211
+ function describeGrowthRate(currentTokens, previousTokens, contextLimit) {
212
+ if (previousTokens === null)
213
+ return "First turn — no growth data.";
214
+ if (currentTokens < previousTokens * 0.7)
215
+ return "Compaction detected — context was truncated or summarized.";
216
+ if (contextLimit <= 0)
217
+ return "Unknown context limit.";
218
+ const growthPct = Math.round(((currentTokens - previousTokens) / contextLimit) * 100);
219
+ if (growthPct <= 5)
220
+ return `Grew ${growthPct}% of limit — steady.`;
221
+ if (growthPct <= 20)
222
+ return `Grew ${growthPct}% of limit — moderate pace.`;
223
+ return `Grew ${growthPct}% of limit — rapid expansion.`;
224
+ }
225
+ // ---------------------------------------------------------------------------
226
+ // Audit 5: Thinking Overhead (weight 10)
227
+ // ---------------------------------------------------------------------------
228
+ function scoreThinking(composition) {
229
+ const totalTok = totalCompositionTokens(composition);
230
+ if (totalTok === 0)
231
+ return 100;
232
+ const thinkingPct = (compositionCategoryTokens(composition, "thinking") / totalTok) * 100;
233
+ return lerp(thinkingPct, [
234
+ [5, 100],
235
+ [10, 85],
236
+ [20, 60],
237
+ [30, 35],
238
+ [31, 15],
239
+ ]);
240
+ }
241
+ function describeThinking(composition) {
242
+ const totalTok = totalCompositionTokens(composition);
243
+ if (totalTok === 0)
244
+ return "No context data.";
245
+ const pct = compositionCategoryPct(composition, "thinking");
246
+ if (pct <= 5)
247
+ return "Thinking blocks are minimal.";
248
+ if (pct <= 15)
249
+ return `Thinking blocks are ${pct}% of context.`;
250
+ return `Thinking blocks are ${pct}% of context — significant hidden overhead.`;
251
+ }
252
+ // ---------------------------------------------------------------------------
253
+ // Public API
254
+ // ---------------------------------------------------------------------------
255
+ function ratingFromScore(score) {
256
+ if (score >= 90)
257
+ return "good";
258
+ if (score >= 50)
259
+ return "needs-work";
260
+ return "poor";
261
+ }
262
+ export function computeHealthScore(entry, previousEntryTokens, sessionToolsUsed, turnCount) {
263
+ const { contextInfo, contextLimit, composition } = entry;
264
+ const messages = contextInfo.messages || [];
265
+ const tools = contextInfo.tools || [];
266
+ const audits = [
267
+ {
268
+ id: "utilization",
269
+ name: "Context Utilization",
270
+ score: scoreUtilization(contextInfo.totalTokens, contextLimit),
271
+ weight: 30,
272
+ description: describeUtilization(contextInfo.totalTokens, contextLimit),
273
+ },
274
+ {
275
+ id: "tool-results",
276
+ name: "Tool Results",
277
+ score: scoreToolResults(composition, messages, contextLimit > 0 ? (contextInfo.totalTokens / contextLimit) * 100 : 0),
278
+ weight: 25,
279
+ description: describeToolResults(composition, messages, contextLimit > 0 ? (contextInfo.totalTokens / contextLimit) * 100 : 0),
280
+ },
281
+ {
282
+ id: "tool-defs",
283
+ name: "Tool Definitions",
284
+ score: scoreToolEfficiency(composition, tools, sessionToolsUsed, turnCount),
285
+ weight: 20,
286
+ description: describeToolEfficiency(composition, tools, sessionToolsUsed),
287
+ },
288
+ {
289
+ id: "growth",
290
+ name: "Growth Rate",
291
+ score: scoreGrowthRate(contextInfo.totalTokens, previousEntryTokens, contextLimit),
292
+ weight: 15,
293
+ description: describeGrowthRate(contextInfo.totalTokens, previousEntryTokens, contextLimit),
294
+ },
295
+ {
296
+ id: "thinking",
297
+ name: "Thinking Overhead",
298
+ score: scoreThinking(composition),
299
+ weight: 10,
300
+ description: describeThinking(composition),
301
+ },
302
+ ];
303
+ const totalWeight = audits.reduce((s, a) => s + a.weight, 0);
304
+ const overall = Math.round(audits.reduce((s, a) => s + a.score * a.weight, 0) / totalWeight);
305
+ return {
306
+ overall,
307
+ rating: ratingFromScore(overall),
308
+ audits,
309
+ };
310
+ }
311
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"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"}