@goodandready/dsh-context-lens 0.1.15 → 0.1.17
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/README.md +19 -5
- package/README.ru.md +19 -5
- package/README.zh.md +11 -1
- package/lib/ast/skeletonizer.js +31 -15
- package/lib/client.js +453 -142
- package/lib/index.js +36 -8
- package/lib/tokens/tracker.js +14 -6
- package/package.json +3 -1
package/lib/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export const Config = z.object({
|
|
|
13
13
|
tokenSavingsTracking: z.boolean().default(true).description('Track and display token budget savings'),
|
|
14
14
|
autoCompressThreshold: z.number().default(4000).description('Auto-compress threshold in chars (0 to disable)'),
|
|
15
15
|
budgetLimit: z.number().default(100000).description('Session token budget; compressions stop counting after this limit'),
|
|
16
|
+
budgetAlertPercent: z.number().default(90).description('Budget percentage threshold (50-99%) for warning alert'),
|
|
16
17
|
autoCollapse: z.boolean().default(true).description('Warn in UI when budget is nearly exhausted (does not force-close the settings card)')
|
|
17
18
|
});
|
|
18
19
|
|
|
@@ -37,6 +38,14 @@ function getFocus(key) {
|
|
|
37
38
|
return focusBySession.get(key);
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
function clearFocus(key) {
|
|
42
|
+
if (key) {
|
|
43
|
+
focusBySession.set(key, { paths: [], updatedAt: new Date().toISOString() });
|
|
44
|
+
} else {
|
|
45
|
+
focusBySession.clear();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
const OUTPUT_SCHEMA = { type: 'object', properties: { success: { type: 'boolean' } }, additionalProperties: true };
|
|
41
50
|
const renderOutput = (_args, result) => JSON.stringify(result, null, 2);
|
|
42
51
|
|
|
@@ -53,6 +62,7 @@ export function apply(ctx, config) {
|
|
|
53
62
|
const cfg = getConfig();
|
|
54
63
|
if (cfg && cfg.tokenSavingsTracking === false) return null;
|
|
55
64
|
if (cfg && typeof cfg.budgetLimit === 'number') tracker.setBudgetLimit(cfg.budgetLimit);
|
|
65
|
+
if (cfg && typeof cfg.budgetAlertPercent === 'number') tracker.setBudgetAlertPercent(cfg.budgetAlertPercent);
|
|
56
66
|
return tracker.record(original, compressed);
|
|
57
67
|
} catch {
|
|
58
68
|
// #39: never record on config/read errors
|
|
@@ -114,12 +124,12 @@ export function apply(ctx, config) {
|
|
|
114
124
|
|
|
115
125
|
ctx.tools.register({
|
|
116
126
|
name: 'context_lens_compress_code',
|
|
117
|
-
description: 'Generate AST skeleton for a large source file (JS/TS/Python/Go/Rust/Java) to save context',
|
|
127
|
+
description: 'Generate AST skeleton for a large source file (JS/TS/Python/Go/Rust/Java/C/C++/SQL) to save context',
|
|
118
128
|
parameters: {
|
|
119
129
|
type: 'object',
|
|
120
130
|
properties: {
|
|
121
131
|
code: { type: 'string', description: 'Source code to skeletonize' },
|
|
122
|
-
language: { type: 'string', enum: ['js', 'ts', 'py', 'python', 'go', 'rust', 'java'], description: 'Language hint' },
|
|
132
|
+
language: { type: 'string', enum: ['js', 'ts', 'py', 'python', 'go', 'rust', 'java', 'c', 'cpp', 'sql'], description: 'Language hint' },
|
|
123
133
|
maxDepth: { type: 'number', description: 'Max depth' },
|
|
124
134
|
filePath: { type: 'string', description: 'File path to check focus (if in focus, returns full code)' },
|
|
125
135
|
sessionId: { type: 'string', description: 'Session id for focus lookup' }
|
|
@@ -178,7 +188,8 @@ export function apply(ctx, config) {
|
|
|
178
188
|
execute: async (params, meta) => {
|
|
179
189
|
const cfg = getConfig();
|
|
180
190
|
if (typeof cfg.budgetLimit === 'number') tracker.setBudgetLimit(cfg.budgetLimit);
|
|
181
|
-
|
|
191
|
+
if (typeof cfg.budgetAlertPercent === 'number') tracker.setBudgetAlertPercent(cfg.budgetAlertPercent);
|
|
192
|
+
const stats = tracker.getStats(cfg.budgetLimit, cfg.budgetAlertPercent);
|
|
182
193
|
const history = tracker.getHistory();
|
|
183
194
|
const key = sessionKey(params || {}, meta);
|
|
184
195
|
return {
|
|
@@ -189,7 +200,8 @@ export function apply(ctx, config) {
|
|
|
189
200
|
autoCollapse: cfg.autoCollapse !== false,
|
|
190
201
|
focus: getFocus(key),
|
|
191
202
|
sessionId: key,
|
|
192
|
-
autoCompressThreshold: cfg.autoCompressThreshold
|
|
203
|
+
autoCompressThreshold: cfg.autoCompressThreshold,
|
|
204
|
+
budgetAlertPercent: cfg.budgetAlertPercent ?? 90
|
|
193
205
|
};
|
|
194
206
|
}
|
|
195
207
|
});
|
|
@@ -202,6 +214,7 @@ export function apply(ctx, config) {
|
|
|
202
214
|
handler: (req, res) => {
|
|
203
215
|
const cfg = getConfig();
|
|
204
216
|
if (typeof cfg.budgetLimit === 'number') tracker.setBudgetLimit(cfg.budgetLimit);
|
|
217
|
+
if (typeof cfg.budgetAlertPercent === 'number') tracker.setBudgetAlertPercent(cfg.budgetAlertPercent);
|
|
205
218
|
let sId = '__default__';
|
|
206
219
|
try {
|
|
207
220
|
const u = new URL(req.url, 'http://127.0.0.1');
|
|
@@ -211,7 +224,7 @@ export function apply(ctx, config) {
|
|
|
211
224
|
res.end(JSON.stringify({
|
|
212
225
|
ok: true,
|
|
213
226
|
plugin: 'dsh-context-lens',
|
|
214
|
-
stats: tracker.getStats(cfg.budgetLimit),
|
|
227
|
+
stats: tracker.getStats(cfg.budgetLimit, cfg.budgetAlertPercent),
|
|
215
228
|
history: tracker.getHistory(),
|
|
216
229
|
focus: getFocus(sId),
|
|
217
230
|
sessionId: sId
|
|
@@ -219,6 +232,23 @@ export function apply(ctx, config) {
|
|
|
219
232
|
}
|
|
220
233
|
}), 'dsh-context-lens status route');
|
|
221
234
|
|
|
235
|
+
// Quick clear-focus API route
|
|
236
|
+
ctx.effect(() => ctx.webServer.register({
|
|
237
|
+
kind: 'exact',
|
|
238
|
+
path: '/dsh-context-lens/clear-focus',
|
|
239
|
+
handler: async (req, res) => {
|
|
240
|
+
let sId = lastActiveSession || '__default__';
|
|
241
|
+
try {
|
|
242
|
+
const u = new URL(req.url, 'http://127.0.0.1');
|
|
243
|
+
const qId = u.searchParams.get('sessionId') || u.searchParams.get('session_id');
|
|
244
|
+
if (qId) sId = qId;
|
|
245
|
+
} catch {}
|
|
246
|
+
clearFocus(sId);
|
|
247
|
+
res.setHeader('content-type', 'application/json');
|
|
248
|
+
res.end(JSON.stringify({ ok: true, sessionId: sId, focus: getFocus(sId) }));
|
|
249
|
+
}
|
|
250
|
+
}), 'dsh-context-lens clear-focus route');
|
|
251
|
+
|
|
222
252
|
// #45: server-backed preview (same compressor as tools)
|
|
223
253
|
ctx.effect(() => ctx.webServer.register({
|
|
224
254
|
kind: 'exact',
|
|
@@ -242,6 +272,4 @@ export function apply(ctx, config) {
|
|
|
242
272
|
}
|
|
243
273
|
}), 'dsh-context-lens compress-preview route');
|
|
244
274
|
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export { compressLog, skeletonize, shouldAutoCompress };
|
|
275
|
+
}
|
package/lib/tokens/tracker.js
CHANGED
|
@@ -7,6 +7,7 @@ let calls = 0;
|
|
|
7
7
|
const history = []; // last 10
|
|
8
8
|
const MAX_HISTORY = 10;
|
|
9
9
|
let defaultBudgetLimit = 100000; // tokens
|
|
10
|
+
let defaultBudgetAlertPercent = 90; // threshold percent for low budget warning
|
|
10
11
|
|
|
11
12
|
export { estimateTokens };
|
|
12
13
|
|
|
@@ -16,6 +17,12 @@ export function setBudgetLimit(limit) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
export function setBudgetAlertPercent(percent) {
|
|
21
|
+
if (typeof percent === 'number' && percent >= 50 && percent <= 99) {
|
|
22
|
+
defaultBudgetAlertPercent = percent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
export function record(originalText, compressedText) {
|
|
20
27
|
const o = estimateTokens(originalText);
|
|
21
28
|
const c = estimateTokens(compressedText);
|
|
@@ -41,16 +48,19 @@ export function record(originalText, compressedText) {
|
|
|
41
48
|
return { originalTokens: o, compressedTokens: c, savedTokens: saved };
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
export function getStats(budgetLimitOverride) {
|
|
51
|
+
export function getStats(budgetLimitOverride, budgetAlertPercentOverride) {
|
|
45
52
|
const limit = (typeof budgetLimitOverride === 'number' && budgetLimitOverride > 0)
|
|
46
53
|
? budgetLimitOverride
|
|
47
54
|
: defaultBudgetLimit;
|
|
55
|
+
const alertPercent = (typeof budgetAlertPercentOverride === 'number' && budgetAlertPercentOverride >= 50 && budgetAlertPercentOverride <= 99)
|
|
56
|
+
? budgetAlertPercentOverride
|
|
57
|
+
: defaultBudgetAlertPercent;
|
|
48
58
|
const saved = Math.max(0, totalOriginal - totalCompressed);
|
|
49
59
|
const pct = totalOriginal ? Math.round((1 - totalCompressed / totalOriginal) * 100) : 0;
|
|
50
60
|
const budgetUsed = totalCompressed;
|
|
51
61
|
const budgetRemaining = Math.max(0, limit - budgetUsed);
|
|
52
62
|
const budgetPercent = Math.min(100, Math.round((budgetUsed / limit) * 100));
|
|
53
|
-
const lowBudget = budgetPercent
|
|
63
|
+
const lowBudget = budgetPercent >= alertPercent;
|
|
54
64
|
return {
|
|
55
65
|
totalOriginal,
|
|
56
66
|
totalCompressed,
|
|
@@ -62,6 +72,7 @@ export function getStats(budgetLimitOverride) {
|
|
|
62
72
|
budgetPercent,
|
|
63
73
|
lowBudget,
|
|
64
74
|
budgetLimit: limit,
|
|
75
|
+
budgetAlertPercent: alertPercent,
|
|
65
76
|
countingStopped: budgetUsed >= limit
|
|
66
77
|
};
|
|
67
78
|
}
|
|
@@ -79,7 +90,4 @@ export function reset() {
|
|
|
79
90
|
totalCompressed = 0;
|
|
80
91
|
calls = 0;
|
|
81
92
|
history.length = 0;
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export default { estimateTokens, setBudgetLimit, record, getStats, getHistory, clearHistory, reset };
|
|
93
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-context-lens",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "DSH plugin for AST context compression, test log filtering, and token budget guard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"lib/",
|
|
15
15
|
"cordis.patch.yml",
|
|
16
16
|
"README.md",
|
|
17
|
+
"README.zh.md",
|
|
18
|
+
"README.ru.md",
|
|
17
19
|
"LICENSE"
|
|
18
20
|
],
|
|
19
21
|
"scripts": {
|