@pcircle/memesh 4.1.7 → 4.2.1

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 (131) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.de.md +48 -10
  4. package/README.es.md +82 -17
  5. package/README.fr.md +49 -11
  6. package/README.ja.md +83 -17
  7. package/README.ko.md +86 -20
  8. package/README.md +12 -7
  9. package/README.pt.md +48 -10
  10. package/README.th.md +46 -8
  11. package/README.vi.md +48 -10
  12. package/README.zh-CN.md +83 -17
  13. package/README.zh-TW.md +110 -44
  14. package/dashboard/dist/index.html +9 -9
  15. package/dist/cli/view-live.js +2 -2
  16. package/dist/cli/view.d.ts.map +1 -1
  17. package/dist/cli/view.js +15 -12
  18. package/dist/cli/view.js.map +1 -1
  19. package/dist/core/analytics.d.ts +17 -0
  20. package/dist/core/analytics.d.ts.map +1 -1
  21. package/dist/core/analytics.js +40 -0
  22. package/dist/core/analytics.js.map +1 -1
  23. package/dist/core/auto-tagger.d.ts +7 -2
  24. package/dist/core/auto-tagger.d.ts.map +1 -1
  25. package/dist/core/auto-tagger.js +12 -4
  26. package/dist/core/auto-tagger.js.map +1 -1
  27. package/dist/core/config.d.ts +2 -0
  28. package/dist/core/config.d.ts.map +1 -1
  29. package/dist/core/config.js +19 -11
  30. package/dist/core/config.js.map +1 -1
  31. package/dist/core/consolidator.d.ts.map +1 -1
  32. package/dist/core/consolidator.js +13 -4
  33. package/dist/core/consolidator.js.map +1 -1
  34. package/dist/core/digest-validator.d.ts +18 -0
  35. package/dist/core/digest-validator.d.ts.map +1 -0
  36. package/dist/core/digest-validator.js +79 -0
  37. package/dist/core/digest-validator.js.map +1 -0
  38. package/dist/core/doctor.d.ts.map +1 -1
  39. package/dist/core/doctor.js +28 -11
  40. package/dist/core/doctor.js.map +1 -1
  41. package/dist/core/dreamer.d.ts +8 -1
  42. package/dist/core/dreamer.d.ts.map +1 -1
  43. package/dist/core/dreamer.js +68 -14
  44. package/dist/core/dreamer.js.map +1 -1
  45. package/dist/core/embedder.d.ts.map +1 -1
  46. package/dist/core/embedder.js +2 -2
  47. package/dist/core/embedder.js.map +1 -1
  48. package/dist/core/extractor.d.ts.map +1 -1
  49. package/dist/core/extractor.js +2 -1
  50. package/dist/core/extractor.js.map +1 -1
  51. package/dist/core/failure-analyzer.d.ts +6 -1
  52. package/dist/core/failure-analyzer.d.ts.map +1 -1
  53. package/dist/core/failure-analyzer.js +10 -2
  54. package/dist/core/failure-analyzer.js.map +1 -1
  55. package/dist/core/install-hooks.d.ts.map +1 -1
  56. package/dist/core/install-hooks.js +1 -7
  57. package/dist/core/install-hooks.js.map +1 -1
  58. package/dist/core/install-id.d.ts.map +1 -1
  59. package/dist/core/install-id.js +2 -3
  60. package/dist/core/install-id.js.map +1 -1
  61. package/dist/core/kg-backfill.d.ts +39 -0
  62. package/dist/core/kg-backfill.d.ts.map +1 -0
  63. package/dist/core/kg-backfill.js +362 -0
  64. package/dist/core/kg-backfill.js.map +1 -0
  65. package/dist/core/llm-client.d.ts +13 -0
  66. package/dist/core/llm-client.d.ts.map +1 -1
  67. package/dist/core/llm-client.js +63 -3
  68. package/dist/core/llm-client.js.map +1 -1
  69. package/dist/core/llm-telemetry.d.ts +35 -0
  70. package/dist/core/llm-telemetry.d.ts.map +1 -0
  71. package/dist/core/llm-telemetry.js +96 -0
  72. package/dist/core/llm-telemetry.js.map +1 -0
  73. package/dist/core/llm-validator.d.ts.map +1 -1
  74. package/dist/core/llm-validator.js +3 -3
  75. package/dist/core/llm-validator.js.map +1 -1
  76. package/dist/core/operations.d.ts.map +1 -1
  77. package/dist/core/operations.js +4 -35
  78. package/dist/core/operations.js.map +1 -1
  79. package/dist/core/paths.d.ts +6 -0
  80. package/dist/core/paths.d.ts.map +1 -0
  81. package/dist/core/paths.js +27 -0
  82. package/dist/core/paths.js.map +1 -0
  83. package/dist/core/prompt-safety.d.ts.map +1 -1
  84. package/dist/core/prompt-safety.js.map +1 -1
  85. package/dist/core/scoring.d.ts +5 -0
  86. package/dist/core/scoring.d.ts.map +1 -1
  87. package/dist/core/scoring.js +8 -0
  88. package/dist/core/scoring.js.map +1 -1
  89. package/dist/core/serializer.js +1 -1
  90. package/dist/core/serializer.js.map +1 -1
  91. package/dist/core/skill-usage-log.js +2 -2
  92. package/dist/core/skill-usage-log.js.map +1 -1
  93. package/dist/core/types.d.ts +2 -2
  94. package/dist/core/types.d.ts.map +1 -1
  95. package/dist/core/verifier.d.ts.map +1 -1
  96. package/dist/core/verifier.js +4 -4
  97. package/dist/core/verifier.js.map +1 -1
  98. package/dist/core/version-check.d.ts.map +1 -1
  99. package/dist/core/version-check.js +4 -3
  100. package/dist/core/version-check.js.map +1 -1
  101. package/dist/db.d.ts.map +1 -1
  102. package/dist/db.js +71 -14
  103. package/dist/db.js.map +1 -1
  104. package/dist/knowledge-graph.d.ts +1 -1
  105. package/dist/knowledge-graph.d.ts.map +1 -1
  106. package/dist/knowledge-graph.js +1 -1
  107. package/dist/knowledge-graph.js.map +1 -1
  108. package/dist/skills-manifest.json +16 -16
  109. package/dist/storage/fts-index.js +1 -1
  110. package/dist/storage/fts-index.js.map +1 -1
  111. package/dist/transports/cli/cli.js +128 -6
  112. package/dist/transports/cli/cli.js.map +1 -1
  113. package/dist/transports/http/server.d.ts.map +1 -1
  114. package/dist/transports/http/server.js +204 -25
  115. package/dist/transports/http/server.js.map +1 -1
  116. package/dist/transports/mcp/handlers.d.ts +1 -1
  117. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  118. package/dist/transports/mcp/handlers.js +1 -1
  119. package/dist/transports/mcp/handlers.js.map +1 -1
  120. package/package.json +2 -2
  121. package/scripts/hooks/_shared.js +177 -14
  122. package/scripts/hooks/post-commit.js +50 -8
  123. package/scripts/hooks/pre-bash-orchestration-nudge.js +8 -3
  124. package/scripts/hooks/pre-compact.js +13 -16
  125. package/scripts/hooks/pre-edit-recall.js +28 -13
  126. package/scripts/hooks/session-start.js +194 -184
  127. package/scripts/hooks/session-summary.js +376 -41
  128. package/dist/core/query-expander.d.ts +0 -4
  129. package/dist/core/query-expander.d.ts.map +0 -1
  130. package/dist/core/query-expander.js +0 -53
  131. package/dist/core/query-expander.js.map +0 -1
