agenr 0.9.21 → 0.9.23

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.
@@ -0,0 +1,241 @@
1
+ // src/utils/entry-utils.ts
2
+ var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
3
+ function toNumber(value) {
4
+ if (typeof value === "number") {
5
+ return value;
6
+ }
7
+ if (typeof value === "bigint") {
8
+ return Number(value);
9
+ }
10
+ if (typeof value === "string" && value.trim()) {
11
+ return Number(value);
12
+ }
13
+ return Number.NaN;
14
+ }
15
+ function toStringValue(value) {
16
+ if (typeof value === "string") {
17
+ return value;
18
+ }
19
+ if (typeof value === "number" || typeof value === "bigint") {
20
+ return String(value);
21
+ }
22
+ return "";
23
+ }
24
+ function toRowsAffected(value) {
25
+ if (typeof value === "number") {
26
+ return value;
27
+ }
28
+ if (typeof value === "bigint") {
29
+ return Number(value);
30
+ }
31
+ if (typeof value === "string" && value.trim().length > 0) {
32
+ return Number(value);
33
+ }
34
+ return 0;
35
+ }
36
+ function parseDaysBetween(now, pastIso) {
37
+ if (!pastIso) {
38
+ return 0;
39
+ }
40
+ const parsed = new Date(pastIso);
41
+ if (Number.isNaN(parsed.getTime())) {
42
+ return 0;
43
+ }
44
+ const delta = (now.getTime() - parsed.getTime()) / MILLISECONDS_PER_DAY;
45
+ if (!Number.isFinite(delta)) {
46
+ return 0;
47
+ }
48
+ return Math.max(delta, 0);
49
+ }
50
+
51
+ // src/db/co-recall.ts
52
+ var DEFAULT_EDGE_INCREMENT = 0.1;
53
+ var MAX_USED_ENTRIES = 20;
54
+ var MIN_EDGE_WEIGHT = 0.05;
55
+ var CO_RECALL_EDGE_TYPE = "co_recalled";
56
+ function normalizePair(a, b) {
57
+ return a < b ? [a, b] : [b, a];
58
+ }
59
+ async function strengthenCoRecallEdges(db, usedEntryIds, timestamp) {
60
+ const uniqueIds = Array.from(
61
+ new Set(
62
+ usedEntryIds.map((id) => id.trim()).filter((id) => id.length > 0)
63
+ )
64
+ ).slice(0, MAX_USED_ENTRIES);
65
+ if (uniqueIds.length < 2) {
66
+ return;
67
+ }
68
+ const now = timestamp || (/* @__PURE__ */ new Date()).toISOString();
69
+ const pairs = [];
70
+ for (let i = 0; i < uniqueIds.length; i += 1) {
71
+ const a = uniqueIds[i];
72
+ if (!a) {
73
+ continue;
74
+ }
75
+ for (let j = i + 1; j < uniqueIds.length; j += 1) {
76
+ const b = uniqueIds[j];
77
+ if (!b || a === b) {
78
+ continue;
79
+ }
80
+ pairs.push(normalizePair(a, b));
81
+ }
82
+ }
83
+ if (pairs.length === 0) {
84
+ return;
85
+ }
86
+ await db.execute("BEGIN");
87
+ try {
88
+ for (const [entryA, entryB] of pairs) {
89
+ await db.execute({
90
+ sql: `
91
+ INSERT INTO co_recall_edges (
92
+ entry_a, entry_b, edge_type, weight, session_count, last_co_recalled, created_at
93
+ )
94
+ VALUES (?, ?, ?, ?, 1, ?, ?)
95
+ ON CONFLICT
96
+ DO UPDATE SET
97
+ weight = MIN(co_recall_edges.weight + excluded.weight, 1.0),
98
+ session_count = co_recall_edges.session_count + 1,
99
+ last_co_recalled = excluded.last_co_recalled
100
+ `,
101
+ args: [
102
+ entryA,
103
+ entryB,
104
+ CO_RECALL_EDGE_TYPE,
105
+ DEFAULT_EDGE_INCREMENT,
106
+ now,
107
+ now
108
+ ]
109
+ });
110
+ }
111
+ await db.execute("COMMIT");
112
+ } catch (error) {
113
+ try {
114
+ await db.execute("ROLLBACK");
115
+ } catch {
116
+ }
117
+ throw error;
118
+ }
119
+ }
120
+ async function decayCoRecallEdges(db, decayFactor = 0.95) {
121
+ if (!Number.isFinite(decayFactor) || decayFactor < 0) {
122
+ throw new Error("decayFactor must be a finite number >= 0");
123
+ }
124
+ await db.execute("BEGIN");
125
+ try {
126
+ await db.execute({
127
+ sql: `
128
+ UPDATE co_recall_edges
129
+ SET weight = weight * ?
130
+ WHERE edge_type = ?
131
+ `,
132
+ args: [decayFactor, CO_RECALL_EDGE_TYPE]
133
+ });
134
+ const pruned = await db.execute({
135
+ sql: `
136
+ DELETE FROM co_recall_edges
137
+ WHERE edge_type = ?
138
+ AND weight < ?
139
+ `,
140
+ args: [CO_RECALL_EDGE_TYPE, MIN_EDGE_WEIGHT]
141
+ });
142
+ await db.execute("COMMIT");
143
+ return toRowsAffected(pruned.rowsAffected);
144
+ } catch (error) {
145
+ try {
146
+ await db.execute("ROLLBACK");
147
+ } catch {
148
+ }
149
+ throw error;
150
+ }
151
+ }
152
+ async function getCoRecallNeighbors(db, entryId, minWeight = 0.1, limit = 10) {
153
+ const normalizedId = entryId.trim();
154
+ if (!normalizedId) {
155
+ return [];
156
+ }
157
+ const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 10;
158
+ const safeMinWeight = Number.isFinite(minWeight) ? Math.max(minWeight, 0) : 0.1;
159
+ const result = await db.execute({
160
+ sql: `
161
+ SELECT
162
+ CASE WHEN entry_a = ? THEN entry_b ELSE entry_a END AS neighbor_id,
163
+ weight,
164
+ session_count,
165
+ last_co_recalled
166
+ FROM co_recall_edges
167
+ WHERE edge_type = ?
168
+ AND (entry_a = ? OR entry_b = ?)
169
+ AND weight >= ?
170
+ ORDER BY weight DESC, session_count DESC, last_co_recalled DESC
171
+ LIMIT ?
172
+ `,
173
+ args: [normalizedId, CO_RECALL_EDGE_TYPE, normalizedId, normalizedId, safeMinWeight, safeLimit]
174
+ });
175
+ return result.rows.map((row) => ({
176
+ entryId: toStringValue(row.neighbor_id),
177
+ weight: toNumber(row.weight),
178
+ sessionCount: toNumber(row.session_count),
179
+ lastCoRecalled: toStringValue(row.last_co_recalled)
180
+ }));
181
+ }
182
+ async function getCoRecallEdgeCounts(db) {
183
+ const result = await db.execute({
184
+ sql: `
185
+ SELECT entry_id, COUNT(*) AS edge_count
186
+ FROM (
187
+ SELECT entry_a AS entry_id
188
+ FROM co_recall_edges
189
+ WHERE edge_type = ?
190
+ UNION ALL
191
+ SELECT entry_b AS entry_id
192
+ FROM co_recall_edges
193
+ WHERE edge_type = ?
194
+ )
195
+ GROUP BY entry_id
196
+ `,
197
+ args: [CO_RECALL_EDGE_TYPE, CO_RECALL_EDGE_TYPE]
198
+ });
199
+ const counts = /* @__PURE__ */ new Map();
200
+ for (const row of result.rows) {
201
+ const entryId = toStringValue(row.entry_id).trim();
202
+ if (!entryId) {
203
+ continue;
204
+ }
205
+ counts.set(entryId, Math.max(0, toNumber(row.edge_count)));
206
+ }
207
+ return counts;
208
+ }
209
+ async function getTopCoRecallEdges(db, limit = 20) {
210
+ const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 20;
211
+ const result = await db.execute({
212
+ sql: `
213
+ SELECT entry_a, entry_b, weight, session_count, last_co_recalled
214
+ FROM co_recall_edges
215
+ WHERE edge_type = ?
216
+ ORDER BY weight DESC, session_count DESC, last_co_recalled DESC
217
+ LIMIT ?
218
+ `,
219
+ args: [CO_RECALL_EDGE_TYPE, safeLimit]
220
+ });
221
+ return result.rows.map((row) => ({
222
+ entryA: toStringValue(row.entry_a),
223
+ entryB: toStringValue(row.entry_b),
224
+ weight: toNumber(row.weight),
225
+ sessionCount: toNumber(row.session_count),
226
+ lastCoRecalled: toStringValue(row.last_co_recalled)
227
+ }));
228
+ }
229
+
230
+ export {
231
+ toNumber,
232
+ toStringValue,
233
+ toRowsAffected,
234
+ parseDaysBetween,
235
+ MAX_USED_ENTRIES,
236
+ strengthenCoRecallEdges,
237
+ decayCoRecallEdges,
238
+ getCoRecallNeighbors,
239
+ getCoRecallEdgeCounts,
240
+ getTopCoRecallEdges
241
+ };
package/dist/cli-main.js CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  describeAuth,
19
19
  dropFtsTriggersAndIndex,
