@rigour-labs/core 5.4.0 → 5.5.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.
- package/dist/context/cache-engine.d.ts +25 -0
- package/dist/context/cache-engine.js +79 -1
- package/dist/context/cache-engine.test.js +37 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/settings.d.ts +15 -2
- package/dist/settings.js +56 -6
- package/dist/storage/context-telemetry.d.ts +8 -0
- package/dist/storage/context-telemetry.js +61 -0
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +1 -1
- package/package.json +6 -6
|
@@ -68,6 +68,31 @@ export declare function setComponentCache(componentName: string, commitSha: stri
|
|
|
68
68
|
export declare function normalizeQuery(query: string): string;
|
|
69
69
|
export declare function getSemanticQueryCache(query: string, commitSha: string, cwd?: string): Promise<SemanticQueryEntry | null>;
|
|
70
70
|
export declare function setSemanticQueryCache(query: string, commitSha: string, entry: SemanticQueryEntry, cwd?: string): Promise<void>;
|
|
71
|
+
/** Jaccard similarity of normalized query tokens — used for quality-safe partial reuse. */
|
|
72
|
+
export declare function queryTokenOverlap(a: string, b: string): number;
|
|
73
|
+
/**
|
|
74
|
+
* Distinctive tokens (len >= 5) must mostly agree — blocks "task service" ≈ "payment service".
|
|
75
|
+
*/
|
|
76
|
+
export declare function distinctiveTokenAgreement(a: string, b: string): number;
|
|
77
|
+
export interface RelatedSemanticHit {
|
|
78
|
+
entry: SemanticQueryEntry;
|
|
79
|
+
overlap: number;
|
|
80
|
+
sourceQuery: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Quality-safe partial semantic reuse: same commit only.
|
|
84
|
+
* Requires high Jaccard (>= 0.75) AND distinctive-token agreement (>= 0.67).
|
|
85
|
+
* Never crosses commits — avoids stale scopes after code moves.
|
|
86
|
+
* File existence is re-validated by the caller before serving.
|
|
87
|
+
*/
|
|
88
|
+
export declare function findRelatedSemanticQueryCache(query: string, commitSha: string, cwd?: string, minOverlap?: number, minDistinctive?: number): Promise<RelatedSemanticHit | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Drop cached scopes that point at files no longer on disk (quality guard).
|
|
91
|
+
*/
|
|
92
|
+
export declare function filterExistingEditScope(editScope: string[], cwd: string): Promise<{
|
|
93
|
+
valid: string[];
|
|
94
|
+
missing: string[];
|
|
95
|
+
}>;
|
|
71
96
|
/**
|
|
72
97
|
* Layer 4: Task Checkpoint Cache
|
|
73
98
|
*/
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* 4. Task checkpoint cache (Subagent handoff packets)
|
|
9
9
|
*/
|
|
10
10
|
import { createHash } from 'crypto';
|
|
11
|
-
import
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { setContextCacheRecord, getContextCacheRecord, listContextCacheRecords, recordCheckpointMetric } from '../storage/index.js';
|
|
12
14
|
/**
|
|
13
15
|
* Generate SHA-256 content hash.
|
|
14
16
|
*/
|
|
@@ -114,6 +116,82 @@ export async function setSemanticQueryCache(query, commitSha, entry, cwd) {
|
|
|
114
116
|
payloadTokens,
|
|
115
117
|
}, cwd);
|
|
116
118
|
}
|
|
119
|
+
function queryTokenSet(query) {
|
|
120
|
+
return new Set(normalizeQuery(query).split(' ').filter((t) => t.length > 1));
|
|
121
|
+
}
|
|
122
|
+
/** Jaccard similarity of normalized query tokens — used for quality-safe partial reuse. */
|
|
123
|
+
export function queryTokenOverlap(a, b) {
|
|
124
|
+
const left = queryTokenSet(a);
|
|
125
|
+
const right = queryTokenSet(b);
|
|
126
|
+
if (left.size === 0 || right.size === 0)
|
|
127
|
+
return 0;
|
|
128
|
+
let inter = 0;
|
|
129
|
+
for (const t of left) {
|
|
130
|
+
if (right.has(t))
|
|
131
|
+
inter++;
|
|
132
|
+
}
|
|
133
|
+
const union = left.size + right.size - inter;
|
|
134
|
+
return union === 0 ? 0 : inter / union;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Distinctive tokens (len >= 5) must mostly agree — blocks "task service" ≈ "payment service".
|
|
138
|
+
*/
|
|
139
|
+
export function distinctiveTokenAgreement(a, b) {
|
|
140
|
+
const left = [...queryTokenSet(a)].filter((t) => t.length >= 5);
|
|
141
|
+
const right = new Set([...queryTokenSet(b)].filter((t) => t.length >= 5));
|
|
142
|
+
if (left.length === 0 || right.size === 0)
|
|
143
|
+
return 0;
|
|
144
|
+
const hits = left.filter((t) => right.has(t)).length;
|
|
145
|
+
return hits / Math.max(left.length, right.size);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Quality-safe partial semantic reuse: same commit only.
|
|
149
|
+
* Requires high Jaccard (>= 0.75) AND distinctive-token agreement (>= 0.67).
|
|
150
|
+
* Never crosses commits — avoids stale scopes after code moves.
|
|
151
|
+
* File existence is re-validated by the caller before serving.
|
|
152
|
+
*/
|
|
153
|
+
export async function findRelatedSemanticQueryCache(query, commitSha, cwd, minOverlap = 0.75, minDistinctive = 0.67) {
|
|
154
|
+
const records = await listContextCacheRecords({ cacheType: 'semantic', commitSha, limit: 80 }, cwd);
|
|
155
|
+
let best = null;
|
|
156
|
+
for (const record of records) {
|
|
157
|
+
try {
|
|
158
|
+
const entry = JSON.parse(record.payloadJson);
|
|
159
|
+
const sourceQuery = entry.query || '';
|
|
160
|
+
const overlap = queryTokenOverlap(query, sourceQuery);
|
|
161
|
+
const distinctive = distinctiveTokenAgreement(query, sourceQuery);
|
|
162
|
+
if (overlap < minOverlap || distinctive < minDistinctive)
|
|
163
|
+
continue;
|
|
164
|
+
if (normalizeQuery(query) === normalizeQuery(sourceQuery))
|
|
165
|
+
continue; // exact path uses getSemanticQueryCache
|
|
166
|
+
if (!best || overlap > best.overlap) {
|
|
167
|
+
best = { entry, overlap, sourceQuery };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// skip bad payloads
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return best;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Drop cached scopes that point at files no longer on disk (quality guard).
|
|
178
|
+
*/
|
|
179
|
+
export async function filterExistingEditScope(editScope, cwd) {
|
|
180
|
+
const valid = [];
|
|
181
|
+
const missing = [];
|
|
182
|
+
for (const file of editScope) {
|
|
183
|
+
try {
|
|
184
|
+
if (await fs.pathExists(path.join(cwd, file)))
|
|
185
|
+
valid.push(file);
|
|
186
|
+
else
|
|
187
|
+
missing.push(file);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
missing.push(file);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return { valid, missing };
|
|
194
|
+
}
|
|
117
195
|
/**
|
|
118
196
|
* Layer 4: Task Checkpoint Cache
|
|
119
197
|
*/
|
|
@@ -8,7 +8,7 @@ vi.mock('./db.js', () => ({
|
|
|
8
8
|
DB_PATH: '/tmp/rigour-test.db',
|
|
9
9
|
RIGOUR_DIR: '/tmp/.rigour',
|
|
10
10
|
}));
|
|
11
|
-
import { getStaticCache, setStaticCache, getComponentCache, setComponentCache, getSemanticQueryCache, setSemanticQueryCache, getTaskCheckpointCache, setTaskCheckpointCache, hashContent, normalizeQuery } from './cache-engine.js';
|
|
11
|
+
import { getStaticCache, setStaticCache, getComponentCache, setComponentCache, getSemanticQueryCache, setSemanticQueryCache, findRelatedSemanticQueryCache, queryTokenOverlap, distinctiveTokenAgreement, filterExistingEditScope, getTaskCheckpointCache, setTaskCheckpointCache, hashContent, normalizeQuery } from './cache-engine.js';
|
|
12
12
|
describe('4-Layer Context Cache Engine', () => {
|
|
13
13
|
const testCwd = path.join(os.tmpdir(), `rigour-cache-test-${Date.now()}`);
|
|
14
14
|
beforeEach(async () => {
|
|
@@ -89,6 +89,42 @@ describe('4-Layer Context Cache Engine', () => {
|
|
|
89
89
|
expect(retrieved?.taskId).toBe('CTP-142');
|
|
90
90
|
expect(retrieved?.decisions).toContain('Added priority field');
|
|
91
91
|
});
|
|
92
|
+
it('Layer 3: finds related semantic queries at same commit for partial reuse', async () => {
|
|
93
|
+
expect(queryTokenOverlap('task priority persistence service', 'task priority persistence service layer')).toBeGreaterThan(0.7);
|
|
94
|
+
expect(distinctiveTokenAgreement('task service', 'payment service')).toBeLessThan(0.67);
|
|
95
|
+
await setSemanticQueryCache('task priority persistence service', 'commit-rel', {
|
|
96
|
+
query: 'task priority persistence service',
|
|
97
|
+
resolvedOwner: 'task-team',
|
|
98
|
+
editScope: ['services/task.ts'],
|
|
99
|
+
validationScope: ['npm test'],
|
|
100
|
+
evidence: ['related'],
|
|
101
|
+
commitSha: 'commit-rel',
|
|
102
|
+
confidence: 0.9,
|
|
103
|
+
}, testCwd);
|
|
104
|
+
const related = await findRelatedSemanticQueryCache('task priority persistence service layer', 'commit-rel', testCwd);
|
|
105
|
+
expect(related).not.toBeNull();
|
|
106
|
+
expect(related?.entry.editScope).toContain('services/task.ts');
|
|
107
|
+
// Same generic stem, different distinctive noun → reject
|
|
108
|
+
await setSemanticQueryCache('payment service billing', 'commit-rel', {
|
|
109
|
+
query: 'payment service billing',
|
|
110
|
+
resolvedOwner: 'pay',
|
|
111
|
+
editScope: ['services/pay.ts'],
|
|
112
|
+
validationScope: [],
|
|
113
|
+
evidence: [],
|
|
114
|
+
commitSha: 'commit-rel',
|
|
115
|
+
confidence: 0.9,
|
|
116
|
+
}, testCwd);
|
|
117
|
+
const crossDomain = await findRelatedSemanticQueryCache('task service billing', 'commit-rel', testCwd);
|
|
118
|
+
expect(crossDomain).toBeNull();
|
|
119
|
+
const otherCommit = await findRelatedSemanticQueryCache('task priority persistence service layer', 'commit-other', testCwd);
|
|
120
|
+
expect(otherCommit).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
it('filters missing edit-scope files for quality', async () => {
|
|
123
|
+
await fs.writeFile(path.join(testCwd, 'alive.ts'), 'export const ok = 1;\n');
|
|
124
|
+
const result = await filterExistingEditScope(['alive.ts', 'gone.ts'], testCwd);
|
|
125
|
+
expect(result.valid).toEqual(['alive.ts']);
|
|
126
|
+
expect(result.missing).toEqual(['gone.ts']);
|
|
127
|
+
});
|
|
92
128
|
it('Layer 1: invalidates static cache when file content changes', async () => {
|
|
93
129
|
const originalContent = 'export function processTask() { return true; }';
|
|
94
130
|
const entry = {
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export * from './utils/logger.js';
|
|
|
12
12
|
export { FileScanner } from './utils/scanner.js';
|
|
13
13
|
export * from './services/score-history.js';
|
|
14
14
|
export * from './hooks/index.js';
|
|
15
|
-
export { loadSettings, saveSettings, getSettingsPath, resolveDeepOptions, getProviderKey, getAgentConfig, getCliPreferences, updateProviderKey, removeProviderKey, getCursorApiKey, updateCursorApiKey } from './settings.js';
|
|
15
|
+
export { loadSettings, saveSettings, getSettingsPath, resolveDeepOptions, getProviderKey, getAgentConfig, getCliPreferences, updateProviderKey, removeProviderKey, getCursorApiKey, isCursorApiKeyConfigured, getCursorApiKeyHint, updateCursorApiKey, removeCursorApiKey, } from './settings.js';
|
|
16
16
|
export type { RigourSettings, ResolvedDeepOptions, CLIDeepOptions } from './settings.js';
|
|
17
17
|
export { DeepAnalysisGate } from './gates/deep-analysis.js';
|
|
18
18
|
export { createProvider } from './inference/index.js';
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ export { FileScanner } from './utils/scanner.js';
|
|
|
13
13
|
export * from './services/score-history.js';
|
|
14
14
|
export * from './hooks/index.js';
|
|
15
15
|
// Settings Module (Global user config at ~/.rigour/settings.json)
|
|
16
|
-
export { loadSettings, saveSettings, getSettingsPath, resolveDeepOptions, getProviderKey, getAgentConfig, getCliPreferences, updateProviderKey, removeProviderKey, getCursorApiKey, updateCursorApiKey } from './settings.js';
|
|
16
|
+
export { loadSettings, saveSettings, getSettingsPath, resolveDeepOptions, getProviderKey, getAgentConfig, getCliPreferences, updateProviderKey, removeProviderKey, getCursorApiKey, isCursorApiKeyConfigured, getCursorApiKeyHint, updateCursorApiKey, removeCursorApiKey, } from './settings.js';
|
|
17
17
|
// Deep Analysis Pipeline (v4.0+)
|
|
18
18
|
export { DeepAnalysisGate } from './gates/deep-analysis.js';
|
|
19
19
|
export { createProvider } from './inference/index.js';
|
package/dist/settings.d.ts
CHANGED
|
@@ -106,10 +106,23 @@ export declare function updateProviderKey(provider: string, apiKey: string): voi
|
|
|
106
106
|
*/
|
|
107
107
|
export declare function removeProviderKey(provider: string): void;
|
|
108
108
|
/**
|
|
109
|
-
* Get Cursor Admin API key
|
|
109
|
+
* Get Cursor Admin API key — prefer env over file-stored secret.
|
|
110
|
+
* Env: RIGOUR_CURSOR_API_KEY or CURSOR_ADMIN_API_KEY
|
|
110
111
|
*/
|
|
111
112
|
export declare function getCursorApiKey(): string | undefined;
|
|
112
113
|
/**
|
|
113
|
-
*
|
|
114
|
+
* Whether a Cursor vendor adapter key is available (env or file).
|
|
115
|
+
*/
|
|
116
|
+
export declare function isCursorApiKeyConfigured(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Last-4 hint for UI status — never return the full key.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getCursorApiKeyHint(): string | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Persist Cursor Admin API key to settings (optional; prefer env in production).
|
|
114
123
|
*/
|
|
115
124
|
export declare function updateCursorApiKey(apiKey: string): void;
|
|
125
|
+
/**
|
|
126
|
+
* Remove file-stored Cursor Admin API key (env vars are untouched).
|
|
127
|
+
*/
|
|
128
|
+
export declare function removeCursorApiKey(): void;
|
package/dist/settings.js
CHANGED
|
@@ -45,10 +45,22 @@ export function saveSettings(settings) {
|
|
|
45
45
|
const settingsPath = getSettingsPath();
|
|
46
46
|
const settingsDir = path.dirname(settingsPath);
|
|
47
47
|
try {
|
|
48
|
-
// Ensure directory exists
|
|
48
|
+
// Ensure directory exists with owner-only access
|
|
49
49
|
fs.ensureDirSync(settingsDir);
|
|
50
|
+
try {
|
|
51
|
+
fs.chmodSync(settingsDir, 0o700);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// ignore chmod failures on platforms that do not support it
|
|
55
|
+
}
|
|
50
56
|
// Write with pretty formatting (2-space indent)
|
|
51
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
57
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
58
|
+
try {
|
|
59
|
+
fs.chmodSync(settingsPath, 0o600);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// ignore chmod failures on platforms that do not support it
|
|
63
|
+
}
|
|
52
64
|
Logger.debug(`Settings saved to ${settingsPath}`);
|
|
53
65
|
}
|
|
54
66
|
catch (error) {
|
|
@@ -185,20 +197,58 @@ export function removeProviderKey(provider) {
|
|
|
185
197
|
}
|
|
186
198
|
}
|
|
187
199
|
/**
|
|
188
|
-
* Get Cursor Admin API key
|
|
200
|
+
* Get Cursor Admin API key — prefer env over file-stored secret.
|
|
201
|
+
* Env: RIGOUR_CURSOR_API_KEY or CURSOR_ADMIN_API_KEY
|
|
189
202
|
*/
|
|
190
203
|
export function getCursorApiKey() {
|
|
204
|
+
const fromEnv = process.env.RIGOUR_CURSOR_API_KEY?.trim() ||
|
|
205
|
+
process.env.CURSOR_ADMIN_API_KEY?.trim();
|
|
206
|
+
if (fromEnv)
|
|
207
|
+
return fromEnv;
|
|
191
208
|
const settings = loadSettings();
|
|
192
|
-
|
|
209
|
+
const fromFile = settings.cursor?.apiKey?.trim();
|
|
210
|
+
return fromFile || undefined;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Whether a Cursor vendor adapter key is available (env or file).
|
|
214
|
+
*/
|
|
215
|
+
export function isCursorApiKeyConfigured() {
|
|
216
|
+
return Boolean(getCursorApiKey());
|
|
193
217
|
}
|
|
194
218
|
/**
|
|
195
|
-
*
|
|
219
|
+
* Last-4 hint for UI status — never return the full key.
|
|
220
|
+
*/
|
|
221
|
+
export function getCursorApiKeyHint() {
|
|
222
|
+
const key = getCursorApiKey();
|
|
223
|
+
if (!key || key.length < 4)
|
|
224
|
+
return undefined;
|
|
225
|
+
return `••••${key.slice(-4)}`;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Persist Cursor Admin API key to settings (optional; prefer env in production).
|
|
196
229
|
*/
|
|
197
230
|
export function updateCursorApiKey(apiKey) {
|
|
231
|
+
const trimmed = apiKey.trim();
|
|
232
|
+
if (!trimmed || trimmed.length > 512) {
|
|
233
|
+
throw new Error('Invalid Cursor Admin API key');
|
|
234
|
+
}
|
|
198
235
|
const settings = loadSettings();
|
|
199
236
|
if (!settings.cursor) {
|
|
200
237
|
settings.cursor = {};
|
|
201
238
|
}
|
|
202
|
-
settings.cursor.apiKey =
|
|
239
|
+
settings.cursor.apiKey = trimmed;
|
|
203
240
|
saveSettings(settings);
|
|
204
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Remove file-stored Cursor Admin API key (env vars are untouched).
|
|
244
|
+
*/
|
|
245
|
+
export function removeCursorApiKey() {
|
|
246
|
+
const settings = loadSettings();
|
|
247
|
+
if (settings.cursor?.apiKey) {
|
|
248
|
+
delete settings.cursor.apiKey;
|
|
249
|
+
if (Object.keys(settings.cursor).length === 0) {
|
|
250
|
+
delete settings.cursor;
|
|
251
|
+
}
|
|
252
|
+
saveSettings(settings);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -62,6 +62,14 @@ export declare function recordModelUsage(usage: ModelUsage, cwd?: string): Promi
|
|
|
62
62
|
* Insert or update cache entry.
|
|
63
63
|
*/
|
|
64
64
|
export declare function setContextCacheRecord(record: ContextCacheRecord, cwd?: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* List cache records by type (and optional commit). Does not increment hit counts.
|
|
67
|
+
*/
|
|
68
|
+
export declare function listContextCacheRecords(opts: {
|
|
69
|
+
cacheType?: ContextCacheRecord['cacheType'];
|
|
70
|
+
commitSha?: string;
|
|
71
|
+
limit?: number;
|
|
72
|
+
}, cwd?: string): Promise<ContextCacheRecord[]>;
|
|
65
73
|
/**
|
|
66
74
|
* Fetch cached context record by cache key. Increments hit count.
|
|
67
75
|
*/
|
|
@@ -112,6 +112,67 @@ export async function setContextCacheRecord(record, cwd) {
|
|
|
112
112
|
cacheData[record.cacheKey] = { ...record, createdAt: timestamp };
|
|
113
113
|
await fs.writeJson(fallbackPath, cacheData, { spaces: 2 });
|
|
114
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* List cache records by type (and optional commit). Does not increment hit counts.
|
|
117
|
+
*/
|
|
118
|
+
export async function listContextCacheRecords(opts, cwd) {
|
|
119
|
+
const limit = opts.limit ?? 50;
|
|
120
|
+
if (isSQLiteAvailable()) {
|
|
121
|
+
try {
|
|
122
|
+
const db = await openDatabase();
|
|
123
|
+
if (db) {
|
|
124
|
+
const clauses = [];
|
|
125
|
+
const params = [];
|
|
126
|
+
if (opts.cacheType) {
|
|
127
|
+
clauses.push('cache_type = ?');
|
|
128
|
+
params.push(opts.cacheType);
|
|
129
|
+
}
|
|
130
|
+
if (opts.commitSha) {
|
|
131
|
+
clauses.push('commit_sha = ?');
|
|
132
|
+
params.push(opts.commitSha);
|
|
133
|
+
}
|
|
134
|
+
const where = clauses.length ? `WHERE ${clauses.join(' AND ')}` : '';
|
|
135
|
+
const rows = await db.all(`SELECT * FROM context_cache ${where} ORDER BY COALESCE(last_hit_at, created_at) DESC LIMIT ?`, ...params, limit);
|
|
136
|
+
await db.close();
|
|
137
|
+
return (rows || []).map((row) => ({
|
|
138
|
+
cacheKey: row.cache_key,
|
|
139
|
+
cacheType: row.cache_type,
|
|
140
|
+
repo: row.repo,
|
|
141
|
+
branch: row.branch,
|
|
142
|
+
commitSha: row.commit_sha,
|
|
143
|
+
dependencyFingerprint: row.dependency_fingerprint,
|
|
144
|
+
payloadJson: row.payload_json,
|
|
145
|
+
payloadTokens: row.payload_tokens,
|
|
146
|
+
hitCount: row.hit_count || 0,
|
|
147
|
+
createdAt: row.created_at,
|
|
148
|
+
lastHitAt: row.last_hit_at,
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// fallback
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const fallbackPath = path.join(getFallbackDir(cwd), 'context-cache.json');
|
|
157
|
+
if (!(await fs.pathExists(fallbackPath)))
|
|
158
|
+
return [];
|
|
159
|
+
try {
|
|
160
|
+
const cacheData = await fs.readJson(fallbackPath);
|
|
161
|
+
return Object.values(cacheData)
|
|
162
|
+
.filter((entry) => {
|
|
163
|
+
if (opts.cacheType && entry.cacheType !== opts.cacheType)
|
|
164
|
+
return false;
|
|
165
|
+
if (opts.commitSha && entry.commitSha !== opts.commitSha)
|
|
166
|
+
return false;
|
|
167
|
+
return true;
|
|
168
|
+
})
|
|
169
|
+
.sort((a, b) => (b.lastHitAt || b.createdAt || 0) - (a.lastHitAt || a.createdAt || 0))
|
|
170
|
+
.slice(0, limit);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
115
176
|
/**
|
|
116
177
|
* Fetch cached context record by cache key. Increments hit count.
|
|
117
178
|
*/
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ export { insertFindings, getFindingsForScan, getDeepFindings } from './findings.
|
|
|
9
9
|
export { reinforcePattern, decayPatterns, getStrongPatterns, getPatterns, getHardRules } from './patterns.js';
|
|
10
10
|
export { checkLocalPatterns, persistAndReinforce, getProjectStats } from './local-memory.js';
|
|
11
11
|
export type { ProjectStats } from './local-memory.js';
|
|
12
|
-
export { recordContextEvent, recordModelUsage, setContextCacheRecord, getContextCacheRecord, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics } from './context-telemetry.js';
|
|
12
|
+
export { recordContextEvent, recordModelUsage, setContextCacheRecord, getContextCacheRecord, listContextCacheRecords, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics } from './context-telemetry.js';
|
|
13
13
|
export type { ContextEvent, ModelUsage, ContextCacheRecord, CheckpointMetric } from './context-telemetry.js';
|
package/dist/storage/index.js
CHANGED
|
@@ -7,4 +7,4 @@ export { insertScan, getRecentScans, getScoreTrendFromDB, getTopIssues } from '.
|
|
|
7
7
|
export { insertFindings, getFindingsForScan, getDeepFindings } from './findings.js';
|
|
8
8
|
export { reinforcePattern, decayPatterns, getStrongPatterns, getPatterns, getHardRules } from './patterns.js';
|
|
9
9
|
export { checkLocalPatterns, persistAndReinforce, getProjectStats } from './local-memory.js';
|
|
10
|
-
export { recordContextEvent, recordModelUsage, setContextCacheRecord, getContextCacheRecord, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics } from './context-telemetry.js';
|
|
10
|
+
export { recordContextEvent, recordModelUsage, setContextCacheRecord, getContextCacheRecord, listContextCacheRecords, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics } from './context-telemetry.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "AI-native quality gate engine with local Bayesian learning. AST analysis, drift detection, Fix Packet generation, and agent self-healing across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://rigour.run",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"@xenova/transformers": "^2.17.2",
|
|
67
67
|
"sqlite3": "^5.1.7",
|
|
68
68
|
"openai": "^4.104.0",
|
|
69
|
-
"@rigour-labs/brain-darwin-arm64": "5.
|
|
70
|
-
"@rigour-labs/brain-darwin-x64": "5.
|
|
71
|
-
"@rigour-labs/brain-linux-
|
|
72
|
-
"@rigour-labs/brain-
|
|
73
|
-
"@rigour-labs/brain-
|
|
69
|
+
"@rigour-labs/brain-darwin-arm64": "5.5.0",
|
|
70
|
+
"@rigour-labs/brain-darwin-x64": "5.5.0",
|
|
71
|
+
"@rigour-labs/brain-linux-x64": "5.5.0",
|
|
72
|
+
"@rigour-labs/brain-win-x64": "5.5.0",
|
|
73
|
+
"@rigour-labs/brain-linux-arm64": "5.5.0"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@types/fs-extra": "^11.0.4",
|