@@ -0,0 +1,362 @@
1
+ import { getDatabase } from '../db.js';
2
+ const SYSTEM_TAG_PREFIXES = [
3
+ 'project:', 'week:', 'severity:', 'scope:', 'source:', 'date:',
4
+ 'type:', 'urgency:', 'host:', 'session:', 'release:',
5
+ ];
6
+ const SYSTEM_TAG_LITERALS = new Set([
7
+ 'session_end', 'auto_saved', 'commit', 'auto-tracked',
8
+ 'session-summary', 'session-insight', 'session_keypoint',
9
+ 'workflow_checkpoint', 'auto', 'auto-captured',
10
+ 'completed', 'plan-completion', 'lesson', 'verification',
11
+ 'engineering-judgment', 'reference', 'plan',
12
+ ]);
13
+ const DATE_TAG_RE = /^\d{4}-\d{2}-\d{2}/;
14
+ const NAME_STOPWORDS = new Set([
15
+ 'the', 'and', 'for', 'with', 'from', 'this', 'that', 'are', 'was', 'has',
16
+ 'fix', 'add', 'get', 'set', 'use', 'via', 'not', 'new', 'old', 'update',
17
+ 'into', 'onto', 'when', 'then', 'also', 'both', 'each', 'more', 'about',
18
+ 'best', 'practices', 'pattern', 'applied', 'standards', 'professional',
19
+ 'using', 'based', 'related', 'general', 'common', 'basic', 'simple',
20
+ 'verification', 'cleanup', 'refactoring', 'implementation', 'migration',
21
+ 'summary', 'overview', 'analysis', 'review', 'report', 'notes',
22
+ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec',
23
+ ]);
24
+ const NUMERIC_RE = /^\d+$/;
25
+ export function tokenizeName(name) {
26
+ return new Set(name.toLowerCase()
27
+ .split(/[\W_]+/)
28
+ .filter((t) => t.length >= 3 && !NAME_STOPWORDS.has(t) && !NUMERIC_RE.test(t)));
29
+ }
30
+ export function jaccardSimilarity(a, b) {
31
+ if (a.size === 0 || b.size === 0)
32
+ return 0;
33
+ let intersection = 0;
34
+ for (const t of a) {
35
+ if (b.has(t))
36
+ intersection++;
37
+ }
38
+ return intersection / (a.size + b.size - intersection);
39
+ }
40
+ export function isTopicalTag(tag) {
41
+ if (!tag)
42
+ return false;
43
+ const lower = tag.toLowerCase();
44
+ if (DATE_TAG_RE.test(lower))
45
+ return false;
46
+ if (SYSTEM_TAG_LITERALS.has(lower))
47
+ return false;
48
+ for (const prefix of SYSTEM_TAG_PREFIXES) {
49
+ if (lower.startsWith(prefix)) {
50
+ if (prefix === 'topic:' || prefix === 'tech:')
51
+ return true;
52
+ return false;
53
+ }
54
+ }
55
+ if (lower.length < 2)
56
+ return false;
57
+ return true;
58
+ }
59
+ export function backfillRelations(opts = {}, db) {
60
+ const conn = db ?? getDatabase();
61
+ const candidates = proposeBackfillCandidates(opts, conn);
62
+ const result = {
63
+ candidatesProposed: candidates.length,
64
+ edgesWritten: 0,
65
+ dryRun: !!opts.dryRun,
66
+ byRule: { tagCooccurrence: 0, projectClustering: 0, sessionCooccurrence: 0, nameTokenSimilarity: 0 },
67
+ };
68
+ if (opts.dryRun)
69
+ return result;
70
+ const insert = conn.prepare('INSERT OR IGNORE INTO relations (from_entity_id, to_entity_id, relation_type) VALUES (?, ?, ?)');
71
+ const tx = conn.transaction((rows) => {
72
+ for (const c of rows) {
73
+ const r = insert.run(c.fromEntityId, c.toEntityId, c.relationType);
74
+ if (r.changes > 0) {
75
+ result.edgesWritten++;
76
+ if (c.relationType === 'related-to')
77
+ result.byRule.tagCooccurrence++;
78
+ else if (c.relationType === 'belongs-to-project')
79
+ result.byRule.projectClustering++;
80
+ else if (c.relationType === 'co-created')
81
+ result.byRule.sessionCooccurrence++;
82
+ else if (c.relationType === 'shares-name-tokens')
83
+ result.byRule.nameTokenSimilarity++;
84
+ }
85
+ }
86
+ });
87
+ tx(candidates);
88
+ return result;
89
+ }
90
+ export function proposeBackfillCandidates(opts = {}, db) {
91
+ const conn = db ?? getDatabase();
92
+ const maxPerSource = opts.maxEdgesPerSource ?? 3;
93
+ const minShared = opts.minSharedTags ?? 2;
94
+ const statusFilter = opts.includeArchived ? "" : "AND e.status = 'active'";
95
+ const projectClause = opts.project ? "AND EXISTS (SELECT 1 FROM tags t2 WHERE t2.entity_id = e.id AND t2.tag = ?)" : "";
96
+ const projectArgs = opts.project ? [`project:${opts.project}`] : [];
97
+ const orphans = conn.prepare(`
98
+ SELECT e.id, e.name, e.type, e.metadata
99
+ FROM entities e
100
+ WHERE 1=1 ${statusFilter}
101
+ ${projectClause}
102
+ AND NOT EXISTS (SELECT 1 FROM relations r WHERE r.from_entity_id = e.id OR r.to_entity_id = e.id)
103
+ `).all(...projectArgs);
104
+ if (orphans.length === 0)
105
+ return [];
106
+ const allTagRows = conn.prepare(`
107
+ SELECT t.entity_id, t.tag
108
+ FROM tags t
109
+ JOIN entities e ON e.id = t.entity_id
110
+ WHERE 1=1 ${statusFilter}
111
+ `).all();
112
+ const tagsByEntity = new Map();
113
+ const entitiesByTag = new Map();
114
+ for (const row of allTagRows) {
115
+ if (!isTopicalTag(row.tag))
116
+ continue;
117
+ let set = tagsByEntity.get(row.entity_id);
118
+ if (!set) {
119
+ set = new Set();
120
+ tagsByEntity.set(row.entity_id, set);
121
+ }
122
+ set.add(row.tag);
123
+ let list = entitiesByTag.get(row.tag);
124
+ if (!list) {
125
+ list = [];
126
+ entitiesByTag.set(row.tag, list);
127
+ }
128
+ list.push(row.entity_id);
129
+ }
130
+ const candidates = [];
131
+ const orphanById = new Map();
132
+ for (const o of orphans)
133
+ orphanById.set(o.id, o);
134
+ const allEntities = conn.prepare(`SELECT e.id, e.name, e.type, e.metadata FROM entities e WHERE 1=1 ${statusFilter}`).all();
135
+ const entityById = new Map();
136
+ for (const e of allEntities)
137
+ entityById.set(e.id, e);
138
+ for (const orphan of orphans) {
139
+ const orphanTags = tagsByEntity.get(orphan.id);
140
+ if (!orphanTags || orphanTags.size < minShared)
141
+ continue;
142
+ const overlapByPeer = new Map();
143
+ for (const tag of orphanTags) {
144
+ const peerIds = entitiesByTag.get(tag) ?? [];
145
+ for (const peerId of peerIds) {
146
+ if (peerId === orphan.id)
147
+ continue;
148
+ overlapByPeer.set(peerId, (overlapByPeer.get(peerId) ?? 0) + 1);
149
+ }
150
+ }
151
+ const ranked = [...overlapByPeer.entries()]
152
+ .filter(([_, n]) => n >= minShared)
153
+ .sort((a, b) => b[1] - a[1])
154
+ .slice(0, maxPerSource);
155
+ for (const [peerId, sharedCount] of ranked) {
156
+ const peer = entityById.get(peerId);
157
+ if (!peer)
158
+ continue;
159
+ candidates.push({
160
+ fromEntityId: orphan.id,
161
+ fromName: orphan.name,
162
+ toEntityId: peer.id,
163
+ toName: peer.name,
164
+ relationType: 'related-to',
165
+ reason: `shares ${sharedCount} topical tag${sharedCount > 1 ? 's' : ''}`,
166
+ strength: sharedCount,
167
+ });
168
+ }
169
+ }
170
+ const consumerTypes = new Set(['lesson_learned', 'lesson', 'decision', 'bug_fix', 'pattern', 'mistake', 'best_practice']);
171
+ const anchorTypes = new Set(['release', 'feature', 'architecture', 'plan']);
172
+ const anchorsByProject = new Map();
173
+ const projectAnchorRows = conn.prepare(`
174
+ SELECT e.id, e.name, e.type, e.created_at, t.tag AS project_tag
175
+ FROM entities e
176
+ JOIN tags t ON t.entity_id = e.id AND t.tag LIKE 'project:%'
177
+ WHERE 1=1 ${statusFilter}
178
+ AND e.type IN (${[...anchorTypes].map(() => '?').join(',')})
179
+ `).all(...anchorTypes);
180
+ for (const r of projectAnchorRows) {
181
+ const project = r.project_tag.slice('project:'.length);
182
+ let list = anchorsByProject.get(project);
183
+ if (!list) {
184
+ list = [];
185
+ anchorsByProject.set(project, list);
186
+ }
187
+ list.push({ id: r.id, name: r.name, type: r.type, created_at: r.created_at });
188
+ }
189
+ for (const list of anchorsByProject.values()) {
190
+ list.sort((a, b) => b.created_at.localeCompare(a.created_at));
191
+ }
192
+ const orphanProjectRows = conn.prepare(`
193
+ SELECT t.entity_id, t.tag
194
+ FROM tags t
195
+ JOIN entities e ON e.id = t.entity_id
196
+ WHERE 1=1 ${statusFilter}
197
+ AND t.tag LIKE 'project:%'
198
+ AND NOT EXISTS (SELECT 1 FROM relations r WHERE r.from_entity_id = e.id OR r.to_entity_id = e.id)
199
+ `).all();
200
+ const orphanProject = new Map();
201
+ for (const r of orphanProjectRows)
202
+ orphanProject.set(r.entity_id, r.tag.slice('project:'.length));
203
+ for (const orphan of orphans) {
204
+ if (!consumerTypes.has(orphan.type))
205
+ continue;
206
+ const project = orphanProject.get(orphan.id);
207
+ if (!project)
208
+ continue;
209
+ const anchors = anchorsByProject.get(project);
210
+ if (!anchors || anchors.length === 0)
211
+ continue;
212
+ const anchor = anchors[0];
213
+ if (anchor.id === orphan.id)
214
+ continue;
215
+ candidates.push({
216
+ fromEntityId: orphan.id,
217
+ fromName: orphan.name,
218
+ toEntityId: anchor.id,
219
+ toName: anchor.name,
220
+ relationType: 'belongs-to-project',
221
+ reason: `same-project anchor (${anchor.type})`,
222
+ strength: 1,
223
+ });
224
+ }
225
+ if (opts.includeSessionCooccurrence) {
226
+ const minScore = opts.minSessionSignalScore ?? 0.6;
227
+ const sessionEligibleTypes = new Set([
228
+ 'lesson_learned', 'lesson', 'decision', 'architecture', 'architecture_decision',
229
+ 'plan', 'feature', 'bug_fix', 'pattern', 'best_practice', 'release',
230
+ ]);
231
+ const getSignalScore = (meta) => {
232
+ try {
233
+ const parsed = JSON.parse(meta ?? '{}');
234
+ const s = parsed?.signal_score;
235
+ return typeof s === 'number' ? s : 1.0;
236
+ }
237
+ catch {
238
+ return 1.0;
239
+ }
240
+ };
241
+ const sessionTagRows = conn.prepare(`
242
+ SELECT t.entity_id, t.tag
243
+ FROM tags t
244
+ JOIN entities e ON e.id = t.entity_id
245
+ WHERE 1=1 ${statusFilter}
246
+ AND t.tag LIKE 'session:%'
247
+ `).all();
248
+ const entitiesBySession = new Map();
249
+ for (const row of sessionTagRows) {
250
+ const ent = entityById.get(row.entity_id);
251
+ if (!ent || !sessionEligibleTypes.has(ent.type))
252
+ continue;
253
+ if (getSignalScore(ent.metadata) < minScore)
254
+ continue;
255
+ let list = entitiesBySession.get(row.tag);
256
+ if (!list) {
257
+ list = [];
258
+ entitiesBySession.set(row.tag, list);
259
+ }
260
+ list.push(row.entity_id);
261
+ }
262
+ const sessionTagsByOrphan = new Map();
263
+ for (const row of sessionTagRows) {
264
+ if (!orphanById.has(row.entity_id))
265
+ continue;
266
+ let list = sessionTagsByOrphan.get(row.entity_id);
267
+ if (!list) {
268
+ list = [];
269
+ sessionTagsByOrphan.set(row.entity_id, list);
270
+ }
271
+ list.push(row.tag);
272
+ }
273
+ for (const orphan of orphans) {
274
+ if (!sessionEligibleTypes.has(orphan.type))
275
+ continue;
276
+ if (getSignalScore(orphan.metadata) < minScore)
277
+ continue;
278
+ const sessionTags = sessionTagsByOrphan.get(orphan.id) ?? [];
279
+ let added = 0;
280
+ const proposedPeers = new Set();
281
+ for (const stag of sessionTags) {
282
+ const peers = (entitiesBySession.get(stag) ?? []).filter((id) => id !== orphan.id);
283
+ for (const peerId of peers) {
284
+ if (added >= maxPerSource)
285
+ break;
286
+ if (proposedPeers.has(peerId))
287
+ continue;
288
+ const peer = entityById.get(peerId);
289
+ if (!peer)
290
+ continue;
291
+ candidates.push({
292
+ fromEntityId: orphan.id,
293
+ fromName: orphan.name,
294
+ toEntityId: peer.id,
295
+ toName: peer.name,
296
+ relationType: 'co-created',
297
+ reason: `co-created in same session (${stag})`,
298
+ strength: 2,
299
+ });
300
+ proposedPeers.add(peerId);
301
+ added++;
302
+ }
303
+ if (added >= maxPerSource)
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ if (opts.includeNameTokenSimilarity) {
309
+ const minJaccard = opts.minNameJaccard ?? 0.50;
310
+ const minSharedTokens = opts.minSharedNameTokens ?? 3;
311
+ const tokensByEntity = new Map();
312
+ for (const e of allEntities) {
313
+ const tokens = tokenizeName(e.name);
314
+ if (tokens.size >= 2)
315
+ tokensByEntity.set(e.id, tokens);
316
+ }
317
+ const proposedNamePairs = new Set();
318
+ for (const orphan of orphans) {
319
+ const orphanTokens = tokensByEntity.get(orphan.id);
320
+ if (!orphanTokens)
321
+ continue;
322
+ const scored = [];
323
+ for (const [candidateId, candidateTokens] of tokensByEntity) {
324
+ if (candidateId === orphan.id)
325
+ continue;
326
+ const pairKey = `${Math.min(orphan.id, candidateId)}-${Math.max(orphan.id, candidateId)}`;
327
+ if (proposedNamePairs.has(pairKey))
328
+ continue;
329
+ let shared = 0;
330
+ for (const t of orphanTokens) {
331
+ if (candidateTokens.has(t))
332
+ shared++;
333
+ }
334
+ if (shared === 0)
335
+ continue;
336
+ const jaccard = jaccardSimilarity(orphanTokens, candidateTokens);
337
+ if (shared >= minSharedTokens || jaccard >= minJaccard) {
338
+ scored.push({ id: candidateId, shared, jaccard });
339
+ }
340
+ }
341
+ scored.sort((a, b) => b.shared - a.shared || b.jaccard - a.jaccard);
342
+ for (const { id: peerId, shared, jaccard } of scored.slice(0, maxPerSource)) {
343
+ const peer = entityById.get(peerId);
344
+ if (!peer)
345
+ continue;
346
+ const pairKey = `${Math.min(orphan.id, peerId)}-${Math.max(orphan.id, peerId)}`;
347
+ proposedNamePairs.add(pairKey);
348
+ candidates.push({
349
+ fromEntityId: orphan.id,
350
+ fromName: orphan.name,
351
+ toEntityId: peer.id,
352
+ toName: peer.name,
353
+ relationType: 'shares-name-tokens',
354
+ reason: `${shared} shared name token(s), Jaccard=${jaccard.toFixed(2)}`,
355
+ strength: shared,
356
+ });
357
+ }
358
+ }
359
+ }
360
+ return candidates;
361
+ }
362
+ //# sourceMappingURL=kg-backfill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kg-backfill.js","sourceRoot":"","sources":["../../src/core/kg-backfill.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,19 @@
1
1
  import type { LLMConfig } from './config.js';
2
+ export type LLMErrorClass = 'auth' | 'rate_limit' | 'upstream' | 'bad_request' | 'network' | 'unknown';
3
+ export interface LLMAttempt {
4
+ provider: LLMConfig['provider'];
5
+ model?: string;
6
+ status: 'ok' | 'fail';
7
+ latencyMs: number;
8
+ errorClass?: LLMErrorClass;
9
+ errorMessage?: string;
10
+ index: number;
11
+ }
2
12
  export interface CallLLMOptions {
3
13
  maxTokens?: number;
14
+ fallbacks?: LLMConfig[];
15
+ onAttempt?: (attempts: LLMAttempt[]) => void;
4
16
  }
5
17
  export declare function callLLM(prompt: string, config: LLMConfig, opts?: CallLLMOptions): Promise<string>;
18
+ export declare function classifyError(e: Error): LLMErrorClass;
6
19
  //# sourceMappingURL=llm-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/core/llm-client.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,WAAW,cAAc;IAE7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,CAiEjB"}
1
+ {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/core/llm-client.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,YAAY,GACZ,UAAU,GACV,aAAa,GACb,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IAEtB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,CAAC,EAAE,aAAa,CAAC;IAE3B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAE7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC;IAQxB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;CAC9C;AAoBD,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,CAqCjB;AA+ED,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,GAAG,aAAa,CAgBrD"}
@@ -1,9 +1,48 @@
1
1
  export async function callLLM(prompt, config, opts = {}) {
2
- const maxTokens = opts.maxTokens ?? 200;
2
+ const chain = [config, ...(opts.fallbacks ?? [])];
3
+ const attempts = [];
4
+ const reportAttempts = () => {
5
+ if (!opts.onAttempt)
6
+ return;
7
+ try {
8
+ opts.onAttempt(attempts);
9
+ }
10
+ catch { }
11
+ };
12
+ let lastErr = null;
13
+ for (let i = 0; i < chain.length; i++) {
14
+ const cfg = chain[i];
15
+ const t0 = Date.now();
16
+ try {
17
+ const text = await callSingle(prompt, cfg, opts.maxTokens ?? 200);
18
+ attempts.push({
19
+ provider: cfg.provider, model: cfg.model,
20
+ status: 'ok', latencyMs: Date.now() - t0, index: i,
21
+ });
22
+ reportAttempts();
23
+ return text;
24
+ }
25
+ catch (err) {
26
+ const e = err instanceof Error ? err : new Error(String(err));
27
+ const klass = classifyError(e);
28
+ attempts.push({
29
+ provider: cfg.provider, model: cfg.model,
30
+ status: 'fail', latencyMs: Date.now() - t0,
31
+ errorClass: klass, errorMessage: redactSecrets(e.message), index: i,
32
+ });
33
+ lastErr = e;
34
+ if (klass === 'bad_request')
35
+ break;
36
+ }
37
+ }
38
+ reportAttempts();
39
+ throw lastErr ?? new Error('callLLM: no providers configured');
40
+ }
41
+ async function callSingle(prompt, config, maxTokens) {
3
42
  if (config.provider === 'anthropic') {
4
43
  const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
5
44
  if (!apiKey)
6
- throw new Error('No API key');
45
+ throw new Error('Anthropic: no API key configured');
7
46
  const res = await fetch('https://api.anthropic.com/v1/messages', {
8
47
  method: 'POST',
9
48
  headers: {
@@ -25,7 +64,7 @@ export async function callLLM(prompt, config, opts = {}) {
25
64
  if (config.provider === 'openai') {
26
65
  const apiKey = config.apiKey || process.env.OPENAI_API_KEY;
27
66
  if (!apiKey)
28
- throw new Error('No API key');
67
+ throw new Error('OpenAI: no API key configured');
29
68
  const res = await fetch('https://api.openai.com/v1/chat/completions', {
30
69
  method: 'POST',
31
70
  headers: {
@@ -61,4 +100,25 @@ export async function callLLM(prompt, config, opts = {}) {
61
100
  }
62
101
  return '';
63
102
  }
103
+ export function classifyError(e) {
104
+ const msg = e.message;
105
+ if (/\b(401|403|invalid_api_key|authentication|x-api-key|unauthorized)\b/i.test(msg))
106
+ return 'auth';
107
+ if (/no API key/i.test(msg))
108
+ return 'auth';
109
+ if (/\b(429|rate.?limit|quota)\b/i.test(msg))
110
+ return 'rate_limit';
111
+ if (/\b(50[023]|service unavailable|bad gateway)\b/i.test(msg))
112
+ return 'upstream';
113
+ if (/\b400\b/.test(msg))
114
+ return 'bad_request';
115
+ if (/(ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|fetch failed|aborted)/i.test(msg))
116
+ return 'network';
117
+ return 'unknown';
118
+ }
119
+ function redactSecrets(msg) {
120
+ return msg
121
+ .replace(/sk-[A-Za-z0-9_-]{8,}/g, 'sk-<REDACTED>')
122
+ .replace(/Bearer\s+[A-Za-z0-9_.-]{8,}/gi, 'Bearer <REDACTED>');
123
+ }
64
124
  //# sourceMappingURL=llm-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-client.js","sourceRoot":"","sources":["../../src/core/llm-client.ts"],"names":[],"mappings":"AA8CA,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,MAAiB,EACjB,OAAuB,EAAE;IAEzB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC;IAExC,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,uCAAuC,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,MAAM;gBACnB,mBAAmB,EAAE,YAAY;gBACjC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,kBAAkB;gBACzC,UAAU,EAAE,SAAS;gBACrB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAuB,CAAC;QACnD,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QAC3D,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,4CAA4C,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,MAAM,EAAE;gBACnC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,aAAa;gBACpC,UAAU,EAAE,SAAS;gBACrB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAoB,CAAC;QAChD,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,wBAAwB,CAAC;QACjE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,eAAe,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,UAAU;gBACjC,MAAM;gBACN,MAAM,EAAE,KAAK;aAKd,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAoB,CAAC;QAChD,OAAO,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"llm-client.js","sourceRoot":"","sources":["../../src/core/llm-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { LLMAttempt } from './llm-client.js';
3
+ export interface RecordTelemetryOpts {
4
+ flow: string;
5
+ project?: string;
6
+ db?: Database.Database;
7
+ }
8
+ export declare function recordTelemetry(attempts: LLMAttempt[], opts: RecordTelemetryOpts): void;
9
+ export interface TelemetrySummary {
10
+ flow: string;
11
+ total_calls: number;
12
+ total_attempts: number;
13
+ successes: number;
14
+ failures: number;
15
+ fallback_used: number;
16
+ median_latency_ms: number | null;
17
+ by_provider: Record<string, {
18
+ ok: number;
19
+ fail: number;
20
+ }>;
21
+ by_error_class: Record<string, number>;
22
+ window_days: number;
23
+ }
24
+ export declare function summariseTelemetry(windowDays?: number, db?: Database.Database): TelemetrySummary[];
25
+ export interface PruneOptions {
26
+ olderThanDays?: number;
27
+ db?: Database.Database;
28
+ }
29
+ export interface PruneResult {
30
+ deletedRows: number;
31
+ cutoffIso: string;
32
+ totalRowsAfter: number;
33
+ }
34
+ export declare function pruneTelemetry(opts?: PruneOptions): PruneResult;
35
+ //# sourceMappingURL=llm-telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-telemetry.d.ts","sourceRoot":"","sources":["../../src/core/llm-telemetry.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,MAAM,WAAW,mBAAmB;IAElC,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACxB;AAcD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAyCvF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,wBAAgB,kBAAkB,CAAC,UAAU,SAAK,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAAG,gBAAgB,EAAE,CAkE9F;AAED,MAAM,WAAW,YAAY;IAE3B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAaD,wBAAgB,cAAc,CAAC,IAAI,GAAE,YAAiB,GAAG,WAAW,CAkBnE"}
@@ -0,0 +1,96 @@
1
+ import { getDatabase } from '../db.js';
2
+ export function recordTelemetry(attempts, opts) {
3
+ if (!attempts || attempts.length === 0)
4
+ return;
5
+ let db;
6
+ try {
7
+ db = opts.db ?? getDatabase();
8
+ }
9
+ catch {
10
+ return;
11
+ }
12
+ const stmt = db.prepare(`
13
+ INSERT INTO llm_telemetry (
14
+ flow, provider, model, project, attempt_index, status,
15
+ latency_ms, error_class, error_message, fallback_used
16
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
17
+ `);
18
+ const tx = db.transaction((rows) => {
19
+ for (const a of rows) {
20
+ try {
21
+ stmt.run(opts.flow, a.provider, a.model ?? null, opts.project ?? null, a.index, a.status, a.latencyMs, a.errorClass ?? null, a.errorMessage ?? null, a.index > 0 ? 1 : 0);
22
+ }
23
+ catch {
24
+ }
25
+ }
26
+ });
27
+ try {
28
+ tx(attempts);
29
+ }
30
+ catch { }
31
+ }
32
+ export function summariseTelemetry(windowDays = 30, db) {
33
+ const conn = db ?? getDatabase();
34
+ const since = new Date(Date.now() - windowDays * 86400000).toISOString();
35
+ const rows = conn.prepare(`
36
+ SELECT flow, provider, status, latency_ms, error_class, attempt_index, fallback_used
37
+ FROM llm_telemetry
38
+ WHERE ts >= ?
39
+ ORDER BY ts ASC
40
+ `).all(since);
41
+ const byFlow = new Map();
42
+ for (const r of rows) {
43
+ let bucket = byFlow.get(r.flow);
44
+ if (!bucket) {
45
+ bucket = { attempts: [], primaryAttempts: 0 };
46
+ byFlow.set(r.flow, bucket);
47
+ }
48
+ bucket.attempts.push(r);
49
+ if (r.attempt_index === 0)
50
+ bucket.primaryAttempts++;
51
+ }
52
+ const out = [];
53
+ for (const [flow, bucket] of byFlow) {
54
+ const successes = bucket.attempts.filter(a => a.status === 'ok').length;
55
+ const failures = bucket.attempts.filter(a => a.status === 'fail').length;
56
+ const fallbackUsed = bucket.attempts.filter(a => a.fallback_used === 1).length;
57
+ const okLatencies = bucket.attempts.filter(a => a.status === 'ok' && a.latency_ms != null).map(a => a.latency_ms).sort((a, b) => a - b);
58
+ const median = okLatencies.length === 0 ? null : okLatencies[Math.floor(okLatencies.length / 2)];
59
+ const byProvider = {};
60
+ for (const a of bucket.attempts) {
61
+ byProvider[a.provider] ??= { ok: 0, fail: 0 };
62
+ byProvider[a.provider][a.status === 'ok' ? 'ok' : 'fail']++;
63
+ }
64
+ const byErrorClass = {};
65
+ for (const a of bucket.attempts) {
66
+ if (a.error_class)
67
+ byErrorClass[a.error_class] = (byErrorClass[a.error_class] ?? 0) + 1;
68
+ }
69
+ out.push({
70
+ flow,
71
+ total_calls: bucket.primaryAttempts,
72
+ total_attempts: bucket.attempts.length,
73
+ successes,
74
+ failures,
75
+ fallback_used: fallbackUsed,
76
+ median_latency_ms: median,
77
+ by_provider: byProvider,
78
+ by_error_class: byErrorClass,
79
+ window_days: windowDays,
80
+ });
81
+ }
82
+ return out.sort((a, b) => b.total_attempts - a.total_attempts);
83
+ }
84
+ export function pruneTelemetry(opts = {}) {
85
+ const olderThanDays = opts.olderThanDays ?? 180;
86
+ const db = opts.db ?? getDatabase();
87
+ const cutoffIso = new Date(Date.now() - olderThanDays * 86400000).toISOString();
88
+ const result = db.prepare('DELETE FROM llm_telemetry WHERE ts < ?').run(cutoffIso);
89
+ const totalRowsAfter = db.prepare('SELECT COUNT(*) AS c FROM llm_telemetry').get().c;
90
+ return {
91
+ deletedRows: result.changes,
92
+ cutoffIso,
93
+ totalRowsAfter,
94
+ };
95
+ }
96
+ //# sourceMappingURL=llm-telemetry.js.map