@dzhechkov/harness-core 0.3.103 → 0.3.105
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/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/recall-hook-policy.d.ts +99 -0
- package/dist/recall-hook-policy.d.ts.map +1 -0
- package/dist/recall-hook-policy.js +132 -0
- package/dist/recall-hook-policy.js.map +1 -0
- package/dist/recall-usage.d.ts +82 -0
- package/dist/recall-usage.d.ts.map +1 -0
- package/dist/recall-usage.js +283 -0
- package/dist/recall-usage.js.map +1 -0
- package/dist/statusline.d.ts +2 -0
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +23 -0
- package/dist/statusline.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +34 -0
- package/src/recall-hook-policy.ts +170 -0
- package/src/recall-usage.ts +373 -0
- package/src/statusline.ts +23 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure recall-usage accounting for the dz APPLY leg.
|
|
3
|
+
*
|
|
4
|
+
* The live hook writes one JSONL event when a learned pattern is actually injected into a prompt.
|
|
5
|
+
* This module parses that append-only log, folds it into per-pattern usage stats, and compacts it
|
|
6
|
+
* into aggregate JSONL rows when it crosses a bounded size. It deliberately knows nothing about the
|
|
7
|
+
* filesystem; callers own reads/writes so the hook and statusline can keep their never-block rules.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export const RECALL_USAGE_LOG_RELATIVE = '.dz/recall-usage.jsonl';
|
|
12
|
+
export const RECALL_USAGE_LOG_MAX_BYTES = 1_048_576;
|
|
13
|
+
export const RECALL_USAGE_COMPACT_TARGET_BYTES = Math.floor(RECALL_USAGE_LOG_MAX_BYTES * 0.75);
|
|
14
|
+
export function formatRecallUsageRecord(input) {
|
|
15
|
+
const rec = normalizeReadRecord(input);
|
|
16
|
+
return rec === undefined ? undefined : `${JSON.stringify(rec)}\n`;
|
|
17
|
+
}
|
|
18
|
+
export function parseRecallUsageLog(text) {
|
|
19
|
+
const records = [];
|
|
20
|
+
let invalidLines = 0;
|
|
21
|
+
for (const line of text.split('\n')) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (trimmed === '')
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(trimmed);
|
|
27
|
+
const record = normalizeRecord(parsed);
|
|
28
|
+
if (record === undefined) {
|
|
29
|
+
invalidLines += 1;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
records.push(record);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
invalidLines += 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { records, validLines: records.length, invalidLines };
|
|
40
|
+
}
|
|
41
|
+
export function aggregateRecallUsage(records) {
|
|
42
|
+
const byId = new Map();
|
|
43
|
+
for (const rec of records) {
|
|
44
|
+
if (isAggregate(rec)) {
|
|
45
|
+
mergeAggregate(byId, rec);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
mergeRead(byId, rec);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return [...byId.values()]
|
|
52
|
+
.map((a) => ({
|
|
53
|
+
dzId: a.dzId,
|
|
54
|
+
reads: a.reads,
|
|
55
|
+
firstReadAt: a.firstReadAt,
|
|
56
|
+
lastReadAt: a.lastReadAt,
|
|
57
|
+
maxScore: a.maxScore,
|
|
58
|
+
avgScore: a.totalScore / a.reads,
|
|
59
|
+
}))
|
|
60
|
+
.sort(compareStats);
|
|
61
|
+
}
|
|
62
|
+
export function buildRecallUsageReport(patterns, parsed) {
|
|
63
|
+
const stats = aggregateRecallUsage(parsed.records);
|
|
64
|
+
const statsById = new Map(stats.map((s) => [s.dzId, s]));
|
|
65
|
+
const patternIds = new Set();
|
|
66
|
+
const all = [];
|
|
67
|
+
for (const p of patterns) {
|
|
68
|
+
if (p.dzId.trim() === '')
|
|
69
|
+
continue;
|
|
70
|
+
if (patternIds.has(p.dzId))
|
|
71
|
+
continue;
|
|
72
|
+
patternIds.add(p.dzId);
|
|
73
|
+
const stat = statsById.get(p.dzId);
|
|
74
|
+
const base = patternRef(p);
|
|
75
|
+
if (stat === undefined) {
|
|
76
|
+
all.push({ ...base, reads: 0 });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
all.push({
|
|
80
|
+
...base,
|
|
81
|
+
reads: stat.reads,
|
|
82
|
+
firstReadAt: stat.firstReadAt,
|
|
83
|
+
lastReadAt: stat.lastReadAt,
|
|
84
|
+
maxScore: stat.maxScore,
|
|
85
|
+
avgScore: stat.avgScore,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const top = all.filter((r) => r.reads > 0).sort(compareRows);
|
|
90
|
+
const neverRead = all.filter((r) => r.reads === 0).sort((a, b) => a.dzId.localeCompare(b.dzId));
|
|
91
|
+
const unknown = stats.filter((s) => !patternIds.has(s.dzId)).sort(compareStats);
|
|
92
|
+
return {
|
|
93
|
+
totalPatterns: all.length,
|
|
94
|
+
usedPatterns: top.length,
|
|
95
|
+
neverReadPatterns: neverRead.length,
|
|
96
|
+
totalReads: stats.reduce((sum, s) => sum + s.reads, 0),
|
|
97
|
+
unknownReadPatterns: unknown.length,
|
|
98
|
+
invalidLines: parsed.invalidLines,
|
|
99
|
+
top,
|
|
100
|
+
neverRead,
|
|
101
|
+
unknown,
|
|
102
|
+
all: all.sort(compareRows),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function shouldCompactRecallUsageLogSize(sizeBytes, maxBytes = RECALL_USAGE_LOG_MAX_BYTES) {
|
|
106
|
+
return Number.isFinite(sizeBytes) && sizeBytes > validMax(maxBytes);
|
|
107
|
+
}
|
|
108
|
+
export function compactRecallUsageLog(text, opts = {}) {
|
|
109
|
+
const maxBytes = validMax(opts.maxBytes ?? RECALL_USAGE_LOG_MAX_BYTES);
|
|
110
|
+
const targetBytes = validTarget(opts.targetBytes ?? Math.floor(maxBytes * 0.75), maxBytes);
|
|
111
|
+
const compactedAt = validTs(opts.compactedAt) ? opts.compactedAt : new Date(0).toISOString();
|
|
112
|
+
const stats = aggregateRecallUsage(parseRecallUsageLog(text).records);
|
|
113
|
+
const lines = stats.map((s) => aggregateLine(s, compactedAt));
|
|
114
|
+
let out = joinLines(lines);
|
|
115
|
+
if (byteLength(out) <= maxBytes)
|
|
116
|
+
return out;
|
|
117
|
+
const kept = [];
|
|
118
|
+
let used = 0;
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const cost = byteLength(`${line}\n`);
|
|
121
|
+
if (kept.length > 0 && used + cost > targetBytes)
|
|
122
|
+
continue;
|
|
123
|
+
if (cost > maxBytes)
|
|
124
|
+
continue;
|
|
125
|
+
if (used + cost <= maxBytes) {
|
|
126
|
+
kept.push(line);
|
|
127
|
+
used += cost;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
out = joinLines(kept);
|
|
131
|
+
return byteLength(out) <= maxBytes ? out : '';
|
|
132
|
+
}
|
|
133
|
+
function normalizeRecord(value) {
|
|
134
|
+
if (!isRecord(value))
|
|
135
|
+
return undefined;
|
|
136
|
+
if (value['kind'] === 'aggregate')
|
|
137
|
+
return normalizeAggregateRecord(value);
|
|
138
|
+
return normalizeReadRecord(value);
|
|
139
|
+
}
|
|
140
|
+
function normalizeReadRecord(value) {
|
|
141
|
+
if (!isRecord(value))
|
|
142
|
+
return undefined;
|
|
143
|
+
const dzId = value['dzId'];
|
|
144
|
+
const score = value['score'];
|
|
145
|
+
const ts = value['ts'];
|
|
146
|
+
if (typeof dzId !== 'string' || dzId.trim() === '')
|
|
147
|
+
return undefined;
|
|
148
|
+
if (typeof score !== 'number' || !Number.isFinite(score))
|
|
149
|
+
return undefined;
|
|
150
|
+
if (!validTs(ts))
|
|
151
|
+
return undefined;
|
|
152
|
+
return { dzId: dzId.trim(), score, ts };
|
|
153
|
+
}
|
|
154
|
+
function normalizeAggregateRecord(value) {
|
|
155
|
+
const dzId = value['dzId'];
|
|
156
|
+
const reads = value['reads'];
|
|
157
|
+
const firstReadAt = value['firstReadAt'];
|
|
158
|
+
const lastReadAt = value['lastReadAt'];
|
|
159
|
+
const maxScore = value['maxScore'];
|
|
160
|
+
const totalScore = value['totalScore'];
|
|
161
|
+
const compactedAt = value['compactedAt'];
|
|
162
|
+
if (typeof dzId !== 'string' || dzId.trim() === '')
|
|
163
|
+
return undefined;
|
|
164
|
+
if (typeof reads !== 'number' || !Number.isInteger(reads) || reads <= 0)
|
|
165
|
+
return undefined;
|
|
166
|
+
if (!validTs(firstReadAt) || !validTs(lastReadAt) || !validTs(compactedAt))
|
|
167
|
+
return undefined;
|
|
168
|
+
if (typeof maxScore !== 'number' || !Number.isFinite(maxScore))
|
|
169
|
+
return undefined;
|
|
170
|
+
if (typeof totalScore !== 'number' || !Number.isFinite(totalScore))
|
|
171
|
+
return undefined;
|
|
172
|
+
return { kind: 'aggregate', dzId: dzId.trim(), reads, firstReadAt, lastReadAt, maxScore, totalScore, compactedAt };
|
|
173
|
+
}
|
|
174
|
+
function mergeRead(byId, rec) {
|
|
175
|
+
const ms = Date.parse(rec.ts);
|
|
176
|
+
const prev = byId.get(rec.dzId);
|
|
177
|
+
if (prev === undefined) {
|
|
178
|
+
byId.set(rec.dzId, {
|
|
179
|
+
dzId: rec.dzId,
|
|
180
|
+
reads: 1,
|
|
181
|
+
firstReadAt: rec.ts,
|
|
182
|
+
firstMs: ms,
|
|
183
|
+
lastReadAt: rec.ts,
|
|
184
|
+
lastMs: ms,
|
|
185
|
+
maxScore: rec.score,
|
|
186
|
+
totalScore: rec.score,
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
prev.reads += 1;
|
|
191
|
+
prev.totalScore += rec.score;
|
|
192
|
+
prev.maxScore = Math.max(prev.maxScore, rec.score);
|
|
193
|
+
if (ms < prev.firstMs) {
|
|
194
|
+
prev.firstMs = ms;
|
|
195
|
+
prev.firstReadAt = rec.ts;
|
|
196
|
+
}
|
|
197
|
+
if (ms >= prev.lastMs) {
|
|
198
|
+
prev.lastMs = ms;
|
|
199
|
+
prev.lastReadAt = rec.ts;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function mergeAggregate(byId, rec) {
|
|
203
|
+
const firstMs = Date.parse(rec.firstReadAt);
|
|
204
|
+
const lastMs = Date.parse(rec.lastReadAt);
|
|
205
|
+
const prev = byId.get(rec.dzId);
|
|
206
|
+
if (prev === undefined) {
|
|
207
|
+
byId.set(rec.dzId, {
|
|
208
|
+
dzId: rec.dzId,
|
|
209
|
+
reads: rec.reads,
|
|
210
|
+
firstReadAt: rec.firstReadAt,
|
|
211
|
+
firstMs,
|
|
212
|
+
lastReadAt: rec.lastReadAt,
|
|
213
|
+
lastMs,
|
|
214
|
+
maxScore: rec.maxScore,
|
|
215
|
+
totalScore: rec.totalScore,
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
prev.reads += rec.reads;
|
|
220
|
+
prev.totalScore += rec.totalScore;
|
|
221
|
+
prev.maxScore = Math.max(prev.maxScore, rec.maxScore);
|
|
222
|
+
if (firstMs < prev.firstMs) {
|
|
223
|
+
prev.firstMs = firstMs;
|
|
224
|
+
prev.firstReadAt = rec.firstReadAt;
|
|
225
|
+
}
|
|
226
|
+
if (lastMs >= prev.lastMs) {
|
|
227
|
+
prev.lastMs = lastMs;
|
|
228
|
+
prev.lastReadAt = rec.lastReadAt;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function aggregateLine(stat, compactedAt) {
|
|
232
|
+
const rec = {
|
|
233
|
+
kind: 'aggregate',
|
|
234
|
+
dzId: stat.dzId,
|
|
235
|
+
reads: stat.reads,
|
|
236
|
+
firstReadAt: stat.firstReadAt,
|
|
237
|
+
lastReadAt: stat.lastReadAt,
|
|
238
|
+
maxScore: stat.maxScore,
|
|
239
|
+
totalScore: stat.avgScore * stat.reads,
|
|
240
|
+
compactedAt,
|
|
241
|
+
};
|
|
242
|
+
return JSON.stringify(rec);
|
|
243
|
+
}
|
|
244
|
+
function patternRef(p) {
|
|
245
|
+
return {
|
|
246
|
+
dzId: p.dzId,
|
|
247
|
+
pattern: p.pattern,
|
|
248
|
+
...(p.domain !== undefined ? { domain: p.domain } : {}),
|
|
249
|
+
...(p.reward !== undefined ? { reward: p.reward } : {}),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function compareStats(a, b) {
|
|
253
|
+
return b.reads - a.reads || Date.parse(b.lastReadAt) - Date.parse(a.lastReadAt) || a.dzId.localeCompare(b.dzId);
|
|
254
|
+
}
|
|
255
|
+
function compareRows(a, b) {
|
|
256
|
+
const aLast = a.lastReadAt === undefined ? 0 : Date.parse(a.lastReadAt);
|
|
257
|
+
const bLast = b.lastReadAt === undefined ? 0 : Date.parse(b.lastReadAt);
|
|
258
|
+
return b.reads - a.reads || bLast - aLast || a.dzId.localeCompare(b.dzId);
|
|
259
|
+
}
|
|
260
|
+
function isAggregate(rec) {
|
|
261
|
+
return 'kind' in rec && rec.kind === 'aggregate';
|
|
262
|
+
}
|
|
263
|
+
function isRecord(value) {
|
|
264
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
265
|
+
}
|
|
266
|
+
function validTs(value) {
|
|
267
|
+
return typeof value === 'string' && value.trim() !== '' && !Number.isNaN(Date.parse(value));
|
|
268
|
+
}
|
|
269
|
+
function validMax(value) {
|
|
270
|
+
return Number.isFinite(value) && value > 0 ? Math.floor(value) : RECALL_USAGE_LOG_MAX_BYTES;
|
|
271
|
+
}
|
|
272
|
+
function validTarget(value, maxBytes) {
|
|
273
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
274
|
+
return Math.floor(maxBytes * 0.75);
|
|
275
|
+
return Math.min(Math.floor(value), maxBytes);
|
|
276
|
+
}
|
|
277
|
+
function joinLines(lines) {
|
|
278
|
+
return lines.length === 0 ? '' : `${lines.join('\n')}\n`;
|
|
279
|
+
}
|
|
280
|
+
function byteLength(text) {
|
|
281
|
+
return text.length;
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=recall-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall-usage.js","sourceRoot":"","sources":["../src/recall-usage.ts"],"names":[],"mappings":"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"}
|
package/dist/statusline.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface FeatureAdrState {
|
|
|
41
41
|
export interface StatuslineData {
|
|
42
42
|
/** Count of learned patterns in the project's unified memory store. */
|
|
43
43
|
readonly patterns: number;
|
|
44
|
+
/** Count of learned patterns that the live recall hook has actually injected at least once. */
|
|
45
|
+
readonly usedPatterns?: number;
|
|
44
46
|
/** Number of sources registered in the durable cross-project knowledge brain. */
|
|
45
47
|
readonly brainSources: number;
|
|
46
48
|
/** Hours since the last `dz consolidate` run, if a watermark is present. */
|
package/dist/statusline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusline.d.ts","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"statusline.d.ts","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,uFAAuF;IACvF,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;CACvC;AAYD,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AA8FD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,eAAe,GAAG,SAAS,CA0B9G;AAED,0FAA0F;AAC1F,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,yBAAyB,EAChC,GAAG,GAAE,MAAmB,GACvB,eAAe,GAAG,SAAS,CA0B7B;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,cAAc,CAyC5F"}
|
package/dist/statusline.js
CHANGED
|
@@ -17,6 +17,7 @@ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'no
|
|
|
17
17
|
import { dirname, join, resolve } from 'node:path';
|
|
18
18
|
import { createRequire } from 'node:module';
|
|
19
19
|
import { listBrain } from './brain.js';
|
|
20
|
+
import { RECALL_USAGE_LOG_RELATIVE, aggregateRecallUsage, parseRecallUsageLog } from './recall-usage.js';
|
|
20
21
|
/** Path of the SQLite pattern store (the Tier-3 backend). */
|
|
21
22
|
function sqlitePatternPath(projectRoot) {
|
|
22
23
|
return join(projectRoot, '.dz', 'memory', 'patterns.sqlite');
|
|
@@ -90,6 +91,20 @@ function countLearnedPatterns(projectRoot) {
|
|
|
90
91
|
}
|
|
91
92
|
return countJsonlPatternsReadonly(projectRoot);
|
|
92
93
|
}
|
|
94
|
+
function countUsedPatternsReadonly(projectRoot) {
|
|
95
|
+
const path = join(projectRoot, RECALL_USAGE_LOG_RELATIVE);
|
|
96
|
+
if (!existsSync(path))
|
|
97
|
+
return undefined;
|
|
98
|
+
try {
|
|
99
|
+
const parsed = parseRecallUsageLog(readFileSync(path, 'utf-8'));
|
|
100
|
+
if (parsed.records.length === 0)
|
|
101
|
+
return undefined;
|
|
102
|
+
return aggregateRecallUsage(parsed.records).length;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
93
108
|
/** Hours since the last consolidation, or `undefined` when never consolidated / unreadable. */
|
|
94
109
|
function consolidatedAgeHours(projectRoot, now) {
|
|
95
110
|
const path = consolidateWatermarkPath(projectRoot);
|
|
@@ -214,6 +229,13 @@ export function statuslineData(projectRoot, now = Date.now()) {
|
|
|
214
229
|
catch {
|
|
215
230
|
brainSources = 0;
|
|
216
231
|
}
|
|
232
|
+
let usedPatterns;
|
|
233
|
+
try {
|
|
234
|
+
usedPatterns = countUsedPatternsReadonly(root);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
usedPatterns = undefined;
|
|
238
|
+
}
|
|
217
239
|
const ageH = consolidatedAgeHours(root, now);
|
|
218
240
|
// Live /feature-adr panel — attached ONLY when a fresh run is in flight (readonly, never throws).
|
|
219
241
|
let featureAdr;
|
|
@@ -225,6 +247,7 @@ export function statuslineData(projectRoot, now = Date.now()) {
|
|
|
225
247
|
}
|
|
226
248
|
return {
|
|
227
249
|
patterns,
|
|
250
|
+
...(usedPatterns !== undefined ? { usedPatterns } : {}),
|
|
228
251
|
brainSources,
|
|
229
252
|
...(ageH !== undefined ? { consolidatedAgeH: ageH } : {}),
|
|
230
253
|
...(featureAdr !== undefined ? { featureAdr } : {}),
|
package/dist/statusline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusline.js","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"statusline.js","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.105",
|
|
4
4
|
"description": "Shared harness logic - skill loading, additive apply, and the init/sync/verify/doctor operations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"@dzhechkov/adapter-opencode": "^0.2.0",
|
|
32
32
|
"yaml": "^2.0.0",
|
|
33
33
|
"@dzhechkov/adapter-agents-md": "0.1.1",
|
|
34
|
-
"@dzhechkov/adapter-copilot": "0.1.1",
|
|
35
|
-
"@dzhechkov/core": "0.2.14",
|
|
36
34
|
"@dzhechkov/adapter-gemini": "0.1.1",
|
|
37
|
-
"@dzhechkov/adapter-
|
|
35
|
+
"@dzhechkov/adapter-copilot": "0.1.1",
|
|
38
36
|
"@dzhechkov/adapter-windsurf": "0.1.1",
|
|
37
|
+
"@dzhechkov/adapter-cursor": "0.1.1",
|
|
38
|
+
"@dzhechkov/core": "0.2.14",
|
|
39
39
|
"@dzhechkov/memory": "0.2.9"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
package/src/index.ts
CHANGED
|
@@ -125,6 +125,40 @@ export { hookDecision, isFenced, isNewLine, ESCAPE_TEACHING } from './claim-chec
|
|
|
125
125
|
export type { HookDecision, HookDecisionOpts } from './claim-check-hook-policy.js';
|
|
126
126
|
export { step8ClaimGate } from './feature-adr-claim-gate.js';
|
|
127
127
|
export type { Step8ClaimCounts, Step8ClaimGate } from './feature-adr-claim-gate.js';
|
|
128
|
+
export {
|
|
129
|
+
detectQueryLang,
|
|
130
|
+
relevanceFloorFor,
|
|
131
|
+
selectHookHits,
|
|
132
|
+
renderHookContext,
|
|
133
|
+
hasEnoughSignal,
|
|
134
|
+
DEFAULT_RECALL_FLOORS,
|
|
135
|
+
DEFAULT_RECALL_HOOK_LIMIT,
|
|
136
|
+
DEFAULT_RECALL_HOOK_BUDGET_CHARS,
|
|
137
|
+
MIN_PROMPT_CHARS,
|
|
138
|
+
MIN_CONTENT_TOKENS,
|
|
139
|
+
} from './recall-hook-policy.js';
|
|
140
|
+
export type { QueryLang, RecallFloors, HookCandidate, HookSelection } from './recall-hook-policy.js';
|
|
141
|
+
export {
|
|
142
|
+
RECALL_USAGE_LOG_RELATIVE,
|
|
143
|
+
RECALL_USAGE_LOG_MAX_BYTES,
|
|
144
|
+
RECALL_USAGE_COMPACT_TARGET_BYTES,
|
|
145
|
+
formatRecallUsageRecord,
|
|
146
|
+
parseRecallUsageLog,
|
|
147
|
+
aggregateRecallUsage,
|
|
148
|
+
buildRecallUsageReport,
|
|
149
|
+
shouldCompactRecallUsageLogSize,
|
|
150
|
+
compactRecallUsageLog,
|
|
151
|
+
} from './recall-usage.js';
|
|
152
|
+
export type {
|
|
153
|
+
RecallUsageReadRecord,
|
|
154
|
+
RecallUsageAggregateRecord,
|
|
155
|
+
RecallUsageRecord,
|
|
156
|
+
ParsedRecallUsageLog,
|
|
157
|
+
RecallUsageStat,
|
|
158
|
+
RecallPatternUsageRef,
|
|
159
|
+
RecallUsagePatternRow,
|
|
160
|
+
RecallUsageReport,
|
|
161
|
+
} from './recall-usage.js';
|
|
128
162
|
export { discoverPackages, publishPackages, bumpPatch, compareVersions, findUnpackagedSkills, orderByDependencies, syncReadmeVersion } from './publish.js';
|
|
129
163
|
export { fetchAllDownloads } from './downloads.js';
|
|
130
164
|
export type { PackageDownloads, DownloadsReport } from './downloads.js';
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure policy for the `dz recall` APPLY leg — the `UserPromptSubmit` hook that grounds a live prompt
|
|
3
|
+
* against the learned-pattern store.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a floor is the whole feature
|
|
6
|
+
*
|
|
7
|
+
* A store nobody reads is a write-only log; an apply-leg with no rank-leg is a noise generator. The
|
|
8
|
+
* sibling failure is live in this repo: agentic-qe's per-prompt hook injects the same five static
|
|
9
|
+
* guidance lines on every turn regardless of topic, and only 10 of its 198 stored patterns ever had
|
|
10
|
+
* `usage_count > 0`. Beating that means one thing above all: **emit nothing when nothing is relevant.**
|
|
11
|
+
*
|
|
12
|
+
* ## Where the numbers come from (MEASURED, not chosen by feel)
|
|
13
|
+
*
|
|
14
|
+
* Calibrated 2026-07-09 on a 32-probe labeled set (16 RU + 16 EN, half relevant / half irrelevant),
|
|
15
|
+
* embedded with `Xenova/paraphrase-multilingual-MiniLM-L12-v2` against the real 103-pattern store.
|
|
16
|
+
* Fixture: `test/fixtures/recall-floor-probes.json`; the dep-gated test re-derives the separation.
|
|
17
|
+
*
|
|
18
|
+
* - **Absolute max-cosine separates perfectly** — a single global floor of `0.353` classified all 32
|
|
19
|
+
* probes correctly. Per language the safe window widens: RU `min(relevant)=0.415`,
|
|
20
|
+
* `max(irrelevant)=0.337`; EN `min(relevant)=0.369`, `max(irrelevant)=0.254`.
|
|
21
|
+
* - **A z-score `(max − mean) / sd` FAILS** (69 % accuracy, negative margin). An off-topic query has a
|
|
22
|
+
* flat, low similarity profile, so its best hit stands out *relative to its own mean* — `"who won the
|
|
23
|
+
* world cup"` scored z = 3.60, higher than half the relevant probes. Distance from your own mean
|
|
24
|
+
* measures flatness, not relevance. This was the elegant idea; the data refuted it.
|
|
25
|
+
* - The language baseline shift is **real but survivable**: an irrelevant Russian query reaches 0.337
|
|
26
|
+
* where an irrelevant English one reaches 0.254. A single floor still works, with a thin 0.032
|
|
27
|
+
* margin; per-language floors triple it. Hence the defaults below.
|
|
28
|
+
*
|
|
29
|
+
* The turns that must stay silent do: `"спасибо"` scores 0.259, `"какой статус?"` 0.318 — both under
|
|
30
|
+
* every floor here.
|
|
31
|
+
*
|
|
32
|
+
* @packageDocumentation
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** Script family of a query — the only axis the floor is calibrated on. */
|
|
36
|
+
export type QueryLang = 'ru' | 'en';
|
|
37
|
+
|
|
38
|
+
/** Per-language relevance floors on the max cosine similarity, `[0,1]`. */
|
|
39
|
+
export interface RecallFloors {
|
|
40
|
+
readonly ru: number;
|
|
41
|
+
readonly en: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* MEASURED defaults. RU sits higher than EN because a multilingual encoder places any Cyrillic text
|
|
46
|
+
* slightly closer to any Latin text than two unrelated Latin texts are to each other — the baseline,
|
|
47
|
+
* not the signal, is what shifts.
|
|
48
|
+
*/
|
|
49
|
+
export const DEFAULT_RECALL_FLOORS: RecallFloors = { ru: 0.38, en: 0.31 };
|
|
50
|
+
|
|
51
|
+
/** Max hits injected into a turn. Three is the ADR default; more is noise, not context. */
|
|
52
|
+
export const DEFAULT_RECALL_HOOK_LIMIT = 3;
|
|
53
|
+
|
|
54
|
+
/** Rough character budget for the injected block (~4 chars/token; Cyrillic runs denser, so this is conservative). */
|
|
55
|
+
export const DEFAULT_RECALL_HOOK_BUDGET_CHARS = 1200;
|
|
56
|
+
|
|
57
|
+
const CYRILLIC = /[Ѐ-ӿ]/;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Which floor applies to this prompt. Cyrillic anywhere ⇒ `'ru'`: a mixed prompt such as
|
|
61
|
+
* `"почему codex барьер даёт ложный grade D"` carries the Russian baseline, so it must be judged by
|
|
62
|
+
* the stricter floor. Never throws — a non-string is `'en'`.
|
|
63
|
+
*/
|
|
64
|
+
export function detectQueryLang(text: unknown): QueryLang {
|
|
65
|
+
if (typeof text !== 'string') return 'en';
|
|
66
|
+
return CYRILLIC.test(text) ? 'ru' : 'en';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The floor for a prompt, given (possibly partial, possibly garbage) configured overrides. */
|
|
70
|
+
export function relevanceFloorFor(text: unknown, floors: Partial<RecallFloors> | undefined): number {
|
|
71
|
+
const lang = detectQueryLang(text);
|
|
72
|
+
const configured = floors?.[lang];
|
|
73
|
+
const valid = typeof configured === 'number' && isFinite(configured) && configured >= 0 && configured <= 1;
|
|
74
|
+
return valid ? configured : DEFAULT_RECALL_FLOORS[lang];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Below this many characters a prompt carries too little signal to judge. */
|
|
78
|
+
export const MIN_PROMPT_CHARS = 10;
|
|
79
|
+
/** …and it must contain at least this many content tokens (length ≥ 3). */
|
|
80
|
+
export const MIN_CONTENT_TOKENS = 2;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A prompt too short to judge. Found by dogfooding the live hook: `"тест"` and `"json"` cleared the
|
|
84
|
+
* cosine floor (0.43) purely because a one-word technical token is genuinely close to technical
|
|
85
|
+
* lessons — the similarity is real, the relevance is not. A floor cannot fix this; the query simply
|
|
86
|
+
* carries no intent. Never throws.
|
|
87
|
+
*/
|
|
88
|
+
export function hasEnoughSignal(text: unknown): boolean {
|
|
89
|
+
if (typeof text !== 'string') return false;
|
|
90
|
+
const t = text.trim();
|
|
91
|
+
if (t.length < MIN_PROMPT_CHARS) return false;
|
|
92
|
+
const tokens = t.split(/[^\p{L}\p{N}]+/u).filter((w) => w.length >= 3);
|
|
93
|
+
return tokens.length >= MIN_CONTENT_TOKENS;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** One ranked candidate from the recall engine. `score` is the relevance in `[0,1]`, NOT the reward. */
|
|
97
|
+
export interface HookCandidate {
|
|
98
|
+
/** Stable dz store id (`metadata.dzId` in the vector mirror), used only for usage accounting. */
|
|
99
|
+
readonly dzId?: string;
|
|
100
|
+
readonly pattern: string;
|
|
101
|
+
readonly score: number;
|
|
102
|
+
readonly domain?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface HookSelection {
|
|
106
|
+
readonly hits: readonly HookCandidate[];
|
|
107
|
+
/** The floor that was applied — reported so the hook's own output can explain its silence. */
|
|
108
|
+
readonly floor: number;
|
|
109
|
+
readonly lang: QueryLang;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Apply the floor, the limit and the character budget. Returns an EMPTY hit list whenever nothing
|
|
114
|
+
* clears the floor — the caller must then print nothing at all and exit 0. Pure, never throws:
|
|
115
|
+
* malformed candidates (missing/NaN score, empty text) are dropped rather than crashing a turn.
|
|
116
|
+
*/
|
|
117
|
+
export function selectHookHits(
|
|
118
|
+
prompt: unknown,
|
|
119
|
+
candidates: readonly HookCandidate[] | null | undefined,
|
|
120
|
+
opts: { floors?: Partial<RecallFloors>; limit?: number; budgetChars?: number } = {},
|
|
121
|
+
): HookSelection {
|
|
122
|
+
const lang = detectQueryLang(prompt);
|
|
123
|
+
const floor = relevanceFloorFor(prompt, opts.floors);
|
|
124
|
+
const limit = intOr(opts.limit, DEFAULT_RECALL_HOOK_LIMIT);
|
|
125
|
+
const budget = intOr(opts.budgetChars, DEFAULT_RECALL_HOOK_BUDGET_CHARS);
|
|
126
|
+
|
|
127
|
+
// A prompt with no intent gets no injection, whatever its cosine says.
|
|
128
|
+
if (!hasEnoughSignal(prompt)) return { hits: [], floor, lang };
|
|
129
|
+
|
|
130
|
+
const clean = (candidates ?? [])
|
|
131
|
+
.filter(
|
|
132
|
+
(c): c is HookCandidate =>
|
|
133
|
+
c !== null &&
|
|
134
|
+
typeof c === 'object' &&
|
|
135
|
+
(c.dzId === undefined || typeof c.dzId === 'string') &&
|
|
136
|
+
typeof c.pattern === 'string' &&
|
|
137
|
+
c.pattern.trim() !== '' &&
|
|
138
|
+
typeof c.score === 'number' &&
|
|
139
|
+
isFinite(c.score),
|
|
140
|
+
)
|
|
141
|
+
.filter((c) => c.score >= floor)
|
|
142
|
+
.sort((a, b) => b.score - a.score);
|
|
143
|
+
|
|
144
|
+
const hits: HookCandidate[] = [];
|
|
145
|
+
let used = 0;
|
|
146
|
+
for (const c of clean) {
|
|
147
|
+
if (hits.length >= limit) break;
|
|
148
|
+
const cost = c.pattern.length;
|
|
149
|
+
// Always admit the top hit even if it alone exceeds the budget — a truncated best lesson beats
|
|
150
|
+
// silence. Subsequent hits must fit.
|
|
151
|
+
if (hits.length > 0 && used + cost > budget) break;
|
|
152
|
+
hits.push(c);
|
|
153
|
+
used += cost;
|
|
154
|
+
}
|
|
155
|
+
return { hits, floor, lang };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function intOr(v: unknown, fallback: number): number {
|
|
159
|
+
return typeof v === 'number' && isFinite(v) && v > 0 ? Math.floor(v) : fallback;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Render the `additionalContext` block. Returns `''` when there is nothing to say — the caller emits
|
|
164
|
+
* NOTHING (not an empty JSON envelope) and exits 0, so an off-topic turn costs the reader zero tokens.
|
|
165
|
+
*/
|
|
166
|
+
export function renderHookContext(selection: HookSelection): string {
|
|
167
|
+
if (selection.hits.length === 0) return '';
|
|
168
|
+
const lines = selection.hits.map((h) => ` - [${h.score.toFixed(2)}${h.domain ? ` / ${h.domain}` : ''}] ${h.pattern}`);
|
|
169
|
+
return `Learned lessons that match this prompt (dz recall, relevance ≥ ${selection.floor.toFixed(2)}):\n${lines.join('\n')}`;
|
|
170
|
+
}
|