20
20
  embed,
21
+ evolveQualityScores,
21
22
  getAuthMethodDefinition,
22
23
  getDb,
23
24
  getOldestPendingReviewCreatedAt,
@@ -49,14 +50,14 @@ import {
49
50
  setStoredCredential,
50
51
  walCheckpoint,
51
52
  writeConfig
52
- } from "./chunk-EY2VW6OI.js";
53
+ } from "./chunk-56GW7EIS.js";
53
54
  import {
54
55
  getCoRecallNeighbors,
55
56
  getTopCoRecallEdges,
56
57
  parseDaysBetween,
57
58
  toNumber,
58
59
  toStringValue
59
- } from "./chunk-QYZIPFIA.js";
60
+ } from "./chunk-RM5SLLEM.js";
60
61
 
61
62
  // src/cli-main.ts
62
63
  import fs37 from "fs/promises";
@@ -1527,6 +1528,49 @@ async function runDbCheckCommand(options, deps) {
1527
1528
  resolvedDeps.closeDbFn(db);
1528
1529
  }
1529
1530
  }
1531
+ async function runDbEvolveQualityCommand(options, deps) {
1532
+ const resolvedDeps = {
1533
+ readConfigFn: deps?.readConfigFn ?? readConfig,
1534
+ getDbFn: deps?.getDbFn ?? getDb,
1535
+ initDbFn: deps?.initDbFn ?? initDb,
1536
+ initSchemaFn: deps?.initSchemaFn ?? initSchema,
1537
+ closeDbFn: deps?.closeDbFn ?? closeDb,
1538
+ backupDbFn: deps?.backupDbFn ?? backupDb,
1539
+ resetDbFn: deps?.resetDbFn ?? resetDb
1540
+ };
1541
+ const dryRun = options.dryRun === true;
1542
+ const config = resolvedDeps.readConfigFn(process.env);
1543
+ const configured = resolveDbPathFromOptions(options.db, config?.db?.path);
1544
+ const db = resolvedDeps.getDbFn(configured);
1545
+ try {
1546
+ await resolvedDeps.initDbFn(db);
1547
+ const evolved = await evolveQualityScores(db, { dryRun });
1548
+ const summary = {
1549
+ updated: evolved.updated,
1550
+ dryRun,
1551
+ stats: evolved.stats
1552
+ };
1553
+ if (options.json) {
1554
+ process.stdout.write(`${JSON.stringify(summary, null, 2)}
1555
+ `);
1556
+ } else {
1557
+ process.stdout.write(
1558
+ `Updated ${summary.updated} entries. Avg quality: ${summary.stats.avgBefore.toFixed(2)} -> ${summary.stats.avgAfter.toFixed(2)}. High: ${summary.stats.high}, Medium: ${summary.stats.medium}, Low: ${summary.stats.low}
1559
+ `
1560
+ );
1561
+ if (dryRun) {
1562
+ process.stdout.write("Dry-run mode enabled - no changes were written.\n");
1563
+ }
1564
+ }
1565
+ return summary;
1566
+ } catch (error) {
1567
+ throw new Error(
1568
+ `Failed to evolve quality scores: ${error instanceof Error ? error.message : String(error)}`
1569
+ );
1570
+ } finally {
1571
+ resolvedDeps.closeDbFn(db);
1572
+ }
1573
+ }
1530
1574
 
1531
1575
  // src/commands/watcher.ts
1532
1576
  import { execFile, spawn } from "child_process";
@@ -19188,7 +19232,7 @@ async function runIngestCommand(inputPaths, options, deps) {
19188
19232
  try {
19189
19233
  const existingIds = await queue.runExclusive(() => getSourceEntryIds(db, target.file));
19190
19234
  if (existingIds.size >= 2) {
19191
- const { strengthenCoRecallEdges, MAX_USED_ENTRIES } = await import("./co-recall-IFMEHHZ2.js");
19235
+ const { strengthenCoRecallEdges, MAX_USED_ENTRIES } = await import("./co-recall-2UNFBE7S.js");
19192
19236
  const idArr = [...existingIds].slice(0, MAX_USED_ENTRIES);
19193
19237
  const expectedEdges = idArr.length * (idArr.length - 1) / 2;
19194
19238
  const edgeCount = await queue.runExclusive(async () => {
@@ -19366,7 +19410,7 @@ async function runIngestCommand(inputPaths, options, deps) {
19366
19410
  try {
19367
19411
  const fileEntryIds = await queue.runExclusive(() => getSourceEntryIds(db, target.file));
19368
19412
  if (fileEntryIds.size >= 2) {
19369
- const { strengthenCoRecallEdges } = await import("./co-recall-IFMEHHZ2.js");
19413
+ const { strengthenCoRecallEdges } = await import("./co-recall-2UNFBE7S.js");
19370
19414
  const edgeTimestamp = resolvedDeps.nowFn().toISOString();
19371
19415
  await queue.runExclusive(() => strengthenCoRecallEdges(db, [...fileEntryIds], edgeTimestamp));
19372
19416
  }
@@ -26238,6 +26282,10 @@ function createProgram() {
26238
26282
  const result = await runDbRebuildIndexCommand({ db: opts.db });
26239
26283
  process.exitCode = result.exitCode;
26240
26284
  });
26285
+ dbCommand.command("evolve-quality").description("Recompute quality scores from recall activity and co-recall graph signals").option("--db <path>", "Database path override").option("--dry-run", "Compute and print score changes without writing", false).option("--json", "Print machine-readable output", false).action(async (opts) => {
26286
+ await runDbEvolveQualityCommand({ db: opts.db, dryRun: opts.dryRun, json: opts.json });
26287
+ process.exitCode = 0;
26288
+ });
26241
26289
  program.command("setup").description("Interactive setup for provider/auth/task-model defaults").action(async () => {
26242
26290
  await runSetup(process.env);
26243
26291
  });
@@ -0,0 +1,16 @@
1
+ import {
2
+ MAX_USED_ENTRIES,
3
+ decayCoRecallEdges,
4
+ getCoRecallEdgeCounts,
5
+ getCoRecallNeighbors,
6
+ getTopCoRecallEdges,
7
+ strengthenCoRecallEdges
8
+ } from "./chunk-RM5SLLEM.js";
9
+ export {
10
+ MAX_USED_ENTRIES,
11
+ decayCoRecallEdges,
12
+ getCoRecallEdgeCounts,
13
+ getCoRecallNeighbors,
14
+ getTopCoRecallEdges,
15
+ strengthenCoRecallEdges
16
+ };